@vincemakes/kiso-runtime 0.46.2 → 0.47.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.
@@ -29,7 +29,7 @@ export { canonicalizeUsageForModel } from "./usage/canonical.js";
29
29
  export { BUILTIN_MANIFESTS, resolveContinuationScope, type ModelRef, type ProviderManifest } from "./provider/manifest.js";
30
30
  export * from "./checkpoint.js";
31
31
  export * from "./request-budget.js";
32
- export { readProfile, readSummary, writeSummary, type ExecutionProfile, type ProfileReadResult } from "./profile.js";
32
+ export { readProfile, readSessionName, readSummary, writeSessionName, writeSummary, type ExecutionProfile, type ProfileReadResult } from "./profile.js";
33
33
  export { SUMMARY_MIGRATION_MARKER, listSessionSidecars, migrateSummaries, sessionSummary, summarizeEvents, summaryMigrationPending, type SessionListing, type SessionSummary } from "./session-summary.js";
34
34
  export * from "./tasks/journal.js";
35
35
  export * from "./tasks/manager.js";
package/dist/internal.js CHANGED
@@ -38,7 +38,7 @@ export { BUILTIN_MANIFESTS, resolveContinuationScope } from "./provider/manifest
38
38
  export * from "./checkpoint.js";
39
39
  export * from "./request-budget.js";
40
40
  // 0.40.0: the listing reads the recorded workspace and profile name.
41
- export { readProfile, readSummary, writeSummary } from "./profile.js";
41
+ export { readProfile, readSessionName, readSummary, writeSessionName, writeSummary } from "./profile.js";
42
42
  export { SUMMARY_MIGRATION_MARKER, listSessionSidecars, migrateSummaries, sessionSummary, summarizeEvents, summaryMigrationPending } from "./session-summary.js";
43
43
  // ADR-0058 §6: the task journal and the TaskManager (internal until the
44
44
  // public shape is proven by the shell and delegate steps)
package/dist/profile.d.ts CHANGED
@@ -83,6 +83,17 @@ export declare function writeProfile(root: string, sessionId: string, profile: E
83
83
  export declare function writeSummary(root: string, sessionId: string, summary: import("./session-summary.js").SessionSummary): void;
84
84
  /** The summary tenant, or null (no sidecar, no summary, or unreadable). */
85
85
  export declare function readSummary(root: string, sessionId: string): import("./session-summary.js").SessionSummary | null;
86
+ /** Graphite R3d — the name the person gave the session (`/name`): the
87
+ * sidecar's third tenant, beside `profile` and `summary`, carried
88
+ * through their writes untouched as they are through its. Session
89
+ * metadata, not an event (ADR-0051 §6's OUT class, the profile's own
90
+ * footing): the derivation never reads it; the lists and the title do,
91
+ * the derived title (`sessionTitle`) the fallback. Null when unnamed or
92
+ * unreadable. */
93
+ export declare function readSessionName(root: string, sessionId: string): string | null;
94
+ /** Name the session, or clear its name (`null`). Atomic and fail-closed
95
+ * like every tenant's write; the others' bytes ride through. */
96
+ export declare function writeSessionName(root: string, sessionId: string, name: string | null): void;
86
97
  export type ProfileReadResult = {
87
98
  readonly kind: "ok";
88
99
  readonly profile: ExecutionProfile;
package/dist/profile.js CHANGED
@@ -80,6 +80,24 @@ export function readSummary(root, sessionId) {
80
80
  const t = currentTenants(root, sessionId).summary;
81
81
  return t !== undefined && typeof t.updatedAt === "number" ? t : null;
82
82
  }
83
+ /** Graphite R3d — the name the person gave the session (`/name`): the
84
+ * sidecar's third tenant, beside `profile` and `summary`, carried
85
+ * through their writes untouched as they are through its. Session
86
+ * metadata, not an event (ADR-0051 §6's OUT class, the profile's own
87
+ * footing): the derivation never reads it; the lists and the title do,
88
+ * the derived title (`sessionTitle`) the fallback. Null when unnamed or
89
+ * unreadable. */
90
+ export function readSessionName(root, sessionId) {
91
+ const n = currentTenants(root, sessionId).name;
92
+ return typeof n === "string" && n.trim() !== "" ? n : null;
93
+ }
94
+ /** Name the session, or clear its name (`null`). Atomic and fail-closed
95
+ * like every tenant's write; the others' bytes ride through. */
96
+ export function writeSessionName(root, sessionId, name) {
97
+ const tenants = { ...currentTenants(root, sessionId) };
98
+ delete tenants.name;
99
+ writeTenants(root, sessionId, name === null ? tenants : { ...tenants, name });
100
+ }
83
101
  function writeTenants(root, sessionId, tenants) {
84
102
  const path = profilePath(root, sessionId);
85
103
  const tmpDir = mkdtempSync(join(root, ".meta-"));
@@ -68,6 +68,9 @@ export interface SessionListing {
68
68
  readonly summary: SessionSummary | null;
69
69
  readonly workspace: string | null;
70
70
  readonly profileName: string | null;
71
+ /** Graphite R3d: the name the person gave it (`/name`), or null —
72
+ * optional, so a listing built before names existed still types */
73
+ readonly name?: string | null;
71
74
  }
72
75
  /** Every session in `root`, from the DIRECTORY and the sidecars only — no
73
76
  * log is opened. The 0.40.0 dogfood's list path. */
@@ -23,7 +23,7 @@
23
23
  */
24
24
  import { existsSync, readdirSync, statSync, writeFileSync } from "node:fs";
25
25
  import { join } from "node:path";
26
- import { readProfile, readSummary, writeSummary } from "./profile.js";
26
+ import { readProfile, readSessionName, readSummary, writeSummary } from "./profile.js";
27
27
  import { executionLedger } from "./ledger.js";
28
28
  import { openRunId } from "./recovery.js";
29
29
  import { sessionTitle } from "./store.js";
@@ -124,6 +124,7 @@ export function listSessionSidecars(root) {
124
124
  summary: readSummary(root, id),
125
125
  workspace: profile.kind === "ok" ? profile.profile.workspace : null,
126
126
  profileName: profile.kind === "ok" ? profile.profile.profileName : null,
127
+ name: readSessionName(root, id),
127
128
  });
128
129
  }
129
130
  return out;
package/dist/session.d.ts CHANGED
@@ -514,6 +514,30 @@ export interface ContextPolicy {
514
514
  readonly model: string;
515
515
  readonly baseUrl?: string;
516
516
  }) => void;
517
+ /** The compaction round (owner, 2026-10-06): an in-run summary call,
518
+ * told as `/compact`'s caller is told one — when it starts (the tier
519
+ * that fired it, and `onStart`'s pre-call data: the covered rounds
520
+ * and their estimated tokens), its progress against the output
521
+ * budget (`onProgress`'s reports), and how it ended: `kept` (a
522
+ * `summarized` event follows), `discarded` (it did not shrink the
523
+ * context; `onDiscard` is told too) or `failed` (both paths refused,
524
+ * or the run was aborted). `pre` and `post` are the context's
525
+ * chars/4 estimates before and after (equal when nothing was kept).
526
+ * Display only: nothing here reaches a request, and a callback that
527
+ * throws changes nothing. */
528
+ readonly onSummary?: (event: {
529
+ readonly phase: "start";
530
+ readonly reason: string;
531
+ readonly info: CompactInfo;
532
+ } | {
533
+ readonly phase: "progress";
534
+ readonly progress: import("./summarize.js").SummaryProgress;
535
+ } | {
536
+ readonly phase: "end";
537
+ readonly outcome: "kept" | "discarded" | "failed";
538
+ readonly pre: number;
539
+ readonly post: number;
540
+ }) => void;
517
541
  };
518
542
  }
519
543
  export interface SessionConfig {
package/dist/session.js CHANGED
@@ -385,7 +385,7 @@ export class AgentSession {
385
385
  const breakerOpen = reason !== "overflow" && this.#summaryFailures >= (tiersPolicy.maxFailures ?? MAX_SUMMARY_FAILURES);
386
386
  if (breakerOpen && !urgent)
387
387
  return [];
388
- const summarized = breakerOpen ? null : await this.#summarizeInRun(events, messages, t.tail, reason, run, tiersPolicy.onDiscard);
388
+ const summarized = breakerOpen ? null : await this.#summarizeInRun(events, messages, t.tail, reason, run, tiersPolicy.onDiscard, tiersPolicy.onSummary);
389
389
  if (summarized !== null)
390
390
  return [summarized];
391
391
  if (!urgent)
@@ -441,10 +441,32 @@ export class AgentSession {
441
441
  /** A2 — one in-run summary: in-band first, the serialised form once on
442
442
  * a rejection; null when neither produced a valid checkpoint. The
443
443
  * summary call's usage and path ride the trace ledger, as /compact's do. */
444
- async #summarizeInRun(events, messages, tail, reason, run, onDiscard) {
444
+ async #summarizeInRun(events, messages, tail, reason, run, onDiscard, onSummary) {
445
445
  const boundary = checkpointBoundarySeq(events, { keepTokens: tail });
446
446
  if (boundary === undefined)
447
447
  return null;
448
+ // the compaction round (owner, 2026-10-06): what /compact's onStart
449
+ // and onProgress tell its caller, told here too — display only, and
450
+ // a callback that throws changes nothing
451
+ const tell = (event) => {
452
+ try {
453
+ onSummary?.(event);
454
+ }
455
+ catch {
456
+ // observation only
457
+ }
458
+ };
459
+ const prevPoint = lastSummaryPoint(events);
460
+ const pre = estimateTokens(projectMessages(events));
461
+ tell({
462
+ phase: "start",
463
+ reason,
464
+ info: {
465
+ coversToSeq: boundary,
466
+ rounds: events.filter((e) => e.type === "user_input" && e.seq > prevPoint && e.seq <= boundary).length,
467
+ tokens: estimateTokens(projectMessages(events.filter((e) => e.seq > prevPoint && e.seq <= boundary && e.type !== "summarized"))),
468
+ },
469
+ });
448
470
  const summaryPrompt = typeof run.systemPrompt === "function" ? run.systemPrompt() : run.systemPrompt;
449
471
  let path;
450
472
  let result;
@@ -453,15 +475,17 @@ export class AgentSession {
453
475
  messages,
454
476
  inBand: { ...(summaryPrompt !== undefined ? { systemPrompt: summaryPrompt } : {}), tools: run.tools() },
455
477
  ...(run.reasoning !== undefined ? { reasoning: run.reasoning } : {}),
456
- serialized: () => serializeCovered({ events, prevPoint: lastSummaryPoint(events), boundary }),
478
+ serialized: () => serializeCovered({ events, prevPoint, boundary }),
457
479
  serializedReasoning: true,
458
480
  budget: MANUAL_SUMMARY_BUDGET,
459
481
  ...(run.signal !== undefined ? { signal: run.signal } : {}),
482
+ ...(onSummary !== undefined ? { onProgress: (progress) => tell({ phase: "progress", progress }) } : {}),
460
483
  }));
461
484
  }
462
485
  catch {
463
486
  if (run.signal?.aborted !== true)
464
487
  this.#summaryFailures += 1;
488
+ tell({ phase: "end", outcome: "failed", pre, post: pre });
465
489
  return null;
466
490
  }
467
491
  // ADR-0055 Amendment 2 (the shrink invariant): a fire is kept only if
@@ -472,7 +496,6 @@ export class AgentSession {
472
496
  // counts toward the breaker.
473
497
  const text = this.#withTasks(result.text);
474
498
  const fire = { type: "summarized", coversToSeq: boundary, summary: text };
475
- const pre = estimateTokens(projectMessages(events));
476
499
  const post = estimateTokens(projectMessages([...events, { ...fire, seq: (events.at(-1)?.seq ?? -1) + 1 }]));
477
500
  const written = estimateTokens([{ role: "user", content: `${SUMMARY_FRAMING}\n\n${text}` }]);
478
501
  const shrinks = pre - post >= written;
@@ -498,9 +521,11 @@ export class AgentSession {
498
521
  catch {
499
522
  // observation only — a notice that cannot be shown changes nothing
500
523
  }
524
+ tell({ phase: "end", outcome: "discarded", pre, post });
501
525
  return null;
502
526
  }
503
527
  this.#summaryFailures = 0;
528
+ tell({ phase: "end", outcome: "kept", pre, post });
504
529
  return fire;
505
530
  }
506
531
  /**
package/dist/store.js CHANGED
@@ -45,6 +45,7 @@
45
45
  import { appendFileSync, closeSync, constants, existsSync, fsyncSync, fstatSync, statSync, ftruncateSync, mkdirSync, openSync, readFileSync, readdirSync, readSync, writeSync, } from "node:fs";
46
46
  import { dirname, join } from "node:path";
47
47
  import { isKisoEvent } from "@vincemakes/kiso-core";
48
+ import { readSessionName } from "./profile.js";
48
49
  import { LockedError, nativeLockAdapter, } from "./lock-adapter.js";
49
50
  /** History that does not parse as a contiguous kiso trajectory. */
50
51
  export class StoreCorruptionError extends Error {
@@ -441,7 +442,9 @@ export class SessionStore {
441
442
  continue;
442
443
  metas.push({
443
444
  id,
444
- title: sessionTitle(records),
445
+ // Graphite R3d: the name the person gave the session, when it has
446
+ // one; the title derived from its first real line otherwise
447
+ title: readSessionName(this.root, id) ?? sessionTitle(records),
445
448
  events: records.length,
446
449
  runs: new Set(records.map((r) => r.runId)).size,
447
450
  createdAt: records[0]?.ts ?? 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-runtime",
3
- "version": "0.46.2",
3
+ "version": "0.47.0",
4
4
  "description": "kiso runtime \u2014 durable multi-turn agent sessions: AgentDefinition, AgentRuntime, AgentSession, Run, append-only JSONL store.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -25,12 +25,12 @@
25
25
  "test": "vitest run"
26
26
  },
27
27
  "dependencies": {
28
- "@vincemakes/kiso-core": "0.46.2"
28
+ "@vincemakes/kiso-core": "0.47.0"
29
29
  },
30
30
  "peerDependencies": {
31
- "@vincemakes/kiso-provider-anthropic": "0.46.2",
32
- "@vincemakes/kiso-provider-openai": "0.46.2",
33
- "@vincemakes/kiso-provider-openai-responses": "0.46.2"
31
+ "@vincemakes/kiso-provider-anthropic": "0.47.0",
32
+ "@vincemakes/kiso-provider-openai": "0.47.0",
33
+ "@vincemakes/kiso-provider-openai-responses": "0.47.0"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "@vincemakes/kiso-provider-anthropic": {
@@ -44,7 +44,7 @@
44
44
  }
45
45
  },
46
46
  "devDependencies": {
47
- "@vincemakes/kiso-evals": "0.46.2",
47
+ "@vincemakes/kiso-evals": "0.47.0",
48
48
  "@types/node": "^26.1.2",
49
49
  "typescript": "^5.7.2",
50
50
  "vitest": "^3.0.0"