Skip to content

HAR-9329 - fix pdfjs icons in final build - #410

Merged
harbournick merged 1 commit into
mainfrom
artem-HAR-9329
Mar 21, 2025
Merged

HAR-9329 - fix pdfjs icons in final build#410
harbournick merged 1 commit into
mainfrom
artem-HAR-9329

Conversation

@artem-harbour

Copy link
Copy Markdown
Contributor

No description provided.

@harbournick harbournick left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@harbournick
harbournick merged commit c69675f into main Mar 21, 2025
@harbournick
harbournick deleted the artem-HAR-9329 branch March 21, 2025 17:22
superdoc-bot Bot pushed a commit that referenced this pull request Jul 14, 2026
…teps/run tiers (#410)

* feat(sdk): custom-actions authoring kit β€” canonical ActionSpec with steps/run tiers (SD-3553/SD-3317)

Customers extend the core preset with their own named actions using only
installed packages: defineAction/extendPreset/composePreset (Node) and
define_action/extend_preset/compose_preset (Python), now public API.

- steps tier (recommended): declarative composition of built-in core actions
  with {{arg}} templating; inherits target resolution, receipts, verification
- run tier: native function in the caller's process with synthesized
  truth-telling receipts (pre/post revision, partialMutation, recovery)
- source tier kept internal (execute_code path), unadvertised pending the
  safety-flag work
- coherent excludeActions across tools/prompt/dispatch for custom presets
  (custom names handled by the wrapper, built-ins forwarded to the base)
- provider dialects fixed for vercel (flat inputSchema shape)
- cross-language parity enforced: templating text forms, defaults, receipt
  shapes, and a drift-guard test parsing Node's action registry
- build-superdoc-action agent skill (SKILL.md + live-verified example packs
  in Python and JavaScript) at packages/sdk/skills/, distributed via GitHub

Cross-reviewed by two independent models; all findings fixed and re-verified
(Node 297 tests, Python 38 kit tests + live smoke, e2e against the CLI host).

* fix(sdk): PR #410 review round β€” compose coherence, reserved names, defaults ordering

- includeCoreActions is now a dispatch boundary too: guessed/stale calls to
  built-ins outside the allowlist are refused (excludedBy: includeCoreActions)
- composed enum rebuild injects only ACTIVE custom names, so excludeActions
  naming a custom action can no longer leak it back into the enum
- shared splitCustomExclusions/throwExcludedAction helpers replace the
  duplicated wrapper logic in extendPreset/composePreset (both languages)
- custom action names may not shadow reserved tool names (superdoc_execute_code etc.)
- schema defaults are applied BEFORE validation, so required-with-default args
  are satisfiable by the default, as documented
- Python PresetDescriptor protocol declares exclude_actions on get_system_prompt
- examples: policy_pack.py explicit-null comments crash fixed (parity with the
  JS twin), table_borders.py encodes lineWeightPt > 0, SKILL.md notes pagination

* fix(sdk): compose allowlist narrows description/args natively; CI host-test guard

- includeCoreActions now derives an exclusion list forwarded to the base, so
  core narrows the enum, grouped description, AND advertised argument
  properties in one place β€” the hand-rolled filterAgentActionEnum/_filter_enum
  rebuilders are deleted (they narrowed only the enum, teaching the model
  actions the preset refuses)
- python tests that exercise the real core preset (host proxy) are marked
  requires_host and skip when no CLI binary is resolvable β€” fixes CI SDK
  validate on runners without the platform companion package
- rename vars -> arg_values in the python runners (shadowed builtin, Ruff A001)
- reserved-tool-names drift guard: python set verified against Node's
  AGENT_TOOL_NAMES catalog declaration

* fix(sdk): synthesize perform_action for custom-only presets

When the base preset drops superdoc_perform_action entirely (empty
includeCoreActions allowlist, or every built-in excluded), active custom
actions were advertised in the prompt and dispatchable β€” but carried by no
tool. Both wrappers now synthesize a provider-shaped custom-only definition
(enum + unioned args + description) so a curated custom-only preset stays
callable. Tests in both languages.

* fix(sdk): grammar in synthesized perform_action description (a action -> an action)

* fix(sdk): standalone presets do not route customs through perform_action

In standalone mode custom actions are advertised as their own provider tools,
so the perform_action route to them was an unadvertised-but-working path β€”
violating the advertised-surface == dispatchable-surface boundary this kit
enforces everywhere else. The route is now gated to merged mode; standalone
calls fall through to the base, which rejects the unknown action name.
Tests in both languages.

* fix(sdk): python enum validation treats explicit None as a value, not an absence

Node validates enum args whenever the key is present (explicit null is
rejected with a teaching error); the Python mirror's 'is not None' guard let
{'mode': None} through β€” and past schema defaults, which only fill MISSING
keys β€” handing the action a live None. Python now validates on key presence
(Node parity). Explicit-null rejection pinned by tests in both languages.

* refactor(sdk): drop source tier from the kit; move footnotes fixture to tests

The kit now exposes two execution tiers β€” steps (declarative) and run
(native). The in-host source tier (JS via superdoc_execute_code) is removed
until the code-act execution path ships with its safety envelope; one comment
in define.ts's module header records that rationale. Removes buildActionCode
+ runSourceAction (Node) and build_action_code + the source dispatch branch +
dead _map_receipt (Python), and the source-specific tests.

The footnotes pack was only ever a test fixture but lived in src/actions/ and
shipped in dist. It's now a run-tier fixture under __tests__/fixtures (Node)
and tests/ (Python), so it no longer ships; the unit + e2e/smoke suites import
it from the new location.

Also strips SD-xxxx ticket numbers from code comments.

Verified: Node 299 tests + tsc + build + e2e; Python custom-actions 42 + smoke;
run-tier footnotes exercised against the real CLI host.

* fix(sdk): keep an action-named argument in standalone custom actions

runCustomAction stripped the 'action' key unconditionally, but that key is the
superdoc_perform_action discriminator ONLY on the merged route. A standalone
custom action is its own tool, where 'action' can be a legitimate declared
argument β€” stripping it dropped the value before defaults/validation, so the
tool advertised as callable then failed or ran with the arg missing. The strip
now happens only on the perform_action route (both languages); tests pin a
standalone action whose schema requires an 'action' argument.

* fix(sdk): narrow the composed tool catalog with includeCoreActions

getTools and getSystemPrompt already narrow the superdoc_perform_action enum
to the includeCoreActions allowlist, but getCatalog returned the base's full
surface β€” so getToolCatalog(composedPreset) reported built-in actions the
preset's enum, prompt, and dispatch all refuse. The catalog's perform_action
row now narrows the same way (both languages); tests assert an out-of-allowlist
built-in is absent from the composed catalog.

* refactor(sdk): rename skill to superdoc-custom-actions; async + cleanup + preset-name guidance

Rename build-superdoc-action -> superdoc-custom-actions (folder + frontmatter),
matching the vendor-prefixed, domain-noun convention (Anthropic authoring
guidance + marketplace practice); groups with future SuperDoc skills and reads
clearly as an install id.

Also folds in skill-content fixes validated by live customer-simulation runs:
- async run-tier guidance: an app on AsyncSuperDocClient / dispatch_async needs
  an  run that awaits every doc.* call (a sync body yields
  'coroutine' object is not subscriptable) β€” Β§1 async example + Β§6 pitfall
- 'clean up when you finish' step: remove verification scratch (opened/saved
  .docx, .superdoc-state/.superdoc-cli-state, out.docx, test __pycache__),
  keeping the app's real sample docs
- default extended-preset id is custom_superdoc_preset (not a codename), in the
  Β§2 instruction and every example

* fix(sdk): narrow composed catalog row beyond the enum (Node + Python)

composePreset / compose_preset get_catalog narrowed only the
superdoc_perform_action action enum while spreading the base row's full
description and every action's argument properties. With includeCoreActions
the enum, system prompt, and dispatch all narrowed, but getToolCatalog()
still advertised inputs (e.g. create_table's rows/columns) for actions the
preset refuses β€” breaking the "advertised == dispatchable" invariant for
catalog-driven UIs/validators.

Rebuild the catalog's perform_action row from the SAME narrowing getTools
drives, so enum, description, and argument properties shrink together with
one implementation (no second copy to drift):
- Node: export buildPerformActionDefinition and build the row from the
  included built-ins (canonical ACTION_NAMES_LIST order).
- Python: source the row from the base's own get_tools(exclude_actions=...)
  (the host builder); when every built-in is excluded the host drops the
  tool, so drop the catalog row too (custom actions stay their own rows).

Tests: strengthen the catalog-narrowing tests to assert args + description
narrow, not just the enum, and add a no-custom case asserting the catalog
row equals the advertised getTools tool. Node 43/43 (bun), Python 45/45.

Addresses PR #410 review comment (narrow composed catalog schemas beyond enum).

* fix(sdk): don't inherit surface exclusions into custom steps (Node + Python)

A steps-tier custom action composes built-in actions. When a toolkit hides a
built-in via excludeActions (to stop the model calling it directly) but still
advertises a custom action whose steps compose that built-in, the surface
exclusion was forwarded into the internal step dispatch β€” core's
defense-in-depth then refused the step, so the advertised custom action
returned a failed receipt.

Surface exclusions govern the MODEL's direct calls (enforced at the top-level
dispatch), not an author's curated composition. Strip them before internal
step dispatch:
- Node: runStepsAction strips excludeActions from invokeOptions.
- Python: _run_steps_action(_async) no longer forwards exclude_actions into the
  base step dispatch; the now-dead param is dropped from _run_custom_action too.

The top-level guard is unchanged: a direct model call to the hidden built-in is
still refused. Regression tests in both languages assert (a) an advertised
steps action composing an excluded built-in still succeeds, (b) internal steps
receive no exclusions, and (c) a direct call to the hidden built-in is refused.
Verified: Node 44/44 + e2e 2/2, Python 46/46 + smoke.

Addresses PR #410 review comment (do not pass surface exclusions into custom steps).

* feat(sdk): one-call createAgentToolkit({actions}) + custom-actions hardening

createAgentToolkit / create_agent_toolkit now accept `actions` (plus optional
`base` / `includeCoreActions`) and build an ephemeral extended preset
internally β€” custom actions with no registerPreset and no preset id to thread
through dispatch. The advanced extendPreset / composePreset + `preset` path
still works unchanged.

Hardening from review + live QA:
- type the run() doc handle (BoundDocApi) instead of unknown
- reject Zod / non-JSON-Schema `input` with a clear error instead of silently
  dropping its types
- reject conflicting arg names, but only on incompatible type/enum β€” a shared
  built-in arg name with an extra description/default is allowed; the compare
  is order-insensitive
- authoring skill: teach the one-call path as primary (register/extend demoted
  to an advanced fallback), add a flat dispatch example and the run-tier
  failed-receipt shape, add a shared-arg-name pitfall; fix the reference_pack
  occurrence falsy-zero bug and an example list-key typo

Tests: Node 51 unit + 2 e2e, Python 51 unit + smoke. Verified end-to-end in the
async collaborative demo app.

Claude-Session: https://claude.ai/code/session_01SraPwksmphffxhhY6Mp9iL

* fix(sdk): snapshot custom-action arrays so the preset surface stays immutable

extendPreset/composePreset aliased the caller's `actions` array β€” getTools read
it live while the byName dispatch map was snapshotted at construction, so
mutating the array afterward (hot-reload / action discovery) desynced the
advertised surface from the dispatchable one. Copy the array at construction,
matching Python (which already snapshots via list()/tuple()).

Node-only; Python was already immune. Regression test: mutating the caller's
array after build leaves the advertised surface unchanged. Node 52, Python 51.

Claude-Session: https://claude.ai/code/session_01SraPwksmphffxhhY6Mp9iL

* fix(sdk): tighten arg-conflict check; Python provider validation + parity; dispatch tests

Review follow-ups on the custom-actions kit:

- Arg-name conflict check now flags ANY structural difference, not just
  type/enum: a differing default, limit, pattern, nested shape, and the
  one-sided-enum case all conflict. Only documentation (description / title /
  examples / $comment) may differ, so reusing a built-in arg name with your own
  description still works. Node + Python.
- Python: restore up-front provider validation in the one-call `actions` path
  (it was building tools without the check `choose_tools` does), and align
  input-schema handling with Node (wrap a bare properties bag).
- Tests: run a custom action through the toolkit's RETURNED dispatch (Node e2e
  + Python), plus one-sided-enum-rejected and description-only-allowed cases.
- Skill: reference_pack `caseSensitive` drops its default to match the built-in
  arg; the section 6 pitfall documents the stricter shared-arg rule.

Node 53 unit + 3 e2e, Python 53.

Claude-Session: https://claude.ai/code/session_01SraPwksmphffxhhY6Mp9iL

* fix(sdk): guard custom-action inputSchema without `properties`

An open object schema like `{ type: 'object', additionalProperties: true }`
passes isJsonSchemaObject (which only checks `type`) but carries no
`properties`, so the merge loop's `Object.entries(action.inputSchema.properties)`
threw and took down the whole preset's getTools().

- coerceInputSchema normalizes a valid object schema missing `properties` to
  {} β€” honors the declared-required type and fixes every consumer at the source.
- The merge loop now guards with `?? {}`, matching its twin
  (synthesizePerformAction) and the Python mirror, which already guards
  everywhere.
- Test: an open-schema action normalizes to {} and merges via chooseTools
  without throwing.

Node 54 unit.

Claude-Session: https://claude.ai/code/session_01SraPwksmphffxhhY6Mp9iL

Ported-From-Source-Repo: superdoc/orbit
Ported-From-Source-Commit: 47d05fe0d25b2026ade83e143e3a8d6f595c2c0c
Ported-Public-Prefix: superdoc/public
superdoc-bot Bot pushed a commit that referenced this pull request Jul 15, 2026
### Chores

- 1.21.0 [skip ci]
- 0.22.0 [skip ci]
- 1.44.2 [skip ci]

### Bug Fixes

- preserve empty toolkit base values
- drop empty perform-action catalog rows
- publish GitHub releases for stable versions only

### Features

- add package-scoped AI release notes to all six public packages (#508)
- custom-actions authoring kit β€” canonical ActionSpec with steps/run tiers (#410)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants