@fungi.computer/shiitake 0.2.0 → 0.3.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 (114) hide show
  1. package/README.md +155 -34
  2. package/dist/agent-control.d.ts +77 -5
  3. package/dist/agent-control.js +271 -65
  4. package/dist/client-entry.d.ts +15 -8
  5. package/dist/client-entry.js +7 -5
  6. package/dist/client-wire.d.ts +24 -8
  7. package/dist/client-wire.js +53 -11
  8. package/dist/client.d.ts +56 -11
  9. package/dist/client.js +1 -1
  10. package/dist/cloudflare.d.ts +42 -23
  11. package/dist/cloudflare.js +76 -54
  12. package/dist/cold-sessions.d.ts +28 -0
  13. package/dist/cold-sessions.js +1 -0
  14. package/dist/delegation.d.ts +214 -0
  15. package/dist/delegation.js +319 -0
  16. package/dist/effect.d.ts +1 -1
  17. package/dist/errors.d.ts +2 -2
  18. package/dist/errors.js +2 -2
  19. package/dist/extension-contract.d.ts +10 -2
  20. package/dist/extensions.d.ts +6 -2
  21. package/dist/fleet.d.ts +43 -9
  22. package/dist/fleet.js +88 -25
  23. package/dist/hosted.js +1 -0
  24. package/dist/http-routes.d.ts +113 -29
  25. package/dist/http-routes.js +18 -1
  26. package/dist/index.d.ts +3 -2
  27. package/dist/internal/accepted-run-executor.d.ts +5 -0
  28. package/dist/internal/accepted-run-executor.js +10 -4
  29. package/dist/internal/admission-door.d.ts +3 -0
  30. package/dist/internal/admission-door.js +12 -2
  31. package/dist/internal/client-boundary.js +7 -1
  32. package/dist/internal/compaction/compaction-slot.d.ts +36 -0
  33. package/dist/internal/compaction/compaction-slot.js +41 -0
  34. package/dist/internal/compaction/compaction.d.ts +11 -8
  35. package/dist/internal/compaction/compaction.js +62 -34
  36. package/dist/internal/compaction/session-compaction.d.ts +8 -16
  37. package/dist/internal/compaction/session-compaction.js +358 -119
  38. package/dist/internal/compaction/settings.d.ts +1 -1
  39. package/dist/internal/compaction/settings.js +5 -0
  40. package/dist/internal/compaction/utils.d.ts +19 -16
  41. package/dist/internal/compaction/utils.js +30 -84
  42. package/dist/internal/contracts.d.ts +40 -13
  43. package/dist/internal/coordinator.js +28 -10
  44. package/dist/internal/effect-client.d.ts +4 -2
  45. package/dist/internal/effect-client.js +29 -0
  46. package/dist/internal/effect-contracts.d.ts +17 -4
  47. package/dist/internal/extension-runtime.d.ts +5 -0
  48. package/dist/internal/extension-runtime.js +184 -89
  49. package/dist/internal/host-meta.d.ts +7 -0
  50. package/dist/internal/model-acquisition.js +7 -1
  51. package/dist/internal/model-preference.d.ts +4 -2
  52. package/dist/internal/model-preference.js +2 -1
  53. package/dist/internal/promise-facade.js +4 -16
  54. package/dist/internal/run-failure-reason.d.ts +10 -0
  55. package/dist/internal/run-failure-reason.js +19 -0
  56. package/dist/internal/run-scope.d.ts +4 -1
  57. package/dist/internal/run-scope.js +38 -5
  58. package/dist/internal/runtime-coordinator.d.ts +2 -1
  59. package/dist/internal/runtime-coordinator.js +65 -4
  60. package/dist/internal/runtime-core.js +1 -0
  61. package/dist/internal/runtime-reconciliation.js +42 -6
  62. package/dist/internal/session-context.d.ts +1 -2
  63. package/dist/internal/session-context.js +8 -30
  64. package/dist/internal/session-status.d.ts +2 -1
  65. package/dist/internal/session-status.js +4 -1
  66. package/dist/internal/woodstock/client-projection.d.ts +6 -5
  67. package/dist/internal/woodstock/client-projection.js +79 -53
  68. package/dist/internal/woodstock/cold-sessions.d.ts +4 -0
  69. package/dist/internal/woodstock/cold-sessions.js +90 -0
  70. package/dist/internal/woodstock/extension-store.d.ts +2 -0
  71. package/dist/internal/woodstock/extension-store.js +4 -0
  72. package/dist/internal/woodstock/fleet-store.d.ts +5 -1
  73. package/dist/internal/woodstock/fleet-store.js +17 -5
  74. package/dist/internal/woodstock/index.d.ts +11 -3
  75. package/dist/internal/woodstock/index.js +33 -14
  76. package/dist/internal/woodstock/progress.d.ts +14 -1
  77. package/dist/internal/woodstock/progress.js +97 -19
  78. package/dist/internal/woodstock/run-recovery.js +6 -4
  79. package/dist/internal/woodstock/session-attention.d.ts +1 -1
  80. package/dist/internal/woodstock/session-attention.js +2 -2
  81. package/dist/internal/woodstock/session-entry.d.ts +110 -43
  82. package/dist/internal/woodstock/session-entry.js +63 -20
  83. package/dist/internal/woodstock/session-inbox.js +2 -0
  84. package/dist/internal/woodstock/session-store.d.ts +104 -24
  85. package/dist/internal/woodstock/session-store.js +937 -246
  86. package/dist/internal/woodstock/storage-admission.d.ts +8 -8
  87. package/dist/internal/woodstock/storage-admission.js +8 -34
  88. package/dist/internal/woodstock/storage-conformance.d.ts +15 -0
  89. package/dist/internal/woodstock/storage-conformance.js +489 -0
  90. package/dist/model-preference.d.ts +2 -2
  91. package/dist/model-preference.js +2 -2
  92. package/dist/node.js +1 -1
  93. package/dist/remote-client.js +8 -1
  94. package/dist/session-attention.d.ts +8 -1
  95. package/dist/session-attention.js +6 -1
  96. package/dist/testing.d.ts +1 -1
  97. package/dist/testing.js +1 -0
  98. package/docs/api/README.md +18 -16
  99. package/docs/api/agent-control.md +171 -1
  100. package/docs/api/client-entry.md +26 -10
  101. package/docs/api/client.md +153 -37
  102. package/docs/api/cloudflare.md +76 -23
  103. package/docs/api/delegation.md +485 -0
  104. package/docs/api/effect.md +20 -2
  105. package/docs/api/extensions.md +21 -9
  106. package/docs/api/fleet.md +159 -104
  107. package/docs/api/http.md +4 -1
  108. package/docs/api/index.md +116 -20
  109. package/docs/api/internal/woodstock/storage-conformance.md +81 -0
  110. package/docs/api/model-preference.md +27 -10
  111. package/docs/api/testing.md +16 -4
  112. package/package.json +26 -14
  113. package/dist/internal/browser-sessions.d.ts +0 -31
  114. package/dist/internal/browser-sessions.js +0 -173
@@ -32,10 +32,10 @@ export function readSessionAttention(owner, sessionId) {
32
32
  });
33
33
  });
34
34
  }
35
- /** Whether any owner still requests attention; no wall-clock expiry heuristic. */
35
+ /** Whether any owner requests inbox attention; drawer-only items stay visible. */
36
36
  export function hasSessionAttention(owner, sessionId) {
37
37
  return (owner.sql
38
- .exec("SELECT 1 FROM session_attention a JOIN shiitake_extension_status s ON s.extension_id = a.extension_id AND s.status = 'running' JOIN session_attention_grants g ON g.extension_id = a.extension_id WHERE a.session_id = ? LIMIT 1", sessionId)
38
+ .exec("SELECT 1 FROM session_attention a JOIN shiitake_extension_status s ON s.extension_id = a.extension_id AND s.status = 'running' JOIN session_attention_grants g ON g.extension_id = a.extension_id WHERE a.session_id = ? AND json_extract(a.value_json, '$.inbox') IS NOT 0 LIMIT 1", sessionId)
39
39
  .toArray().length > 0);
40
40
  }
41
41
  /** Upsert only the calling extension's item, in the calling transaction. */
@@ -1,10 +1,13 @@
1
- import type { Message, MuleIdentity, MuleToolResult, ToolCall, Usage, UserMessage } from "@fungi.computer/mule/effect";
1
+ import type { ModelMessage } from "../../client.js";
2
+ import type { ImageContent, JsonValue, MuleIdentity, TextContent, ToolCall, Usage, UserMessage } from "@fungi.computer/mule/effect";
2
3
  import * as Schema from "effect/Schema";
3
4
  import * as Result from "effect/Result";
5
+ /** An archive owner's opaque receipt: a non-empty string of at most 4096 bytes. */
6
+ export declare const CompactionReceiptSchema: Schema.String;
4
7
  /** Provider-native usage grammar shared by stored messages and settlement facts. */
5
8
  export declare const usage: Schema.Codec<Usage>;
6
- /** Exact Pi message grammar stored by Woodstock without normalization. */
7
- export declare const StoredPiMessageSchema: Schema.Codec<Message>;
9
+ /** Model content only; application data is carried by the surrounding entry. */
10
+ export declare const StoredPiMessageSchema: Schema.Codec<ModelMessage>;
8
11
  declare const LiveRetryEventSchema: Schema.Union<readonly [Schema.Struct<{
9
12
  readonly type: Schema.Literal<"auto_retry_start">;
10
13
  readonly run: Schema.Codec<MuleIdentity, MuleIdentity, never, never>;
@@ -44,7 +47,7 @@ declare const StoredSessionEntrySchema: Schema.Union<readonly [Schema.Struct<{
44
47
  readonly executionId: Schema.String;
45
48
  readonly adapter: Schema.String;
46
49
  readonly buildSha: Schema.NullOr<Schema.String>;
47
- readonly tag: Schema.Literals<readonly ["SourceInvalid", "GuestThrew", "DeadlineExceeded", "Cancelled", "DispatchLost", "SandboxCrashed", "BadResponse", "ResultTooLarge", "ResultNotJson", "CapabilityFailed", "Unknown"]>;
50
+ readonly tag: Schema.Literals<readonly ["SourceInvalid", "GuestThrew", "DeadlineExceeded", "SandboxBusy", "Cancelled", "DispatchLost", "SandboxCrashed", "BadResponse", "ResultTooLarge", "ResultNotJson", "CapabilityFailed", "Unknown"]>;
48
51
  readonly fields: Schema.$Record<Schema.String, Schema.Codec<import("zod").JSONType, import("zod").JSONType, never, never>>;
49
52
  readonly healthAlert: Schema.Boolean;
50
53
  }>;
@@ -157,10 +160,11 @@ declare const StoredSessionEntrySchema: Schema.Union<readonly [Schema.Struct<{
157
160
  readonly workId: Schema.String;
158
161
  }>, Schema.Struct<{
159
162
  readonly kind: Schema.Literal<"message">;
163
+ readonly data: Schema.optionalKey<Schema.Codec<JsonValue, JsonValue, never, never>>;
160
164
  readonly run: Schema.Codec<MuleIdentity, MuleIdentity, never, never>;
161
165
  readonly turn: Schema.Codec<MuleIdentity, MuleIdentity, never, never>;
162
166
  readonly message: Schema.Codec<MuleIdentity, MuleIdentity, never, never>;
163
- readonly value: Schema.Codec<Message, Message, never, never>;
167
+ readonly value: Schema.Codec<ModelMessage, ModelMessage, never, never>;
164
168
  readonly workId: Schema.String;
165
169
  }>, Schema.Struct<{
166
170
  readonly kind: Schema.Literal<"tool_intent">;
@@ -176,11 +180,17 @@ declare const StoredSessionEntrySchema: Schema.Union<readonly [Schema.Struct<{
176
180
  readonly workId: Schema.String;
177
181
  }>, Schema.Struct<{
178
182
  readonly kind: Schema.Literal<"tool_outcome">;
183
+ readonly data: Schema.optionalKey<Schema.Codec<JsonValue, JsonValue, never, never>>;
179
184
  readonly run: Schema.Codec<MuleIdentity, MuleIdentity, never, never>;
180
185
  readonly turn: Schema.Codec<MuleIdentity, MuleIdentity, never, never>;
181
186
  readonly toolCall: Schema.Codec<MuleIdentity, MuleIdentity, never, never>;
182
187
  readonly call: Schema.Codec<ToolCall, ToolCall, never, never>;
183
- readonly result: Schema.Codec<MuleToolResult, MuleToolResult, never, never>;
188
+ readonly result: Schema.Struct<{
189
+ readonly content: Schema.mutable<Schema.$Array<Schema.Union<readonly [Schema.Codec<TextContent, TextContent, never, never>, Schema.Codec<ImageContent, ImageContent, never, never>]>>>;
190
+ readonly usage: Schema.optional<Schema.Codec<Usage, Usage, never, never>>;
191
+ readonly isError: Schema.Boolean;
192
+ readonly terminate: Schema.optional<Schema.Boolean>;
193
+ }>;
184
194
  readonly workId: Schema.String;
185
195
  }>, Schema.Struct<{
186
196
  readonly kind: Schema.Literal<"live_retry">;
@@ -205,30 +215,57 @@ declare const StoredSessionEntrySchema: Schema.Union<readonly [Schema.Struct<{
205
215
  readonly workId: Schema.String;
206
216
  }>, Schema.Struct<{
207
217
  readonly kind: Schema.Literal<"compaction">;
208
- readonly resumesRun: Schema.optionalKey<Schema.Boolean>;
209
- readonly trigger: Schema.optionalKey<Schema.Literals<readonly ["manual", "threshold", "overflow"]>>;
210
- /** Estimated context tokens right after this compaction. */
211
- readonly tokensAfter: Schema.optionalKey<Schema.Number>;
212
- readonly firstKeptEntryId: Schema.String;
213
- readonly summary: Schema.String;
214
- readonly tokensBefore: Schema.Number;
215
- readonly usage: Schema.Codec<Usage, Usage, never, never>;
216
- readonly contextRevision: Schema.String;
217
- readonly details: Schema.optionalKey<Schema.Struct<{
218
- readonly readFiles: Schema.$Array<Schema.String>;
219
- readonly modifiedFiles: Schema.$Array<Schema.String>;
220
- }>>;
218
+ readonly head: Schema.String;
219
+ readonly model: Schema.Tuple<readonly [Schema.Codec<UserMessage, UserMessage, never, never>]>;
220
+ readonly data: Schema.Struct<{
221
+ readonly reason: Schema.optionalKey<Schema.Literals<readonly ["manual", "threshold", "overflow"]>>;
222
+ readonly resumesRun: Schema.Boolean;
223
+ readonly tokensBefore: Schema.Number;
224
+ /** Estimated context tokens right after this compaction. */
225
+ readonly tokensAfter: Schema.optionalKey<Schema.Number>;
226
+ readonly usage: Schema.Codec<Usage, Usage, never, never>;
227
+ readonly contextRevision: Schema.String;
228
+ /**
229
+ * The archive owner's opaque receipt for this compaction, committed in
230
+ * the same append as the transition. Absent when no handoff archived it.
231
+ */
232
+ readonly receipt: Schema.optionalKey<Schema.String>;
233
+ readonly details: Schema.optionalKey<Schema.Struct<{
234
+ readonly readFiles: Schema.$Array<Schema.String>;
235
+ readonly modifiedFiles: Schema.$Array<Schema.String>;
236
+ }>>;
237
+ }>;
238
+ readonly workId: Schema.String;
239
+ }>, Schema.Struct<{
240
+ readonly kind: Schema.Literal<"compaction_notice">;
241
+ readonly trigger: Schema.Literals<readonly ["manual", "threshold", "overflow"]>;
242
+ readonly result: Schema.Literal<"nothing_to_compact">;
243
+ readonly diagnostic: Schema.optionalKey<Schema.String>;
221
244
  readonly workId: Schema.String;
222
245
  }>, Schema.Struct<{
223
246
  readonly kind: Schema.Literal<"compaction_notice">;
224
247
  readonly trigger: Schema.Literals<readonly ["manual", "threshold", "overflow"]>;
225
- readonly result: Schema.Literals<readonly ["nothing_to_compact", "failed"]>;
248
+ readonly result: Schema.Literal<"failed">;
249
+ readonly usage: Schema.optionalKey<Schema.Codec<Usage, Usage, never, never>>;
226
250
  readonly diagnostic: Schema.optionalKey<Schema.String>;
227
251
  readonly workId: Schema.String;
252
+ }>, Schema.Struct<{
253
+ readonly kind: Schema.Literal<"compaction_notice">;
254
+ readonly trigger: Schema.Literals<readonly ["manual", "threshold", "overflow"]>;
255
+ readonly result: Schema.Literal<"stale">;
256
+ readonly usage: Schema.optionalKey<Schema.Codec<Usage, Usage, never, never>>;
257
+ readonly workId: Schema.String;
258
+ }>, Schema.Struct<{
259
+ readonly kind: Schema.Literal<"compaction_notice">;
260
+ readonly trigger: Schema.Literals<readonly ["manual", "threshold", "overflow"]>;
261
+ readonly result: Schema.Literal<"insufficient">;
262
+ readonly usage: Schema.optionalKey<Schema.Codec<Usage, Usage, never, never>>;
263
+ readonly workId: Schema.String;
228
264
  }>, Schema.Struct<{
229
265
  readonly kind: Schema.Literal<"run_terminal">;
230
266
  readonly run: Schema.Codec<MuleIdentity, MuleIdentity, never, never>;
231
267
  readonly terminal: Schema.Codec<MuleIdentity, MuleIdentity, never, never>;
268
+ readonly diagnostic: Schema.optionalKey<Schema.String>;
232
269
  readonly outcome: Schema.Literals<readonly ["completed", "cancelled", "failed"]>;
233
270
  readonly workId: Schema.String;
234
271
  }>, Schema.Struct<{
@@ -271,7 +308,7 @@ export declare function commandContextMessage(entry: PromptCommandEntry): UserMe
271
308
  * What a client sees of an operator line: the party's words as a user
272
309
  * message, the operator's as an assistant message from provider `operator`.
273
310
  */
274
- export declare function operatorClientMessage(entry: OperatorSessionEntry): Message;
311
+ export declare function operatorClientMessage(entry: OperatorSessionEntry): ModelMessage;
275
312
  /** Decode the one JSON representation admitted by retained Session storage. */
276
313
  export declare function decodeStoredSessionEntry(value: string): Result.Result<{
277
314
  readonly kind: "sandbox_failure";
@@ -281,7 +318,7 @@ export declare function decodeStoredSessionEntry(value: string): Result.Result<{
281
318
  readonly executionId: string;
282
319
  readonly adapter: string;
283
320
  readonly buildSha: string | null;
284
- readonly tag: "Unknown" | "SourceInvalid" | "GuestThrew" | "DeadlineExceeded" | "Cancelled" | "DispatchLost" | "SandboxCrashed" | "BadResponse" | "ResultTooLarge" | "ResultNotJson" | "CapabilityFailed";
321
+ readonly tag: "Unknown" | "SourceInvalid" | "GuestThrew" | "DeadlineExceeded" | "SandboxBusy" | "Cancelled" | "DispatchLost" | "SandboxCrashed" | "BadResponse" | "ResultTooLarge" | "ResultNotJson" | "CapabilityFailed";
285
322
  readonly fields: {
286
323
  readonly [x: string]: import("zod").JSONType;
287
324
  };
@@ -300,7 +337,7 @@ export declare function decodeStoredSessionEntry(value: string): Result.Result<{
300
337
  readonly preference: {
301
338
  readonly providerId: string;
302
339
  readonly modelId: string;
303
- readonly reasoning?: "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;
340
+ readonly reasoning?: "high" | "low" | "max" | "medium" | "minimal" | "xhigh" | undefined;
304
341
  } | null;
305
342
  } | {
306
343
  readonly kind: "command";
@@ -395,10 +432,11 @@ export declare function decodeStoredSessionEntry(value: string): Result.Result<{
395
432
  } | {
396
433
  readonly kind: "message";
397
434
  readonly run: MuleIdentity;
398
- readonly turn: MuleIdentity;
399
435
  readonly message: MuleIdentity;
400
- readonly value: Message;
401
436
  readonly workId: string;
437
+ readonly value: ModelMessage;
438
+ readonly turn: MuleIdentity;
439
+ readonly data?: JsonValue;
402
440
  } | {
403
441
  readonly kind: "tool_intent";
404
442
  readonly replay: "unsafe" | "safe";
@@ -414,11 +452,17 @@ export declare function decodeStoredSessionEntry(value: string): Result.Result<{
414
452
  } | {
415
453
  readonly kind: "tool_outcome";
416
454
  readonly run: MuleIdentity;
455
+ readonly workId: string;
456
+ readonly call: ToolCall;
417
457
  readonly turn: MuleIdentity;
418
458
  readonly toolCall: MuleIdentity;
419
- readonly call: ToolCall;
420
- readonly result: MuleToolResult;
421
- readonly workId: string;
459
+ readonly result: {
460
+ readonly content: (TextContent | ImageContent)[];
461
+ readonly isError: boolean;
462
+ readonly usage?: Usage | undefined;
463
+ readonly terminate?: boolean | undefined;
464
+ };
465
+ readonly data?: JsonValue;
422
466
  } | {
423
467
  readonly kind: "live_retry";
424
468
  readonly event: {
@@ -442,31 +486,54 @@ export declare function decodeStoredSessionEntry(value: string): Result.Result<{
442
486
  readonly workId: string;
443
487
  } | {
444
488
  readonly kind: "compaction";
445
- readonly summary: string;
446
- readonly workId: string;
447
- readonly usage: Usage;
448
- readonly firstKeptEntryId: string;
449
- readonly tokensBefore: number;
450
- readonly contextRevision: string;
451
- readonly resumesRun?: boolean;
452
- readonly trigger?: "manual" | "threshold" | "overflow";
453
- readonly tokensAfter?: number;
454
- readonly details?: {
455
- readonly readFiles: readonly string[];
456
- readonly modifiedFiles: readonly string[];
489
+ readonly head: string;
490
+ readonly model: readonly [UserMessage];
491
+ readonly data: {
492
+ readonly usage: Usage;
493
+ readonly resumesRun: boolean;
494
+ readonly tokensBefore: number;
495
+ readonly contextRevision: string;
496
+ readonly reason?: "manual" | "threshold" | "overflow";
497
+ readonly receipt?: string;
498
+ readonly details?: {
499
+ readonly readFiles: readonly string[];
500
+ readonly modifiedFiles: readonly string[];
501
+ };
502
+ readonly tokensAfter?: number;
457
503
  };
504
+ readonly workId: string;
458
505
  } | {
459
506
  readonly kind: "compaction_notice";
460
507
  readonly workId: string;
461
- readonly result: "failed" | "nothing_to_compact";
508
+ readonly result: "nothing_to_compact";
462
509
  readonly trigger: "manual" | "threshold" | "overflow";
463
510
  readonly diagnostic?: string;
511
+ } | {
512
+ readonly kind: "compaction_notice";
513
+ readonly workId: string;
514
+ readonly result: "failed";
515
+ readonly trigger: "manual" | "threshold" | "overflow";
516
+ readonly usage?: Usage;
517
+ readonly diagnostic?: string;
518
+ } | {
519
+ readonly kind: "compaction_notice";
520
+ readonly workId: string;
521
+ readonly result: "stale";
522
+ readonly trigger: "manual" | "threshold" | "overflow";
523
+ readonly usage?: Usage;
524
+ } | {
525
+ readonly kind: "compaction_notice";
526
+ readonly workId: string;
527
+ readonly result: "insufficient";
528
+ readonly trigger: "manual" | "threshold" | "overflow";
529
+ readonly usage?: Usage;
464
530
  } | {
465
531
  readonly kind: "run_terminal";
466
532
  readonly run: MuleIdentity;
467
- readonly terminal: MuleIdentity;
468
- readonly outcome: "completed" | "failed" | "cancelled";
469
533
  readonly workId: string;
534
+ readonly outcome: "completed" | "failed" | "cancelled";
535
+ readonly terminal: MuleIdentity;
536
+ readonly diagnostic?: string;
470
537
  } | {
471
538
  readonly kind: "work_terminal";
472
539
  readonly workId: string;
@@ -10,6 +10,8 @@ const closed = { onExcessProperty: "error" };
10
10
  const encoder = new TextEncoder();
11
11
  const boundedText = (maximumBytes) => Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.makeFilter((value) => encoder.encode(value).byteLength <= maximumBytes)));
12
12
  const boundedId = boundedText(256);
13
+ /** An archive owner's opaque receipt: a non-empty string of at most 4096 bytes. */
14
+ export const CompactionReceiptSchema = boundedText(4096);
13
15
  const digest = Schema.String.pipe(Schema.check(Schema.isPattern(/^[0-9a-f]{64}$/u)));
14
16
  const jsonValue = Schema.suspend(() => Schema.Union([
15
17
  Schema.String,
@@ -42,6 +44,7 @@ const StoredToolCallSchema = Schema.Struct({
42
44
  arguments: Schema.Record(Schema.String, jsonValue),
43
45
  thoughtSignature: Schema.optionalKey(Schema.String),
44
46
  namespace: Schema.optionalKey(Schema.String),
47
+ argumentsError: Schema.optionalKey(Schema.String),
45
48
  });
46
49
  /** Provider-native usage grammar shared by stored messages and settlement facts. */
47
50
  export const usage = Schema.Struct({
@@ -148,18 +151,19 @@ const assistantMessage = Schema.Struct({
148
151
  providerThinkingLevel: Schema.optionalKey(Schema.String),
149
152
  endTurn: Schema.optionalKey(Schema.Boolean),
150
153
  timestamp: Schema.Number,
154
+ durationMs: Schema.optionalKey(Schema.Number),
151
155
  });
152
156
  const toolResultMessage = Schema.Struct({
153
157
  role: Schema.Literal("toolResult"),
154
158
  toolCallId: Schema.String,
155
159
  toolName: Schema.String,
156
160
  content: Schema.mutable(Schema.Array(Schema.Union([textContent, imageContent]))),
157
- details: Schema.optionalKey(jsonValue),
158
161
  usage: Schema.optionalKey(usage),
159
162
  isError: Schema.Boolean,
160
163
  timestamp: Schema.Number,
164
+ durationMs: Schema.optionalKey(Schema.Number),
161
165
  });
162
- /** Exact Pi message grammar stored by Woodstock without normalization. */
166
+ /** Model content only; application data is carried by the surrounding entry. */
163
167
  export const StoredPiMessageSchema = Schema.Union([
164
168
  systemMessage,
165
169
  userMessage,
@@ -212,7 +216,6 @@ const runContract = Schema.Struct({
212
216
  });
213
217
  const StoredToolResultSchema = Schema.Struct({
214
218
  content: Schema.mutable(Schema.Array(Schema.Union([textContent, imageContent]))),
215
- details: Schema.optional(jsonValue),
216
219
  usage: Schema.optional(usage),
217
220
  isError: Schema.Boolean,
218
221
  terminate: Schema.optional(Schema.Boolean),
@@ -327,6 +330,7 @@ const StoredSessionEntrySchema = Schema.Union([
327
330
  Schema.Struct({
328
331
  ...common,
329
332
  kind: Schema.Literal("message"),
333
+ data: Schema.optionalKey(jsonValue),
330
334
  run: CausalIdentitySchema,
331
335
  turn: CausalIdentitySchema,
332
336
  message: CausalIdentitySchema,
@@ -345,6 +349,7 @@ const StoredSessionEntrySchema = Schema.Union([
345
349
  Schema.Struct({
346
350
  ...common,
347
351
  kind: Schema.Literal("tool_outcome"),
352
+ data: Schema.optionalKey(jsonValue),
348
353
  run: CausalIdentitySchema,
349
354
  turn: CausalIdentitySchema,
350
355
  toolCall: CausalIdentitySchema,
@@ -356,39 +361,77 @@ const StoredSessionEntrySchema = Schema.Union([
356
361
  kind: Schema.Literal("live_retry"),
357
362
  event: LiveRetryEventSchema,
358
363
  }),
364
+ // Pi Durable's compaction entry (`compaction.ts`): the summary is the
365
+ // user message the model reads, and `head` names the first kept entry.
366
+ // Clients render a divider from `data` and never show the summary.
359
367
  Schema.Struct({
360
368
  ...common,
361
369
  kind: Schema.Literal("compaction"),
362
- resumesRun: Schema.optionalKey(Schema.Boolean),
363
- // Optional only because Sessions compacted before these facts existed
364
- // are still live; every new compaction records both.
365
- trigger: Schema.optionalKey(CompactionTriggerSchema),
366
- /** Estimated context tokens right after this compaction. */
367
- tokensAfter: Schema.optionalKey(Schema.Number),
368
- firstKeptEntryId: boundedId,
369
- summary: Schema.String,
370
- tokensBefore: Schema.Number,
371
- usage,
372
- contextRevision: boundedId,
373
- details: Schema.optionalKey(Schema.Struct({
374
- readFiles: Schema.Array(Schema.String),
375
- modifiedFiles: Schema.Array(Schema.String),
376
- })),
370
+ head: boundedId,
371
+ model: Schema.Tuple([userMessage]),
372
+ data: Schema.Struct({
373
+ // Absent only on rows from before these facts were recorded; the
374
+ // store rewrite never invents them, and every new row has both.
375
+ reason: Schema.optionalKey(CompactionTriggerSchema),
376
+ resumesRun: Schema.Boolean,
377
+ tokensBefore: Schema.Number,
378
+ /** Estimated context tokens right after this compaction. */
379
+ tokensAfter: Schema.optionalKey(Schema.Number),
380
+ usage,
381
+ contextRevision: boundedId,
382
+ /**
383
+ * The archive owner's opaque receipt for this compaction, committed in
384
+ * the same append as the transition. Absent when no handoff archived it.
385
+ */
386
+ receipt: Schema.optionalKey(CompactionReceiptSchema),
387
+ details: Schema.optionalKey(Schema.Struct({
388
+ readFiles: Schema.Array(Schema.String),
389
+ modifiedFiles: Schema.Array(Schema.String),
390
+ })),
391
+ }),
377
392
  }),
378
393
  // A compaction that committed nothing: a manual request with nothing to
379
- // summarize, or any compaction that failed. Clients show it as a result.
394
+ // summarize, any compaction that failed, or a finished summary dropped
395
+ // unplaced: stale (its head is off the selected lineage or older than the
396
+ // context start) or insufficient (placed, the context would still be over
397
+ // the limit). A completed summary keeps its `usage`, including when its
398
+ // handoff fails. Nothing to compact still refuses usage. Clients show each
399
+ // as a result.
380
400
  Schema.Struct({
381
401
  ...common,
382
402
  kind: Schema.Literal("compaction_notice"),
383
403
  trigger: CompactionTriggerSchema,
384
- result: Schema.Literals(["nothing_to_compact", "failed"]),
404
+ result: Schema.Literal("nothing_to_compact"),
385
405
  diagnostic: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(200))),
386
406
  }),
407
+ Schema.Struct({
408
+ ...common,
409
+ kind: Schema.Literal("compaction_notice"),
410
+ trigger: CompactionTriggerSchema,
411
+ result: Schema.Literal("failed"),
412
+ usage: Schema.optionalKey(usage),
413
+ diagnostic: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(200))),
414
+ }),
415
+ Schema.Struct({
416
+ ...common,
417
+ kind: Schema.Literal("compaction_notice"),
418
+ trigger: CompactionTriggerSchema,
419
+ result: Schema.Literal("stale"),
420
+ usage: Schema.optionalKey(usage),
421
+ }),
422
+ Schema.Struct({
423
+ ...common,
424
+ kind: Schema.Literal("compaction_notice"),
425
+ trigger: CompactionTriggerSchema,
426
+ result: Schema.Literal("insufficient"),
427
+ usage: Schema.optionalKey(usage),
428
+ }),
387
429
  Schema.Struct({
388
430
  ...common,
389
431
  kind: Schema.Literal("run_terminal"),
390
432
  run: CausalIdentitySchema,
391
433
  terminal: CausalIdentitySchema,
434
+ diagnostic: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(200))),
392
435
  outcome: Schema.Literals(["completed", "cancelled", "failed"]),
393
436
  }),
394
437
  Schema.Struct({
@@ -102,6 +102,8 @@ export function prepareSessionInbox(owner) {
102
102
  ON session_inbox(tier, last_activity_at DESC, session_id)`);
103
103
  owner.sql.exec(`CREATE INDEX IF NOT EXISTS idx_session_inbox_revision
104
104
  ON session_inbox(revision)`);
105
+ owner.sql.exec(`CREATE INDEX IF NOT EXISTS idx_session_inbox_coldest
106
+ ON session_inbox(last_activity_at, session_id)`);
105
107
  owner.sql.exec(`
106
108
  CREATE TABLE IF NOT EXISTS session_inbox_clock (
107
109
  singleton INTEGER PRIMARY KEY CHECK (singleton = 1),