@cueframe/kernel 0.2.22 → 0.2.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/_members/composition/scene/clipRules.d.ts +10 -0
  2. package/dist/_members/mcp/core.d.ts +16 -1
  3. package/dist/_members/mcp/generated/operations.d.ts +2 -0
  4. package/dist/animate/preparation-facts.js +2 -2
  5. package/dist/animate.js +3 -3
  6. package/dist/authoring/scene.js +2 -2
  7. package/dist/authoring.js +2 -2
  8. package/dist/{chunk-DJWCD3RF.js → chunk-3OOMVQ6I.js} +4 -4
  9. package/dist/{chunk-VDSO2KZY.js → chunk-5BAWOULP.js} +1 -1
  10. package/dist/{chunk-CDZBSLVA.js → chunk-H5CPILOK.js} +2 -2
  11. package/dist/{chunk-DEDZKZ6G.js → chunk-JBWSK2YD.js} +2 -2
  12. package/dist/{chunk-E54DK225.js → chunk-JCQTSVZQ.js} +1 -1
  13. package/dist/{chunk-PQDALM2G.js → chunk-JNQKX4OI.js} +1 -1
  14. package/dist/{chunk-YV5AYMNK.js → chunk-JRJQECCF.js} +1 -1
  15. package/dist/{chunk-NG7DP46H.js → chunk-MMZMS3S4.js} +1 -1
  16. package/dist/{chunk-BAVEHXVC.js → chunk-NXEJASGI.js} +9 -7
  17. package/dist/{chunk-TZ7DKL2G.js → chunk-OBA6NW4S.js} +1 -1
  18. package/dist/{chunk-URQQTAHZ.js → chunk-PNJ7DACK.js} +122 -111
  19. package/dist/{chunk-PRSRV7AT.js → chunk-TE3PNQG6.js} +2 -2
  20. package/dist/{chunk-WLU5XPDG.js → chunk-TXI53LIT.js} +2 -2
  21. package/dist/{chunk-LD4XQQRL.js → chunk-WAUVKF2F.js} +1 -1
  22. package/dist/{chunk-7YL7NJJF.js → chunk-XACXNDFL.js} +6 -1
  23. package/dist/component-runtime/browserOptions.js +2 -2
  24. package/dist/component-runtime/render.js +3 -3
  25. package/dist/component-runtime.js +4 -4
  26. package/dist/compose.js +6 -6
  27. package/dist/composition/scene.js +3 -1
  28. package/dist/composition-ops.js +89 -32
  29. package/dist/core/render.js +2 -2
  30. package/dist/core.js +2 -2
  31. package/dist/mcp/adapter.js +3 -3
  32. package/dist/mcp/core.js +3 -1
  33. package/dist/mcp/curation.js +1 -1
  34. package/dist/mcp/server.js +4 -4
  35. package/dist/mcp.js +4 -4
  36. package/dist/primitives/effects.js +4 -4
  37. package/dist/primitives/layouts.js +4 -4
  38. package/dist/primitives/scenes.js +4 -4
  39. package/dist/primitives.js +6 -6
  40. package/dist/render-harness.js +6 -6
  41. package/package.json +11 -11
@@ -14,6 +14,16 @@
14
14
  */
15
15
  import type { Composition, Gap, TimelineClip, Track } from '../validators/composition.js';
16
16
  import { type SceneShotSpecV2 } from './schema.js';
17
+ /**
18
+ * What a scene slot admits, stated once. The refusal below names these formats;
19
+ * so does the `scene.add` / `scene.update` contract, which reads them from here.
20
+ * They were only ever in the refusal, so the only way to learn them was to bind
21
+ * the wrong media and read the error.
22
+ */
23
+ export declare const SCENE_SLOT_MEDIA_FORMATS: {
24
+ readonly image: "PNG, JPEG or WebP";
25
+ readonly video: "MP4 or WebM";
26
+ };
17
27
  export type SceneClipIssueCode = 'validation_error' | 'invalid_composition';
18
28
  /** One rejection: a path into the clip (or request) and an actionable detail. */
19
29
  export interface SceneClipRuleIssue {
@@ -38,6 +38,19 @@ export type ToolResult = {
38
38
  structuredContent?: Record<string, unknown>;
39
39
  };
40
40
  export declare function text(s: string): ToolResult;
41
+ /**
42
+ * A JSON response, carried BOTH ways: the rendered prose a human reads, and the
43
+ * parsed object a program can consume.
44
+ *
45
+ * Curated tools used to return prose only, so `create_render` promised
46
+ * `{id,status,warnings?}` and delivered "Render queued.\n\nrenderId: …". A
47
+ * generic MCP consumer had to scrape it (CUE-15 P0). `structuredContent` is the
48
+ * protocol's channel for exactly this; the text block stays as display.
49
+ *
50
+ * Attached only for a non-null, non-array OBJECT, which is what the protocol
51
+ * allows — a bare array or scalar would be rejected by a validating client.
52
+ */
53
+ export declare function textWithData(s: string, data: unknown): ToolResult;
41
54
  export declare function errText(s: string): ToolResult;
42
55
  export declare function firstText(r: ToolResult): string;
43
56
  export declare function sniffImageMediaType(base64: string): string | undefined;
@@ -45,7 +58,9 @@ export declare function sniffAudioMediaType(base64: string): string | undefined;
45
58
  export declare function withMedia(payload: string, media: {
46
59
  data: string;
47
60
  kind: 'image' | 'audio';
48
- }[]): ToolResult;
61
+ }[],
62
+ /** The parsed response, carried alongside the media for programmatic callers. */
63
+ data?: unknown): ToolResult;
49
64
  export declare function fetchAsBase64(url: string, opts?: {
50
65
  timeoutMs?: number;
51
66
  maxBytes?: number;
@@ -27,6 +27,8 @@ export interface GeneratedOperation {
27
27
  bodyKey: string | null;
28
28
  description: string;
29
29
  annotations: GeneratedAnnotations;
30
+ /** The 2xx JSON body as a self-contained JSON Schema, when it is an object. */
31
+ outputSchema?: Record<string, unknown>;
30
32
  }
31
33
  export interface GeneratedQueryParameter {
32
34
  name: string;
@@ -4,11 +4,11 @@ import {
4
4
  sceneGrainPreparationCpuAllocationV1,
5
5
  scenePresetBuilderDescriptorV1,
6
6
  sceneSlabPreparationFactsV1
7
- } from "../chunk-TZ7DKL2G.js";
7
+ } from "../chunk-OBA6NW4S.js";
8
8
  import {
9
9
  photographicStudioPreparationFactsV1,
10
10
  sceneFocusPreparationAllocationsV1
11
- } from "../chunk-7YL7NJJF.js";
11
+ } from "../chunk-XACXNDFL.js";
12
12
  import "../chunk-2L7PYYJK.js";
13
13
  import "../chunk-2ESYSVXG.js";
14
14
  export {
package/dist/animate.js CHANGED
@@ -102,7 +102,7 @@ import {
102
102
  useStage,
103
103
  weightsAt,
104
104
  worldTransform
105
- } from "./chunk-DEDZKZ6G.js";
105
+ } from "./chunk-JBWSK2YD.js";
106
106
  import {
107
107
  DEFAULT_LIGHTING_PROFILE,
108
108
  DEVICE_GLASS_OPACITY_ENCODED,
@@ -161,7 +161,7 @@ import {
161
161
  studioShadowFrustum,
162
162
  verifyPhotographicStudioHdr,
163
163
  withNormalisedFaceUv
164
- } from "./chunk-TZ7DKL2G.js";
164
+ } from "./chunk-OBA6NW4S.js";
165
165
  import {
166
166
  ALLOWED_BAKE_SCALES,
167
167
  DEFAULT_BAKE_SCALE,
@@ -183,7 +183,7 @@ import {
183
183
  projectedSlotEdges,
184
184
  sceneFocusPreparationAllocationsV1,
185
185
  selectSceneBakeScale
186
- } from "./chunk-7YL7NJJF.js";
186
+ } from "./chunk-XACXNDFL.js";
187
187
  import "./chunk-2L7PYYJK.js";
188
188
  import "./chunk-AVTEPAWI.js";
189
189
  import "./chunk-2ESYSVXG.js";
@@ -13,7 +13,7 @@ import {
13
13
  sceneTrackIdFor,
14
14
  validateSceneAdd,
15
15
  validateSceneUpdate
16
- } from "../chunk-E54DK225.js";
16
+ } from "../chunk-JCQTSVZQ.js";
17
17
  import {
18
18
  SCENE_TRANSITION_KINDS,
19
19
  collectSceneClipIssues,
@@ -22,7 +22,7 @@ import {
22
22
  offFrameLattice,
23
23
  readSceneSourceRef,
24
24
  sceneClipShapeIssues
25
- } from "../chunk-7YL7NJJF.js";
25
+ } from "../chunk-XACXNDFL.js";
26
26
  import "../chunk-2L7PYYJK.js";
27
27
  import "../chunk-2ESYSVXG.js";
28
28
  export {
package/dist/authoring.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  hasSceneOp,
5
5
  isSceneOp,
6
6
  materializeSceneOpsCore
7
- } from "./chunk-E54DK225.js";
7
+ } from "./chunk-JCQTSVZQ.js";
8
8
  import {
9
9
  ZERO_USAGE,
10
10
  buildDirectorTools,
@@ -67,7 +67,7 @@ import "./chunk-7PA7FGLD.js";
67
67
  import {
68
68
  collectSceneClipIssues,
69
69
  isSceneShotClip
70
- } from "./chunk-7YL7NJJF.js";
70
+ } from "./chunk-XACXNDFL.js";
71
71
  import "./chunk-2L7PYYJK.js";
72
72
  import "./chunk-AVTEPAWI.js";
73
73
  import "./chunk-2ESYSVXG.js";
@@ -312,7 +312,7 @@ Call wait_job(kind="compose", id="${j.composeJobId}", projectId="${a.projectId}"
312
312
  name: "apply_composition",
313
313
  operationId: "applyComposition",
314
314
  pathArgs: { projectId: "id" },
315
- description: 'Atomically apply an array of CompositionOps to a project composition. All ops succeed or none do (transactional). Pass `if_match` for optimistic-concurrency control (409 stale_etag on mismatch) and `dry_run: true` to validate the batch without persisting. Use this to seed a composition (add media clips) or make targeted edits (set a crop intent, reorder clips, set the format). CAPTIONS: attach content with {type:"captions.fromTranscript", mediaId, window?} \u2014 the server slices the cached word-timed transcript, rebases times, and sentence-splits into segments (no pasting words; 422 media_no_transcript if the media has no speech); style it with {type:"setCaptionStyle", style}; or set explicit words with {type:"setCaptions", segments, style?} (e.g. translations or your own VO timings). Brand is NOT set here \u2014 it lives on the project (create_project / PATCH /projects/:id with brandKitId). CARDS: a {kind:"card", html, tokens} clip projects each `tokens` KEY `x` to the CSS custom property `--cf-x`, so the html must read it as `var(--cf-x)` \u2014 write `tokens:{"plate":"#0af"}` + `background:var(--cf-plate)`. Do NOT put dashes in the key: `"--plate"` becomes `--cf---plate` and your `var(--plate)` then resolves to NOTHING, which CSS silently degrades to a transparent background and black text. Responses carry `warnings[]` when a card reads a var nothing defines. SCENE SHOTS: for a 3D product shot \u2014 a tilted page screenshot, a lit laptop/phone showing a real screenshot, two-colour type, a colour-field backdrop, focus/grain/vignette and a camera move \u2014 use {type:"scene.add", clipId, newTrack|trackId, startTime, duration, scene, assets} and revise it with {type:"scene.update", clipId, scene?, assets?, startTime?, duration?}. You author a scene SPEC, never wrapper TSX; the server registers the component for you. There is NO built-in scene primitive in list_catalog \u2014 READ cueframe://scene-shot first for the JSON schema, the canonical V2 world-objects recipe with nested groups, slabs, pages, phones, laptops, world/screen text, admitted surfaces, camera motion, lighting, and the current resource limits.',
315
+ description: 'Atomically apply an array of CompositionOps to a project composition. All ops succeed or none do (transactional). Pass `if_match` for optimistic-concurrency control (409 stale_etag on mismatch) and `dry_run: true` to validate the batch without persisting. Use this to seed a composition (add media clips) or make targeted edits (set a crop intent, reorder clips, set the format). CAPTIONS: attach content with {type:"captions.fromTranscript", mediaId, window?} \u2014 the server slices the cached word-timed transcript, rebases times, and sentence-splits into segments (no pasting words; 422 media_no_transcript if the media has no speech); style it with {type:"setCaptionStyle", style}; or set explicit words with {type:"setCaptions", segments, style?} (e.g. translations or your own VO timings). Brand is NOT set here \u2014 it lives on the project (create_project / update_project with brandKitId \u2014 or PATCH /projects/:id over REST). CARDS: a {kind:"card", html, tokens} clip projects each `tokens` KEY `x` to the CSS custom property `--cf-x`, so the html must read it as `var(--cf-x)` \u2014 write `tokens:{"plate":"#0af"}` + `background:var(--cf-plate)`. Do NOT put dashes in the key: `"--plate"` becomes `--cf---plate` and your `var(--plate)` then resolves to NOTHING, which CSS silently degrades to a transparent background and black text. Responses carry `warnings[]` when a card reads a var nothing defines. SCENE SHOTS: for a 3D product shot \u2014 a tilted page screenshot, a lit laptop/phone showing a real screenshot, two-colour type, a colour-field backdrop, focus/grain/vignette and a camera move \u2014 use {type:"scene.add", clipId, newTrack|trackId, startTime, duration, scene, assets} and revise it with {type:"scene.update", clipId, scene?, assets?, startTime?, duration?}. You author a scene SPEC, never wrapper TSX; the server registers the component for you. There is NO built-in scene primitive in list_catalog \u2014 READ cueframe://scene-shot first for the JSON schema, the canonical V2 world-objects recipe with nested groups, slabs, pages, phones, laptops, world/screen text, admitted surfaces, camera motion, lighting, and the current resource limits.',
316
316
  okFormat: (j, a) => {
317
317
  const warns = formatWarnings(j);
318
318
  if (j && typeof j.valid === "boolean") {
@@ -348,7 +348,7 @@ ${JSON.stringify(r.errors ?? [], null, 2)}${warns}`;
348
348
  name: "create_render",
349
349
  operationId: "createRender",
350
350
  pathArgs: { projectId: "id" },
351
- description: "Queue an MP4 render of a project's composition. Returns { id (renderId), status, warnings? } \u2014 `warnings[]` carries non-fatal advisories (omitted when none). The render themes from the project's brand kit (bind one via create_project / PATCH /projects/:id with brandKitId; without one the output is unbranded). Then call wait_job(kind=\"render\", id=renderId, projectId=...) to block until the file is ready and get the download URL, or register a webhook (create_webhook on render.completed \u2014 status rides the payload).",
351
+ description: "Queue an MP4 render of a project's composition. Returns { id (renderId), status, warnings? } \u2014 `warnings[]` carries non-fatal advisories (omitted when none). The render themes from the project's brand kit (bind one via create_project / update_project with brandKitId \u2014 or PATCH /projects/:id over REST; without one the output is unbranded). Then call wait_job(kind=\"render\", id=renderId, projectId=...) to block until the file is ready and get the download URL, or register a webhook (create_webhook on render.completed \u2014 status rides the payload).",
352
352
  okFormat: (j, a) => `Render queued.
353
353
 
354
354
  renderId: ${j.id}
@@ -552,7 +552,7 @@ Poll get_media_facts(mediaItemId="${a.mediaItemId}", kind="${a.body?.kind}", sta
552
552
  {
553
553
  name: "create_project",
554
554
  operationId: "createProject",
555
- description: "Create a new project \u2014 the unit you compose and render into. compose / apply_composition / create_render / the preview family all require a projectId; this mints one. Pass name (required) plus optionally a format (aspectRatio/fps/resolution) and brandKitId. brandKitId binds a brand kit to the PROJECT (pass the kitId from create_brand_kit): colors/fonts/motion theme every render of this project automatically (omit it and the output is unbranded). Bind or change it later via PATCH /projects/:id. Returns the ProjectResponse (id + metadata)."
555
+ description: "Create a new project \u2014 the unit you compose and render into. compose / apply_composition / create_render / the preview family all require a projectId; this mints one. Pass name (required) plus optionally a format (aspectRatio/fps/resolution) and brandKitId. brandKitId binds a brand kit to the PROJECT (pass the kitId from create_brand_kit): colors/fonts/motion theme every render of this project automatically (omit it and the output is unbranded). Bind or change it later via update_project (PATCH /projects/:id over REST). Returns the ProjectResponse (id + metadata)."
556
556
  },
557
557
  {
558
558
  name: "new_composition",
@@ -806,7 +806,7 @@ Render it with create_render(projectId="${a.projectId}", body={ compositionId: "
806
806
  {
807
807
  name: "create_brand_kit",
808
808
  operationId: "createBrandKit",
809
- description: "Create or UPSERT a brand kit (re-POSTing the same kitId updates it in place \u2014 this is also the brand-kit UPDATE path). Sets fonts/colors/logo. This is brand step 0 of the workflow: author the kit, then bind it to a PROJECT so colors/fonts/motion theme the output AUTOMATICALLY \u2014 pass its kitId as brandKitId to create_project, or attach it to an existing project via PATCH /projects/:id. Without a bound kit, create_render produces UNBRANDED output. Tenant-scoped (no project arg)."
809
+ description: "Create or UPSERT a brand kit (re-POSTing the same kitId updates it in place \u2014 this is also the brand-kit UPDATE path). Sets fonts/colors/logo. This is brand step 0 of the workflow: author the kit, then bind it to a PROJECT so colors/fonts/motion theme the output AUTOMATICALLY \u2014 pass its kitId as brandKitId to create_project, or attach it to an existing project via update_project (PATCH /projects/:id over REST). Without a bound kit, create_render produces UNBRANDED output. Tenant-scoped (no project arg)."
810
810
  },
811
811
  {
812
812
  name: "extract_brand_kit",
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-ZVG446DJ.js";
5
5
  import {
6
6
  STUDIO_SHADOW_MAP_BUDGET
7
- } from "./chunk-7YL7NJJF.js";
7
+ } from "./chunk-XACXNDFL.js";
8
8
 
9
9
  // ../execution/component-runtime/src/webglProbe.ts
10
10
  function webglBackend(platform, hardware) {
@@ -15,7 +15,7 @@ import {
15
15
  componentBrowserBackend,
16
16
  componentBrowserOptions,
17
17
  readGpuAttestation
18
- } from "./chunk-VDSO2KZY.js";
18
+ } from "./chunk-5BAWOULP.js";
19
19
  import {
20
20
  ComponentCapturePageRasterAttestationV1,
21
21
  ComponentGraphicsApiV2,
@@ -28,7 +28,7 @@ import {
28
28
  } from "./chunk-ZVG446DJ.js";
29
29
  import {
30
30
  parseSceneShotSpecV2
31
- } from "./chunk-7YL7NJJF.js";
31
+ } from "./chunk-XACXNDFL.js";
32
32
  import {
33
33
  BUNDLED_FONT_FACES
34
34
  } from "./chunk-AVTEPAWI.js";
@@ -19,7 +19,7 @@ import {
19
19
  slabTriangleCount,
20
20
  takeSceneEnvironment,
21
21
  useSceneActualResourceRegistrarV1
22
- } from "./chunk-TZ7DKL2G.js";
22
+ } from "./chunk-OBA6NW4S.js";
23
23
  import {
24
24
  PHOTOGRAPHIC_STUDIO_RIG_ID,
25
25
  SCENE_SLAB_CONTENT_OFFSET,
@@ -31,7 +31,7 @@ import {
31
31
  sceneTextureBytes,
32
32
  sceneVideoMidpointAddressV1,
33
33
  selectSceneBakeScale
34
- } from "./chunk-7YL7NJJF.js";
34
+ } from "./chunk-XACXNDFL.js";
35
35
  import {
36
36
  resolveCaptionFaces
37
37
  } from "./chunk-AVTEPAWI.js";
@@ -8,7 +8,7 @@ import {
8
8
  sceneShotImageSlots,
9
9
  sceneShotVideoSlots,
10
10
  sceneSpecIssues
11
- } from "./chunk-7YL7NJJF.js";
11
+ } from "./chunk-XACXNDFL.js";
12
12
 
13
13
  // ../authoring/src/scene/validate.ts
14
14
  var SceneAuthoringError = class extends Error {
@@ -51,7 +51,7 @@ import {
51
51
  sceneFullMipLevels,
52
52
  sceneTextureBytes,
53
53
  selectSceneBakeScale
54
- } from "./chunk-7YL7NJJF.js";
54
+ } from "./chunk-XACXNDFL.js";
55
55
  import {
56
56
  SCENE_CONTEXT_GL_BUDGET_BYTES,
57
57
  SCENE_MAX_TRIANGLES,
@@ -24,7 +24,7 @@ import {
24
24
  } from "./chunk-W2245F6G.js";
25
25
  import {
26
26
  FlexLayout
27
- } from "./chunk-DEDZKZ6G.js";
27
+ } from "./chunk-JBWSK2YD.js";
28
28
 
29
29
  // ../execution/primitives/src/layouts/chat-to-preview-layout/index.tsx
30
30
  import { Easing, interpolate, useCurrentFrame, useVideoConfig } from "remotion";
@@ -5,7 +5,7 @@ import {
5
5
  isOk,
6
6
  opById,
7
7
  safeParse
8
- } from "./chunk-URQQTAHZ.js";
8
+ } from "./chunk-PNJ7DACK.js";
9
9
 
10
10
  // ../mcp/src/wait.ts
11
11
  var defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -2,10 +2,10 @@ import {
2
2
  querySchemaShape,
3
3
  serializeQuery,
4
4
  waitForJob
5
- } from "./chunk-NG7DP46H.js";
5
+ } from "./chunk-MMZMS3S4.js";
6
6
  import {
7
7
  CURATED_TOOLS
8
- } from "./chunk-DJWCD3RF.js";
8
+ } from "./chunk-3OOMVQ6I.js";
9
9
  import {
10
10
  GENERATED_OPERATIONS,
11
11
  apiErrorFrom,
@@ -21,8 +21,9 @@ import {
21
21
  safeParse,
22
22
  sniffImageMediaType,
23
23
  text,
24
+ textWithData,
24
25
  withMedia
25
- } from "./chunk-URQQTAHZ.js";
26
+ } from "./chunk-PNJ7DACK.js";
26
27
 
27
28
  // ../mcp/src/prompts.ts
28
29
  var skillListCache = null;
@@ -3616,7 +3617,7 @@ function registerResources(server, ex) {
3616
3617
  }),
3617
3618
  {
3618
3619
  title: "Component catalog",
3619
- description: "The component catalog: the FULL built-in primitive catalog (96 primitives + 7 scenes \u2014 lower-third, cinematic-title, color-grade, the scenes \u2026) PLUS your org-installed custom components. This is 'discover what to build with'. resources/list enumerates EVERY entry with its discovery facets (source/category/kind/tier/useCase) and a placement hint; read one for its full prop schema. NOT only your authored components. URI: cueframe://component/{componentId}.",
3620
+ description: "The component catalog: the FULL built-in primitive catalog (lower-third, cinematic-title, color-grade, the `scenes`-category templates \u2026) PLUS your org-installed custom components. This is 'discover what to build with'. resources/list enumerates EVERY entry with its discovery facets (source/category/kind/tier/useCase) and a placement hint; read one for its full prop schema. NOT only your authored components. NOTE the word 'scene' means two different things: the `scenes` CATEGORY here is composed built-in templates you place by primitiveId, whereas a SCENE SHOT (the scene.add op, cueframe://scene-shot) is a 3D spec you author and has no catalog entry at all. URI: cueframe://component/{componentId}.",
3620
3621
  mimeType: "application/json"
3621
3622
  },
3622
3623
  async (uri, { componentId }) => jsonResource(uri, await read(ex, "getComponent", () => String(componentId)))
@@ -3747,7 +3748,8 @@ function registerCuratedTools(server, ex, opts) {
3747
3748
  const bodySchema = bodySchemaFor(op);
3748
3749
  if (bodySchema) inputSchema.body = bodySchema;
3749
3750
  const annotations = { ...op.annotations, ...spec.annotations };
3750
- server.registerTool(spec.name, { title: spec.title ?? titleCase(spec.name), description: spec.description, inputSchema: z.object(inputSchema), annotations }, async (args, extra) => timed(opts?.onEvent, spec.name, async (report) => {
3751
+ const outputSchema = op.outputSchema && !spec.okText ? z.fromJSONSchema(op.outputSchema) : void 0;
3752
+ server.registerTool(spec.name, { title: spec.title ?? titleCase(spec.name), description: spec.description, inputSchema: z.object(inputSchema), ...outputSchema ? { outputSchema } : {}, annotations }, async (args, extra) => timed(opts?.onEvent, spec.name, async (report) => {
3751
3753
  const a = { ...spec.defaults ?? {}, ...args };
3752
3754
  try {
3753
3755
  const query = serializeQuery(op.queryParams, a);
@@ -3760,9 +3762,9 @@ function registerCuratedTools(server, ex, opts) {
3760
3762
  const urls = spec.preview.urls(json).filter(Boolean);
3761
3763
  const data = await fetchPreviews(urls, spec.preview.cap ?? 12);
3762
3764
  report({ preview: { urls: urls.length, fetched: data.length } });
3763
- if (data.length) return withMedia(payload, data.map((d) => ({ data: d, kind })));
3765
+ if (data.length) return withMedia(payload, data.map((d) => ({ data: d, kind })), json);
3764
3766
  }
3765
- return text(payload);
3767
+ return textWithData(payload, json);
3766
3768
  }, query);
3767
3769
  } catch (err) {
3768
3770
  return errText(`${spec.name} failed: ${fmtErr(err)}`);
@@ -18,7 +18,7 @@ import {
18
18
  sceneW5GeneratedRigAllocationsV1,
19
19
  sceneW5PresetAllocationsV1,
20
20
  sceneW5WorldTextAllocationsV1
21
- } from "./chunk-7YL7NJJF.js";
21
+ } from "./chunk-XACXNDFL.js";
22
22
 
23
23
  // ../execution/animate/src/three/toneMapping.ts
24
24
  import {