@womp/spark-agent 6.5.0 → 8.0.0

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 (40) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +7 -4
  3. package/dist/agent.d.ts +3 -6
  4. package/dist/agent.js +41 -23
  5. package/dist/capabilities/geometry.d.ts +17 -5
  6. package/dist/capabilities/geometry.js +11 -12
  7. package/dist/compaction.d.ts +41 -8
  8. package/dist/compaction.js +241 -77
  9. package/dist/context-window.d.ts +23 -0
  10. package/dist/context-window.js +141 -0
  11. package/dist/generated/geometry-declarations.d.ts +1 -1
  12. package/dist/generated/geometry-declarations.js +1 -1
  13. package/dist/geometry/backendRegistry.d.ts +1 -0
  14. package/dist/geometry/common.d.ts +5 -2
  15. package/dist/geometry/common.js +18 -3
  16. package/dist/geometry/compiler.js +2 -2
  17. package/dist/geometry/diagnostics.d.ts +2 -7
  18. package/dist/geometry/diagnostics.js +3 -51
  19. package/dist/geometry/graph.d.ts +1 -1
  20. package/dist/geometry/graph.js +1 -0
  21. package/dist/geometry/index.d.ts +0 -1
  22. package/dist/geometry/index.js +0 -3
  23. package/dist/geometry/lift.js +105 -113
  24. package/dist/geometry/lower.js +29 -49
  25. package/dist/geometry/schemas/flowir-dialect.json +117 -117
  26. package/dist/geometry/writeParamData.js +4 -4
  27. package/dist/geometry.d.ts +2 -5
  28. package/dist/geometry.js +7 -11
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +2 -1
  31. package/dist/intent-bench.js +1 -1
  32. package/dist/sdk-geometry-host.d.ts +1 -1
  33. package/dist/sdk-geometry-host.js +253 -251
  34. package/dist/ui.d.ts +7 -0
  35. package/dist/ui.js +1 -0
  36. package/dist/womp-scene-api.d.ts +9 -1
  37. package/dist/womp-scene-api.js +41 -32
  38. package/package.json +2 -2
  39. package/dist/context-budget.d.ts +0 -65
  40. package/dist/context-budget.js +0 -364
package/CHANGELOG.md CHANGED
@@ -4,6 +4,92 @@ Notable changes to `@womp/spark-agent`, newest first. Versions follow
4
4
  [Semantic Versioning](https://semver.org/). Add an entry with each version bump; describe what
5
5
  changed for hosts and users, and how to migrate across breaking changes.
6
6
 
7
+ ## 8.0.0 — 2026-10-12
8
+
9
+ Geometry Nodes moves to FlowIR 0.5.0. The dialect is FlowIR's strict, flat format, the
10
+ `geometry-nodes-reference` skill is the prompt FlowIR renders from it, and the names the agent
11
+ writes come back when it reads the graph, so a follow-up edit can refer to them.
12
+
13
+ ### Changed
14
+
15
+ - `@womp/flowir` is 0.5.0. The geometry dialect declares its types, enum ports, casts and the
16
+ `Geometry` program output. `param` and `const` declare Int, Float and Vec3; other types are
17
+ rejected instead of being dropped when the graph is written.
18
+ - A write stores each statement's name in `graphExt.nodes[id].flowirSymbol`, and a read returns
19
+ those names. Graphs written without stored names read back as before.
20
+ - Compiler diagnostics are formatted by FlowIR, within the existing count and size bounds.
21
+ - `geometry-nodes` (skill version 6) and `geometry-nodes-reference` (version 3) are rewritten
22
+ for the new dialect.
23
+
24
+ ### Added
25
+
26
+ - `GeometryTarget.transform` and `GeometryTarget.bounds`: the target's position, rotation and
27
+ size relative to its parent, and its world-space extent, in project units. Both are `null`
28
+ where they do not apply.
29
+ - An applied `GeometryWriteResult` also carries the committed `source`, `transform` and
30
+ `bounds`, read back from the scene.
31
+
32
+ ### Removed
33
+
34
+ - `loadGeoNodesDialect` from `@womp/spark-agent/geometry`.
35
+
36
+ ### Migration
37
+
38
+ - `geometryReference()` returns a string instead of `{ rules, catalog }`, and
39
+ `createGeometryCapability` takes that string. Pass `geometryReference()` through unchanged.
40
+ - A host that builds `GeometryTarget` values itself, rather than through
41
+ `createSdkGeometryHost`, must set `transform` and `bounds` (`null` when unknown).
42
+
43
+ ## 7.0.0 — 2026-10-12
44
+
45
+ Compaction is now the only thing that takes messages out of what the model reads, and it can run
46
+ before any step of a turn, not just the first. The per-step trimming that replaced earlier images,
47
+ tool results and whole turns with placeholder text is gone: it rewrote the start of the prompt
48
+ whenever it fired, which threw away the provider's prompt cache on every later step. A request
49
+ that is still over the model's context window after compaction is sent as it is and fails with
50
+ the provider's error.
51
+
52
+ ### Changed
53
+
54
+ - A run given `history` checks the conversation before every step. Once it reaches the compaction
55
+ threshold during a turn, everything before the current user message and the turn's steps before
56
+ its most recent `COMPACTION_KEEP_RECENT_TOKENS` are summarized; the user's message is kept
57
+ verbatim. The summary request is the first kept step's request plus one instruction, so it is
58
+ served from the prompt cache. A compaction that would save less than
59
+ `COMPACTION_MIN_SAVED_RATIO` of the threshold is skipped, so a turn whose own message is over
60
+ the threshold does not summarize on every step.
61
+ - A summary covers only the messages it replaces, before a turn as well as during one. It used to
62
+ tell of the kept messages too, and the model, reading them again after it, took that work for
63
+ done twice.
64
+ - `SparkCompaction.firstKeptStep` records a compaction written during its turn: the first step of
65
+ the recording assistant message the model still reads. `applyCompaction` (and so
66
+ `convertSparkMessages`) leaves the earlier steps out, so the next turn rebuilds exactly the
67
+ messages the last step was sent. A run may now record more than one `data-compaction` part; the
68
+ latest is the one in force. Hosts must store and reload message parts in order, including
69
+ `step-start`.
70
+ - When to compact is measured from the provider's count for the conversation's last step after the
71
+ latest compaction, including the steps of the message that recorded it.
72
+
73
+ ### Added
74
+
75
+ - `applyCompaction` and `latestCompaction` are exported from the package root, so a host can tell
76
+ which stored messages, and which of their images, the model will be sent.
77
+
78
+ ### Removed
79
+
80
+ - `fitMessagesToContext`, `ContextBudgetOptions`, `ContextBudgetReport`, `ContextBudgetResult`,
81
+ `TRIM_TRIGGER_RATIO`, `TRIM_TARGET_RATIO`, `SMALL_TOOL_OUTPUT_TOKENS`,
82
+ `PROTECTED_CURRENT_STEPS` and the `OMITTED_HISTORY_TEXT`, `OMITTED_HISTORY_IMAGE_TEXT` and
83
+ `OMITTED_TOOL_OUTPUT_TEXT` notes.
84
+ - `SparkAgentOptions.onContextBudget`.
85
+
86
+ ### Migration
87
+
88
+ - Remove any `onContextBudget` handler and any host-side trimming. Pass `history` to have long
89
+ conversations compacted; a run given `messages` is sent exactly what it is given.
90
+ - `contextWindowFor`, `estimateMessagesTokens`, `estimateRequestTokens`, `CHARS_PER_TOKEN` and
91
+ `IMAGE_TOKENS` are unchanged; they now live in `src/context-window.ts`.
92
+
7
93
  ## 6.5.0 — 2026-10-12
8
94
 
9
95
  The agent proposes a goal during its turn, instead of the host asking a separate model call to
package/README.md CHANGED
@@ -75,9 +75,11 @@ The default model-step limit is 100; reaching it returns `status: "incomplete"`,
75
75
  restart automatically to bypass it. A generation that ends on any other non-`stop` reason fails the
76
76
  run with the unified and provider finish reasons in its error and diagnostics.
77
77
 
78
- Before each model step, Spark trims older images, large tool results, and whole earlier turns to
79
- keep the request inside the model's context window. The latest user message and the most recent
80
- steps are never trimmed.
78
+ When a run is given its stored `history`, Spark compacts it before any model step once the
79
+ conversation reaches the compaction threshold: earlier turns, and earlier steps of a long turn, are
80
+ replaced by a summary recorded on the run's message as a `data-compaction` part. Nothing else
81
+ shortens a request; one that is still over the model's context window fails with the provider's
82
+ error.
81
83
 
82
84
  ### Artifacts
83
85
 
@@ -355,7 +357,8 @@ features, patch for backward-compatible fixes.
355
357
 
356
358
  - `src/agent.ts` — AI SDK stream and Spark tool orchestration
357
359
  - `src/prompt.ts` — shared system prompt
358
- - `src/context-budget.ts` — per-step context-window trimming
360
+ - `src/compaction.ts` — conversation compaction before each model step
361
+ - `src/context-window.ts` — model context windows and request size estimates
359
362
  - `src/ui.ts` — browser-safe protocol types and validation schemas
360
363
  - `src/client.ts` — durable `ChatTransport` implementation
361
364
  - `src/server/` — service, storage contracts, Express adapter, artifacts, and standalone composition
package/dist/agent.d.ts CHANGED
@@ -2,7 +2,6 @@ import { streamText, type LanguageModel, type ModelMessage } from "ai";
2
2
  import { type SparkGoalOffer, type SparkPersistence } from "./agent-tools.js";
3
3
  import type { SparkArtifactResolver, SparkCapabilities } from "./capabilities.js";
4
4
  import type { JavaScriptExecutor } from "./executor.js";
5
- import { type ContextBudgetReport } from "./context-budget.js";
6
5
  import { type SparkCompactionLimits } from "./compaction.js";
7
6
  import type { SparkUIMessage, SparkUIMessageChunk } from "./ui.js";
8
7
  export type SparkAgentResult = {
@@ -17,8 +16,8 @@ export type SparkAgentOptions = {
17
16
  messages?: ModelMessage[];
18
17
  /**
19
18
  * The stored conversation. It is converted with `convertSparkMessages`, and
20
- * compacted first once it is long enough (./compaction.ts); the new
21
- * compaction is written to this run's message as a `data-compaction` part.
19
+ * compacted before any step once it is long enough (./compaction.ts); each
20
+ * new compaction is written to this run's message as a `data-compaction` part.
22
21
  */
23
22
  history?: SparkUIMessage[];
24
23
  model: LanguageModel;
@@ -38,12 +37,10 @@ export type SparkAgentOptions = {
38
37
  /** Gives the model `propose_goal`; absent, it has no way to offer a goal. */
39
38
  proposeGoal?: SparkGoalOffer;
40
39
  prepareMessages?(messages: ModelMessage[]): Promise<ModelMessage[]>;
41
- /** The model's context window. Absent: `contextWindowFor(modelId)`. */
40
+ /** The model's context window, which caps when `history` is compacted. Absent: `contextWindowFor(modelId)`. */
42
41
  contextWindow?: number;
43
42
  /** When `history` is compacted. Absent: the defaults in ./compaction.ts. */
44
43
  compaction?: SparkCompactionLimits;
45
- /** Called when a step's messages had to be trimmed to fit, or still do not fit. */
46
- onContextBudget?(report: ContextBudgetReport): void;
47
44
  };
48
45
  export type SparkAgentRun = {
49
46
  stream: ReadableStream<SparkUIMessageChunk>;
package/dist/agent.js CHANGED
@@ -4,8 +4,8 @@ import { createUIMessageStream, stepCountIs, streamText, } from "ai";
4
4
  import { createSparkTools } from "./agent-tools.js";
5
5
  import { sparkSystemPrompt } from "./prompt.js";
6
6
  import { calculateStepCost } from "./pricing.js";
7
- import { contextWindowFor, fitMessagesToContext } from "./context-budget.js";
8
- import { compactSparkHistory } from "./compaction.js";
7
+ import { contextWindowFor } from "./context-window.js";
8
+ import { compactSparkHistory, createStepCompaction, latestCompaction } from "./compaction.js";
9
9
  import { convertSparkMessages } from "./model-history.js";
10
10
  function errorMessage(error) {
11
11
  return sparkErrorDiagnostics(error).message;
@@ -131,11 +131,14 @@ export function runSparkAgent(options) {
131
131
  });
132
132
  const readSystem = () => sparkSystemPrompt(options.capabilities.skills, options.instructions);
133
133
  let messages = options.messages ?? [];
134
+ // Compaction before each later step; only for a stored conversation,
135
+ // where the compaction can be recorded.
136
+ let compactStep;
134
137
  if (options.history !== undefined) {
135
138
  const history = options.history;
136
- const compacted = await compactSparkHistory({
137
- history,
138
- convert: (compaction) => convertSparkMessages(history, tools, { compaction, skills: options.capabilities.skills }),
139
+ const skills = options.capabilities.skills;
140
+ let compactions = 0;
141
+ const summaryOptions = {
139
142
  model: options.model,
140
143
  modelId: options.modelId,
141
144
  system: readSystem(),
@@ -149,12 +152,29 @@ export function runSparkAgent(options) {
149
152
  type: "data-run-status",
150
153
  data: { runId: options.runId, status: "running", label: "Making room so we can keep talking" },
151
154
  }),
155
+ };
156
+ const record = (compaction) => writer.write({
157
+ type: "data-compaction",
158
+ id: `compaction-${options.messageId}${compactions++ === 0 ? "" : `-${compactions}`}`,
159
+ data: compaction,
160
+ });
161
+ const compacted = await compactSparkHistory({
162
+ ...summaryOptions,
163
+ history,
164
+ convert: (compaction) => convertSparkMessages(history, tools, { compaction, skills }),
152
165
  });
153
166
  messages = compacted.messages;
154
- if (compacted.compaction !== undefined) {
155
- writer.write({ type: "data-compaction", id: `compaction-${options.messageId}`, data: compacted.compaction });
156
- }
167
+ if (compacted.compaction !== undefined)
168
+ record(compacted.compaction);
157
169
  controller.signal.throwIfAborted();
170
+ compactStep = createStepCompaction({
171
+ ...summaryOptions,
172
+ history,
173
+ previous: compacted.compaction ?? latestCompaction(history)?.compaction,
174
+ skills,
175
+ convert: (stored) => convertSparkMessages(stored, tools, { skills }),
176
+ onCompaction: record,
177
+ });
158
178
  }
159
179
  const generation = streamText({
160
180
  model: options.model,
@@ -166,25 +186,23 @@ export function runSparkAgent(options) {
166
186
  stopWhen: stepCountIs(maxSteps),
167
187
  maxOutputTokens: options.maxOutputTokens,
168
188
  providerOptions: options.providerOptions,
169
- prepareStep: async ({ messages }) => {
189
+ prepareStep: async ({ messages, steps }) => {
170
190
  controller.signal.throwIfAborted();
171
- const prepared = options.prepareMessages === undefined
191
+ // The first step was compacted above, before the request was built.
192
+ // The AI SDK sends each later step what the one before it was sent,
193
+ // so a compaction here holds for the rest of the turn.
194
+ const last = steps.at(-1)?.usage;
195
+ const current = compactStep === undefined || steps.length === 0
172
196
  ? messages
173
- : await options.prepareMessages(messages);
197
+ : await compactStep(messages, { inputTokens: last?.inputTokens, outputTokens: last?.outputTokens });
198
+ controller.signal.throwIfAborted();
199
+ const prepared = options.prepareMessages === undefined
200
+ ? current
201
+ : await options.prepareMessages(current);
174
202
  controller.signal.throwIfAborted();
175
- const system = readSystem();
176
- // After the host's own preparation, so what is measured is what is sent.
177
- const fitted = fitMessagesToContext(prepared, {
178
- contextWindow,
179
- maxOutputTokens: options.maxOutputTokens,
180
- system,
181
- tools,
182
- });
183
- if (fitted.report && (fitted.messages !== prepared || !fitted.report.fits))
184
- options.onContextBudget?.(fitted.report);
185
203
  return {
186
- system,
187
- messages: fitted.messages,
204
+ system: readSystem(),
205
+ messages: prepared,
188
206
  };
189
207
  },
190
208
  onError: ({ error }) => {
@@ -1,9 +1,19 @@
1
1
  import type { SparkCapability, SparkInvocationContext } from "../capabilities.js";
2
- export type GeometryParamValue = number | {
2
+ export type GeometryVector = {
3
3
  x: number;
4
4
  y: number;
5
5
  z: number;
6
6
  };
7
+ export type GeometryParamValue = number | GeometryVector;
8
+ export type GeometryTransform = {
9
+ position: GeometryVector;
10
+ rotation: GeometryVector;
11
+ size: GeometryVector;
12
+ };
13
+ export type GeometryBounds = {
14
+ min: GeometryVector;
15
+ max: GeometryVector;
16
+ };
7
17
  export type GeometryInstance = {
8
18
  instanceId: number;
9
19
  objectIds: number[];
@@ -16,6 +26,8 @@ export type GeometryTarget = {
16
26
  graphId?: number;
17
27
  instanceId?: number;
18
28
  source: string | null;
29
+ transform: GeometryTransform | null;
30
+ bounds: GeometryBounds | null;
19
31
  instances: GeometryInstance[];
20
32
  diagnostics: string[];
21
33
  };
@@ -28,6 +40,9 @@ export type GeometryWriteResult = {
28
40
  objectId: number;
29
41
  graphId?: number;
30
42
  instanceId?: number;
43
+ source?: string;
44
+ transform?: GeometryTransform | null;
45
+ bounds?: GeometryBounds | null;
31
46
  affectedObjectIds: number[];
32
47
  diagnostics: string[];
33
48
  };
@@ -39,7 +54,4 @@ export interface GeometryHost {
39
54
  read(objectId: number, context: SparkInvocationContext): Promise<GeometryTarget>;
40
55
  write(options: GeometryWrite, context: SparkInvocationContext): Promise<GeometryWriteResult>;
41
56
  }
42
- export declare function createGeometryCapability(host: GeometryHost, reference: {
43
- rules: string;
44
- catalog: string;
45
- }): SparkCapability<WompGeometryApi>;
57
+ export declare function createGeometryCapability(host: GeometryHost, reference: string): SparkCapability<WompGeometryApi>;
@@ -12,23 +12,22 @@ export function createGeometryCapability(host, reference) {
12
12
  skills: [
13
13
  {
14
14
  name: "geometry-nodes",
15
- version: "5",
15
+ version: "6",
16
16
  description: "Create and edit visual Geometry Nodes graphs with adjustable parameters and animation.",
17
17
  instructions: `Use womp.geometry for requested Geometry Nodes, parametric organic/procedural geometry, or animation.
18
18
  Keep follow-up edits to an existing Geometry Nodes object in its graph, preserving its adjustable parameters and instances.
19
- Read the target after any scene edit this build needs. read(0) reads the scene root as a creation container.
19
+ An Area is a scene object that holds one Geometry Nodes graph; a Group is a container. read(0) reads the scene root as a creation container.
20
+ read returns the target's FlowIR source, its instances with their parameter overrides (in FlowIR units), its transform and its bounds. transform is position, rotation and size relative to the parent, in project units as the scene API reports them; an Area's size is a dimensionless scale, and the scene root's transform is null. bounds is the world-space extent in project units, null unless the target is a top-level Area whose graph renders geometry. Read the target again after another scene edit changes it.
21
+ If source is null and diagnostics is non-empty, the existing graph cannot be edited without loss. Explain the limitation; never treat it as empty or create a replacement to bypass the refusal.
22
+ Read geometry-nodes-reference before writing source. source is the complete FlowIR text for the target; JavaScript calls execute JavaScript, and source is a FlowIR string, not JavaScript or JSON.
20
23
  write updates an existing shared graph, attaches a new graph to an Area without one, or creates a new Area beneath the root/Group target. Use the returned objectId for follow-up edits.
21
- Read geometry-nodes-reference before writing source. Supply the complete FlowIR text after inspecting the target. JavaScript calls execute JavaScript; source is a FlowIR string, not JavaScript or JSON.
22
- Inspect the current target before replacing its graph; preserve unrelated geometry and parameter overrides.
23
- If source is null and diagnostics are present, the existing graph cannot be edited without loss. Explain the limitation; never treat it as empty or create a replacement to bypass the refusal.
24
- Preserve unrelated statements, parameter names, and FlowIR node IDs from the read. Shared graph edits affect all listed instances; report the affected objects. Valid overrides migrate by parameter name and type. Removed or type-changed parameters return to graph defaults and are reported.
24
+ Preserve unrelated statements, parameter names, FlowIR node IDs and parameter overrides from the read. Shared graph edits affect all listed instances; report the affected objects. Valid overrides migrate by parameter name and type. Removed or type-changed parameters return to graph defaults and are reported.
25
25
  Use min/max/step for naturally bounded parameters and omit ranges for free-form positions/rotations. Meaningful parameter names become editor labels. Do not invent label fields.
26
26
  SetMaterial assigns one scene material to every primitive it receives. Its Material input is a scene material ID, not a color; 0 selects the scene default material.
27
- Obtain that ID from the scene-editing skill inside one scene.access, where those lookups live: materialList with materialGetName and materialGetColor to reuse an existing material, materialCreate with materialSetColor and materialSetName for a new one, or listSuperMaterials with materialImport for a library material. Prefer reusing a material that already matches the request over creating another, and do not recolor a shared material unless every object using it should change.
28
- Create or import the material inside scene.access before writing the geometry target, all within one JavaScript call. Each call has a fresh scope and cannot read an earlier call's variables.
29
- Positions and sizes are millimetres; Boolean Blend uses the conversion in geometry-nodes-reference. Coordinates are right-handed, +X right, +Y up, +Z forward. Rotations are degrees, intrinsic X-Z-Y.
27
+ Obtain that ID from the scene-editing skill inside womp.scene.access, in the same JavaScript call as the write and before it: materialList with materialGetName and materialGetColor to reuse an existing material, materialCreate with materialSetColor and materialSetName for a new one, or listSuperMaterials with materialImport for a library material. Prefer reusing a material that already matches the request over creating another, and do not recolor a shared material unless every object using it should change.
28
+ FlowIR positions and sizes are millimetres; Boolean Blend uses the conversion in geometry-nodes-reference. Coordinates are right-handed, +X right, +Y up, +Z forward. Rotations are degrees, intrinsic X-Z-Y.
30
29
  On compiler errors, repair the source in this same conversation and retry with a fresh read. A rejected write made no change. Committed/unknown effects remain in execution receipts even if a later call fails; inspect before retrying.
31
- After applying, read the returned object and use the scene screenshot API with emitImage to inspect the applied result.`,
30
+ When status is "applied", the write result also holds the committed target read back from the scene: source, transform and bounds. Print it; it verifies the graph, so do not read the target again to check it. When the target's latest source is already printed in this conversation, make its next edit in a single call: read, replace and write. Use the scene screenshot API with emitImage to inspect the applied result.`,
32
31
  declarations: WOMP_GEOMETRY_DECLARATIONS,
33
32
  examples: [
34
33
  "const target = await womp.geometry.read(objectId); print(target);",
@@ -38,9 +37,9 @@ After applying, read the returned object and use the scene screenshot API with e
38
37
  },
39
38
  {
40
39
  name: "geometry-nodes-reference",
41
- version: "2",
40
+ version: "3",
42
41
  description: "FlowIR syntax, types, enums, and supported Geometry Nodes catalog; read before writing a graph.",
43
- instructions: `${reference.rules}\n${reference.catalog}`,
42
+ instructions: reference,
44
43
  declarations: "",
45
44
  examples: [],
46
45
  },
@@ -3,10 +3,12 @@ import type { SparkSkill } from "./capabilities.js";
3
3
  import { type SparkCompaction, type SparkUIMessage } from "./ui.js";
4
4
  /** Compact once the conversation reaches this many tokens. */
5
5
  export declare const COMPACTION_THRESHOLD_TOKENS = 256000;
6
- /** Recent whole turns kept verbatim, up to this many tokens, besides the current turn. */
6
+ /** Recent whole turns, or recent steps of the current turn, kept verbatim, up to this many tokens. */
7
7
  export declare const COMPACTION_KEEP_RECENT_TOKENS = 16000;
8
8
  /** The user's newest images from the summarized messages that the summary message carries. */
9
9
  export declare const COMPACTION_USER_IMAGES = 4;
10
+ /** A compaction during a turn saves at least this share of the threshold, or is not made. */
11
+ export declare const COMPACTION_MIN_SAVED_RATIO = 0.25;
10
12
  /**
11
13
  * When a conversation is compacted, for a host that exercises compaction
12
14
  * without filling a production-sized conversation, such as local development.
@@ -19,27 +21,28 @@ export type SparkCompactionLimits = {
19
21
  };
20
22
  export declare const COMPACTION_PROMPT = "Write a checkpoint summary of this conversation so far. It replaces the earlier messages in your context, so the work must be able to continue from it alone. Reply with the summary only, without calling tools. This request is not part of the conversation: leave it out of the summary.\nIf the conversation begins with an earlier summary, carry its content forward and update it.\nUse these sections:\n## Goal\n## User preferences and constraints\n## Decisions and current scene state (objects with their names and IDs)\n## Done\n## Open and next steps\n## Artifacts and images (each artifact ID, and what each image the user attached shows)\n## Errors and approaches to avoid\nKeep exact names, IDs, numbers and the user's own wording for requirements. Stay under 1,500 words.";
21
23
  export declare const COMPACTION_NOTE = "[Earlier messages in this conversation were replaced by the summary below. The scene itself is unchanged; inspect it for its exact state.]";
24
+ export declare const COMPACTION_STEPS_NOTE = "[Earlier messages in this conversation, and the earlier steps of your work on the message after this one, were replaced by the summary below. The scene itself is unchanged; inspect it for its exact state.]";
22
25
  /** The latest compaction in the conversation whose kept message is still in it. */
23
26
  export declare function latestCompaction(history: SparkUIMessage[]): {
24
27
  compaction: SparkCompaction;
25
28
  carrier: number;
29
+ part: number;
26
30
  firstKept: number;
27
31
  } | undefined;
28
32
  /**
29
33
  * The conversation as the model reads it: the messages before the compaction's
30
34
  * kept message replaced by its summary, with the newest COMPACTION_USER_IMAGES
31
- * images the user attached to them. `compaction` defaults to the latest one in `history`; `skills` are the
32
- * host's, to send the current text of the skills it names. Without a
33
- * compaction, `history` is returned as it is.
35
+ * images the user attached to them, and -- for the latest compaction, when it was
36
+ * written during its turn -- the recording message's steps before
37
+ * `firstKeptStep` left out with them. `compaction` defaults to the latest one in
38
+ * `history`; `skills` are the host's, to send the current text of the skills it
39
+ * names. Without a compaction, `history` is returned as it is.
34
40
  */
35
41
  export declare function applyCompaction(history: SparkUIMessage[], options?: {
36
42
  compaction?: SparkCompaction;
37
43
  skills?: readonly SparkSkill[];
38
44
  }): SparkUIMessage[];
39
- export type CompactSparkHistoryOptions = {
40
- history: SparkUIMessage[];
41
- /** `history` as model messages, with `compaction` applied when given. */
42
- convert(compaction?: SparkCompaction): Promise<ModelMessage[]>;
45
+ type SummaryOptions = {
43
46
  model: LanguageModel;
44
47
  modelId: string;
45
48
  system: string;
@@ -53,6 +56,11 @@ export type CompactSparkHistoryOptions = {
53
56
  onCompacting?(): void;
54
57
  limits?: SparkCompactionLimits;
55
58
  };
59
+ export type CompactSparkHistoryOptions = SummaryOptions & {
60
+ history: SparkUIMessage[];
61
+ /** `history` as model messages, with `compaction` applied when given. */
62
+ convert(compaction?: SparkCompaction): Promise<ModelMessage[]>;
63
+ };
56
64
  /**
57
65
  * The turn's model messages, compacted first when the conversation has reached
58
66
  * the threshold. `compaction` is the new one, for the host to record; it is
@@ -62,3 +70,28 @@ export declare function compactSparkHistory(options: CompactSparkHistoryOptions)
62
70
  messages: ModelMessage[];
63
71
  compaction?: SparkCompaction;
64
72
  }>;
73
+ export type StepCompactionOptions = SummaryOptions & {
74
+ /** The stored conversation, ending with the current user message. */
75
+ history: SparkUIMessage[];
76
+ /** The compaction the turn started from: the one written before its first step, else `history`'s latest. */
77
+ previous?: SparkCompaction;
78
+ /** The host's skills, for the summary message's skill text. */
79
+ skills?: readonly SparkSkill[];
80
+ /** Stored messages as model messages. */
81
+ convert(messages: SparkUIMessage[]): Promise<ModelMessage[]>;
82
+ /** A new compaction, for the host to record on the turn's message. */
83
+ onCompaction(compaction: SparkCompaction): void;
84
+ };
85
+ /** What the provider reported for the step before. */
86
+ export type StepUsage = {
87
+ inputTokens?: number;
88
+ outputTokens?: number;
89
+ };
90
+ /**
91
+ * Compaction before each later step of a turn. Returns the step's messages,
92
+ * compacted when the conversation has reached the threshold; the AI SDK carries
93
+ * what a step was sent into the next, so a compaction holds for the rest of the
94
+ * turn.
95
+ */
96
+ export declare function createStepCompaction(options: StepCompactionOptions): (messages: ModelMessage[], last?: StepUsage) => Promise<ModelMessage[]>;
97
+ export {};