@womp/spark-agent 5.12.0 → 5.12.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.
package/README.md CHANGED
@@ -348,7 +348,8 @@ Prompt caching is enabled for every listed model: Claude Opus 5 and Fable 5 use
348
348
  automatic 5-minute caching, and GPT-6 Astra uses implicit caching with a 30-minute TTL.
349
349
  The providers manage the cache as message history grows across tool steps; no local
350
350
  response cache is used. Cache hits require matching prefixes, sufficient prompt length,
351
- and an unexpired entry. Cache writes can cost more than uncached input, while subsequent
351
+ and an unexpired entry. Goal state stays out of the system prompt: objectives,
352
+ goal rules and evaluator feedback arrive in appended goal messages. Cache writes can cost more than uncached input, while subsequent
352
353
  cache reads are cheaper. The UI displays actual reported reads/writes, not assumed savings.
353
354
  See [Claude caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)
354
355
  and [OpenAI caching](https://developers.openai.com/api/docs/guides/prompt-caching).
package/dist/agent.js CHANGED
@@ -124,6 +124,8 @@ export function runSparkAgent(options) {
124
124
  controller,
125
125
  write: (chunk) => writer.write(chunk),
126
126
  });
127
+ // Must stay identical across the turns of a conversation: any change misses the
128
+ // provider's prompt cache for everything after it. Changing state belongs in messages.
127
129
  const readSystem = () => [
128
130
  options.instructions ?? SPARK_AGENT_PROMPT,
129
131
  options.context,
@@ -23,7 +23,7 @@ export function createSparkRunExecutor(options) {
23
23
  runId: context.runId,
24
24
  messageId: context.assistantMessageId,
25
25
  signal: context.signal,
26
- context: [host.context, context.goal ? `Active goal: ${JSON.stringify(context.goal.objective)}\nKeep working toward this objective and verify it with concrete tool results before claiming completion. Do not ask whether to continue. If you need user input or access, explain exactly what is missing. Latest evaluation: ${context.goal.lastReason ?? "Not evaluated yet."}` : undefined].filter(Boolean).join("\n\n"),
26
+ context: host.context,
27
27
  });
28
28
  return { stream: run.stream, result: run.result.finally(() => host.dispose()) };
29
29
  }
@@ -76,12 +76,20 @@ function normalizeUserMessage(message) {
76
76
  },
77
77
  };
78
78
  }
79
- /** Budget accounting stays in the host; the worker receives the task and progress. */
79
+ const GOAL_WORK_RULES = "Keep working toward this objective and verify it with concrete tool results before claiming completion. Do not ask whether to continue. If you need user input or access, explain exactly what is missing.";
80
+ /**
81
+ * Budget accounting stays in the host; the worker receives the task and progress.
82
+ * Goal state travels in these appended messages, not the system prompt, so each
83
+ * turn reuses the provider's cached prefix.
84
+ */
80
85
  function goalContinuationText(goal) {
81
- return `Continue working toward the goal: ${goal.objective}\nProgress check: ${goal.lastReason}`
86
+ return `Continue working toward the goal: ${goal.objective}\n${GOAL_WORK_RULES}\nProgress check: ${goal.lastReason}`
82
87
  + (wompifyContextSchema.safeParse(goal.settings.wompify).success
83
88
  ? "\nKeep refining the existing reconstruction at the same detail level. Compare it with the reference and improve the remaining shape and color discrepancies." : "");
84
89
  }
90
+ function goalStartText(goal, action) {
91
+ return `${action === "set" ? "Goal" : "Resume the goal"}: ${goal.objective}\n${GOAL_WORK_RULES}`;
92
+ }
85
93
  export class SparkAgentService {
86
94
  store;
87
95
  executeRun;
@@ -222,7 +230,7 @@ export class SparkAgentService {
222
230
  } : { ...current, settings: runSettings, status: "active", updatedAt: now(),
223
231
  idleTurns: 0, };
224
232
  const inputMessage = normalizeUserMessage(message ?? {
225
- id: crypto.randomUUID(), role: "user", parts: [{ type: "text", text: command.action === "set" ? goal.objective : `Resume the goal: ${goal.objective}` }],
233
+ id: crypto.randomUUID(), role: "user", parts: [{ type: "text", text: goalStartText(goal, command.action) }],
226
234
  });
227
235
  await validateUIMessages({ messages: [inputMessage], metadataSchema: sparkMessageMetadataSchema, dataSchemas: sparkDataPartSchemas });
228
236
  await this.store.saveConversationGoal(conversationId, goal);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@womp/spark-agent",
3
- "version": "5.12.0",
3
+ "version": "5.12.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",