@vincemakes/kiso-runtime 0.26.0 → 0.26.2

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/dist/agent.js CHANGED
@@ -28,13 +28,17 @@ export class AgentRuntime {
28
28
  // E1: extension tools join the registry — a collision with a built-in
29
29
  // name throws here, at agent creation: a loud startup failure.
30
30
  for (const ext of definition.extensions ?? []) {
31
- for (const tool of ext.tools ?? [])
32
- this.#registry.register(tool);
33
- // 0.1.26 (MCP lazy connection): an extension's tools array is LIVE — the
34
- // registry consults it on every lookup, so tools registered by a
35
- // background connect (the MCP bridge's servers) are callable the
36
- // moment they land, without a session rebuild.
37
- this.#registry.registerLive(() => ext.tools ?? []);
31
+ // CX-1 F7a (audit F7): extension tools are reached ONLY through
32
+ // their live source — never frozen into static entries that would
33
+ // win every lookup and mask a background refresh (the MCP bridge
34
+ // replacing its cached definitions). The loud startup collision
35
+ // stays: a startup tool sharing a built-in's name (or an earlier
36
+ // extension's) throws here, at agent creation.
37
+ for (const tool of ext.tools ?? []) {
38
+ if (this.#registry.has(tool.name))
39
+ throw new Error(`Tool already registered: ${tool.name} (extension ${ext.name})`);
40
+ }
41
+ this.#registry.registerLive(() => ext.tools ?? [], ext.name);
38
42
  }
39
43
  this.#adapterPromise = resolveAdapter(definition);
40
44
  }
package/dist/summarize.js CHANGED
@@ -197,6 +197,16 @@ export async function summarizeConversation(options) {
197
197
  const { adapter, model, messages } = options;
198
198
  let text = "";
199
199
  let usage = null;
200
+ // CX-1 F3 (audit F3): the turn's SHAPE is validated, not just its text.
201
+ // A max_tokens cut after the last required heading, a turn with no
202
+ // stop, a turn that called a tool — all passed the section check and
203
+ // were persisted as a checkpoint that was not one. Exactly one stop,
204
+ // reason end_turn, zero tool-call events, no model output after the
205
+ // stop; `usage` after the stop is the one permitted trailer.
206
+ let stops = 0;
207
+ let stopReason;
208
+ let toolCalls = 0;
209
+ let afterStop;
200
210
  for await (const ev of adapter.stream({
201
211
  model,
202
212
  messages,
@@ -204,13 +214,31 @@ export async function summarizeConversation(options) {
204
214
  ...(options.signal !== undefined ? { signal: options.signal } : {}),
205
215
  ...(options.maxOutputTokens !== undefined ? { maxTokens: options.maxOutputTokens } : {}),
206
216
  })) {
217
+ if (stops > 0 && ev.type !== "usage" && ev.type !== "stop" && afterStop === undefined)
218
+ afterStop = ev.type;
207
219
  if (ev.type === "text_delta")
208
220
  text += ev.text;
221
+ else if (ev.type === "tool_call_start" || ev.type === "tool_call_end" || ev.type === "tool_call_input_delta")
222
+ toolCalls += 1;
223
+ else if (ev.type === "stop") {
224
+ stops += 1;
225
+ stopReason = ev.reason;
226
+ }
209
227
  // The LAST usage event is the call's (a turn reports usage once).
210
228
  if (ev.type === "usage" && ev.known) {
211
229
  usage = { inputTokens: ev.inputTokens, outputTokens: ev.outputTokens, cacheRead: ev.cacheRead, cacheWrite: ev.cacheWrite };
212
230
  }
213
231
  }
232
+ if (stops === 0)
233
+ throw new Error("the summary turn never stopped — not a complete turn");
234
+ if (stops > 1)
235
+ throw new Error(`the summary turn stopped ${stops} times — not a complete turn`);
236
+ if (toolCalls > 0)
237
+ throw new Error("the summary turn called a tool — a summary is text, never a tool call");
238
+ if (stopReason !== "end_turn")
239
+ throw new Error(`the summary turn ended with ${String(stopReason)} — not a complete turn`);
240
+ if (afterStop !== undefined)
241
+ throw new Error(`the summary turn produced ${afterStop} after its stop — not a complete turn`);
214
242
  const trimmed = text.trim();
215
243
  if (trimmed === "") {
216
244
  throw new Error("the summary call produced no text");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-runtime",
3
- "version": "0.26.0",
3
+ "version": "0.26.2",
4
4
  "description": "kiso runtime — durable multi-turn agent sessions: AgentDefinition, AgentRuntime, AgentSession, Run, append-only JSONL store.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -25,11 +25,11 @@
25
25
  "test": "vitest run"
26
26
  },
27
27
  "dependencies": {
28
- "@vincemakes/kiso-core": "0.26.0"
28
+ "@vincemakes/kiso-core": "0.26.2"
29
29
  },
30
30
  "peerDependencies": {
31
- "@vincemakes/kiso-provider-anthropic": "0.26.0",
32
- "@vincemakes/kiso-provider-openai": "0.26.0"
31
+ "@vincemakes/kiso-provider-anthropic": "0.26.2",
32
+ "@vincemakes/kiso-provider-openai": "0.26.2"
33
33
  },
34
34
  "peerDependenciesMeta": {
35
35
  "@vincemakes/kiso-provider-anthropic": {
@@ -40,7 +40,7 @@
40
40
  }
41
41
  },
42
42
  "devDependencies": {
43
- "@vincemakes/kiso-evals": "0.26.0",
43
+ "@vincemakes/kiso-evals": "0.26.2",
44
44
  "@types/node": "^26.1.2",
45
45
  "typescript": "^5.7.2",
46
46
  "vitest": "^3.0.0"