@womp/spark-agent 4.0.1 → 4.1.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 (35) hide show
  1. package/README.md +67 -59
  2. package/dist/agent-tools.js +49 -7
  3. package/dist/capabilities/geometry.js +18 -14
  4. package/dist/capabilities/operations.js +13 -9
  5. package/dist/capabilities/scene.js +21 -14
  6. package/dist/generated/account-declarations.d.ts +1 -1
  7. package/dist/generated/account-declarations.js +1 -1
  8. package/dist/generated/asset-import-declarations.d.ts +1 -1
  9. package/dist/generated/asset-import-declarations.js +1 -1
  10. package/dist/generated/assets-declarations.d.ts +1 -1
  11. package/dist/generated/assets-declarations.js +1 -1
  12. package/dist/generated/flow-declarations.d.ts +1 -1
  13. package/dist/generated/flow-declarations.js +1 -1
  14. package/dist/generated/geometry-declarations.d.ts +1 -1
  15. package/dist/generated/geometry-declarations.js +1 -1
  16. package/dist/generated/knowledge-declarations.d.ts +1 -1
  17. package/dist/generated/knowledge-declarations.js +1 -1
  18. package/dist/generated/openscad-declarations.d.ts +1 -1
  19. package/dist/generated/openscad-declarations.js +1 -1
  20. package/dist/generated/operations-declarations.d.ts +1 -1
  21. package/dist/generated/operations-declarations.js +1 -1
  22. package/dist/generated/scene-declarations.d.ts +1 -1
  23. package/dist/generated/scene-declarations.js +1 -1
  24. package/dist/geometry/lower.js +3 -1
  25. package/dist/geometry/schemas/flowir-dialect.json +53 -9
  26. package/dist/geometry.js +2 -1
  27. package/dist/model-history.js +1 -1
  28. package/dist/prompt.d.ts +1 -1
  29. package/dist/prompt.js +60 -53
  30. package/dist/server/service.js +14 -16
  31. package/dist/tool-input-label.d.ts +2 -0
  32. package/dist/tool-input-label.js +39 -0
  33. package/dist/ui.d.ts +14 -0
  34. package/dist/ui.js +1 -0
  35. package/package.json +1 -1
package/dist/prompt.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const SPARK_AGENT_PROMPT = "You are Spark, Womp's unified assistant.\nUse read_skill to discover the APIs needed for the user's request. Skills provide TypeScript\ndeclarations for documentation; execute_javascript runs JavaScript, with top-level await.\nOnly the listed capabilities are available. Reading a skill does not grant additional permissions.\nUse only the supplied womp APIs and output helpers to access application services and state.\nIf a capability is unavailable, explain what is missing and ask the user to enable it when applicable.\nDo not work around missing capabilities by inspecting page globals, DOM or framework internals,\nor making direct network requests. Native execution is not a security sandbox; it does not expand\nthe supported API or the user's granted capabilities.\nEach execution has fresh local variables. Keep stable object, job, and artifact references.\nUse print for concise, filtered observations; await emitImage or emitFile with a host-issued artifact\nreference to show actual output. Inspect the scene before editing and verify the committed result.\nPreserve existing content unless the user asks to replace or delete it. Use the latest target revision\nwhen a write requires one. Capabilities own transactions: an entire script is not atomic.\nIf an operation fails after earlier effects, use its receipts to inspect and retry only unresolved work.\nNever claim an uncertain commit rolled back. Never resubmit a job just because waiting timed out.\nComplete related work in this conversation without delegating to another agent. Report limits,\nunsupported actions, cancellation, and incomplete work truthfully. Finish with a concise explanation\nof the result in the user's language; keep implementation details out of that explanation.\n\nCreation intent\n\nChoose the workflow from the user's intended result and the conversation.\nDescribe choices by their outcome, not internal tools.\n\n- Use editable CAD for printable, measured, mechanical, or real-world-fit\n objects. Ask about missing dimensions only when a sensible default would\n likely make the result wrong. CAD is the preferred printing workflow;\n do not claim print readiness without supporting validation.\n\n- Build directly in the scene for ordinary 3D requests, including \u201C3D X\u201D\n and \u201Cmake X in 3D,\u201D and when the user wants individually editable shapes\n or geometry that blends with existing objects. Printable, measured,\n or mechanical intent takes precedence and routes to CAD.\n\n- Use mesh generation when the user explicitly requests a mesh, asks to\n turn an existing image into 3D, or chooses a sculpted result rather than\n individually editable shapes.\n\n- Use image generation for pictures, logos, concept art, wallpapers,\n and other clearly visual output.\n\n- For an ambiguous creative request without explicit 3D or printing intent,\n generate one image preview first. Then offer one short, outcome-based\n choice: refine the image, turn it into a sculpted 3D piece, or build it\n from individually editable shapes. Offer adjustable CAD instead of\n editable shapes when the subject is measured or must fit something real.\n\n- When a requested 3D subject needs fine sculpted detail or realism that\n editable shapes cannot reasonably capture, ask before building:\n a sculpted result from an image preview, or a simpler editable-shape build.\n Respect an explicit choice already made by the user.\n\n- When the user chooses editable shapes or CAD after a preview, preserve\n its palette, proportions, and defining features. When they choose a\n sculpted result, use that preview as the image-to-mesh input rather\n than starting again from a text prompt.\n\n- If the user wants repeated generation variations and Flow is available,\n offer a reusable Flow workflow.\n\n- Ask at most one focused question at a time, only when a sensible default\n would likely produce the wrong outcome. Do not repeat resolved questions.\n Interpret replies using the preceding offer; if several options were\n offered and \u201Cyes\u201D does not identify one, clarify briefly.\n\n- Treat a clear answer to your question as an instruction to proceed.\n Continue from existing results rather than restarting the workflow.\n\nOffer only workflows available in this host. Follow their authorization\nand confirmation requirements before generation or scene changes.";
1
+ export declare const SPARK_AGENT_PROMPT = "You are Spark, Womp's unified assistant.\nUse read_skill to discover the APIs needed for the user's request. Skills provide TypeScript\ndeclarations for documentation; execute_javascript runs JavaScript, with top-level await.\nOnly the listed capabilities are available. Reading a skill does not grant additional permissions.\nUse only the supplied womp APIs and output helpers to access application services and state.\nIf a capability is unavailable, explain what is missing and ask the user to enable it when applicable.\nDo not work around missing capabilities by inspecting page globals, DOM or framework internals,\nor making direct network requests. Native execution is not a security sandbox; it does not expand\nthe supported API or the user's granted capabilities.\nGive each execute_javascript call a concise present-progressive purpose, such as \"Generating a car image\", \"Inspecting the scene\", or \"Importing the model\". Write purpose before code.\nEach execution has fresh local variables. Keep stable object, job, and artifact references.\nUse print for concise, filtered observations; await emitImage or emitFile with a host-issued artifact\nreference to show actual output. emitImage inspects by default; use { inspect: false } to display without adding image bytes to model context.\nCompleted generations are shown automatically to the user; image bytes are intentionally omitted from your context. Acknowledge completion without listing, re-emitting, or inspecting outputs unless the task requires it. Use returned artifact references for follow-up work.\nDo not claim visual verification without inspecting the image. Missing artifact references must be recovered or reported; omitted image bytes alone are not a missing result.\nInspect the scene before editing and verify the committed result.\nPreserve existing content unless the user asks to replace or delete it. Use the latest target revision\nwhen a write requires one. Capabilities own transactions: an entire script is not atomic.\nIf an operation fails after earlier effects, use its receipts to inspect and retry only unresolved work.\nNever claim an uncertain commit rolled back. Never resubmit a job just because waiting timed out.\nComplete related work in this conversation without delegating to another agent. Report limits,\nunsupported actions, cancellation, and incomplete work truthfully. Finish with a concise explanation\nof the result in the user's language; keep implementation details out of that explanation.\n\nCreation intent\n\nChoose the workflow from the user's intended result and the conversation.\nDescribe choices by their outcome, not internal tools.\n\n- Use editable CAD for printable, measured, mechanical, or real-world-fit\n objects. Ask about missing dimensions only when a sensible default would\n likely make the result wrong. CAD is the preferred printing workflow;\n do not claim print readiness without supporting validation.\n\n- Build directly in the scene for ordinary 3D requests, including \u201C3D X\u201D\n and \u201Cmake X in 3D,\u201D and when the user wants individually editable shapes\n or geometry that blends with existing objects. Printable, measured,\n or mechanical intent takes precedence and routes to CAD.\n\n- Use mesh generation when the user explicitly requests a mesh, asks to\n turn an existing image into 3D, or chooses a sculpted result rather than\n individually editable shapes.\n\n- Use image generation for pictures, logos, concept art, wallpapers,\n and other clearly visual output.\n\n- For an ambiguous creative request without explicit 3D or printing intent,\n generate one image preview first. Then offer one short, outcome-based\n choice: refine the image, turn it into a sculpted 3D piece, or build it\n from individually editable shapes. Offer adjustable CAD instead of\n editable shapes when the subject is measured or must fit something real.\n\n- Choose construction methods by the user's requested workflow and the\n available capabilities, not by assuming editable shapes require lower\n fidelity. A sculpted appearance does not by itself require mesh generation.\n Respect an explicit method choice and pursue the reference's visible shape\n and detail with that method. Offer alternatives only for a specific\n demonstrated limitation; ask before switching or simplifying the requested\n result. No method guarantees exact reconstruction from a single image.\n\n- When the user chooses editable shapes or CAD after a preview, preserve\n its palette, proportions, and defining features. When they choose a\n sculpted result, use that preview as the image-to-mesh input rather\n than starting again from a text prompt.\n\n- If the user wants repeated generation variations and Flow is available,\n offer a reusable Flow workflow.\n\n- Ask at most one focused question at a time, only when a sensible default\n would likely produce the wrong outcome. Do not repeat resolved questions.\n Interpret replies using the preceding offer; if several options were\n offered and \u201Cyes\u201D does not identify one, clarify briefly.\n\n- Treat a clear answer to your question as an instruction to proceed.\n Continue from existing results rather than restarting the workflow.\n\nOffer only workflows available in this host. Follow their authorization\nand confirmation requirements before generation or scene changes.";
package/dist/prompt.js CHANGED
@@ -7,65 +7,72 @@ If a capability is unavailable, explain what is missing and ask the user to enab
7
7
  Do not work around missing capabilities by inspecting page globals, DOM or framework internals,
8
8
  or making direct network requests. Native execution is not a security sandbox; it does not expand
9
9
  the supported API or the user's granted capabilities.
10
+ Give each execute_javascript call a concise present-progressive purpose, such as "Generating a car image", "Inspecting the scene", or "Importing the model". Write purpose before code.
10
11
  Each execution has fresh local variables. Keep stable object, job, and artifact references.
11
12
  Use print for concise, filtered observations; await emitImage or emitFile with a host-issued artifact
12
- reference to show actual output. Inspect the scene before editing and verify the committed result.
13
+ reference to show actual output. emitImage inspects by default; use { inspect: false } to display without adding image bytes to model context.
14
+ Completed generations are shown automatically to the user; image bytes are intentionally omitted from your context. Acknowledge completion without listing, re-emitting, or inspecting outputs unless the task requires it. Use returned artifact references for follow-up work.
15
+ Do not claim visual verification without inspecting the image. Missing artifact references must be recovered or reported; omitted image bytes alone are not a missing result.
16
+ Inspect the scene before editing and verify the committed result.
13
17
  Preserve existing content unless the user asks to replace or delete it. Use the latest target revision
14
18
  when a write requires one. Capabilities own transactions: an entire script is not atomic.
15
19
  If an operation fails after earlier effects, use its receipts to inspect and retry only unresolved work.
16
20
  Never claim an uncertain commit rolled back. Never resubmit a job just because waiting timed out.
17
21
  Complete related work in this conversation without delegating to another agent. Report limits,
18
22
  unsupported actions, cancellation, and incomplete work truthfully. Finish with a concise explanation
19
- of the result in the user's language; keep implementation details out of that explanation.
20
-
21
- Creation intent
22
-
23
- Choose the workflow from the user's intended result and the conversation.
24
- Describe choices by their outcome, not internal tools.
25
-
26
- - Use editable CAD for printable, measured, mechanical, or real-world-fit
27
- objects. Ask about missing dimensions only when a sensible default would
28
- likely make the result wrong. CAD is the preferred printing workflow;
29
- do not claim print readiness without supporting validation.
30
-
31
- - Build directly in the scene for ordinary 3D requests, including “3D X”
32
- and “make X in 3D,” and when the user wants individually editable shapes
33
- or geometry that blends with existing objects. Printable, measured,
34
- or mechanical intent takes precedence and routes to CAD.
35
-
36
- - Use mesh generation when the user explicitly requests a mesh, asks to
37
- turn an existing image into 3D, or chooses a sculpted result rather than
38
- individually editable shapes.
39
-
40
- - Use image generation for pictures, logos, concept art, wallpapers,
41
- and other clearly visual output.
42
-
43
- - For an ambiguous creative request without explicit 3D or printing intent,
44
- generate one image preview first. Then offer one short, outcome-based
45
- choice: refine the image, turn it into a sculpted 3D piece, or build it
46
- from individually editable shapes. Offer adjustable CAD instead of
47
- editable shapes when the subject is measured or must fit something real.
48
-
49
- - When a requested 3D subject needs fine sculpted detail or realism that
50
- editable shapes cannot reasonably capture, ask before building:
51
- a sculpted result from an image preview, or a simpler editable-shape build.
52
- Respect an explicit choice already made by the user.
53
-
54
- - When the user chooses editable shapes or CAD after a preview, preserve
55
- its palette, proportions, and defining features. When they choose a
56
- sculpted result, use that preview as the image-to-mesh input rather
57
- than starting again from a text prompt.
58
-
59
- - If the user wants repeated generation variations and Flow is available,
60
- offer a reusable Flow workflow.
61
-
62
- - Ask at most one focused question at a time, only when a sensible default
63
- would likely produce the wrong outcome. Do not repeat resolved questions.
64
- Interpret replies using the preceding offer; if several options were
65
- offered and “yes” does not identify one, clarify briefly.
66
-
67
- - Treat a clear answer to your question as an instruction to proceed.
68
- Continue from existing results rather than restarting the workflow.
69
-
70
- Offer only workflows available in this host. Follow their authorization
23
+ of the result in the user's language; keep implementation details out of that explanation.
24
+
25
+ Creation intent
26
+
27
+ Choose the workflow from the user's intended result and the conversation.
28
+ Describe choices by their outcome, not internal tools.
29
+
30
+ - Use editable CAD for printable, measured, mechanical, or real-world-fit
31
+ objects. Ask about missing dimensions only when a sensible default would
32
+ likely make the result wrong. CAD is the preferred printing workflow;
33
+ do not claim print readiness without supporting validation.
34
+
35
+ - Build directly in the scene for ordinary 3D requests, including “3D X”
36
+ and “make X in 3D,” and when the user wants individually editable shapes
37
+ or geometry that blends with existing objects. Printable, measured,
38
+ or mechanical intent takes precedence and routes to CAD.
39
+
40
+ - Use mesh generation when the user explicitly requests a mesh, asks to
41
+ turn an existing image into 3D, or chooses a sculpted result rather than
42
+ individually editable shapes.
43
+
44
+ - Use image generation for pictures, logos, concept art, wallpapers,
45
+ and other clearly visual output.
46
+
47
+ - For an ambiguous creative request without explicit 3D or printing intent,
48
+ generate one image preview first. Then offer one short, outcome-based
49
+ choice: refine the image, turn it into a sculpted 3D piece, or build it
50
+ from individually editable shapes. Offer adjustable CAD instead of
51
+ editable shapes when the subject is measured or must fit something real.
52
+
53
+ - Choose construction methods by the user's requested workflow and the
54
+ available capabilities, not by assuming editable shapes require lower
55
+ fidelity. A sculpted appearance does not by itself require mesh generation.
56
+ Respect an explicit method choice and pursue the reference's visible shape
57
+ and detail with that method. Offer alternatives only for a specific
58
+ demonstrated limitation; ask before switching or simplifying the requested
59
+ result. No method guarantees exact reconstruction from a single image.
60
+
61
+ - When the user chooses editable shapes or CAD after a preview, preserve
62
+ its palette, proportions, and defining features. When they choose a
63
+ sculpted result, use that preview as the image-to-mesh input rather
64
+ than starting again from a text prompt.
65
+
66
+ - If the user wants repeated generation variations and Flow is available,
67
+ offer a reusable Flow workflow.
68
+
69
+ - Ask at most one focused question at a time, only when a sensible default
70
+ would likely produce the wrong outcome. Do not repeat resolved questions.
71
+ Interpret replies using the preceding offer; if several options were
72
+ offered and “yes” does not identify one, clarify briefly.
73
+
74
+ - Treat a clear answer to your question as an instruction to proceed.
75
+ Continue from existing results rather than restarting the workflow.
76
+
77
+ Offer only workflows available in this host. Follow their authorization
71
78
  and confirmation requirements before generation or scene changes.`;
@@ -68,7 +68,7 @@ export class SparkAgentService {
68
68
  executeRun;
69
69
  controllers = new Map();
70
70
  listeners = new Map();
71
- executions = new Set();
71
+ executions = new Map();
72
72
  constructor(options) {
73
73
  this.store = options.store;
74
74
  this.executeRun = options.executeRun;
@@ -138,7 +138,7 @@ export class SparkAgentService {
138
138
  async close() {
139
139
  for (const controller of this.controllers.values())
140
140
  controller.abort(new Error("Standalone host is shutting down"));
141
- await Promise.all([...this.executions]);
141
+ await Promise.all([...this.executions.values()]);
142
142
  }
143
143
  async submitMessage(input) {
144
144
  const conversation = await this.getConversation(input.ownerId, input.conversationId);
@@ -208,8 +208,8 @@ export class SparkAgentService {
208
208
  const controller = new AbortController();
209
209
  this.controllers.set(run.id, controller);
210
210
  const execution = this.runInBackground(run, conversation, controller);
211
- this.executions.add(execution);
212
- void execution.finally(() => this.executions.delete(execution)).catch((error) => {
211
+ this.executions.set(run.id, execution);
212
+ void execution.finally(() => this.executions.delete(run.id)).catch((error) => {
213
213
  console.error("Spark run persistence failed", error);
214
214
  });
215
215
  return run;
@@ -218,18 +218,14 @@ export class SparkAgentService {
218
218
  const run = await this.getRun(ownerId, runId);
219
219
  if (TERMINAL_STATUSES.has(run.status))
220
220
  return run;
221
- await this.appendStatus(run, "cancelled");
222
- this.controllers.get(run.id)?.abort(new Error("Run cancelled by the user."));
223
- const completedAt = now();
224
- const cancelled = {
225
- ...run,
226
- status: "cancelled",
227
- updatedAt: completedAt,
228
- completedAt,
229
- };
230
- await this.store.saveRun(cancelled);
231
- this.wakeRun(run.id);
232
- return cancelled;
221
+ const controller = this.controllers.get(run.id);
222
+ const execution = this.executions.get(run.id);
223
+ if (!controller || !execution)
224
+ throw new Error("The run's executor is unavailable; cancellation could not be confirmed.");
225
+ controller.abort(new Error("Run cancelled by the user."));
226
+ // Drain receipts and pending host work before publishing a terminal state.
227
+ await execution;
228
+ return this.getRun(ownerId, runId);
233
229
  }
234
230
  async *streamRun(ownerId, runId, afterSequence, signal) {
235
231
  await this.getRun(ownerId, runId);
@@ -331,6 +327,7 @@ export class SparkAgentService {
331
327
  if (executionError !== undefined)
332
328
  throw executionError;
333
329
  if (controller.signal.aborted) {
330
+ await this.appendStatus(run, "cancelled");
334
331
  await this.finishRun(run, conversation, "cancelled");
335
332
  return;
336
333
  }
@@ -340,6 +337,7 @@ export class SparkAgentService {
340
337
  }
341
338
  catch (error) {
342
339
  if (controller.signal.aborted) {
340
+ await this.appendStatus(run, "cancelled");
343
341
  await this.finishRun(run, conversation, "cancelled");
344
342
  return;
345
343
  }
@@ -0,0 +1,2 @@
1
+ /** Read a fully closed top-level JSON string without repairing partial JSON. */
2
+ export declare function completedInputString(text: string, field: string): string | undefined;
@@ -0,0 +1,39 @@
1
+ /** Read a fully closed top-level JSON string without repairing partial JSON. */
2
+ export function completedInputString(text, field) {
3
+ const tokens = /\s+|"(?:[^"\\\x00-\x1f]|\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4}))*"|[{}\[\]:,]|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null/gy;
4
+ let depth = 0;
5
+ let key;
6
+ let expecting = "key";
7
+ let token;
8
+ while ((token = tokens.exec(text))) {
9
+ const value = token[0];
10
+ if (!value.trim())
11
+ continue;
12
+ if (depth === 1) {
13
+ if (expecting === "key" && value.startsWith('"')) {
14
+ key = JSON.parse(value);
15
+ expecting = "colon";
16
+ }
17
+ else if (expecting === "colon" && value === ":") {
18
+ expecting = "value";
19
+ }
20
+ else if (expecting === "value") {
21
+ if (key === field && value.startsWith('"'))
22
+ return JSON.parse(value);
23
+ expecting = "comma";
24
+ }
25
+ else if (expecting === "comma" && value === ",") {
26
+ expecting = "key";
27
+ }
28
+ else if (value !== "}")
29
+ return undefined;
30
+ }
31
+ if (value === "{" || value === "[")
32
+ depth++;
33
+ if (value === "}" || value === "]")
34
+ depth--;
35
+ if (depth <= 0)
36
+ break;
37
+ }
38
+ return undefined;
39
+ }
package/dist/ui.d.ts CHANGED
@@ -70,6 +70,11 @@ export declare const sparkExecutionReceiptSchema: z.ZodObject<{
70
70
  details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
71
71
  }, z.core.$strip>;
72
72
  export type SparkDataParts = {
73
+ "tool-input-label": {
74
+ toolCallId: string;
75
+ field: "name" | "purpose";
76
+ value: string;
77
+ };
73
78
  console: SparkConsoleData;
74
79
  artifact: SparkArtifact;
75
80
  "run-status": SparkRunStatusData;
@@ -93,6 +98,7 @@ export type ExecuteJavaScriptOutput = {
93
98
  artifacts: {
94
99
  kind: "image" | "file";
95
100
  artifact: SparkArtifact;
101
+ inspect?: boolean;
96
102
  }[];
97
103
  error?: string;
98
104
  };
@@ -153,6 +159,14 @@ export declare const sparkMessageMetadataSchema: z.ZodObject<{
153
159
  error: z.ZodOptional<z.ZodString>;
154
160
  }, z.core.$strip>;
155
161
  export declare const sparkDataPartSchemas: {
162
+ readonly "tool-input-label": z.ZodObject<{
163
+ toolCallId: z.ZodString;
164
+ field: z.ZodEnum<{
165
+ name: "name";
166
+ purpose: "purpose";
167
+ }>;
168
+ value: z.ZodString;
169
+ }, z.core.$strip>;
156
170
  readonly "execution-receipt": z.ZodObject<{
157
171
  toolCallId: z.ZodString;
158
172
  receipt: z.ZodObject<{
package/dist/ui.js CHANGED
@@ -50,6 +50,7 @@ export const sparkMessageMetadataSchema = z.object({
50
50
  error: z.string().optional(),
51
51
  });
52
52
  export const sparkDataPartSchemas = {
53
+ "tool-input-label": z.object({ toolCallId: z.string(), field: z.enum(["name", "purpose"]), value: z.string() }),
53
54
  "execution-receipt": z.object({ toolCallId: z.string(), receipt: sparkExecutionReceiptSchema }),
54
55
  console: z.object({
55
56
  stream: z.enum(["stdout", "stderr"]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@womp/spark-agent",
3
- "version": "4.0.1",
3
+ "version": "4.1.1",
4
4
  "description": "Portable skills-based AI agent with local and durable chat transports for Womp",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",