@code-yeongyu/senpi 2026.11.6-2 → 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.
- package/CHANGELOG.md +52 -0
- package/dist/bundle/chunks/{bun-extension-importer-RCGPQTI2.js → bun-extension-importer-GQ6IKEXD.js} +2 -2
- package/dist/bundle/chunks/{chunk-GSKCWXXG.js → chunk-3CRPNPTR.js} +1 -1
- package/dist/bundle/chunks/{chunk-RQ6CHXQ2.js → chunk-3TZQXZKH.js} +1 -1
- package/dist/bundle/chunks/{chunk-QN2BHP3M.js → chunk-44BJPS5I.js} +1 -1
- package/dist/bundle/chunks/{chunk-WGRKM3N6.js → chunk-45MVD7BU.js} +1 -1
- package/dist/bundle/chunks/chunk-4JIBEZZE.js +106 -0
- package/dist/bundle/chunks/{chunk-CF5OGBC4.js → chunk-4NYNMAYF.js} +1 -1
- package/dist/bundle/chunks/{chunk-X5ZVYNOL.js → chunk-4UR6UFBH.js} +1 -1
- package/dist/bundle/chunks/{chunk-LNPAT22L.js → chunk-527Q2UYM.js} +9 -8
- package/dist/bundle/chunks/{chunk-HLM46XEB.js → chunk-622VYTRI.js} +1 -1
- package/dist/bundle/chunks/{chunk-GKAYPJ4E.js → chunk-7PROV6BB.js} +1 -1
- package/dist/bundle/chunks/{chunk-4E7GDG4H.js → chunk-7VMEE62L.js} +1 -1
- package/dist/bundle/chunks/{chunk-ECW7VBMB.js → chunk-HXNXISJD.js} +1 -1
- package/dist/bundle/chunks/{chunk-C7OKUC7L.js → chunk-K3UHGDUQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-47PPZKPO.js → chunk-LM6DOWQH.js} +4 -4
- package/dist/bundle/chunks/chunk-LPYBKMPT.js +2 -0
- package/dist/bundle/chunks/{chunk-2FDW2LQL.js → chunk-M7GF73FO.js} +2 -2
- package/dist/bundle/chunks/{chunk-D5MRJWUK.js → chunk-OCMGRBJ5.js} +221 -229
- package/dist/bundle/chunks/{chunk-TIPKAMSS.js → chunk-SGAFIMAU.js} +1 -1
- package/dist/bundle/chunks/{chunk-7PSBD5KS.js → chunk-STGOYIXC.js} +1 -1
- package/dist/bundle/chunks/{chunk-DSWDJ7HT.js → chunk-WQ4RBPMS.js} +1 -1
- package/dist/bundle/chunks/{chunk-7III44PV.js → chunk-WX2HB4DD.js} +1 -1
- package/dist/bundle/chunks/chunk-XZDCMDUH.js +2 -0
- package/dist/bundle/chunks/{chunk-GNSMNSL7.js → chunk-Y5L4UFMI.js} +2 -2
- package/dist/bundle/chunks/{cli-main-T74YJGIF.js → cli-main-E4NDWAUD.js} +1 -1
- package/dist/bundle/chunks/{dispatch-BAK2YZKD.js → dispatch-VDIYSXQN.js} +1 -1
- package/dist/bundle/chunks/{hand-entry-AYRUGE2A.js → hand-entry-5X5Z5Y3D.js} +1 -1
- package/dist/bundle/chunks/{headless-host-ES74ZB6M.js → headless-host-YXUGONR3.js} +1 -1
- package/dist/bundle/chunks/{host-command-YRXZE4TV.js → host-command-VHX2ILLM.js} +1 -1
- package/dist/bundle/chunks/{host-session-command-N7IN7ZDV.js → host-session-command-P3MRW63Z.js} +1 -1
- package/dist/bundle/chunks/interactive-mode-XUSBLLWI.js +2 -0
- package/dist/bundle/chunks/main-3TWVKTJN.js +2 -0
- package/dist/bundle/chunks/{multi-session-host-XSUJDHFZ.js → multi-session-host-HRGM66PY.js} +20 -17
- package/dist/bundle/chunks/{package-manager-cli-GLUNPQJU.js → package-manager-cli-WSH7U4YE.js} +1 -1
- package/dist/bundle/chunks/{role-RRFFHZF5.js → role-4BUU46VW.js} +3 -3
- package/dist/bundle/chunks/{rotation-stream-BN2YK2MC.js → rotation-stream-TODBIHXJ.js} +1 -1
- package/dist/bundle/chunks/rpc-mode-OAPIV46G.js +2 -0
- package/dist/bundle/chunks/{run-attached-tui-W236SEOR.js → run-attached-tui-MXCC5IZR.js} +1 -1
- package/dist/bundle/chunks/{runtime-session-OBXYK4PI.js → runtime-session-VO3X4OE3.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-B2EJTBOE.js → schedule-command-MX56D6UE.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-YIMLHGLG.js → session-control-endpoint-IL6ERD4U.js} +1 -1
- package/dist/bundle/chunks/{session-picker-E6ZONUJB.js → session-picker-6VRC25MJ.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +114 -110
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/core/agent-session-runtime.d.ts +2 -0
- package/dist/core/agent-session-runtime.js +9 -2
- package/dist/core/agent-session-services.d.ts +2 -0
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session.d.ts +32 -3
- package/dist/core/agent-session.js +142 -29
- package/dist/core/credential-pool/rotation-slots.d.ts +3 -3
- package/dist/core/credential-pool/state-store.d.ts +1 -1
- package/dist/core/egress/classify.d.ts +8 -3
- package/dist/core/egress/classify.js +177 -158
- package/dist/core/egress/console-redactor.d.ts +7 -0
- package/dist/core/egress/console-redactor.js +74 -0
- package/dist/core/egress/credentials.d.ts +73 -0
- package/dist/core/egress/credentials.js +20 -0
- package/dist/core/egress/device-custody.d.ts +1 -1
- package/dist/core/egress/device-custody.js +18 -15
- package/dist/core/egress/device-proxy-call.d.ts +59 -0
- package/dist/core/egress/device-proxy-call.js +148 -0
- package/dist/core/egress/device-proxy-lost-calls.d.ts +27 -0
- package/dist/core/egress/device-proxy-lost-calls.js +28 -0
- package/dist/core/egress/device-proxy-ports.d.ts +49 -0
- package/dist/core/egress/device-proxy-ports.js +2 -0
- package/dist/core/egress/device-proxy-request.d.ts +34 -0
- package/dist/core/egress/device-proxy-request.js +69 -0
- package/dist/core/egress/device-proxy-waits.d.ts +40 -0
- package/dist/core/egress/device-proxy-waits.js +67 -0
- package/dist/core/egress/device-proxy.d.ts +3 -0
- package/dist/core/egress/device-proxy.js +214 -0
- package/dist/core/egress/endpoint.js +2 -1
- package/dist/core/egress/entry-verify.d.ts +13 -0
- package/dist/core/egress/entry-verify.js +33 -0
- package/dist/core/egress/hpke.d.ts +63 -0
- package/dist/core/egress/hpke.js +192 -0
- package/dist/core/egress/key-policy-template.d.ts +7 -1
- package/dist/core/egress/ledger-schema.d.ts +80 -0
- package/dist/core/egress/ledger-schema.js +117 -0
- package/dist/core/egress/ledger.d.ts +55 -0
- package/dist/core/egress/ledger.js +159 -0
- package/dist/core/egress/pinned-infra.d.ts +23 -2
- package/dist/core/egress/pinned-infra.js +9 -2
- package/dist/core/egress/placement-claim.d.ts +69 -0
- package/dist/core/egress/placement-claim.js +115 -0
- package/dist/core/egress/pool-state.d.ts +18 -0
- package/dist/core/egress/pool-state.js +5 -0
- package/dist/core/egress/redact.d.ts +10 -0
- package/dist/core/egress/redact.js +134 -0
- package/dist/core/egress/sealed-format.d.ts +101 -0
- package/dist/core/egress/sealed-format.js +174 -0
- package/dist/core/egress/sealed-source.d.ts +35 -0
- package/dist/core/egress/sealed-source.js +140 -0
- package/dist/core/egress/verified-keys.js +1 -1
- package/dist/core/egress/wire.d.ts +228 -0
- package/dist/core/egress/wire.js +49 -0
- package/dist/core/extensions/builtin/ask-user/escape-residue.d.ts +50 -0
- package/dist/core/extensions/builtin/ask-user/escape-residue.js +113 -0
- package/dist/core/extensions/builtin/ask-user/extension.js +7 -1
- package/dist/core/extensions/builtin/ask-user/resume.js +2 -1
- package/dist/core/extensions/builtin/ask-user/tool.d.ts +3 -0
- package/dist/core/extensions/builtin/ask-user/tool.js +8 -0
- package/dist/core/extensions/builtin/goal/index.js +46 -0
- package/dist/core/extensions/builtin/goal/stop-pause.d.ts +1 -0
- package/dist/core/extensions/builtin/goal/stop-pause.js +4 -2
- package/dist/core/extensions/builtin/monitor-state-event.d.ts +26 -0
- package/dist/core/extensions/builtin/monitor-state-event.js +2 -0
- package/dist/core/extensions/builtin/permission-system/index.js +10 -4
- package/dist/core/extensions/builtin/permission-system/preset-registry.d.ts +2 -0
- package/dist/core/extensions/builtin/permission-system/preset-registry.js +11 -0
- package/dist/core/extensions/builtin/permission-system/settings.d.ts +2 -0
- package/dist/core/extensions/builtin/permission-system/settings.js +10 -1
- package/dist/core/extensions/builtin/terminal/background-age.d.ts +25 -0
- package/dist/core/extensions/builtin/terminal/background-age.js +91 -0
- package/dist/core/extensions/builtin/terminal/extension-state.d.ts +1 -1
- package/dist/core/extensions/builtin/terminal/extension-state.js +21 -3
- package/dist/core/extensions/builtin/terminal/notify.d.ts +6 -0
- package/dist/core/extensions/builtin/terminal/notify.js +39 -5
- package/dist/core/extensions/builtin/terminal/session-bundle.d.ts +9 -2
- package/dist/core/extensions/builtin/terminal/session-bundle.js +36 -1
- package/dist/core/extensions/builtin/terminal/settings.d.ts +2 -0
- package/dist/core/extensions/builtin/terminal/settings.js +8 -0
- package/dist/core/extensions/builtin/terminal/tools/background-auto-reap.d.ts +15 -0
- package/dist/core/extensions/builtin/terminal/tools/background-auto-reap.js +87 -0
- package/dist/core/extensions/builtin/terminal/tools/bash.d.ts +3 -1
- package/dist/core/extensions/builtin/terminal/tools/bash.js +44 -15
- package/dist/core/extensions/builtin/terminal/tools/child-placement.d.ts +8 -0
- package/dist/core/extensions/builtin/terminal/tools/child-placement.js +43 -6
- package/dist/core/extensions/builtin/terminal/tools/context.d.ts +14 -2
- package/dist/core/extensions/bun-extension-importer.js +4 -3
- package/dist/core/extensions/bun-extension-load-turns.d.ts +4 -0
- package/dist/core/extensions/bun-extension-load-turns.js +45 -0
- package/dist/core/extensions/bun-extension-registry.d.ts +1 -0
- package/dist/core/extensions/bun-extension-registry.js +19 -1
- package/dist/core/extensions/loader.js +5 -0
- package/dist/core/extensions/session-control-types.d.ts +15 -0
- package/dist/core/extensions/session-control-types.js +11 -0
- package/dist/core/extensions/session-dialog-api.d.ts +5 -0
- package/dist/core/extensions/session-dialog-api.js +13 -0
- package/dist/core/extensions/types.d.ts +14 -1
- package/dist/core/external-admission.d.ts +16 -2
- package/dist/core/external-admission.js +22 -4
- package/dist/core/permission-decision.d.ts +22 -0
- package/dist/core/permission-decision.js +53 -0
- package/dist/core/permission-mode.d.ts +56 -0
- package/dist/core/permission-mode.js +133 -0
- package/dist/core/retry-fallback/controller-types.d.ts +6 -0
- package/dist/core/retry-fallback/controller.d.ts +9 -0
- package/dist/core/retry-fallback/controller.js +34 -3
- package/dist/core/retry-fallback/unusable.d.ts +25 -1
- package/dist/core/retry-fallback/unusable.js +87 -2
- package/dist/core/retry-fallback/usage-limit.d.ts +6 -1
- package/dist/core/retry-fallback/usage-limit.js +12 -4
- package/dist/core/sdk.d.ts +6 -1
- package/dist/core/sdk.js +3 -0
- package/dist/core/session-log.js +1 -1
- package/dist/core/stall-warning.d.ts +41 -0
- package/dist/core/stall-warning.js +72 -0
- package/dist/core/terminal-settings.d.ts +1 -0
- package/dist/core/turn-origin.d.ts +31 -0
- package/dist/core/turn-origin.js +64 -0
- package/dist/modes/interactive/components/remote-delivery-message.d.ts +2 -1
- package/dist/modes/interactive/components/remote-delivery-message.js +13 -5
- package/dist/modes/rpc/admit-external-message-command.d.ts +37 -0
- package/dist/modes/rpc/admit-external-message-command.js +61 -0
- package/dist/modes/rpc/admit-external-message-wire.d.ts +42 -0
- package/dist/modes/rpc/admit-external-message-wire.js +55 -0
- package/dist/modes/rpc/client-input-handler.d.ts +2 -0
- package/dist/modes/rpc/client-input-handler.js +2 -0
- package/dist/modes/rpc/connection-handler.js +30 -5
- package/dist/modes/rpc/connection-roles.d.ts +6 -0
- package/dist/modes/rpc/connection-roles.js +13 -0
- package/dist/modes/rpc/delegated-drive-origin.d.ts +9 -0
- package/dist/modes/rpc/delegated-drive-origin.js +16 -0
- package/dist/modes/rpc/effect-commands.d.ts +7 -1
- package/dist/modes/rpc/host-bare-endpoint-registration.d.ts +7 -0
- package/dist/modes/rpc/host-bare-endpoint-registration.js +35 -0
- package/dist/modes/rpc/host-capabilities.d.ts +2 -0
- package/dist/modes/rpc/host-capabilities.js +3 -0
- package/dist/modes/rpc/host-handover-parked.d.ts +11 -0
- package/dist/modes/rpc/host-handover-parked.js +17 -0
- package/dist/modes/rpc/host-handover-reopen.js +18 -6
- package/dist/modes/rpc/host-handover-resident-writer.d.ts +16 -0
- package/dist/modes/rpc/host-handover-resident-writer.js +57 -0
- package/dist/modes/rpc/host-idle-handover.js +1 -0
- package/dist/modes/rpc/host-warm.d.ts +16 -1
- package/dist/modes/rpc/host-warm.js +33 -6
- package/dist/modes/rpc/method-classes-schema-delivery.d.ts +32 -0
- package/dist/modes/rpc/method-classes-schema-delivery.js +22 -0
- package/dist/modes/rpc/method-classes-schema-session.d.ts +36 -0
- package/dist/modes/rpc/method-classes-schema-session.js +3 -0
- package/dist/modes/rpc/method-classes-schema.d.ts +36 -0
- package/dist/modes/rpc/method-classes.d.ts +2 -0
- package/dist/modes/rpc/method-classes.js +4 -0
- package/dist/modes/rpc/multi-session-host.js +6 -1
- package/dist/modes/rpc/permission-preset-command.d.ts +6 -0
- package/dist/modes/rpc/permission-preset-command.js +27 -0
- package/dist/modes/rpc/rpc-input-validation.js +4 -3
- package/dist/modes/rpc/rpc-mutation-response-types.d.ts +7 -0
- package/dist/modes/rpc/rpc-response-types.d.ts +2 -1
- package/dist/modes/rpc/rpc-session-command-types.d.ts +6 -1
- package/dist/modes/rpc/rpc-session-event-types.d.ts +5 -2
- package/dist/modes/rpc/rpc-session-state-types.d.ts +2 -1
- package/dist/modes/rpc/rpc-session-state.js +2 -0
- package/dist/modes/rpc/session-attachment-commands.js +3 -3
- package/dist/modes/rpc/session-event-writer-connections.js +1 -0
- package/dist/modes/rpc/session-event-writer.d.ts +1 -1
- package/dist/modes/rpc/session-registry-attach.d.ts +0 -9
- package/dist/modes/rpc/session-registry-attach.js +16 -3
- package/dist/modes/rpc/session-registry-types.d.ts +2 -0
- package/dist/modes/rpc/session-registry.d.ts +2 -0
- package/dist/modes/rpc/session-registry.js +16 -3
- package/dist/modes/rpc/session-router-close.js +43 -6
- package/dist/modes/rpc/session-router-context.js +2 -0
- package/dist/modes/rpc/session-router-occupancy.js +2 -11
- package/dist/modes/rpc/session-router-open-profile.js +4 -0
- package/dist/modes/rpc/session-router-open.d.ts +1 -1
- package/dist/modes/rpc/session-router-open.js +6 -17
- package/dist/modes/rpc/session-router-residency.d.ts +24 -0
- package/dist/modes/rpc/session-router-residency.js +90 -0
- package/dist/modes/rpc/session-router-routing.js +7 -1
- package/dist/modes/rpc/session-status.js +4 -1
- package/dist/modes/rpc/session-worker.js +4 -0
- package/dist/modes/rpc/tool-child/terminal-jobs.d.ts +1 -0
- package/dist/modes/rpc/tool-child/terminal-jobs.js +17 -1
- package/dist/modes/rpc/worker-session-registry.js +5 -2
- package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
- package/docs/engine-socket/fixtures/rpc-inbound-samples.json +29 -2
- package/docs/extensions.md +12 -0
- package/docs/rpc.md +129 -12
- package/docs/terminal-tools.md +25 -1
- package/native/socket-secret/prebuilds/win32-arm64/senpi_socket_secret.win32-arm64.node +0 -0
- package/native/socket-secret/prebuilds/win32-x64/senpi_socket_secret.win32-x64.node +0 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-C7HEEBFH.js +0 -2
- package/dist/bundle/chunks/chunk-XCMII2VQ.js +0 -98
- package/dist/bundle/chunks/interactive-mode-B5SQDLH7.js +0 -2
- package/dist/bundle/chunks/main-UQFVFCNY.js +0 -2
- package/dist/bundle/chunks/rpc-mode-JYN3E7P7.js +0 -2
|
@@ -10,6 +10,7 @@ import { SessionAttachOrder } from "./session-attach-order.js";
|
|
|
10
10
|
import { tearDownReleased } from "./session-router-close.js";
|
|
11
11
|
import { routingIdOf } from "./session-router-errors.js";
|
|
12
12
|
import { sweepIdleSessions } from "./session-router-occupancy.js";
|
|
13
|
+
import { followRetainedRecord } from "./session-router-residency.js";
|
|
13
14
|
import { registryStatusSource } from "./session-status-source.js";
|
|
14
15
|
export class RouterContext {
|
|
15
16
|
constructor(registry, writer, defaults, createBinding = createRpcSessionBinding, connectionOptions = {}, idle) {
|
|
@@ -74,6 +75,7 @@ export class RouterContext {
|
|
|
74
75
|
: { effectId: latest.effectId, kind: latest.kind, state: latest.state };
|
|
75
76
|
});
|
|
76
77
|
writer.afterRecord = (sessionId) => {
|
|
78
|
+
followRetainedRecord(this, sessionId);
|
|
77
79
|
const session = this.registry.peek(sessionId)?.runtime?.session;
|
|
78
80
|
if (session === undefined)
|
|
79
81
|
return;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { recordHandoverParkedSession } from "./host-handover-parked.js";
|
|
2
|
-
import { parkedEntryFromProfile } from "./host-handover-parked-open.js";
|
|
3
|
-
import { hostInstanceId } from "./protocol-identity.js";
|
|
4
1
|
import { readDrainVerdicts } from "./session-drain.js";
|
|
5
2
|
import { holdUnattendedTurns } from "./session-drain-hold.js";
|
|
6
3
|
import { forgetSessionOwnership } from "./session-router-attachments.js";
|
|
7
4
|
import { finalizeClose, tryClaimClose } from "./session-router-close.js";
|
|
5
|
+
import { recordRetainedSession } from "./session-router-residency.js";
|
|
8
6
|
import { selectSweepEvictions } from "./session-sweep.js";
|
|
9
7
|
const DRAIN_SWEEP_MS = 50;
|
|
10
8
|
/**
|
|
@@ -128,14 +126,7 @@ export async function evictIdleSession(host, sessionId, reason) {
|
|
|
128
126
|
parkedPath !== undefined &&
|
|
129
127
|
retained?.retainOnDisconnect === true &&
|
|
130
128
|
retained.sessionPath !== undefined) {
|
|
131
|
-
await
|
|
132
|
-
...parkedEntryFromProfile({
|
|
133
|
-
sessionPath: retained.sessionPath,
|
|
134
|
-
contextOverlay: retained.contextOverlay,
|
|
135
|
-
...(retained.durableSessionId !== undefined ? { durableSessionId: retained.durableSessionId } : {}),
|
|
136
|
-
}, retained.profile, Object.keys(host.defaults.hostContext ?? {})),
|
|
137
|
-
parkedBy: host.defaults.hostContext?.host_instance ?? hostInstanceId(),
|
|
138
|
-
}).catch((cause) => {
|
|
129
|
+
await recordRetainedSession(host, retained, retained.sessionPath, false).catch((cause) => {
|
|
139
130
|
process.stderr.write(`senpi rpc handover park record ${sessionId} failed: ${String(cause)}\n`);
|
|
140
131
|
});
|
|
141
132
|
}
|
|
@@ -70,6 +70,10 @@ export function validatedOpenProfile(host, command, options) {
|
|
|
70
70
|
: { host_socket: host.defaults.hostContext.host_socket }),
|
|
71
71
|
},
|
|
72
72
|
permissionPreset: command.permissionPreset ?? defaults?.permissionPreset,
|
|
73
|
+
// An embedder's host-level preset is the host default, never a client's choice (remote approval-mode rule).
|
|
74
|
+
...(command.permissionPreset === undefined && defaults?.permissionPreset !== undefined
|
|
75
|
+
? { permissionPresetSource: "host_default" }
|
|
76
|
+
: {}),
|
|
73
77
|
creationModel: command.provider && command.modelId
|
|
74
78
|
? { provider: command.provider, modelId: command.modelId }
|
|
75
79
|
: defaults?.creationModel,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type OpenAcceptance } from "./compact-open-admission.ts";
|
|
2
|
-
import {
|
|
2
|
+
import type { HandoverParkedEntry } from "./host-handover-parked.ts";
|
|
3
3
|
import type { RpcCommand, RpcResponse } from "./rpc-types.ts";
|
|
4
4
|
import type { RouterContext } from "./session-router-context.ts";
|
|
5
5
|
export declare function openWithBarrier(host: RouterContext, command: Extract<RpcCommand, {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { buildRpcSessionState } from "./connection-handler.js";
|
|
2
2
|
import { compactUpdatesEnabled } from "../../core/engine-socket-flag.js";
|
|
3
3
|
import { startOpenTimer } from "../../core/open-timing.js";
|
|
4
|
+
import { openReplyPermissionMode } from "../../core/permission-mode.js";
|
|
4
5
|
import { compactOpen } from "./compact-open-admission.js";
|
|
5
6
|
import { CompactAdmissionError } from "./compact-admission-error.js";
|
|
6
7
|
import { runAdmissionProducer } from "./compact-admission-producer.js";
|
|
7
|
-
import { clearHandoverParkedSession } from "./host-handover-parked.js";
|
|
8
8
|
import { parkedOpenCommand } from "./host-handover-parked-open.js";
|
|
9
9
|
import { sessionHeldCheck } from "./session-held.js";
|
|
10
10
|
import { forgetSessionOwnership, releaseOwnedSession, releaseOwnerAttachment } from "./session-router-attachments.js";
|
|
@@ -13,6 +13,7 @@ import { code, detail, error } from "./session-router-errors.js";
|
|
|
13
13
|
import { sweepDrain } from "./session-router-occupancy.js";
|
|
14
14
|
import { invalidSpawnedBy, validatedOpenProfile } from "./session-router-open-profile.js";
|
|
15
15
|
import { relocationConnection } from "./session-router-relocation.js";
|
|
16
|
+
import { syncRetainedRecord } from "./session-router-residency.js";
|
|
16
17
|
import { liveToolMediaScope, toolMediaPersister } from "./tool-media-store.js";
|
|
17
18
|
export function openWithBarrier(host, command) {
|
|
18
19
|
if (compactUpdatesEnabled() && command.admissionId !== undefined)
|
|
@@ -48,22 +49,6 @@ function openPhysicalWithBarrier(host, command, accept, signal) {
|
|
|
48
49
|
// A late open's physical session is released by its admission (the accept/rollback path, 4272-admission-
|
|
49
50
|
// abandonment), so the late response itself owns nothing to release here.
|
|
50
51
|
const opened = signal === undefined ? start() : runAdmissionProducer(signal, start, async () => { });
|
|
51
|
-
// A manual reopen-by-path supersedes the handover auto-reopen for that session: clear its
|
|
52
|
-
// record entry, or a later generation would reopen a second copy (MEDIUM-1, senpi#3282 review).
|
|
53
|
-
// Cleared only after the open SUCCEEDS (MEDIUM-A): if the open fails - a session_path_in_use
|
|
54
|
-
// during a handover, or a bad profile - the entry must stay so a later generation can still
|
|
55
|
-
// reopen the session. open() resolves `undefined` on success (the response is written through
|
|
56
|
-
// the writer) and an RpcResponse only on failure, so success is `response === undefined`.
|
|
57
|
-
if (command.sessionPath !== undefined && host.handoverParkedDir !== undefined) {
|
|
58
|
-
const dir = host.handoverParkedDir;
|
|
59
|
-
const sessionPath = command.sessionPath;
|
|
60
|
-
void opened.then((response) => {
|
|
61
|
-
if (response === undefined)
|
|
62
|
-
void clearHandoverParkedSession(dir, sessionPath).catch(() => { });
|
|
63
|
-
}, () => {
|
|
64
|
-
// A rejection means the open failed before producing a response; the entry stays.
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
52
|
return opened.finally(() => {
|
|
68
53
|
resolveBarrier();
|
|
69
54
|
opens.delete(barrier);
|
|
@@ -214,6 +199,9 @@ export async function open(host, command, owner, options) {
|
|
|
214
199
|
releaseOwnerAttachment(host, owner, openedSession.sessionId);
|
|
215
200
|
await releaseOwnedSession(host, openedSession.sessionId);
|
|
216
201
|
}
|
|
202
|
+
// After the open SUCCEEDS (MEDIUM-A): a failed open keeps any record entry, so a later start
|
|
203
|
+
// still reopens that session.
|
|
204
|
+
await syncRetainedRecord(host, openedSession.sessionId, command.sessionPath);
|
|
217
205
|
if (options?.accept) {
|
|
218
206
|
return undefined;
|
|
219
207
|
}
|
|
@@ -230,6 +218,7 @@ export async function open(host, command, owner, options) {
|
|
|
230
218
|
data: {
|
|
231
219
|
sessionId: opened.sessionId,
|
|
232
220
|
state: replyState,
|
|
221
|
+
...openReplyPermissionMode(replyState),
|
|
233
222
|
...(opened.attached ? { attached: true } : {}),
|
|
234
223
|
...(host.defaults.sessionPresence
|
|
235
224
|
? { presence: host.defaults.sessionPresence.view(replyState.sessionId) }
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RouterContext } from "./session-router-context.ts";
|
|
2
|
+
import type { RpcSessionEntry } from "./session-registry-types.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Writes the record entry of a retained session under `sessionPath`, stamped with this host instance, and drops
|
|
5
|
+
* the entry it was recorded under before when the session has since moved to another transcript (senpi#6190).
|
|
6
|
+
* `resident` stamps the writing process: the session is open here. A park writes it unstamped.
|
|
7
|
+
*/
|
|
8
|
+
export declare function recordRetainedSession(host: RouterContext, retained: RpcSessionEntry, sessionPath: string, resident: boolean): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Brings the record in line with a session this host just opened or attached: a retained session is
|
|
11
|
+
* recorded as resident here, so a restart reopens it; a non-retained open by path supersedes any
|
|
12
|
+
* earlier park of that path, whose entry is cleared so no later start reopens a second copy
|
|
13
|
+
* (MEDIUM-1, senpi#3282 review). Runs only after the open succeeded, so a failed open keeps the entry.
|
|
14
|
+
*/
|
|
15
|
+
export declare function syncRetainedRecord(host: RouterContext, sessionId: string, requestedPath: string | undefined): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Called after every record a session publishes: a retained session whose transcript was switched (`new_session`,
|
|
18
|
+
* `switch_session`, a fork) moves its record entry to the new file at once, so a crash restores the transcript the
|
|
19
|
+
* session is on, never the one it left. A string compare until the path actually moves.
|
|
20
|
+
*/
|
|
21
|
+
export declare function followRetainedRecord(host: RouterContext, sessionId: string): void;
|
|
22
|
+
/** An explicit close or reclaim ends the session for good: drop every key its record was written under. */
|
|
23
|
+
export declare function clearRetainedRecord(host: RouterContext, entry: RpcSessionEntry | undefined): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=session-router-residency.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The retained-session record a host keeps for the NEXT start of its endpoint: one per-session
|
|
3
|
+
* entry in the handover-parked record (`host-handover-parked.ts`), written when a session becomes
|
|
4
|
+
* retained-and-resident here, moved when the session switches to another transcript, and rewritten
|
|
5
|
+
* when it parks. A restart on the same socket and agent dir - after a handoff, a crash, or a kill
|
|
6
|
+
* mid-turn - reopens every entry a previous process wrote by its session file, the way a TUI resumes
|
|
7
|
+
* from its session file, so `list_sessions` (and the relay that mirrors it) lists the session again
|
|
8
|
+
* without anyone re-opening it by hand.
|
|
9
|
+
*/
|
|
10
|
+
import { clearHandoverParkedSession, recordHandoverParkedSession } from "./host-handover-parked.js";
|
|
11
|
+
import { parkedEntryFromProfile } from "./host-handover-parked-open.js";
|
|
12
|
+
import { currentResidentWriter } from "./host-handover-resident-writer.js";
|
|
13
|
+
import { hostInstanceId } from "./protocol-identity.js";
|
|
14
|
+
const reportRecordFailure = (sessionId) => (cause) => {
|
|
15
|
+
process.stderr.write(`senpi rpc retained session record ${sessionId} failed: ${String(cause)}\n`);
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Writes the record entry of a retained session under `sessionPath`, stamped with this host instance, and drops
|
|
19
|
+
* the entry it was recorded under before when the session has since moved to another transcript (senpi#6190).
|
|
20
|
+
* `resident` stamps the writing process: the session is open here. A park writes it unstamped.
|
|
21
|
+
*/
|
|
22
|
+
export async function recordRetainedSession(host, retained, sessionPath, resident) {
|
|
23
|
+
const dir = host.handoverParkedDir;
|
|
24
|
+
if (dir === undefined)
|
|
25
|
+
return;
|
|
26
|
+
const previous = retained.recordedPath;
|
|
27
|
+
retained.recordedPath = sessionPath;
|
|
28
|
+
if (previous !== undefined && previous !== sessionPath)
|
|
29
|
+
await clearHandoverParkedSession(dir, previous);
|
|
30
|
+
const durableSessionId = retained.runtime?.session.sessionId ?? retained.durableSessionId;
|
|
31
|
+
await recordHandoverParkedSession(dir, {
|
|
32
|
+
...parkedEntryFromProfile({
|
|
33
|
+
sessionPath,
|
|
34
|
+
contextOverlay: retained.contextOverlay,
|
|
35
|
+
...(durableSessionId !== undefined ? { durableSessionId } : {}),
|
|
36
|
+
}, retained.profile, Object.keys(host.defaults.hostContext ?? {})),
|
|
37
|
+
parkedBy: host.defaults.hostContext?.host_instance ?? hostInstanceId(),
|
|
38
|
+
...(resident ? { residentWriter: currentResidentWriter() } : {}),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/** The session path a live entry writes now; a replacement moves it before the registry's metadata catches up. */
|
|
42
|
+
const currentPath = (entry) => entry.runtime?.session.sessionFile ?? entry.sessionPath;
|
|
43
|
+
/**
|
|
44
|
+
* Brings the record in line with a session this host just opened or attached: a retained session is
|
|
45
|
+
* recorded as resident here, so a restart reopens it; a non-retained open by path supersedes any
|
|
46
|
+
* earlier park of that path, whose entry is cleared so no later start reopens a second copy
|
|
47
|
+
* (MEDIUM-1, senpi#3282 review). Runs only after the open succeeded, so a failed open keeps the entry.
|
|
48
|
+
*/
|
|
49
|
+
export async function syncRetainedRecord(host, sessionId, requestedPath) {
|
|
50
|
+
const dir = host.handoverParkedDir;
|
|
51
|
+
if (dir === undefined)
|
|
52
|
+
return;
|
|
53
|
+
const entry = host.registry.peek(sessionId);
|
|
54
|
+
const sessionPath = entry === undefined ? undefined : currentPath(entry);
|
|
55
|
+
if (entry?.retainOnDisconnect === true && sessionPath !== undefined) {
|
|
56
|
+
await recordRetainedSession(host, entry, sessionPath, true).catch(reportRecordFailure(sessionId));
|
|
57
|
+
if (requestedPath === undefined || requestedPath === sessionPath)
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (requestedPath !== undefined)
|
|
61
|
+
await clearHandoverParkedSession(dir, requestedPath).catch(() => { });
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Called after every record a session publishes: a retained session whose transcript was switched (`new_session`,
|
|
65
|
+
* `switch_session`, a fork) moves its record entry to the new file at once, so a crash restores the transcript the
|
|
66
|
+
* session is on, never the one it left. A string compare until the path actually moves.
|
|
67
|
+
*/
|
|
68
|
+
export function followRetainedRecord(host, sessionId) {
|
|
69
|
+
if (host.handoverParkedDir === undefined)
|
|
70
|
+
return;
|
|
71
|
+
const entry = host.registry.peek(sessionId);
|
|
72
|
+
if (entry?.retainOnDisconnect !== true || entry.recordedPath === undefined || entry.state !== "open")
|
|
73
|
+
return;
|
|
74
|
+
const sessionPath = currentPath(entry);
|
|
75
|
+
if (sessionPath === undefined || sessionPath === entry.recordedPath)
|
|
76
|
+
return;
|
|
77
|
+
void recordRetainedSession(host, entry, sessionPath, true).catch(reportRecordFailure(sessionId));
|
|
78
|
+
}
|
|
79
|
+
/** An explicit close or reclaim ends the session for good: drop every key its record was written under. */
|
|
80
|
+
export async function clearRetainedRecord(host, entry) {
|
|
81
|
+
const dir = host.handoverParkedDir;
|
|
82
|
+
if (dir === undefined || entry === undefined)
|
|
83
|
+
return;
|
|
84
|
+
const keys = new Set([entry.recordedPath, entry.sessionPath, entry.runtime?.session.sessionFile]);
|
|
85
|
+
entry.recordedPath = undefined;
|
|
86
|
+
for (const key of keys)
|
|
87
|
+
if (key !== undefined)
|
|
88
|
+
await clearHandoverParkedSession(dir, key).catch(() => { });
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=session-router-residency.js.map
|
|
@@ -24,6 +24,7 @@ import { answerListSessions, answerProtocolInfo, answerSubscriptionLimits } from
|
|
|
24
24
|
import { acknowledgePrompt, otherRequestsSettled } from "./session-router-observation.js";
|
|
25
25
|
import { sweepDrain } from "./session-router-occupancy.js";
|
|
26
26
|
import { openWithBarrier } from "./session-router-open.js";
|
|
27
|
+
import { syncRetainedRecord } from "./session-router-residency.js";
|
|
27
28
|
import { answerSetSessionContext, answerSubscribeSessions, answerUnsubscribeSessions, notAttachedRefusal, } from "./session-status-commands.js";
|
|
28
29
|
import { unloadSession } from "./session-unload.js";
|
|
29
30
|
/**
|
|
@@ -245,7 +246,12 @@ export function setSessionContext(host, command) {
|
|
|
245
246
|
return notAttachedRefusal(command);
|
|
246
247
|
try {
|
|
247
248
|
const entry = host.registry.getForCommand(command.sessionId, command.type);
|
|
248
|
-
|
|
249
|
+
const answered = answerSetSessionContext(command, entry, host.writer.status);
|
|
250
|
+
// The record carries the overlay a restart reopens the session with (a terminal task_status
|
|
251
|
+
// is not reopened at all), so it follows each accepted patch.
|
|
252
|
+
if (answered.success)
|
|
253
|
+
void syncRetainedRecord(host, command.sessionId, undefined);
|
|
254
|
+
return answered;
|
|
249
255
|
}
|
|
250
256
|
catch (cause) {
|
|
251
257
|
return error(command.id, command.type, code(cause), detail(cause));
|
|
@@ -57,7 +57,10 @@ export function deriveSessionStatus(entry, runtime, fanout, terminal, cause) {
|
|
|
57
57
|
export function terminalOfLifecycle(record) {
|
|
58
58
|
const reason = typeof record.reason === "string" ? record.reason : undefined;
|
|
59
59
|
if (record.type === "session_parked")
|
|
60
|
-
return {
|
|
60
|
+
return {
|
|
61
|
+
status: "unloaded",
|
|
62
|
+
reason: reason === "unloaded" ? "unload_session" : reason === "host_shutdown" ? "host_shutdown" : "idle",
|
|
63
|
+
};
|
|
61
64
|
if (record.type !== "session_closed")
|
|
62
65
|
return undefined;
|
|
63
66
|
if (reason === "handoff_parked")
|
|
@@ -278,6 +278,8 @@ async function handle(message) {
|
|
|
278
278
|
const bound = roleConnection(message.connection);
|
|
279
279
|
if (message.delegation !== undefined && connectionRoles.retain(bound, message.delegation).kind === "conflict")
|
|
280
280
|
throw new Error(DELEGATION_AUTHORITY_CONFLICT);
|
|
281
|
+
if (message.delegation !== undefined)
|
|
282
|
+
connectionRoles.noteCarriedDelegation(bound);
|
|
281
283
|
if (message.roles !== undefined)
|
|
282
284
|
connectionRoles.adopt(bound, message.roles, message.delegation?.incarnation);
|
|
283
285
|
const bindingEntry = entry;
|
|
@@ -336,6 +338,8 @@ async function handle(message) {
|
|
|
336
338
|
const resolved = message.delegation === undefined ? undefined : connectionRoles.retain(connection, message.delegation);
|
|
337
339
|
if (resolved?.kind !== "conflict" && message.roles !== undefined)
|
|
338
340
|
connectionRoles.adopt(connection, message.roles, message.delegation?.incarnation);
|
|
341
|
+
if (message.delegation !== undefined)
|
|
342
|
+
connectionRoles.noteCarriedDelegation(connection);
|
|
339
343
|
if (message.origin !== undefined)
|
|
340
344
|
connectionRoles.declareOrigin(connection, message.origin);
|
|
341
345
|
const activeBinding = binding;
|
|
@@ -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
|
-
|
|
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,3 +1,4 @@
|
|
|
1
|
+
import { clientNamedPreset, withClientPreset } from "../../core/permission-mode.js";
|
|
1
2
|
import { outsideCommand } from "./command-authority.js";
|
|
2
3
|
import { refreshesSessionActivity } from "./session-command-activity.js";
|
|
3
4
|
import { publishedSessionContext } from "./session-context-patch.js";
|
|
@@ -163,7 +164,9 @@ export class WorkerSessionRegistry {
|
|
|
163
164
|
return undefined;
|
|
164
165
|
}
|
|
165
166
|
async attach(owner, path, options, requested = { cwd: "" }) {
|
|
166
|
-
const { promptSurface, browserEngine
|
|
167
|
+
const { promptSurface, browserEngine } = requested;
|
|
168
|
+
// A host-default preset folded into a preset-less attach is not a client choice (see session-registry-attach.ts).
|
|
169
|
+
const permissionPreset = clientNamedPreset(requested);
|
|
167
170
|
const entry = this.entries.get(owner);
|
|
168
171
|
if (entry?.state !== "open" || !entry.worker?.bindingReady || entry.worker.snapshot?.sessionPath !== path)
|
|
169
172
|
throw new RpcSessionRegistryError("session_path_in_use");
|
|
@@ -178,7 +181,7 @@ export class WorkerSessionRegistry {
|
|
|
178
181
|
}
|
|
179
182
|
// Sent even when the record already names it: only the worker sees its live session (senpi#2842).
|
|
180
183
|
if (permissionPreset !== undefined) {
|
|
181
|
-
entry.profile = frozenProfile(
|
|
184
|
+
entry.profile = frozenProfile(withClientPreset(entry.profile, permissionPreset));
|
|
182
185
|
await entry.worker.setPermissionPreset(permissionPreset);
|
|
183
186
|
}
|
|
184
187
|
const result = this.openResult(owner, entry);
|
|
@@ -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\":\"3860136b2a1b07c20373ed361df07c045bd1e84fce001917e271ca0e4b903e63\",\"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_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\":[],\"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\":[]}},\"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": "
|
|
3
|
+
"methodClassesDigest": "7ea18de0fb5d28f89aabdc17cbaca72e973cdea7d5928fd82d91ccced025000e",
|
|
4
4
|
"sampleId": "00000000-0000-7000-8000-000000000000",
|
|
5
5
|
"samplePathRoot": "/nonexistent/senpi-rpc-inbound-sample",
|
|
6
|
-
"methodCount":
|
|
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",
|
|
@@ -1065,6 +1082,16 @@
|
|
|
1065
1082
|
"modelId": "rpc-sample-model"
|
|
1066
1083
|
}
|
|
1067
1084
|
},
|
|
1085
|
+
{
|
|
1086
|
+
"method": "set_permission_preset",
|
|
1087
|
+
"class": "device_admin",
|
|
1088
|
+
"sampleClass": "device_admin",
|
|
1089
|
+
"connectionLocal": false,
|
|
1090
|
+
"sample": {
|
|
1091
|
+
"type": "set_permission_preset",
|
|
1092
|
+
"permissionPreset": "ask"
|
|
1093
|
+
}
|
|
1094
|
+
},
|
|
1068
1095
|
{
|
|
1069
1096
|
"method": "set_project_setting",
|
|
1070
1097
|
"class": "device_admin",
|
package/docs/extensions.md
CHANGED
|
@@ -885,6 +885,18 @@ pi.on("ui_prompt_end", async (event, ctx) => {
|
|
|
885
885
|
});
|
|
886
886
|
```
|
|
887
887
|
|
|
888
|
+
#### Permission mode and session-wide dialogs
|
|
889
|
+
|
|
890
|
+
`pi.getPermissionPreset()` returns the preset the permission system enforces for this session right now, or `undefined` when no permission system runs for it or its setup failed.
|
|
891
|
+
|
|
892
|
+
When a client moves a live session to another preset (`set_permission_preset`, or an attach naming one), the session announces it on the `pi.events` bus. A session's initial preset is not announced; read it with `pi.getPermissionPreset()`.
|
|
893
|
+
|
|
894
|
+
| Channel | Payload | Meaning |
|
|
895
|
+
|---------|---------|---------|
|
|
896
|
+
| `permission_preset_changed` | `{ permissionPreset, permissionPresetSource, permissionPresetStatus, effectivePermissionPreset }` | The session's approval mode changed; the payload is the same mode `get_state` reports. |
|
|
897
|
+
|
|
898
|
+
`pi.sessionDialog.select / confirm / input / editor` raise a dialog addressed to every client attached to the session, not only to the connection whose command is running. Use it for a prompt raised after that command returned, such as a background child's permission request a task runner forwards. The first answer wins; a later answer to the same dialog is refused with `already_answered`. In the terminal UI it shows like any other dialog. The same addressing is available on `ctx.ui` dialogs with the `audience: "session"` option.
|
|
899
|
+
|
|
888
900
|
#### Pending-question bus events
|
|
889
901
|
|
|
890
902
|
These additive events use `pi.events.on(...)`, not `pi.on(...)`:
|