@vgai/sdk 0.5.0 → 0.5.1

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 (54) hide show
  1. package/package.json +2 -2
  2. package/src/account.ts +5 -4
  3. package/src/cinematic/capabilities-operations.ts +3 -3
  4. package/src/cinematic/cue-operations.ts +11 -11
  5. package/src/cinematic/gsap-operations.ts +5 -5
  6. package/src/cinematic/index.ts +3 -3
  7. package/src/cinematic/preview-operations.ts +10 -10
  8. package/src/cinematic/preview-transport.ts +2 -2
  9. package/src/cinematic/render-operations.ts +15 -15
  10. package/src/cinematic/render-transport.ts +2 -2
  11. package/src/cinematic/theatre-operations.ts +17 -17
  12. package/src/editor/camera-operations.ts +7 -7
  13. package/src/editor/console-operations.ts +5 -5
  14. package/src/editor/hierarchy-operations.ts +5 -5
  15. package/src/editor/index.ts +3 -3
  16. package/src/editor/open-operations.ts +10 -10
  17. package/src/editor/screenshot-operations.ts +5 -5
  18. package/src/editor/selection-operations.ts +7 -7
  19. package/src/editor/session-operations.ts +3 -3
  20. package/src/editor/source-location-operations.ts +6 -6
  21. package/src/editor/transport.ts +24 -11
  22. package/src/errors.ts +8 -8
  23. package/src/generations.ts +12 -1
  24. package/src/http/http-projection.ts +26 -26
  25. package/src/index.ts +22 -30
  26. package/src/mcp/index.ts +2 -2
  27. package/src/mcp/mcp-projection.ts +25 -25
  28. package/src/mcp/mcp-server.ts +2 -2
  29. package/src/operations.ts +5 -5
  30. package/src/play/control-operations.ts +10 -10
  31. package/src/play/debug-command-operations.ts +12 -12
  32. package/src/play/index.ts +3 -3
  33. package/src/play/input-operations.ts +10 -10
  34. package/src/play/lifecycle-operations.ts +11 -11
  35. package/src/play/log-operations.ts +7 -7
  36. package/src/play/run-ticks-operations.ts +8 -8
  37. package/src/play/state-operations.ts +9 -9
  38. package/src/play/status-operations.ts +7 -7
  39. package/src/play/transport.ts +93 -22
  40. package/src/project/asset-operations.ts +8 -8
  41. package/src/project/component-operations.ts +10 -10
  42. package/src/project/discovery-operations.ts +9 -9
  43. package/src/project/entity-operations.ts +8 -8
  44. package/src/project/index.ts +4 -4
  45. package/src/project/input-map-operations.ts +9 -9
  46. package/src/project/inspection-operation.ts +3 -3
  47. package/src/project/manifest-operations.ts +9 -9
  48. package/src/project/scene-operations.ts +14 -14
  49. package/src/project/shared.ts +17 -17
  50. package/src/project-tool-catalog.ts +21 -5
  51. package/src/registry.ts +39 -39
  52. package/src/render/render-cinematic.ts +24 -1
  53. package/src/tools.ts +19 -12
  54. package/src/types.ts +4 -4
@@ -12,8 +12,8 @@
12
12
  */
13
13
 
14
14
  import { z } from 'zod';
15
- import { OperationError } from '../errors.js';
16
- import { defineOperation, type OperationRegistry } from '../registry.js';
15
+ import { ToolError } from '../errors.js';
16
+ import { defineTool, type ToolRegistry } from '../registry.js';
17
17
  import {
18
18
  EDITOR_NOT_RUNNING_ERROR,
19
19
  EDITOR_READ_TIMEOUT_MS,
@@ -56,7 +56,7 @@ const EditorHierarchyInspectResult = z.object({
56
56
  ),
57
57
  });
58
58
 
59
- export const editorHierarchyInspect = defineOperation({
59
+ export const editorHierarchyInspect = defineTool({
60
60
  name: 'editor.hierarchy.inspect',
61
61
  summary: "Inspect the entity hierarchy of the target editor session's currently loaded scene.",
62
62
  description:
@@ -80,7 +80,7 @@ export const editorHierarchyInspect = defineOperation({
80
80
  'editor.hierarchy.inspect',
81
81
  ).catch(() => undefined);
82
82
  if (!hierarchy) {
83
- throw new OperationError(
83
+ throw new ToolError(
84
84
  'HIERARCHY_UNAVAILABLE',
85
85
  'The connected editor session did not answer the hierarchy-state read in time.',
86
86
  {},
@@ -90,6 +90,6 @@ export const editorHierarchyInspect = defineOperation({
90
90
  },
91
91
  });
92
92
 
93
- export function registerHierarchyOperations(registry: OperationRegistry): void {
93
+ export function registerHierarchyOperations(registry: ToolRegistry): void {
94
94
  registry.register(editorHierarchyInspect);
95
95
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * B3 — `editor.*` operations
3
3
  * (docs/AI-NATIVE-AUTHORING-IMPLEMENTATION-SPEC.md §8 B3). Registered
4
- * separately from B1's `registerBuiltinOperations` (`../operations.ts`) and
4
+ * separately from B1's `registerBuiltinTools` (`../operations.ts`) and
5
5
  * B2's `registerProjectOperations` (`../project/index.ts`) — the default
6
6
  * `operations` singleton (`../index.ts`) calls all three.
7
7
  */
@@ -39,7 +39,7 @@ export {
39
39
  withTimeout,
40
40
  } from './transport.js';
41
41
 
42
- import type { OperationRegistry } from '../registry.js';
42
+ import type { ToolRegistry } from '../registry.js';
43
43
  import { registerCameraOperations } from './camera-operations.js';
44
44
  import { registerConsoleOperations } from './console-operations.js';
45
45
  import { registerHierarchyOperations } from './hierarchy-operations.js';
@@ -50,7 +50,7 @@ import { registerSessionOperations } from './session-operations.js';
50
50
  import { registerSourceLocationOperations } from './source-location-operations.js';
51
51
 
52
52
  /** Register every B3 `editor.*` operation onto `registry`. */
53
- export function registerEditorOperations(registry: OperationRegistry): void {
53
+ export function registerEditorOperations(registry: ToolRegistry): void {
54
54
  registerSessionOperations(registry);
55
55
  registerSelectionOperations(registry);
56
56
  registerHierarchyOperations(registry);
@@ -22,8 +22,8 @@
22
22
  */
23
23
 
24
24
  import { z } from 'zod';
25
- import { OperationError } from '../errors.js';
26
- import { defineOperation, type OperationRegistry } from '../registry.js';
25
+ import { ToolError } from '../errors.js';
26
+ import { defineTool, type ToolRegistry } from '../registry.js';
27
27
  import {
28
28
  EDITOR_COMMAND_TIMEOUT_MS,
29
29
  EDITOR_NOT_RUNNING_ERROR,
@@ -58,7 +58,7 @@ const EditorSceneOpenInput = z.object({
58
58
  .describe('Project-relative path to a .vscn.json scene file to open in the editor.'),
59
59
  });
60
60
 
61
- export const editorSceneOpen = defineOperation({
61
+ export const editorSceneOpen = defineTool({
62
62
  name: 'editor.scene.open',
63
63
  summary: 'Open a scene file in a connected editor session.',
64
64
  description:
@@ -87,7 +87,7 @@ export const editorSceneOpen = defineOperation({
87
87
  error: err instanceof Error ? err.message : String(err),
88
88
  }));
89
89
  if (!result.ok) {
90
- throw new OperationError('COMMAND_FAILED', result.error ?? 'open-scene command failed', {
90
+ throw new ToolError('COMMAND_FAILED', result.error ?? 'open-scene command failed', {
91
91
  message: result.error ?? 'open-scene command failed',
92
92
  });
93
93
  }
@@ -115,7 +115,7 @@ const EditorAssetOpenInput = z.object({
115
115
  kind: AssetKindSchema,
116
116
  });
117
117
 
118
- export const editorAssetOpen = defineOperation({
118
+ export const editorAssetOpen = defineTool({
119
119
  name: 'editor.asset.open',
120
120
  summary: 'Open an asset as a tab in a connected editor session.',
121
121
  description:
@@ -144,7 +144,7 @@ export const editorAssetOpen = defineOperation({
144
144
  error: err instanceof Error ? err.message : String(err),
145
145
  }));
146
146
  if (!result.ok) {
147
- throw new OperationError('COMMAND_FAILED', result.error ?? 'open-asset-tab command failed', {
147
+ throw new ToolError('COMMAND_FAILED', result.error ?? 'open-asset-tab command failed', {
148
148
  message: result.error ?? 'open-asset-tab command failed',
149
149
  });
150
150
  }
@@ -160,7 +160,7 @@ const EditorStoryOpenInput = z.object({
160
160
  path: z.string().describe('Project-relative path to a *.stories.tsx/*.stories.ts module.'),
161
161
  });
162
162
 
163
- export const editorStoryOpen = defineOperation({
163
+ export const editorStoryOpen = defineTool({
164
164
  name: 'editor.story.open',
165
165
  summary: 'Open a Storybook CSF story in a connected editor session.',
166
166
  description:
@@ -187,14 +187,14 @@ export const editorStoryOpen = defineOperation({
187
187
  'editor.story.open',
188
188
  ).catch(() => undefined);
189
189
  if (!result) {
190
- throw new OperationError(
190
+ throw new ToolError(
191
191
  'STORY_OPEN_UNSUPPORTED',
192
192
  'The connected editor has no wire-level command to open a story today.',
193
193
  {},
194
194
  );
195
195
  }
196
196
  if (!result.ok) {
197
- throw new OperationError('COMMAND_FAILED', result.error ?? 'open-story command failed', {
197
+ throw new ToolError('COMMAND_FAILED', result.error ?? 'open-story command failed', {
198
198
  message: result.error ?? 'open-story command failed',
199
199
  });
200
200
  }
@@ -202,7 +202,7 @@ export const editorStoryOpen = defineOperation({
202
202
  },
203
203
  });
204
204
 
205
- export function registerOpenOperations(registry: OperationRegistry): void {
205
+ export function registerOpenOperations(registry: ToolRegistry): void {
206
206
  registry.register(editorSceneOpen);
207
207
  registry.register(editorAssetOpen);
208
208
  registry.register(editorStoryOpen);
@@ -16,8 +16,8 @@
16
16
  */
17
17
 
18
18
  import { z } from 'zod';
19
- import { OperationError } from '../errors.js';
20
- import { defineOperation, type OperationRegistry } from '../registry.js';
19
+ import { ToolError } from '../errors.js';
20
+ import { defineTool, type ToolRegistry } from '../registry.js';
21
21
  import {
22
22
  EDITOR_NOT_RUNNING_ERROR,
23
23
  EDITOR_READ_TIMEOUT_MS,
@@ -56,7 +56,7 @@ const EditorViewportScreenshotCaptureResult = z
56
56
  })
57
57
  .describe('A viewport image — fresh when possible, the last-saved thumbnail otherwise.');
58
58
 
59
- export const editorViewportScreenshotCapture = defineOperation({
59
+ export const editorViewportScreenshotCapture = defineTool({
60
60
  name: 'editor.viewport.screenshot.capture',
61
61
  summary: "Capture the target editor session's live viewport (falls back to its saved thumbnail).",
62
62
  description:
@@ -84,7 +84,7 @@ export const editorViewportScreenshotCapture = defineOperation({
84
84
  'editor.viewport.screenshot.capture',
85
85
  ).catch(() => undefined);
86
86
  if (!shot) {
87
- throw new OperationError(
87
+ throw new ToolError(
88
88
  'SCREENSHOT_UNAVAILABLE',
89
89
  'No fresh capture or saved thumbnail is available for this session, or the read timed out.',
90
90
  {},
@@ -94,6 +94,6 @@ export const editorViewportScreenshotCapture = defineOperation({
94
94
  },
95
95
  });
96
96
 
97
- export function registerScreenshotOperations(registry: OperationRegistry): void {
97
+ export function registerScreenshotOperations(registry: ToolRegistry): void {
98
98
  registry.register(editorViewportScreenshotCapture);
99
99
  }
@@ -10,8 +10,8 @@
10
10
  */
11
11
 
12
12
  import { z } from 'zod';
13
- import { OperationError } from '../errors.js';
14
- import { defineOperation, type OperationRegistry } from '../registry.js';
13
+ import { ToolError } from '../errors.js';
14
+ import { defineTool, type ToolRegistry } from '../registry.js';
15
15
  import {
16
16
  EDITOR_COMMAND_TIMEOUT_MS,
17
17
  EDITOR_NOT_RUNNING_ERROR,
@@ -51,7 +51,7 @@ const EditorSelectionGetResult = z
51
51
  })
52
52
  .describe('Live selection snapshot from the resolved editor session.');
53
53
 
54
- export const editorSelectionGet = defineOperation({
54
+ export const editorSelectionGet = defineTool({
55
55
  name: 'editor.selection.get',
56
56
  summary: 'Read the current entity selection from a connected editor session.',
57
57
  description:
@@ -75,7 +75,7 @@ export const editorSelectionGet = defineOperation({
75
75
  'editor.selection.get',
76
76
  ).catch(() => undefined);
77
77
  if (!selection) {
78
- throw new OperationError(
78
+ throw new ToolError(
79
79
  'SELECTION_UNAVAILABLE',
80
80
  'The connected editor session did not answer the selection-state read in time.',
81
81
  {},
@@ -97,7 +97,7 @@ const EditorSelectionSetInput = z
97
97
 
98
98
  const EditorSelectionSetResult = z.object({ ok: z.literal(true) });
99
99
 
100
- export const editorSelectionSet = defineOperation({
100
+ export const editorSelectionSet = defineTool({
101
101
  name: 'editor.selection.set',
102
102
  summary: 'Set the entity selection in a connected editor session.',
103
103
  description:
@@ -130,7 +130,7 @@ export const editorSelectionSet = defineOperation({
130
130
  error: err instanceof Error ? err.message : String(err),
131
131
  }));
132
132
  if (!result.ok) {
133
- throw new OperationError('COMMAND_FAILED', result.error ?? 'select command failed', {
133
+ throw new ToolError('COMMAND_FAILED', result.error ?? 'select command failed', {
134
134
  message: result.error ?? 'select command failed',
135
135
  });
136
136
  }
@@ -138,7 +138,7 @@ export const editorSelectionSet = defineOperation({
138
138
  },
139
139
  });
140
140
 
141
- export function registerSelectionOperations(registry: OperationRegistry): void {
141
+ export function registerSelectionOperations(registry: ToolRegistry): void {
142
142
  registry.register(editorSelectionGet);
143
143
  registry.register(editorSelectionSet);
144
144
  }
@@ -19,7 +19,7 @@
19
19
  */
20
20
 
21
21
  import { z } from 'zod';
22
- import { defineOperation, type OperationRegistry } from '../registry.js';
22
+ import { defineTool, type ToolRegistry } from '../registry.js';
23
23
  import { EDITOR_SESSION_DISCOVERY_TIMEOUT_MS, getTransport } from './transport.js';
24
24
 
25
25
  const EditorSessionListInput = z
@@ -41,7 +41,7 @@ const EditorSessionListResult = z.object({
41
41
  .describe('Every live session that answered a liveness probe, in no particular order.'),
42
42
  });
43
43
 
44
- export const editorSessionList = defineOperation({
44
+ export const editorSessionList = defineTool({
45
45
  name: 'editor.session.list',
46
46
  summary: 'List every live, probe-verified editor dev-server session on this machine.',
47
47
  description:
@@ -68,6 +68,6 @@ export const editorSessionList = defineOperation({
68
68
  },
69
69
  });
70
70
 
71
- export function registerSessionOperations(registry: OperationRegistry): void {
71
+ export function registerSessionOperations(registry: ToolRegistry): void {
72
72
  registry.register(editorSessionList);
73
73
  }
@@ -14,8 +14,8 @@
14
14
  */
15
15
 
16
16
  import { z } from 'zod';
17
- import { OperationError } from '../errors.js';
18
- import { defineOperation, type OperationRegistry } from '../registry.js';
17
+ import { ToolError } from '../errors.js';
18
+ import { defineTool, type ToolRegistry } from '../registry.js';
19
19
  import {
20
20
  EDITOR_NOT_RUNNING_ERROR,
21
21
  EDITOR_READ_TIMEOUT_MS,
@@ -50,7 +50,7 @@ const EditorSourceLocationLookupResult = z
50
50
  })
51
51
  .describe('Source location for the given oid. Never mutates anything.');
52
52
 
53
- export const editorSourceLocationLookup = defineOperation({
53
+ export const editorSourceLocationLookup = defineTool({
54
54
  name: 'editor.sourceLocation.lookup',
55
55
  summary: "Map an inspected React element's oid to its exact component/source location.",
56
56
  description:
@@ -81,7 +81,7 @@ export const editorSourceLocationLookup = defineOperation({
81
81
  'editor.sourceLocation.lookup',
82
82
  ).catch(() => undefined);
83
83
  if (!index) {
84
- throw new OperationError(
84
+ throw new ToolError(
85
85
  'SOURCE_INDEX_UNAVAILABLE',
86
86
  'The connected editor session did not answer the source-location index read in time.',
87
87
  {},
@@ -89,7 +89,7 @@ export const editorSourceLocationLookup = defineOperation({
89
89
  }
90
90
  const entry = index[input.oid];
91
91
  if (!entry) {
92
- throw new OperationError(
92
+ throw new ToolError(
93
93
  'SOURCE_LOCATION_NOT_FOUND',
94
94
  `No source location for oid "${input.oid}".`,
95
95
  {
@@ -101,6 +101,6 @@ export const editorSourceLocationLookup = defineOperation({
101
101
  },
102
102
  });
103
103
 
104
- export function registerSourceLocationOperations(registry: OperationRegistry): void {
104
+ export function registerSourceLocationOperations(registry: ToolRegistry): void {
105
105
  registry.register(editorSourceLocationLookup);
106
106
  }
@@ -21,7 +21,7 @@
21
21
  * EDITOR_NOT_RUNNING rather than hanging").
22
22
  *
23
23
  * `EditorTransport` is INJECTABLE via `ctx['editorTransport']` (a plain
24
- * bag key on `OperationContext`'s open `[key: string]: unknown` — no change
24
+ * bag key on `ToolContext`'s open `[key: string]: unknown` — no change
25
25
  * to `types.ts` needed) so tests can swap in a mock/fake transport and
26
26
  * exercise every op headlessly, with no real browser or dev server
27
27
  * (see `../../test/editor-operations.test.ts`).
@@ -109,9 +109,9 @@ import { existsSync, readFileSync, realpathSync } from 'node:fs';
109
109
  import { homedir } from 'node:os';
110
110
  import { join, resolve } from 'node:path';
111
111
  import { z } from 'zod';
112
- import { OperationError } from '../errors.js';
113
- import type { ErrorDefinition } from '../registry.js';
114
- import type { OperationContext } from '../types.js';
112
+ import { ToolError } from '../errors.js';
113
+ import type { ToolErrorDefinition } from '../registry.js';
114
+ import type { ToolContext } from '../types.js';
115
115
 
116
116
  // ---------------------------------------------------------------------------
117
117
  // Named timeouts (§8 B3 AC: "enforce a named timeout, don't block forever")
@@ -172,6 +172,8 @@ export interface EditorSessionInfo {
172
172
  project: string | null;
173
173
  /** Dev-server process id, when known from the local session registry (null for an unregistered/legacy server the caller only probed by port). */
174
174
  pid: number | null;
175
+ /** Registry discriminator. `kind: 'e2e'` is a standalone proof server, never an editor-control target. */
176
+ kind?: string;
175
177
  /** Exact explicitly targeted editor origin/base URL, including protocol and host. */
176
178
  url?: string;
177
179
  }
@@ -295,6 +297,7 @@ interface RegistrySessionEntry {
295
297
  port: number;
296
298
  pid: number;
297
299
  startedAt: string;
300
+ kind?: string;
298
301
  }
299
302
 
300
303
  function isRegistrySessionEntry(v: unknown): v is RegistrySessionEntry {
@@ -304,7 +307,8 @@ function isRegistrySessionEntry(v: unknown): v is RegistrySessionEntry {
304
307
  (typeof s['project'] === 'string' || s['project'] === null) &&
305
308
  typeof s['port'] === 'number' &&
306
309
  typeof s['pid'] === 'number' &&
307
- typeof s['startedAt'] === 'string'
310
+ typeof s['startedAt'] === 'string' &&
311
+ (s['kind'] === undefined || typeof s['kind'] === 'string')
308
312
  );
309
313
  }
310
314
 
@@ -328,7 +332,10 @@ function readRegisteredSessions(): RegistrySessionEntry[] {
328
332
  try {
329
333
  const raw: unknown = JSON.parse(readFileSync(registryFile, 'utf8'));
330
334
  return Array.isArray(raw)
331
- ? raw.filter(isRegistrySessionEntry).filter((s) => pidAlive(s.pid))
335
+ ? raw
336
+ .filter(isRegistrySessionEntry)
337
+ .filter((s) => s.kind !== 'e2e')
338
+ .filter((s) => pidAlive(s.pid))
332
339
  : [];
333
340
  } catch {
334
341
  return [];
@@ -400,7 +407,12 @@ export class HttpEditorTransport implements EditorTransport {
400
407
  );
401
408
  if (body === undefined) return undefined;
402
409
  const project = (body as { project?: { path?: string } | null }).project?.path ?? null;
403
- const info: EditorSessionInfo = { port: s.port, project, pid: s.pid };
410
+ const info: EditorSessionInfo = {
411
+ port: s.port,
412
+ project,
413
+ pid: s.pid,
414
+ ...(s.kind !== undefined ? { kind: s.kind } : {}),
415
+ };
404
416
  return info;
405
417
  }),
406
418
  );
@@ -577,7 +589,7 @@ export class HttpEditorTransport implements EditorTransport {
577
589
  const defaultTransport = new HttpEditorTransport();
578
590
 
579
591
  /** Resolve the transport to use: `ctx['editorTransport']` when injected (tests), else the shared real transport. */
580
- export function getTransport(ctx: OperationContext): EditorTransport {
592
+ export function getTransport(ctx: ToolContext): EditorTransport {
581
593
  const injected = ctx['editorTransport'];
582
594
  return (injected as EditorTransport | undefined) ?? defaultTransport;
583
595
  }
@@ -586,7 +598,7 @@ export function getTransport(ctx: OperationContext): EditorTransport {
586
598
  // EDITOR_NOT_RUNNING + deterministic session resolution
587
599
  // ---------------------------------------------------------------------------
588
600
 
589
- export const EDITOR_NOT_RUNNING_ERROR: ErrorDefinition = {
601
+ export const EDITOR_NOT_RUNNING_ERROR: ToolErrorDefinition = {
590
602
  code: 'EDITOR_NOT_RUNNING',
591
603
  summary:
592
604
  'No live, responsive editor session is available to target (none running, none matching ' +
@@ -637,12 +649,12 @@ function portOf(url: string): number | undefined {
637
649
  * surfaces EDITOR_NOT_RUNNING within that bound, never a hang.
638
650
  */
639
651
  export async function resolveEditorSession(
640
- ctx: OperationContext,
652
+ ctx: ToolContext,
641
653
  transport: EditorTransport,
642
654
  ): Promise<EditorSessionInfo> {
643
655
  const editorUrl = ctx.editorUrl;
644
656
  const notRunning = (): never => {
645
- throw new OperationError('EDITOR_NOT_RUNNING', 'No editor connected.', {
657
+ throw new ToolError('EDITOR_NOT_RUNNING', 'No editor connected.', {
646
658
  ...(editorUrl !== undefined ? { editorUrl } : {}),
647
659
  });
648
660
  };
@@ -669,6 +681,7 @@ export async function resolveEditorSession(
669
681
  } catch {
670
682
  return notRunning();
671
683
  }
684
+ sessions = sessions.filter((session) => session.kind !== 'e2e');
672
685
  if (sessions.length === 0) return notRunning();
673
686
 
674
687
  if (editorUrl !== undefined) {
package/src/errors.ts CHANGED
@@ -3,7 +3,7 @@ import type { z } from 'zod';
3
3
  /**
4
4
  * Core, registry-level error codes — always available regardless of which
5
5
  * operation was dispatched. Operation-specific codes are declared per
6
- * operation on `OperationDefinition.errors` (see `registry.ts`).
6
+ * operation on `ToolDefinition.errors` (see `registry.ts`).
7
7
  */
8
8
  export const CORE_ERROR_CODES = {
9
9
  /** `dispatch()` was called with a name no operation is registered under. */
@@ -11,7 +11,7 @@ export const CORE_ERROR_CODES = {
11
11
  /** Input failed the operation's Zod input schema. */
12
12
  INVALID_INPUT: 'INVALID_INPUT',
13
13
  /** The impl's return value failed the operation's Zod result schema, or a
14
- * thrown OperationError's `data` failed its declared error-code schema —
14
+ * thrown ToolError's `data` failed its declared error-code schema —
15
15
  * either way, an implementation bug, not a caller bug. */
16
16
  INVALID_OUTPUT: 'INVALID_OUTPUT',
17
17
  /** The impl threw something that isn't a declared, structured error. */
@@ -46,32 +46,32 @@ export interface StructuredOperationError {
46
46
  * copies of @vgai/sdk (for example, an editor host dispatching a standalone
47
47
  * project's tool). `instanceof` alone cannot cross that package boundary.
48
48
  */
49
- export const OPERATION_ERROR_BRAND = Symbol.for('@vgai/sdk.OperationError');
49
+ export const OPERATION_ERROR_BRAND = Symbol.for('@vgai/sdk.ToolError');
50
50
 
51
51
  /**
52
52
  * The only way an operation `impl` should signal an EXPECTED, contractual
53
53
  * failure (as opposed to an unexpected bug/exception). `code` must be one
54
- * the operation's `OperationDefinition.errors` declares — `dispatch()`
54
+ * the operation's `ToolDefinition.errors` declares — `dispatch()`
55
55
  * cross-checks it and validates `data` against that code's schema, so an
56
56
  * undeclared code or mismatched data is itself normalized into a structured
57
57
  * error rather than silently forwarded (see `registry.ts`'s
58
58
  * `normalizeThrown`).
59
59
  */
60
- export class OperationError extends Error {
60
+ export class ToolError extends Error {
61
61
  readonly [OPERATION_ERROR_BRAND] = true;
62
62
  readonly code: string;
63
63
  readonly data: unknown;
64
64
 
65
65
  constructor(code: string, message: string, data?: unknown) {
66
66
  super(message);
67
- this.name = 'OperationError';
67
+ this.name = 'ToolError';
68
68
  this.code = code;
69
69
  this.data = data;
70
70
  }
71
71
  }
72
72
 
73
- export function isOperationError(value: unknown): value is OperationError {
74
- if (value instanceof OperationError) return true;
73
+ export function isOperationError(value: unknown): value is ToolError {
74
+ if (value instanceof ToolError) return true;
75
75
  if (value === null || typeof value !== 'object') return false;
76
76
  const candidate = value as Record<PropertyKey, unknown>;
77
77
  return (
@@ -48,13 +48,18 @@ export const GenerationJobSchema = z.object({
48
48
  createdAt: z.string().datetime(),
49
49
  updatedAt: z.string().datetime(),
50
50
  progress: z.number().min(0).max(1).optional(),
51
+ providerStatus: z.string().optional(),
52
+ queuePosition: z.number().int().nonnegative().optional(),
51
53
  message: z.string().optional(),
54
+ lastPolledAt: z.string().datetime().optional(),
55
+ lastProviderChangeAt: z.string().datetime().optional(),
52
56
  pollError: z.string().optional(),
53
57
  pollErrorAt: z.string().datetime().optional(),
54
58
  pollFailureCount: z.number().int().nonnegative().optional(),
55
59
  nextPollAt: z.string().datetime().optional(),
56
60
  billing: GenerationBillingSchema,
57
61
  poll: GenerationOperationReferenceSchema,
62
+ cancel: GenerationOperationReferenceSchema.optional(),
58
63
  accept: GenerationOperationReferenceSchema.optional(),
59
64
  acceptedAt: z.string().datetime().optional(),
60
65
  provenanceOperationId: z.string().optional(),
@@ -79,9 +84,12 @@ export interface GenerationJobDraft {
79
84
  mode: 'mock' | 'direct' | 'managed';
80
85
  status: GenerationJobStatus;
81
86
  progress?: number;
87
+ providerStatus?: string;
88
+ queuePosition?: number;
82
89
  message?: string;
83
90
  billing: GenerationBilling;
84
91
  poll: { tool: string; input: unknown };
92
+ cancel?: { tool: string; input: unknown };
85
93
  accept?: { tool: string; input: unknown };
86
94
  }
87
95
 
@@ -90,8 +98,11 @@ export interface GenerationJobUpdate {
90
98
  externalId: string;
91
99
  status?: GenerationJobStatus;
92
100
  progress?: number;
101
+ providerStatus?: string;
102
+ queuePosition?: number;
93
103
  message?: string;
94
104
  billing?: GenerationBilling;
105
+ cancel?: { tool: string; input: unknown };
95
106
  accepted?: {
96
107
  provenanceOperationId: string;
97
108
  outputPaths: string[];
@@ -106,7 +117,7 @@ export type GenerationToolContribution =
106
117
  toJob(input: unknown, result: unknown): GenerationJobDraft;
107
118
  }
108
119
  | {
109
- role: 'poll' | 'accept';
120
+ role: 'poll' | 'cancel' | 'accept';
110
121
  provider: string;
111
122
  toUpdate(input: unknown, result: unknown): GenerationJobUpdate;
112
123
  };