@code-yeongyu/senpi 2026.11.6-3 → 2026.11.9

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 (147) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/bundle/chunks/{chunk-JMQOLOC2.js → chunk-3CRPNPTR.js} +1 -1
  3. package/dist/bundle/chunks/{chunk-5LKB732P.js → chunk-3TZQXZKH.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-X53PD4ZC.js → chunk-45MVD7BU.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-L7ZIS3MC.js → chunk-4JIBEZZE.js} +3 -3
  6. package/dist/bundle/chunks/{chunk-CF5OGBC4.js → chunk-4NYNMAYF.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-6CEDL5S2.js → chunk-4UR6UFBH.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-F5JLDCYD.js → chunk-527Q2UYM.js} +5 -5
  9. package/dist/bundle/chunks/{chunk-7DRWPZ3N.js → chunk-622VYTRI.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-GKAYPJ4E.js → chunk-7PROV6BB.js} +1 -1
  11. package/dist/bundle/chunks/{chunk-4E7GDG4H.js → chunk-7VMEE62L.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-CFEHJ4VU.js → chunk-HXNXISJD.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-4BATXPB7.js → chunk-K3UHGDUQ.js} +1 -1
  14. package/dist/bundle/chunks/{chunk-SB6MXNO5.js → chunk-M7GF73FO.js} +2 -2
  15. package/dist/bundle/chunks/{chunk-V2QAYGOK.js → chunk-OCMGRBJ5.js} +22 -22
  16. package/dist/bundle/chunks/{chunk-EO2VPZ2K.js → chunk-SGAFIMAU.js} +1 -1
  17. package/dist/bundle/chunks/{chunk-BASS47UD.js → chunk-STGOYIXC.js} +1 -1
  18. package/dist/bundle/chunks/{chunk-DSWDJ7HT.js → chunk-WQ4RBPMS.js} +1 -1
  19. package/dist/bundle/chunks/{chunk-MJTCZUXS.js → chunk-WX2HB4DD.js} +1 -1
  20. package/dist/bundle/chunks/chunk-XZDCMDUH.js +2 -0
  21. package/dist/bundle/chunks/{chunk-LUZVGPQ7.js → chunk-Y5L4UFMI.js} +1 -1
  22. package/dist/bundle/chunks/{cli-main-RWHDZKTQ.js → cli-main-E4NDWAUD.js} +1 -1
  23. package/dist/bundle/chunks/{hand-entry-G5LYF62Q.js → hand-entry-5X5Z5Y3D.js} +1 -1
  24. package/dist/bundle/chunks/{headless-host-ES74ZB6M.js → headless-host-YXUGONR3.js} +1 -1
  25. package/dist/bundle/chunks/{host-command-I2JZ5JM7.js → host-command-VHX2ILLM.js} +1 -1
  26. package/dist/bundle/chunks/{host-session-command-Y52NFPP2.js → host-session-command-P3MRW63Z.js} +1 -1
  27. package/dist/bundle/chunks/{interactive-mode-PA7DGVS6.js → interactive-mode-XUSBLLWI.js} +1 -1
  28. package/dist/bundle/chunks/{main-OBL6375C.js → main-3TWVKTJN.js} +1 -1
  29. package/dist/bundle/chunks/{multi-session-host-NM6I5BWZ.js → multi-session-host-HRGM66PY.js} +1 -1
  30. package/dist/bundle/chunks/{package-manager-cli-GNRQ5MVR.js → package-manager-cli-WSH7U4YE.js} +1 -1
  31. package/dist/bundle/chunks/{role-F56BS2ZQ.js → role-4BUU46VW.js} +3 -3
  32. package/dist/bundle/chunks/{rotation-stream-BN2YK2MC.js → rotation-stream-TODBIHXJ.js} +1 -1
  33. package/dist/bundle/chunks/{rpc-mode-G4KIP7XS.js → rpc-mode-OAPIV46G.js} +1 -1
  34. package/dist/bundle/chunks/{run-attached-tui-XTGPAGYM.js → run-attached-tui-MXCC5IZR.js} +1 -1
  35. package/dist/bundle/chunks/{schedule-command-L4M3TSQ3.js → schedule-command-MX56D6UE.js} +1 -1
  36. package/dist/bundle/chunks/{session-control-endpoint-V46WMCDF.js → session-control-endpoint-IL6ERD4U.js} +1 -1
  37. package/dist/bundle/chunks/{session-picker-AG6KSR5A.js → session-picker-6VRC25MJ.js} +1 -1
  38. package/dist/bundle/chunks/session-worker.js +44 -44
  39. package/dist/bundle/cli.js +2 -2
  40. package/dist/bundle/index.js +1 -1
  41. package/dist/bundle/rpc-entry.js +1 -1
  42. package/dist/bundle/runtime-manifest.json +1 -1
  43. package/dist/core/agent-session-services.d.ts +2 -0
  44. package/dist/core/agent-session-services.js +1 -0
  45. package/dist/core/agent-session.d.ts +8 -0
  46. package/dist/core/agent-session.js +51 -4
  47. package/dist/core/egress/classify.d.ts +8 -3
  48. package/dist/core/egress/classify.js +177 -158
  49. package/dist/core/egress/console-redactor.d.ts +7 -0
  50. package/dist/core/egress/console-redactor.js +74 -0
  51. package/dist/core/egress/credentials.d.ts +73 -0
  52. package/dist/core/egress/credentials.js +20 -0
  53. package/dist/core/egress/device-custody.d.ts +1 -1
  54. package/dist/core/egress/device-custody.js +18 -15
  55. package/dist/core/egress/device-proxy-call.d.ts +59 -0
  56. package/dist/core/egress/device-proxy-call.js +148 -0
  57. package/dist/core/egress/device-proxy-lost-calls.d.ts +27 -0
  58. package/dist/core/egress/device-proxy-lost-calls.js +28 -0
  59. package/dist/core/egress/device-proxy-ports.d.ts +49 -0
  60. package/dist/core/egress/device-proxy-ports.js +2 -0
  61. package/dist/core/egress/device-proxy-request.d.ts +34 -0
  62. package/dist/core/egress/device-proxy-request.js +69 -0
  63. package/dist/core/egress/device-proxy-waits.d.ts +40 -0
  64. package/dist/core/egress/device-proxy-waits.js +67 -0
  65. package/dist/core/egress/device-proxy.d.ts +3 -0
  66. package/dist/core/egress/device-proxy.js +214 -0
  67. package/dist/core/egress/endpoint.js +2 -1
  68. package/dist/core/egress/entry-verify.d.ts +13 -0
  69. package/dist/core/egress/entry-verify.js +33 -0
  70. package/dist/core/egress/hpke.js +13 -9
  71. package/dist/core/egress/key-policy-template.d.ts +7 -1
  72. package/dist/core/egress/ledger-schema.d.ts +80 -0
  73. package/dist/core/egress/ledger-schema.js +117 -0
  74. package/dist/core/egress/ledger.d.ts +55 -0
  75. package/dist/core/egress/ledger.js +159 -0
  76. package/dist/core/egress/pinned-infra.d.ts +23 -2
  77. package/dist/core/egress/pinned-infra.js +9 -2
  78. package/dist/core/egress/redact.d.ts +10 -0
  79. package/dist/core/egress/redact.js +134 -0
  80. package/dist/core/egress/sealed-source.d.ts +35 -0
  81. package/dist/core/egress/sealed-source.js +140 -0
  82. package/dist/core/egress/verified-keys.js +1 -1
  83. package/dist/core/egress/wire.d.ts +5 -3
  84. package/dist/core/egress/wire.js +5 -3
  85. package/dist/core/extensions/builtin/monitor-state-event.d.ts +26 -0
  86. package/dist/core/extensions/builtin/monitor-state-event.js +2 -0
  87. package/dist/core/extensions/builtin/terminal/background-age.d.ts +25 -0
  88. package/dist/core/extensions/builtin/terminal/background-age.js +91 -0
  89. package/dist/core/extensions/builtin/terminal/extension-state.d.ts +1 -1
  90. package/dist/core/extensions/builtin/terminal/extension-state.js +21 -3
  91. package/dist/core/extensions/builtin/terminal/notify.d.ts +6 -0
  92. package/dist/core/extensions/builtin/terminal/notify.js +39 -5
  93. package/dist/core/extensions/builtin/terminal/session-bundle.d.ts +9 -2
  94. package/dist/core/extensions/builtin/terminal/session-bundle.js +36 -1
  95. package/dist/core/extensions/builtin/terminal/settings.d.ts +2 -0
  96. package/dist/core/extensions/builtin/terminal/settings.js +8 -0
  97. package/dist/core/extensions/builtin/terminal/tools/background-auto-reap.d.ts +15 -0
  98. package/dist/core/extensions/builtin/terminal/tools/background-auto-reap.js +87 -0
  99. package/dist/core/extensions/builtin/terminal/tools/bash.d.ts +2 -0
  100. package/dist/core/extensions/builtin/terminal/tools/bash.js +6 -6
  101. package/dist/core/extensions/builtin/terminal/tools/child-placement.d.ts +8 -0
  102. package/dist/core/extensions/builtin/terminal/tools/child-placement.js +43 -6
  103. package/dist/core/extensions/builtin/terminal/tools/context.d.ts +11 -2
  104. package/dist/core/extensions/session-control-types.d.ts +15 -0
  105. package/dist/core/extensions/session-control-types.js +11 -0
  106. package/dist/core/external-admission.d.ts +16 -2
  107. package/dist/core/external-admission.js +22 -4
  108. package/dist/core/retry-fallback/controller.d.ts +1 -0
  109. package/dist/core/retry-fallback/controller.js +3 -0
  110. package/dist/core/retry-fallback/unusable.d.ts +2 -0
  111. package/dist/core/retry-fallback/unusable.js +7 -1
  112. package/dist/core/retry-fallback/usage-limit.d.ts +6 -1
  113. package/dist/core/retry-fallback/usage-limit.js +9 -4
  114. package/dist/core/sdk.d.ts +6 -1
  115. package/dist/core/sdk.js +1 -0
  116. package/dist/core/terminal-settings.d.ts +1 -0
  117. package/dist/core/turn-origin.d.ts +4 -0
  118. package/dist/core/turn-origin.js +10 -0
  119. package/dist/modes/interactive/components/remote-delivery-message.d.ts +2 -1
  120. package/dist/modes/interactive/components/remote-delivery-message.js +13 -5
  121. package/dist/modes/rpc/admit-external-message-command.d.ts +37 -0
  122. package/dist/modes/rpc/admit-external-message-command.js +61 -0
  123. package/dist/modes/rpc/admit-external-message-wire.d.ts +42 -0
  124. package/dist/modes/rpc/admit-external-message-wire.js +55 -0
  125. package/dist/modes/rpc/connection-handler.js +14 -0
  126. package/dist/modes/rpc/effect-commands.d.ts +1 -1
  127. package/dist/modes/rpc/host-idle-handover.js +1 -0
  128. package/dist/modes/rpc/method-classes-schema-delivery.d.ts +32 -0
  129. package/dist/modes/rpc/method-classes-schema-delivery.js +22 -0
  130. package/dist/modes/rpc/method-classes-schema-session.d.ts +27 -0
  131. package/dist/modes/rpc/method-classes-schema-session.js +2 -0
  132. package/dist/modes/rpc/method-classes-schema.d.ts +27 -0
  133. package/dist/modes/rpc/method-classes.d.ts +1 -0
  134. package/dist/modes/rpc/method-classes.js +2 -0
  135. package/dist/modes/rpc/rpc-input-validation.js +4 -3
  136. package/dist/modes/rpc/rpc-response-types.d.ts +2 -1
  137. package/dist/modes/rpc/rpc-session-command-types.d.ts +2 -1
  138. package/dist/modes/rpc/tool-child/terminal-jobs.d.ts +1 -0
  139. package/dist/modes/rpc/tool-child/terminal-jobs.js +17 -1
  140. package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
  141. package/docs/engine-socket/fixtures/rpc-inbound-samples.json +19 -2
  142. package/docs/rpc.md +57 -0
  143. package/docs/terminal-tools.md +25 -1
  144. package/native/socket-secret/prebuilds/win32-arm64/senpi_socket_secret.win32-arm64.node +0 -0
  145. package/native/socket-secret/prebuilds/win32-x64/senpi_socket_secret.win32-x64.node +0 -0
  146. package/package.json +6 -6
  147. package/dist/bundle/chunks/chunk-UODSYQ2D.js +0 -2
@@ -0,0 +1,55 @@
1
+ /** The bound every id and label of the record stays inside, as the other local field checks bound theirs. */
2
+ const MAX_ID_CHARACTERS = 256;
3
+ const SENDER_FIELDS = {
4
+ agent: { required: ["session_id"], optional: ["name"] },
5
+ command_line: { required: [], optional: ["user"] },
6
+ external: { required: ["platform"], optional: ["author"] },
7
+ };
8
+ const SENDER_SHAPE = 'sender must be { kind: "agent", session_id, name? }, { kind: "command_line", user? } or { kind: "external", platform, author? }, each value a non-empty string of at most 256 characters.';
9
+ function boundedId(value) {
10
+ return typeof value === "string" && value.length > 0 && value.length <= MAX_ID_CHARACTERS;
11
+ }
12
+ /** A well-formed sender of a known kind with no other field, so nothing beyond the label can ride along. */
13
+ function isDeliverySender(value) {
14
+ if (typeof value !== "object" || value === null || Array.isArray(value))
15
+ return false;
16
+ const kind = Reflect.get(value, "kind");
17
+ if (typeof kind !== "string" || !Object.hasOwn(SENDER_FIELDS, kind))
18
+ return false;
19
+ const { required, optional } = SENDER_FIELDS[kind];
20
+ const allowed = new Set(["kind", ...required, ...optional]);
21
+ return (Object.keys(value).every((key) => allowed.has(key)) &&
22
+ required.every((key) => boundedId(Reflect.get(value, key))) &&
23
+ optional.every((key) => Reflect.get(value, key) === undefined || boundedId(Reflect.get(value, key))));
24
+ }
25
+ function fieldProblem(value, maxTextCharacters) {
26
+ if (!boundedId(value.deliveryId))
27
+ return "needs deliveryId, a non-empty string of at most 256 characters.";
28
+ if (typeof value.text !== "string" || value.text.trim() === "" || value.text.length > maxTextCharacters)
29
+ return `needs text, a non-empty string of at most ${maxTextCharacters} characters.`;
30
+ if (value.deliverAs !== "steer" && value.deliverAs !== "followUp")
31
+ return 'deliverAs must be "steer" or "followUp".';
32
+ if (value.displayText !== undefined &&
33
+ (typeof value.displayText !== "string" || value.displayText.length > maxTextCharacters))
34
+ return `displayText must be a string of at most ${maxTextCharacters} characters.`;
35
+ if (value.expectedTurnId !== undefined && !boundedId(value.expectedTurnId))
36
+ return "expectedTurnId must be a non-empty string of at most 256 characters; read it from get_state.currentTurnId.";
37
+ if (value.chainCount !== undefined && !(Number.isSafeInteger(value.chainCount) && value.chainCount >= 1))
38
+ return "chainCount must be a positive integer (1 for a chain's first hop).";
39
+ // The device is stamped by the engine from the connection; a record that names one is refused, never copied.
40
+ if (Object.hasOwn(value, "remote_origin") || Object.hasOwn(value, "remoteOrigin"))
41
+ return "must not name remote_origin: the engine stamps the device the connection speaks for.";
42
+ if (value.whenIdle !== undefined && value.whenIdle !== "start" && value.whenIdle !== "queue")
43
+ return 'whenIdle must be "start" or "queue"; omit it to start a turn on an idle session.';
44
+ if (value.sender !== undefined && !isDeliverySender(value.sender))
45
+ return SENDER_SHAPE;
46
+ return undefined;
47
+ }
48
+ /** Why an `admit_external_message` record is refused, prefixed with its type; `undefined` for any other record. */
49
+ export function admitExternalMessageFieldError(value, maxTextCharacters) {
50
+ if (value.type !== "admit_external_message")
51
+ return undefined;
52
+ const problem = fieldProblem(value, maxTextCharacters);
53
+ return problem === undefined ? undefined : `admit_external_message ${problem}`;
54
+ }
55
+ //# sourceMappingURL=admit-external-message-wire.js.map
@@ -1,6 +1,7 @@
1
1
  import { isHostOwnedToolRuntimeCapability, toolRuntimeCapabilities, } from "../../cli/tool-runtime.js";
2
2
  import { messagePathProjectRoot, resolveMessagePath } from "../../core/message-path-resolution.js";
3
3
  import { startOpenTimer } from "../../core/open-timing.js";
4
+ import { admitExternalMessage } from "./admit-external-message-command.js";
4
5
  import { apiKeyLoginCredential } from "./api-key-login-credential.js";
5
6
  import { clientFacingIdentity } from "./client-admission-record.js";
6
7
  import { ExtensionOwnerLifetime } from "./extension-owner-lifetime.js";
@@ -1232,6 +1233,19 @@ export function createRpcConnectionHandler(runtimeHost, sink, options = {}) {
1232
1233
  const result = (await sessionControl?.wake(deliveryIds)) ?? {};
1233
1234
  return success(id, "wake", { admitted: result.admitted ?? [] });
1234
1235
  }
1236
+ case "admit_external_message": {
1237
+ const peer = {
1238
+ origin: connectionRoles.originOf(currentConnectionId()),
1239
+ connectionOrigin: connectionOrigin(),
1240
+ };
1241
+ const answer = admitExternalMessage(session, command, peer);
1242
+ if (!answer.ok) {
1243
+ const { refusal } = answer;
1244
+ return error(id, command.type, refusal.message, refusal.errorCode, "errorData" in refusal ? refusal.errorData : undefined);
1245
+ }
1246
+ turnRequested = true;
1247
+ return success(id, command.type, answer.data);
1248
+ }
1235
1249
  case "new_session": {
1236
1250
  const options = command.parentSession ? { parentSession: command.parentSession } : undefined;
1237
1251
  const result = await runtimeHost.newSession(options);
@@ -37,7 +37,7 @@ export declare function runAbort(ctx: EffectCommandContext, command: Command<"ab
37
37
  * or no longer exists.
38
38
  */
39
39
  export declare function runQueuedInputChange(ctx: EffectCommandContext, command: Command<"dequeue_message"> | Command<"edit_queued_message">): Promise<RpcResponse>;
40
- export declare function runSetThinkingLevel(ctx: EffectCommandContext, command: Command<"set_thinking_level">): Promise<import("./session-move-wire.ts").RpcMoveSessionResponse | import("./compact-admission-error.ts").UnknownAdmissionResponse | {
40
+ export declare function runSetThinkingLevel(ctx: EffectCommandContext, command: Command<"set_thinking_level">): Promise<import("./admit-external-message-wire.ts").RpcAdmitExternalMessageResponse | import("./session-move-wire.ts").RpcMoveSessionResponse | import("./compact-admission-error.ts").UnknownAdmissionResponse | {
41
41
  readonly id?: string;
42
42
  readonly type: "response";
43
43
  readonly command: "attach_session";
@@ -15,6 +15,7 @@ const NEW_WORK_COMMANDS = new Set([
15
15
  "bash",
16
16
  "compact",
17
17
  "wake",
18
+ "admit_external_message",
18
19
  "edit_assistant_message",
19
20
  "edit_user_message",
20
21
  ]);
@@ -0,0 +1,32 @@
1
+ /** The schema of `admit_external_message`, a relayed peer-agent message admitted as a delivery (senpi#6233). */
2
+ import Type from "typebox";
3
+ export declare const DELIVERY_RECORD_SCHEMAS: {
4
+ admit_external_message: Type.TObject<{
5
+ id: Type.TOptional<Type.TString>;
6
+ admissionId: Type.TOptional<Type.TString>;
7
+ type: Type.TLiteral<"admit_external_message">;
8
+ } & {
9
+ readonly sessionId: Type.TOptional<Type.TString>;
10
+ } & {
11
+ readonly deliveryId: Type.TString;
12
+ readonly text: Type.TString;
13
+ readonly sender: Type.TOptional<Type.TUnion<[Type.TObject<{
14
+ kind: Type.TLiteral<"agent">;
15
+ session_id: Type.TString;
16
+ name: Type.TOptional<Type.TString>;
17
+ }>, Type.TObject<{
18
+ kind: Type.TLiteral<"command_line">;
19
+ user: Type.TOptional<Type.TString>;
20
+ }>, Type.TObject<{
21
+ kind: Type.TLiteral<"external">;
22
+ platform: Type.TString;
23
+ author: Type.TOptional<Type.TString>;
24
+ }>]>>;
25
+ readonly displayText: Type.TOptional<Type.TString>;
26
+ readonly deliverAs: Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>;
27
+ readonly expectedTurnId: Type.TOptional<Type.TString>;
28
+ readonly whenIdle: Type.TOptional<Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>>;
29
+ readonly chainCount: Type.TOptional<Type.TInteger>;
30
+ }>;
31
+ };
32
+ //# sourceMappingURL=method-classes-schema-delivery.d.ts.map
@@ -0,0 +1,22 @@
1
+ /** The schema of `admit_external_message`, a relayed peer-agent message admitted as a delivery (senpi#6233). */
2
+ import Type from "typebox";
3
+ import { Id, literals, Opt, OptId, OptStr, Str, session } from "./method-classes-schema-fields.js";
4
+ /** `SessionControlSender`: each kind's fields and no other, so nothing beyond the label rides along. */
5
+ const DeliverySender = Type.Union([
6
+ Type.Object({ kind: Type.Literal("agent"), session_id: Id, name: OptId }, { additionalProperties: false }),
7
+ Type.Object({ kind: Type.Literal("command_line"), user: OptId }, { additionalProperties: false }),
8
+ Type.Object({ kind: Type.Literal("external"), platform: Id, author: OptId }, { additionalProperties: false }),
9
+ ]);
10
+ export const DELIVERY_RECORD_SCHEMAS = {
11
+ admit_external_message: session("admit_external_message", {
12
+ deliveryId: Id,
13
+ text: Str,
14
+ sender: Opt(DeliverySender),
15
+ displayText: OptStr,
16
+ deliverAs: literals("steer", "followUp"),
17
+ expectedTurnId: OptId,
18
+ whenIdle: Opt(literals("start", "queue")),
19
+ chainCount: Opt(Type.Integer({ minimum: 1, maximum: Number.MAX_SAFE_INTEGER })),
20
+ }),
21
+ };
22
+ //# sourceMappingURL=method-classes-schema-delivery.js.map
@@ -1,6 +1,33 @@
1
1
  /** The schemas of the session-routed inbound records (senpi#4324). */
2
2
  import Type from "typebox";
3
3
  export declare const SESSION_RECORD_SCHEMAS: {
4
+ admit_external_message: Type.TObject<{
5
+ id: Type.TOptional<Type.TString>;
6
+ admissionId: Type.TOptional<Type.TString>;
7
+ type: Type.TLiteral<"admit_external_message">;
8
+ } & {
9
+ readonly sessionId: Type.TOptional<Type.TString>;
10
+ } & {
11
+ readonly deliveryId: Type.TString;
12
+ readonly text: Type.TString;
13
+ readonly sender: Type.TOptional<Type.TUnion<[Type.TObject<{
14
+ kind: Type.TLiteral<"agent">;
15
+ session_id: Type.TString;
16
+ name: Type.TOptional<Type.TString>;
17
+ }>, Type.TObject<{
18
+ kind: Type.TLiteral<"command_line">;
19
+ user: Type.TOptional<Type.TString>;
20
+ }>, Type.TObject<{
21
+ kind: Type.TLiteral<"external">;
22
+ platform: Type.TString;
23
+ author: Type.TOptional<Type.TString>;
24
+ }>]>>;
25
+ readonly displayText: Type.TOptional<Type.TString>;
26
+ readonly deliverAs: Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>;
27
+ readonly expectedTurnId: Type.TOptional<Type.TString>;
28
+ readonly whenIdle: Type.TOptional<Type.TUnion<[Type.TLiteral<string>, ...Type.TLiteral<string>[]]>>;
29
+ readonly chainCount: Type.TOptional<Type.TInteger>;
30
+ }>;
4
31
  prompt: Type.TObject<{
5
32
  id: Type.TOptional<Type.TString>;
6
33
  admissionId: Type.TOptional<Type.TString>;
@@ -1,6 +1,7 @@
1
1
  /** The schemas of the session-routed inbound records (senpi#4324). */
2
2
  import Type from "typebox";
3
3
  import { Bool, Id, Images, literals, ModelEntries, Num, Opt, OptBool, OptId, OptNum, OptPath, OptStr, PathStr, RetryFallback, RPC_INBOUND_LIMITS, Secret, Str, Strings, session, ThinkingLevel, } from "./method-classes-schema-fields.js";
4
+ import { DELIVERY_RECORD_SCHEMAS } from "./method-classes-schema-delivery.js";
4
5
  /** A thread call's hop count: 1 for the first call of a chain, one more per hop. */
5
6
  const ChainCount = Type.Integer({ minimum: 1, maximum: Number.MAX_SAFE_INTEGER });
6
7
  const steerOrFollowUp = (type) => session(type, {
@@ -220,6 +221,7 @@ const SURFACE_AND_ACCOUNT_SCHEMAS = {
220
221
  };
221
222
  export const SESSION_RECORD_SCHEMAS = {
222
223
  ...PROMPTING_SCHEMAS,
224
+ ...DELIVERY_RECORD_SCHEMAS,
223
225
  ...STATE_AND_MODEL_SCHEMAS,
224
226
  ...BASH_AND_TREE_SCHEMAS,
225
227
  ...SURFACE_AND_ACCOUNT_SCHEMAS,
@@ -29,6 +29,33 @@ export type RpcInboundSchemaDisagreements<Schemas extends RpcInboundSchemaTable>
29
29
  [K in RpcMethodType]: Agrees<RpcInboundRecordOf<K>, Static<Schemas[K]>> extends true ? never : K;
30
30
  }[RpcMethodType];
31
31
  export declare const RPC_INBOUND_SCHEMAS: {
32
+ readonly admit_external_message: import("typebox").TObject<{
33
+ id: import("typebox").TOptional<import("typebox").TString>;
34
+ admissionId: import("typebox").TOptional<import("typebox").TString>;
35
+ type: import("typebox").TLiteral<"admit_external_message">;
36
+ } & {
37
+ readonly sessionId: import("typebox").TOptional<import("typebox").TString>;
38
+ } & {
39
+ readonly deliveryId: import("typebox").TString;
40
+ readonly text: import("typebox").TString;
41
+ readonly sender: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TObject<{
42
+ kind: import("typebox").TLiteral<"agent">;
43
+ session_id: import("typebox").TString;
44
+ name: import("typebox").TOptional<import("typebox").TString>;
45
+ }>, import("typebox").TObject<{
46
+ kind: import("typebox").TLiteral<"command_line">;
47
+ user: import("typebox").TOptional<import("typebox").TString>;
48
+ }>, import("typebox").TObject<{
49
+ kind: import("typebox").TLiteral<"external">;
50
+ platform: import("typebox").TString;
51
+ author: import("typebox").TOptional<import("typebox").TString>;
52
+ }>]>>;
53
+ readonly displayText: import("typebox").TOptional<import("typebox").TString>;
54
+ readonly deliverAs: import("typebox").TUnion<[import("typebox").TLiteral<string>, ...import("typebox").TLiteral<string>[]]>;
55
+ readonly expectedTurnId: import("typebox").TOptional<import("typebox").TString>;
56
+ readonly whenIdle: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TLiteral<string>, ...import("typebox").TLiteral<string>[]]>>;
57
+ readonly chainCount: import("typebox").TOptional<import("typebox").TInteger>;
58
+ }>;
32
59
  readonly get_protocol_info: import("typebox").TObject<{
33
60
  id: import("typebox").TOptional<import("typebox").TString>;
34
61
  admissionId: import("typebox").TOptional<import("typebox").TString>;
@@ -145,6 +145,7 @@ export declare const RPC_METHOD_CLASS: {
145
145
  readonly pause_for_run: "drive";
146
146
  readonly resume_for_run: "drive";
147
147
  readonly wake: "drive";
148
+ readonly admit_external_message: "drive";
148
149
  readonly release_tool_barrier: "drive";
149
150
  readonly request_self_settle: "drive";
150
151
  readonly "eval_cells.stop": "drive";
@@ -193,6 +193,8 @@ export const RPC_METHOD_CLASS = {
193
193
  pause_for_run: "drive",
194
194
  resume_for_run: "drive",
195
195
  wake: "drive",
196
+ // the engine writes its own fixed delivery entry: no role=user, input event, command or template expansion (senpi#6233)
197
+ admit_external_message: "drive",
196
198
  release_tool_barrier: "drive",
197
199
  request_self_settle: "drive",
198
200
  "eval_cells.stop": "drive",
@@ -1,6 +1,7 @@
1
1
  import { isBrowserEngine } from "../../core/browser-engine.js";
2
2
  import { clientMessageIdentitySchema } from "../../core/client-message-identity.js";
3
3
  import { MAX_TOOL_BARRIER_ID_LENGTH, toolBarrierSpecError } from "../../core/tool-barrier.js";
4
+ import { admitExternalMessageFieldError } from "./admit-external-message-wire.js";
4
5
  import { validatePauseCommand } from "./pause-command-validation.js";
5
6
  export const MAX_RPC_MESSAGE_CHARACTERS = 1_000_000;
6
7
  /**
@@ -141,9 +142,9 @@ export function rpcCommandPayloadError(command) {
141
142
  !(typeof value.effectId === "string" && value.effectId.length > 0 && value.effectId.length <= 256)) {
142
143
  return "effectId must be a non-empty string of at most 256 characters.";
143
144
  }
144
- const pauseFieldError = validatePauseCommand(value);
145
- if (pauseFieldError !== undefined)
146
- return pauseFieldError;
145
+ const fieldError = validatePauseCommand(value) ?? admitExternalMessageFieldError(value, MAX_RPC_MESSAGE_CHARACTERS);
146
+ if (fieldError !== undefined)
147
+ return fieldError;
147
148
  if (value.type === "get_pending_inputs" && value.knownClientMessageIds !== undefined) {
148
149
  const ids = value.knownClientMessageIds;
149
150
  if (!Array.isArray(ids) ||
@@ -1,3 +1,4 @@
1
+ import type { RpcAdmitExternalMessageResponse } from "./admit-external-message-wire.ts";
1
2
  import type { RpcAttachmentResponse } from "./attachment-types.ts";
2
3
  import type { UnknownAdmissionResponse } from "./compact-admission-error.ts";
3
4
  import type { RpcHostCommandResponse } from "./rpc-host-response-types.ts";
@@ -12,5 +13,5 @@ export type RpcResponse = {
12
13
  data?: {
13
14
  capabilities: readonly string[];
14
15
  };
15
- } | UnknownAdmissionResponse | RpcAttachmentResponse | RpcHostCommandResponse | RpcReadResponse | RpcMutationResponse | RpcPauseResponse;
16
+ } | UnknownAdmissionResponse | RpcAttachmentResponse | RpcHostCommandResponse | RpcReadResponse | RpcMutationResponse | RpcAdmitExternalMessageResponse | RpcPauseResponse;
16
17
  //# sourceMappingURL=rpc-response-types.d.ts.map
@@ -5,6 +5,7 @@ import type { BashResult } from "../../core/bash-executor.ts";
5
5
  import type { ClientMessageIdentity } from "../../core/client-message-identity.ts";
6
6
  import type { SessionEntry } from "../../core/session-manager.ts";
7
7
  import type { ToolBarrierSpec } from "../../core/tool-barrier.ts";
8
+ import type { RpcAdmitExternalMessageCommand } from "./admit-external-message-wire.ts";
8
9
  import type { RpcRecoveryCommand } from "./rpc-recovery-command-types.ts";
9
10
  import type { RpcRemoteOrigin } from "./remote-origin.ts";
10
11
  import type { RpcSessionModelEntry } from "./rpc-session-state-types.ts";
@@ -196,7 +197,7 @@ export type RpcSessionCommand = {
196
197
  id?: string;
197
198
  type: "wake";
198
199
  delivery_ids?: string[];
199
- } | {
200
+ } | RpcAdmitExternalMessageCommand | {
200
201
  id?: string;
201
202
  type: "get_state";
202
203
  } | {
@@ -14,6 +14,7 @@ export interface TerminalJobArgs {
14
14
  readonly defaultRows: number;
15
15
  readonly timeoutAction?: TimeoutAction;
16
16
  readonly redactSecretsInOutput?: boolean;
17
+ readonly backgroundAutoReapMinutes?: number;
17
18
  }
18
19
  /**
19
20
  * The handlers. The child's one terminal manager (shared by every terminal job of this child) is made on the first job,
@@ -21,6 +21,7 @@ function parseArgs(value) {
21
21
  throw new ToolChildJobError("terminal_job_bad_args", "a terminal job needs cwd, toolCallId and env");
22
22
  const shellPath = field("shellPath");
23
23
  const timeoutAction = field("timeoutAction");
24
+ const autoReap = field("backgroundAutoReapMinutes");
24
25
  return {
25
26
  params: field("params"),
26
27
  toolCallId,
@@ -31,6 +32,7 @@ function parseArgs(value) {
31
32
  defaultRows: Number(field("defaultRows")) || 0,
32
33
  redactSecretsInOutput: field("redactSecretsInOutput") === true,
33
34
  ...(timeoutAction === "background" || timeoutAction === "kill" ? { timeoutAction } : {}),
35
+ ...(typeof autoReap === "number" && Number.isFinite(autoReap) ? { backgroundAutoReapMinutes: autoReap } : {}),
34
36
  };
35
37
  }
36
38
  function barrierFor(job) {
@@ -67,6 +69,9 @@ function exitSummary(id, runtime) {
67
69
  ? null
68
70
  : { exitCode: exit.exitCode, signal: exit.signal, cancelled: exit.cancelled, timedOut: exit.timedOut },
69
71
  output: output.length > NOTICE_TAIL_MAX_CHARS ? output.slice(output.length - NOTICE_TAIL_MAX_CHARS - 1) : output,
72
+ ...(runtime.autoReapedAfterMinutes === undefined
73
+ ? {}
74
+ : { autoReapedAfterMinutes: runtime.autoReapedAfterMinutes }),
70
75
  };
71
76
  }
72
77
  /**
@@ -87,8 +92,19 @@ export function createTerminalJobHandlers(injected) {
87
92
  const contextFor = (args, job) => ({
88
93
  manager: managerFor(job.generation),
89
94
  ...(args.timeoutAction === undefined ? {} : { timeoutAction: args.timeoutAction }),
90
- onBackgroundStart: (id, description, startedAtMs) => tell(job, { event: "background_start", id, description, startedAtMs }),
95
+ ...(args.backgroundAutoReapMinutes === undefined
96
+ ? {}
97
+ : { backgroundAutoReapMinutes: args.backgroundAutoReapMinutes }),
98
+ onBackgroundStart: (id, description, startedAtMs, command, autoReapMinutes) => tell(job, {
99
+ event: "background_start",
100
+ id,
101
+ description,
102
+ startedAtMs,
103
+ ...(command === undefined ? {} : { command }),
104
+ ...(autoReapMinutes === undefined ? {} : { autoReapMinutes }),
105
+ }),
91
106
  onBackgroundExit: (id, runtime) => tell(job, exitSummary(id, runtime)),
107
+ onBackgroundReapFailed: (id, autoReapMinutes, reason) => tell(job, { event: "background_reap_failed", id, autoReapMinutes, reason }),
92
108
  cwd: args.cwd,
93
109
  ...(args.shellPath === undefined ? {} : { shellPath: args.shellPath }),
94
110
  defaultCols: args.defaultCols,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "rpcClientRequests": "{\"type\":\"get_protocol_info\",\"id\":\"rpc-auth-protocol\",\"observe\":true,\"auth\":{\"client_nonce\":\"<public-nonce>\"}}\n{\"type\":\"set_client_info\",\"width\":100,\"capabilities\":[],\"id\":\"req_1\"}\n{\"type\":\"open_session\",\"cwd\":\"<root>/cwd\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"id\":\"req_2\"}\n{\"type\":\"get_entries\",\"sessionId\":\"rpc-1\",\"id\":\"req_3\"}\n{\"type\":\"close_session\",\"sessionId\":\"rpc-1\",\"id\":\"req_4\"}\n",
3
- "rpcClientFrames": "{\"id\":\"rpc-auth-protocol\",\"type\":\"response\",\"command\":\"get_protocol_info\",\"success\":true,\"data\":{\"protocolVersion\":1,\"serverVersion\":\"<server-version>\",\"capabilities\":[\"<capabilities>\"],\"mode\":\"multi\",\"instanceId\":\"<uuid-1>\",\"generation\":0,\"engineVersion\":\"<server-version>\",\"engineOrdinal\":\"<engine-ordinal>\",\"launch_profile\":{\"profile_id\":\"ca7a49435f02009fdda5dac49d29408dcfeb1ab5374353784c5a9def467f5be1\",\"core\":{\"extensions\":[],\"multi_session\":false,\"session_runtime\":\"worker\"}},\"agentDir\":\"<root>/agent\",\"method_classes\":{\"version\":1,\"digest\":\"67e7dac5622360f9e5fc471764f5a69c43c3abcc22bed55859761cbb53ede37c\",\"classes\":{\"get_protocol_info\":\"observe\",\"get_subscription_limits\":\"observe\",\"list_sessions\":\"observe\",\"list_hands\":\"observe\",\"get_state\":\"observe\",\"get_snapshot\":\"observe\",\"get_entries\":\"observe\",\"get_messages\":\"observe\",\"get_tree\":\"observe\",\"get_fork_messages\":\"observe\",\"get_last_assistant_text\":\"observe\",\"get_session_stats\":\"observe\",\"get_effect_status\":\"dynamic\",\"get_pending_inputs\":\"observe\",\"get_follow_up_messages\":\"observe\",\"get_steering_messages\":\"observe\",\"get_commands\":\"observe\",\"get_loaded_surfaces\":\"observe\",\"get_project_trust\":\"observe\",\"get_available_models\":\"observe\",\"get_available_thinking_levels\":\"observe\",\"get_model_thinking_level\":\"observe\",\"get_fast_mode\":\"observe\",\"get_media\":\"observe\",\"memory_report\":\"observe\",\"eval_cells.list\":\"observe\",\"eval_cells.peek\":\"observe\",\"prompt\":\"dynamic\",\"steer\":\"dynamic\",\"follow_up\":\"dynamic\",\"abort\":\"drive\",\"interrupt\":\"drive\",\"abort_retry\":\"drive\",\"abort_compaction\":\"drive\",\"abort_branch_summary\":\"drive\",\"compact\":\"drive\",\"clear_queue\":\"drive\",\"dequeue_message\":\"drive\",\"edit_queued_message\":\"drive\",\"hold_input\":\"drive\",\"withdraw_held_input\":\"drive\",\"append_user_message\":\"drive\",\"edit_user_message\":\"drive\",\"continue_from_leaf\":\"drive\",\"navigate_tree\":\"drive\",\"set_label\":\"drive\",\"set_session_name\":\"drive\",\"set_thinking_level\":\"dynamic\",\"set_model\":\"dynamic\",\"set_auto_compaction\":\"drive\",\"set_permission_preset\":\"device_admin\",\"set_retry_fallback\":\"drive\",\"pause_for_run\":\"drive\",\"resume_for_run\":\"drive\",\"wake\":\"drive\",\"release_tool_barrier\":\"drive\",\"request_self_settle\":\"drive\",\"eval_cells.stop\":\"drive\",\"append_session_entry\":\"dynamic\",\"extension_ui_response\":\"answer\",\"extension_ui_progress\":\"answer\",\"new_session\":\"dynamic\",\"open_session\":\"dynamic\",\"resume_session\":\"thread\",\"fork\":\"thread\",\"clone\":\"thread\",\"close_session\":\"thread\",\"unload_session\":\"thread\",\"set_session_context\":\"thread\",\"attach_session\":\"thread\",\"select_hand\":\"device_admin\",\"bash\":\"device_admin\",\"abort_bash\":\"device_admin\",\"record_bash_result\":\"device_admin\",\"cleanup_bash_output\":\"device_admin\",\"extension_request\":\"device_admin\",\"reload\":\"device_admin\",\"check_reload_veto\":\"device_admin\",\"resolve_path\":\"device_admin\",\"login_start\":\"device_admin\",\"login_cancel\":\"device_admin\",\"login_api_key\":\"device_admin\",\"logout\":\"device_admin\",\"verify_api_key\":\"device_admin\",\"get_auth_providers\":\"device_admin\",\"get_provider_accounts\":\"device_admin\",\"account_order\":\"device_admin\",\"account_pin\":\"device_admin\",\"account_remove\":\"device_admin\",\"account_reset\":\"device_admin\",\"test_provider_account\":\"device_admin\",\"set_favorite_models\":\"device_admin\",\"set_scoped_models\":\"device_admin\",\"cycle_model\":\"device_admin\",\"cycle_thinking_level\":\"device_admin\",\"set_fast_mode\":\"device_admin\",\"set_steering_mode\":\"device_admin\",\"set_follow_up_mode\":\"device_admin\",\"set_auto_retry\":\"device_admin\",\"set_project_trust\":\"device_admin\",\"get_project_settings\":\"device_admin\",\"set_project_setting\":\"device_admin\",\"edit_assistant_message\":\"device_admin\",\"send_custom_message\":\"device_admin\",\"switch_session\":\"device_admin\",\"import_jsonl\":\"device_admin\",\"export_html\":\"device_admin\",\"export_jsonl\":\"device_admin\",\"set_client_info\":\"connection_local\",\"subscribe_sessions\":\"connection_local\",\"unsubscribe_sessions\":\"connection_local\",\"record_user_activity\":\"connection_local\",\"detach_connection\":\"connection_local\",\"release_session\":\"connection_local\",\"warm\":\"connection_local\",\"host_response\":\"connection_local\",\"release_attachment\":\"connection_local\",\"reclaim_session\":\"connection_local\",\"move_session\":\"connection_local\",\"get_recovery_page\":\"connection_local\",\"release_recovery\":\"connection_local\",\"cancel_attempt\":\"connection_local\",\"reset_stream\":\"connection_local\"},\"dynamic_versions\":{\"get_effect_status\":1,\"prompt\":1,\"steer\":1,\"follow_up\":1,\"set_thinking_level\":1,\"set_model\":1,\"append_session_entry\":1,\"new_session\":1,\"open_session\":2}},\"memory_pressure\":false,\"path_identity_resolver\":{\"state\":\"not_started\",\"detail\":null}}}\n{\"id\":\"req_1\",\"type\":\"response\",\"command\":\"set_client_info\",\"success\":true}\n{\"type\":\"queued\",\"for_request\":\"req_2\",\"position\":1,\"in_flight\":0}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-2>\",\"method\":\"setWidget\",\"widgetKey\":\"todo-sidebar\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-3>\",\"method\":\"setStatus\",\"statusKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-4>\",\"method\":\"setWidget\",\"widgetKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-5>\",\"method\":\"setStatus\",\"statusKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-6>\",\"method\":\"setWidget\",\"widgetKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-7>\",\"method\":\"setStatus\",\"statusKey\":\"monitors\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-8>\",\"method\":\"setStatus\",\"statusKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-9>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-10>\",\"method\":\"setStatus\",\"statusKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-11>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"entry_appended\",\"entry\":{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"},\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-12>\",\"method\":\"setStatus\",\"statusKey\":\"todo-waiting\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-13>\",\"method\":\"setStatus\",\"statusKey\":\"goal\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_opened\",\"sessionId\":\"rpc-1\",\"durableSessionId\":\"<uuid-14>\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"kind\":\"interactive\",\"cwd\":\"<root>/cwd\"}\n{\"id\":\"req_2\",\"type\":\"response\",\"command\":\"open_session\",\"success\":true,\"data\":{\"sessionId\":\"rpc-1\",\"state\":{\"answeredUiRequests\":[],\"paused\":false,\"pausedNoticeCount\":0,\"holds\":[],\"lifecycle\":{\"state\":\"done\",\"seq\":0,\"epoch\":0,\"epochOrigin\":\"automatic\",\"humanInputRevision\":0,\"selfSettleEligible\":true,\"restoring\":false,\"persisted\":false,\"runPaused\":false,\"since\":\"2026-10-29T00:00:00.000Z\",\"role\":\"root\",\"rootSessionId\":\"<uuid-14>\",\"activityRevision\":{\"instanceId\":\"<uuid-15>\",\"revision\":0},\"waitingOn\":{\"children\":0,\"background\":[],\"human\":[]},\"holds\":[],\"observedAt\":\"2026-10-29T00:00:00.000Z\"},\"pendingQuestions\":[],\"pendingDialogs\":[],\"permissionPreset\":\"full-access\",\"permissionPresetSource\":\"host_default\",\"permissionPresetStatus\":\"applied\",\"effectivePermissionPreset\":\"full-access\",\"model\":{\"id\":\"faux-a\",\"name\":\"faux-a\",\"api\":\"faux:fixture\",\"provider\":\"faux\",\"baseUrl\":\"http://localhost:0\",\"reasoning\":false,\"input\":[\"text\",\"image\"],\"cost\":{\"input\":0,\"output\":0,\"cacheRead\":0,\"cacheWrite\":0},\"contextWindow\":128000,\"maxTokens\":16384},\"pendingModelSwitch\":null,\"thinkingLevel\":\"off\",\"thinkingLevelSource\":\"default\",\"sessionModelThinkingLevels\":{\"faux/faux-a\":\"off\"},\"fastMode\":false,\"isStreaming\":false,\"pausedHeldInputCount\":0,\"runPaused\":false,\"pause\":{\"pauseSeq\":0,\"records\":[]},\"isCompacting\":false,\"retryAttempt\":0,\"isBashRunning\":false,\"steeringMode\":\"all\",\"followUpMode\":\"one-at-a-time\",\"sessionFile\":\"<root>/cwd/session.jsonl\",\"sessionId\":\"<uuid-14>\",\"cwd\":\"<root>/cwd\",\"projectTrusted\":false,\"entries\":[{\"type\":\"model_change\",\"id\":\"<entry-3>\",\"parentId\":null,\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"thinking_level_change\",\"id\":\"<entry-2>\",\"parentId\":\"<entry-3>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"thinkingLevel\":\"off\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"}],\"steering\":[],\"followUp\":[],\"ordered\":[],\"autoCompactionEnabled\":true,\"messageCount\":0,\"pendingMessageCount\":0,\"usageTotals\":{\"input\":0,\"output\":0,\"cacheRead\":0,\"cacheWrite\":0,\"cost\":0},\"contextUsage\":{\"tokens\":0,\"contextWindow\":128000,\"percent\":0},\"favoriteModels\":[],\"scopedModels\":[]},\"permissionPreset\":\"full-access\",\"permissionPresetSource\":\"host_default\",\"permissionPresetStatus\":\"applied\"},\"sessionId\":\"rpc-1\"}\n{\"id\":\"req_3\",\"type\":\"response\",\"command\":\"get_entries\",\"success\":true,\"data\":{\"entries\":[{\"type\":\"model_change\",\"id\":\"<entry-3>\",\"parentId\":null,\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"thinking_level_change\",\"id\":\"<entry-2>\",\"parentId\":\"<entry-3>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"thinkingLevel\":\"off\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"}],\"leafId\":\"<entry-1>\"},\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_closed\",\"sessionId\":\"rpc-1\",\"reason\":\"client_close\"}\n{\"id\":\"req_4\",\"type\":\"response\",\"command\":\"close_session\",\"success\":true,\"data\":{},\"sessionId\":\"rpc-1\"}\n",
3
+ "rpcClientFrames": "{\"id\":\"rpc-auth-protocol\",\"type\":\"response\",\"command\":\"get_protocol_info\",\"success\":true,\"data\":{\"protocolVersion\":1,\"serverVersion\":\"<server-version>\",\"capabilities\":[\"<capabilities>\"],\"mode\":\"multi\",\"instanceId\":\"<uuid-1>\",\"generation\":0,\"engineVersion\":\"<server-version>\",\"engineOrdinal\":\"<engine-ordinal>\",\"launch_profile\":{\"profile_id\":\"ca7a49435f02009fdda5dac49d29408dcfeb1ab5374353784c5a9def467f5be1\",\"core\":{\"extensions\":[],\"multi_session\":false,\"session_runtime\":\"worker\"}},\"agentDir\":\"<root>/agent\",\"method_classes\":{\"version\":1,\"digest\":\"7ea18de0fb5d28f89aabdc17cbaca72e973cdea7d5928fd82d91ccced025000e\",\"classes\":{\"get_protocol_info\":\"observe\",\"get_subscription_limits\":\"observe\",\"list_sessions\":\"observe\",\"list_hands\":\"observe\",\"get_state\":\"observe\",\"get_snapshot\":\"observe\",\"get_entries\":\"observe\",\"get_messages\":\"observe\",\"get_tree\":\"observe\",\"get_fork_messages\":\"observe\",\"get_last_assistant_text\":\"observe\",\"get_session_stats\":\"observe\",\"get_effect_status\":\"dynamic\",\"get_pending_inputs\":\"observe\",\"get_follow_up_messages\":\"observe\",\"get_steering_messages\":\"observe\",\"get_commands\":\"observe\",\"get_loaded_surfaces\":\"observe\",\"get_project_trust\":\"observe\",\"get_available_models\":\"observe\",\"get_available_thinking_levels\":\"observe\",\"get_model_thinking_level\":\"observe\",\"get_fast_mode\":\"observe\",\"get_media\":\"observe\",\"memory_report\":\"observe\",\"eval_cells.list\":\"observe\",\"eval_cells.peek\":\"observe\",\"prompt\":\"dynamic\",\"steer\":\"dynamic\",\"follow_up\":\"dynamic\",\"abort\":\"drive\",\"interrupt\":\"drive\",\"abort_retry\":\"drive\",\"abort_compaction\":\"drive\",\"abort_branch_summary\":\"drive\",\"compact\":\"drive\",\"clear_queue\":\"drive\",\"dequeue_message\":\"drive\",\"edit_queued_message\":\"drive\",\"hold_input\":\"drive\",\"withdraw_held_input\":\"drive\",\"append_user_message\":\"drive\",\"edit_user_message\":\"drive\",\"continue_from_leaf\":\"drive\",\"navigate_tree\":\"drive\",\"set_label\":\"drive\",\"set_session_name\":\"drive\",\"set_thinking_level\":\"dynamic\",\"set_model\":\"dynamic\",\"set_auto_compaction\":\"drive\",\"set_permission_preset\":\"device_admin\",\"set_retry_fallback\":\"drive\",\"pause_for_run\":\"drive\",\"resume_for_run\":\"drive\",\"wake\":\"drive\",\"admit_external_message\":\"drive\",\"release_tool_barrier\":\"drive\",\"request_self_settle\":\"drive\",\"eval_cells.stop\":\"drive\",\"append_session_entry\":\"dynamic\",\"extension_ui_response\":\"answer\",\"extension_ui_progress\":\"answer\",\"new_session\":\"dynamic\",\"open_session\":\"dynamic\",\"resume_session\":\"thread\",\"fork\":\"thread\",\"clone\":\"thread\",\"close_session\":\"thread\",\"unload_session\":\"thread\",\"set_session_context\":\"thread\",\"attach_session\":\"thread\",\"select_hand\":\"device_admin\",\"bash\":\"device_admin\",\"abort_bash\":\"device_admin\",\"record_bash_result\":\"device_admin\",\"cleanup_bash_output\":\"device_admin\",\"extension_request\":\"device_admin\",\"reload\":\"device_admin\",\"check_reload_veto\":\"device_admin\",\"resolve_path\":\"device_admin\",\"login_start\":\"device_admin\",\"login_cancel\":\"device_admin\",\"login_api_key\":\"device_admin\",\"logout\":\"device_admin\",\"verify_api_key\":\"device_admin\",\"get_auth_providers\":\"device_admin\",\"get_provider_accounts\":\"device_admin\",\"account_order\":\"device_admin\",\"account_pin\":\"device_admin\",\"account_remove\":\"device_admin\",\"account_reset\":\"device_admin\",\"test_provider_account\":\"device_admin\",\"set_favorite_models\":\"device_admin\",\"set_scoped_models\":\"device_admin\",\"cycle_model\":\"device_admin\",\"cycle_thinking_level\":\"device_admin\",\"set_fast_mode\":\"device_admin\",\"set_steering_mode\":\"device_admin\",\"set_follow_up_mode\":\"device_admin\",\"set_auto_retry\":\"device_admin\",\"set_project_trust\":\"device_admin\",\"get_project_settings\":\"device_admin\",\"set_project_setting\":\"device_admin\",\"edit_assistant_message\":\"device_admin\",\"send_custom_message\":\"device_admin\",\"switch_session\":\"device_admin\",\"import_jsonl\":\"device_admin\",\"export_html\":\"device_admin\",\"export_jsonl\":\"device_admin\",\"set_client_info\":\"connection_local\",\"subscribe_sessions\":\"connection_local\",\"unsubscribe_sessions\":\"connection_local\",\"record_user_activity\":\"connection_local\",\"detach_connection\":\"connection_local\",\"release_session\":\"connection_local\",\"warm\":\"connection_local\",\"host_response\":\"connection_local\",\"release_attachment\":\"connection_local\",\"reclaim_session\":\"connection_local\",\"move_session\":\"connection_local\",\"get_recovery_page\":\"connection_local\",\"release_recovery\":\"connection_local\",\"cancel_attempt\":\"connection_local\",\"reset_stream\":\"connection_local\"},\"dynamic_versions\":{\"get_effect_status\":1,\"prompt\":1,\"steer\":1,\"follow_up\":1,\"set_thinking_level\":1,\"set_model\":1,\"append_session_entry\":1,\"new_session\":1,\"open_session\":2}},\"memory_pressure\":false,\"path_identity_resolver\":{\"state\":\"not_started\",\"detail\":null}}}\n{\"id\":\"req_1\",\"type\":\"response\",\"command\":\"set_client_info\",\"success\":true}\n{\"type\":\"queued\",\"for_request\":\"req_2\",\"position\":1,\"in_flight\":0}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-2>\",\"method\":\"setWidget\",\"widgetKey\":\"todo-sidebar\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-3>\",\"method\":\"setStatus\",\"statusKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-4>\",\"method\":\"setWidget\",\"widgetKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-5>\",\"method\":\"setStatus\",\"statusKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-6>\",\"method\":\"setWidget\",\"widgetKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-7>\",\"method\":\"setStatus\",\"statusKey\":\"monitors\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-8>\",\"method\":\"setStatus\",\"statusKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-9>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-10>\",\"method\":\"setStatus\",\"statusKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-11>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"entry_appended\",\"entry\":{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"},\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-12>\",\"method\":\"setStatus\",\"statusKey\":\"todo-waiting\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-13>\",\"method\":\"setStatus\",\"statusKey\":\"goal\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_opened\",\"sessionId\":\"rpc-1\",\"durableSessionId\":\"<uuid-14>\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"kind\":\"interactive\",\"cwd\":\"<root>/cwd\"}\n{\"id\":\"req_2\",\"type\":\"response\",\"command\":\"open_session\",\"success\":true,\"data\":{\"sessionId\":\"rpc-1\",\"state\":{\"answeredUiRequests\":[],\"paused\":false,\"pausedNoticeCount\":0,\"holds\":[],\"lifecycle\":{\"state\":\"done\",\"seq\":0,\"epoch\":0,\"epochOrigin\":\"automatic\",\"humanInputRevision\":0,\"selfSettleEligible\":true,\"restoring\":false,\"persisted\":false,\"runPaused\":false,\"since\":\"2026-10-29T00:00:00.000Z\",\"role\":\"root\",\"rootSessionId\":\"<uuid-14>\",\"activityRevision\":{\"instanceId\":\"<uuid-15>\",\"revision\":0},\"waitingOn\":{\"children\":0,\"background\":[],\"human\":[]},\"holds\":[],\"observedAt\":\"2026-10-29T00:00:00.000Z\"},\"pendingQuestions\":[],\"pendingDialogs\":[],\"permissionPreset\":\"full-access\",\"permissionPresetSource\":\"host_default\",\"permissionPresetStatus\":\"applied\",\"effectivePermissionPreset\":\"full-access\",\"model\":{\"id\":\"faux-a\",\"name\":\"faux-a\",\"api\":\"faux:fixture\",\"provider\":\"faux\",\"baseUrl\":\"http://localhost:0\",\"reasoning\":false,\"input\":[\"text\",\"image\"],\"cost\":{\"input\":0,\"output\":0,\"cacheRead\":0,\"cacheWrite\":0},\"contextWindow\":128000,\"maxTokens\":16384},\"pendingModelSwitch\":null,\"thinkingLevel\":\"off\",\"thinkingLevelSource\":\"default\",\"sessionModelThinkingLevels\":{\"faux/faux-a\":\"off\"},\"fastMode\":false,\"isStreaming\":false,\"pausedHeldInputCount\":0,\"runPaused\":false,\"pause\":{\"pauseSeq\":0,\"records\":[]},\"isCompacting\":false,\"retryAttempt\":0,\"isBashRunning\":false,\"steeringMode\":\"all\",\"followUpMode\":\"one-at-a-time\",\"sessionFile\":\"<root>/cwd/session.jsonl\",\"sessionId\":\"<uuid-14>\",\"cwd\":\"<root>/cwd\",\"projectTrusted\":false,\"entries\":[{\"type\":\"model_change\",\"id\":\"<entry-3>\",\"parentId\":null,\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"thinking_level_change\",\"id\":\"<entry-2>\",\"parentId\":\"<entry-3>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"thinkingLevel\":\"off\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"}],\"steering\":[],\"followUp\":[],\"ordered\":[],\"autoCompactionEnabled\":true,\"messageCount\":0,\"pendingMessageCount\":0,\"usageTotals\":{\"input\":0,\"output\":0,\"cacheRead\":0,\"cacheWrite\":0,\"cost\":0},\"contextUsage\":{\"tokens\":0,\"contextWindow\":128000,\"percent\":0},\"favoriteModels\":[],\"scopedModels\":[]},\"permissionPreset\":\"full-access\",\"permissionPresetSource\":\"host_default\",\"permissionPresetStatus\":\"applied\"},\"sessionId\":\"rpc-1\"}\n{\"id\":\"req_3\",\"type\":\"response\",\"command\":\"get_entries\",\"success\":true,\"data\":{\"entries\":[{\"type\":\"model_change\",\"id\":\"<entry-3>\",\"parentId\":null,\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"thinking_level_change\",\"id\":\"<entry-2>\",\"parentId\":\"<entry-3>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"thinkingLevel\":\"off\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"}],\"leafId\":\"<entry-1>\"},\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_closed\",\"sessionId\":\"rpc-1\",\"reason\":\"client_close\"}\n{\"id\":\"req_4\",\"type\":\"response\",\"command\":\"close_session\",\"success\":true,\"data\":{},\"sessionId\":\"rpc-1\"}\n",
4
4
  "subscribeRequests": "{\"type\":\"subscribe_sessions\",\"mirror\":\"all\",\"id\":\"subscriber-1\"}\n{\"type\":\"unsubscribe_sessions\",\"subscriptionId\":\"sub-1\",\"id\":\"subscriber-2\"}\n",
5
5
  "subscribeFrames": "{\"id\":\"subscriber-1\",\"type\":\"response\",\"command\":\"subscribe_sessions\",\"success\":true,\"data\":{\"subscriptionId\":\"sub-1\",\"snapshot\":[],\"seq\":0,\"hostGeneration\":\"0\",\"hostInstanceId\":\"<uuid-1>\"}}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-2>\",\"method\":\"setWidget\",\"widgetKey\":\"todo-sidebar\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-3>\",\"method\":\"setStatus\",\"statusKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-4>\",\"method\":\"setWidget\",\"widgetKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-5>\",\"method\":\"setStatus\",\"statusKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-6>\",\"method\":\"setWidget\",\"widgetKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-7>\",\"method\":\"setStatus\",\"statusKey\":\"monitors\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-8>\",\"method\":\"setStatus\",\"statusKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-9>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-10>\",\"method\":\"setStatus\",\"statusKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-11>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"entry_appended\",\"entry\":{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"},\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-12>\",\"method\":\"setStatus\",\"statusKey\":\"todo-waiting\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-13>\",\"method\":\"setStatus\",\"statusKey\":\"goal\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_opened\",\"sessionId\":\"rpc-1\",\"durableSessionId\":\"<uuid-14>\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"kind\":\"interactive\",\"cwd\":\"<root>/cwd\"}\n{\"type\":\"session_status\",\"subscriptionId\":\"sub-1\",\"seq\":1,\"sessionId\":\"rpc-1\",\"status\":\"idle\",\"kind\":\"interactive\",\"cwd\":\"<root>/cwd\",\"attachments\":1,\"durableSessionId\":\"<uuid-14>\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"model\":{\"provider\":\"faux\",\"id\":\"faux-a\"},\"thinkingLevel\":\"off\",\"pendingQueue\":{\"steering\":0,\"followUp\":0},\"lastChange\":{\"at\":\"2026-10-29T00:00:00.000Z\",\"cause\":\"open\",\"by\":\"client\"}}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-15>\",\"method\":\"setStatus\",\"statusKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-16>\",\"method\":\"setWidget\",\"widgetKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-17>\",\"method\":\"setStatus\",\"statusKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-18>\",\"method\":\"setWidget\",\"widgetKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-19>\",\"method\":\"setStatus\",\"statusKey\":\"monitors\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-20>\",\"method\":\"setStatus\",\"statusKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-21>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-22>\",\"method\":\"setStatus\",\"statusKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-23>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-24>\",\"method\":\"setStatus\",\"statusKey\":\"loop\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_closed\",\"sessionId\":\"rpc-1\",\"reason\":\"client_close\"}\n{\"type\":\"session_status\",\"subscriptionId\":\"sub-1\",\"seq\":2,\"sessionId\":\"rpc-1\",\"status\":\"closed\",\"reason\":\"client_close\",\"kind\":\"interactive\",\"cwd\":\"<root>/cwd\",\"attachments\":1,\"durableSessionId\":\"<uuid-14>\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"model\":{\"provider\":\"faux\",\"id\":\"faux-a\"},\"thinkingLevel\":\"off\",\"pendingQueue\":{\"steering\":0,\"followUp\":0},\"lastChange\":{\"at\":\"2026-10-29T00:00:00.000Z\",\"cause\":\"close\",\"by\":\"client\"}}\n{\"id\":\"subscriber-2\",\"type\":\"response\",\"command\":\"unsubscribe_sessions\",\"success\":true}\n"
6
6
  }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "methodClassesVersion": 1,
3
- "methodClassesDigest": "67e7dac5622360f9e5fc471764f5a69c43c3abcc22bed55859761cbb53ede37c",
3
+ "methodClassesDigest": "7ea18de0fb5d28f89aabdc17cbaca72e973cdea7d5928fd82d91ccced025000e",
4
4
  "sampleId": "00000000-0000-7000-8000-000000000000",
5
5
  "samplePathRoot": "/nonexistent/senpi-rpc-inbound-sample",
6
- "methodCount": 123,
6
+ "methodCount": 124,
7
7
  "methods": [
8
8
  {
9
9
  "method": "abort",
@@ -94,6 +94,23 @@
94
94
  "name": "rpc-sample-account"
95
95
  }
96
96
  },
97
+ {
98
+ "method": "admit_external_message",
99
+ "class": "drive",
100
+ "sampleClass": "drive",
101
+ "connectionLocal": false,
102
+ "sample": {
103
+ "type": "admit_external_message",
104
+ "deliveryId": "00000000-0000-7000-8000-000000000000",
105
+ "text": "Sample delivery.",
106
+ "sender": {
107
+ "kind": "agent",
108
+ "session_id": "00000000-0000-7000-8000-000000000000"
109
+ },
110
+ "deliverAs": "followUp",
111
+ "whenIdle": "queue"
112
+ }
113
+ },
97
114
  {
98
115
  "method": "append_session_entry",
99
116
  "class": "dynamic",
package/docs/rpc.md CHANGED
@@ -5953,6 +5953,32 @@ Response:
5953
5953
 
5954
5954
  `kind` is the admission outcome (`started`, `queued`, `steered`, `already_admitted`, `held_draft`, `turn_conflict`); `admitted` is `[]` when no drain is registered.
5955
5955
 
5956
+ #### admit_external_message
5957
+
5958
+ Admits a message another agent sent this session (a relayed peer delivery) exactly as `pi.session.admitExternalMessage` does in process (multi-session hosts: session-scoped). The engine writes its own `session_control_delivery` custom entry, with `details.sender` and `details.display_text` for human surfaces: never a `role: "user"` message, never the extension `input` event, and a `/`-led `text` is not dispatched as a command or expanded as a template. Method class `drive`.
5959
+
5960
+ ```json
5961
+ {"type": "admit_external_message", "sessionId": "rpc-1", "deliveryId": "d7", "text": "[from peer] build is green", "sender": {"kind": "agent", "session_id": "s-42", "name": "reviewer"}, "displayText": "build is green", "deliverAs": "followUp"}
5962
+ ```
5963
+
5964
+ Response:
5965
+ ```json
5966
+ {
5967
+ "type": "response",
5968
+ "command": "admit_external_message",
5969
+ "success": true,
5970
+ "data": { "kind": "started", "turnId": "0" }
5971
+ }
5972
+ ```
5973
+
5974
+ - `deliveryId` (1-256 chars), `text` (non-empty) and `deliverAs` (`steer` | `followUp`) are required. `sender` is `{ kind: "agent", session_id, name? }`, `{ kind: "command_line", user? }` or `{ kind: "external", platform, author? }` with no other field.
5975
+ - `whenIdle`: `start` (default) starts a turn on an idle session; `queue` holds it for the next turn.
5976
+ - `expectedTurnId` is `get_state.currentTurnId` (a string). A steer whose `expectedTurnId` is not the current turn, or a mid-turn steer that names none, answers `kind: "turn_conflict"` and admits nothing. The reply's `turnId` is the session's turn at admission, in the same form.
5977
+ - `chainCount` is a thread call's hop count, checked against `threads.chainCountLimit` before anything is admitted (refused with `chain_count_limit` / `invalid_chain_count`, as on `prompt`/`steer`/`follow_up`); the admitted hop is written as `details.chain_count`.
5978
+ - `kind` is the same outcome `wake` reports (`held_draft`: retry; nothing was queued). The ledger keys a local connection's `deliveryId` as `rpc:local/<deliveryId>` and a remote device's as `device:<deviceId>/<deliveryId>`, so RPC ids never collide with in-process deliveries or with another device's. An id the runtime already holds, or that the transcript already holds an entry for (after a restart too), answers `already_admitted`.
5979
+ - On a connection that speaks for a remote device (a delegated connection, or one whose `set_client_info` declared `remoteOrigin`), the engine stamps that device as `details.remote_origin` and writes `text` unchanged, so the model reads exactly what a delivery on a local connection carries and no device (senpi#6250). It keeps `text` as `details.display_text` when no `displayText` is given, and refuses a `command_line` sender (`sender_not_allowed`). A delegated connection that names no remote device is refused (`delegated_origin_unknown`), never admitted as a local delivery. A record that names `remote_origin` is refused on every connection. The turn that consumes the delivery takes the connection's origin, so a remote device's follow-up runs under the delegated approval-mode rule even inside a local turn.
5980
+ - Once `release_session` has closed the session's admission, the record answers `success: false` with the release's message: the delivery stays with its sender.
5981
+
5956
5982
  #### release_session
5957
5983
 
5958
5984
  Multi-session hosts only. Hands the session to a runtime outside the host; see "Handing a session over (`release_session`)".
@@ -6447,6 +6473,37 @@ capability:
6447
6473
  }
6448
6474
  ```
6449
6475
 
6476
+ #### Background session age
6477
+
6478
+ The terminal builtin emits `terminal_background_age` on the same path, and on the in-process `pi.events`
6479
+ bus, when a background bash session is still running at 10 minutes and then every 30 minutes (10, 40,
6480
+ 70, ...), and when the opt-in auto-reap (`terminal.backgroundAutoReapMinutes` or the `bash` parameter
6481
+ `auto_reap_minutes`) has stopped one, or once when its stop did not end the session. `data` has `kind`
6482
+ (`running`, `reaped`, or `reap_failed`), `id` (the `bash_id`), `description`, optional `command`,
6483
+ `startedAtMs`, `ageMs`, `ageMinutes`, `autoReapMinutes` (the age at which the session is stopped
6484
+ automatically, or `null` when nothing will stop it), `reason` (on `reap_failed` only: why the stop did not
6485
+ end it), and `stop`, the call that stops it. After `reap_failed` the session is still running, the
6486
+ `running` reports go on, and the auto-reap does not try again. Nothing is stopped by this event; a client that wants the session gone calls `kill_bash`
6487
+ with `stop.args`. A report that came due while the host slept arrives once, not once per missed interval.
6488
+
6489
+ ```json
6490
+ {
6491
+ "type": "extension_event",
6492
+ "name": "terminal_background_age",
6493
+ "data": {
6494
+ "kind": "running",
6495
+ "id": "bash_3",
6496
+ "description": "npm run dev",
6497
+ "command": "npm run dev",
6498
+ "startedAtMs": 1710000000000,
6499
+ "ageMs": 600000,
6500
+ "ageMinutes": 10,
6501
+ "autoReapMinutes": null,
6502
+ "stop": { "tool": "kill_bash", "args": { "bash_id": "bash_3" } }
6503
+ }
6504
+ }
6505
+ ```
6506
+
6450
6507
  #### Job widgets
6451
6508
 
6452
6509
  The `job-widgets` builtin emits `job_widget_state` on the same path: live, display-ready widgets for the