@code-yeongyu/senpi 2026.10.25-4 → 2026.10.26-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/dist/bundle/chunks/{anthropic-messages-WBASBTIW.js → anthropic-messages-ODSFJCXR.js} +3 -3
- package/dist/bundle/chunks/{args-B444OQBK.js → args-SWKJAYQD.js} +1 -1
- package/dist/bundle/chunks/azure-openai-responses-REGXS4XO.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +3 -3
- package/dist/bundle/chunks/chunk-2XF6W6F6.js +410 -0
- package/dist/bundle/chunks/{chunk-WDPQ6CZJ.js → chunk-4QVORFQ2.js} +1 -1
- package/dist/bundle/chunks/{chunk-6AOVUTUR.js → chunk-5W3DTM2J.js} +2 -2
- package/dist/bundle/chunks/{chunk-E6WYH3ZL.js → chunk-6GAMRAVM.js} +9 -7
- package/dist/bundle/chunks/{chunk-N7IN46Q5.js → chunk-7IZH2KQX.js} +9 -7
- package/dist/bundle/chunks/{chunk-7GZUFOM3.js → chunk-ARSENVDY.js} +1 -1
- package/dist/bundle/chunks/{chunk-STMXIBXF.js → chunk-CNDPCYNT.js} +1 -1
- package/dist/bundle/chunks/{chunk-XF3LJC3O.js → chunk-CYOHFREV.js} +1 -1
- package/dist/bundle/chunks/{chunk-E6D4RIT7.js → chunk-DNDZPKIQ.js} +2 -2
- package/dist/bundle/chunks/{chunk-E4LBKOZG.js → chunk-EQNUL2WB.js} +4 -4
- package/dist/bundle/chunks/{chunk-2RB5EL4X.js → chunk-ESNSRUW4.js} +1 -1
- package/dist/bundle/chunks/{chunk-4AOMNOGY.js → chunk-FQDARFHT.js} +1 -1
- package/dist/bundle/chunks/{chunk-BWA4FVFW.js → chunk-GPPOPK76.js} +3 -3
- package/dist/bundle/chunks/{chunk-SBGIXMX3.js → chunk-GWGNVYPB.js} +1 -1
- package/dist/bundle/chunks/{chunk-KKD4CYCI.js → chunk-H4WJ4LY3.js} +1 -1
- package/dist/bundle/chunks/{chunk-V2UYXTRR.js → chunk-HWTD4QF3.js} +1 -1
- package/dist/bundle/chunks/chunk-I2WFLKZ2.js +5 -0
- package/dist/bundle/chunks/{chunk-WD6WBYC5.js → chunk-IHKHCWWG.js} +1 -1
- package/dist/bundle/chunks/{chunk-T36LJ6MW.js → chunk-IY4G44MN.js} +1 -1
- package/dist/bundle/chunks/{chunk-BZ7726QO.js → chunk-J2YAYTB2.js} +1 -1
- package/dist/bundle/chunks/{chunk-UFJ2K7Q7.js → chunk-JH7MVRNJ.js} +1 -1
- package/dist/bundle/chunks/chunk-KBSFTXAT.js +2 -0
- package/dist/bundle/chunks/{chunk-OLCDIITS.js → chunk-KRO63T4Q.js} +1 -1
- package/dist/bundle/chunks/{chunk-TTU2RNVX.js → chunk-KTDIIF2F.js} +1 -1
- package/dist/bundle/chunks/{chunk-KNVNKDER.js → chunk-L2O6K3SJ.js} +1 -1
- package/dist/bundle/chunks/{chunk-3BTN337S.js → chunk-NDNIMC5W.js} +1 -1
- package/dist/bundle/chunks/{chunk-ITGYN22E.js → chunk-ODRGPC5S.js} +1 -1
- package/dist/bundle/chunks/{chunk-4MOZXOJX.js → chunk-PDG4XWO2.js} +1 -1
- package/dist/bundle/chunks/{chunk-3QCYBOKN.js → chunk-PPECSSWX.js} +1 -1
- package/dist/bundle/chunks/{chunk-4P7WARQZ.js → chunk-PY4ZQHTN.js} +1 -1
- package/dist/bundle/chunks/{chunk-C2MQ4QXN.js → chunk-RPW3XQW3.js} +48 -42
- package/dist/bundle/chunks/{chunk-JMOUU75H.js → chunk-RQ5JTXUC.js} +1 -1
- package/dist/bundle/chunks/chunk-TQ67PB7U.js +13 -0
- package/dist/bundle/chunks/{chunk-5JJDR6XI.js → chunk-UJPG4ROT.js} +1 -1
- package/dist/bundle/chunks/{chunk-FHXR4ZAC.js → chunk-XM36IFP3.js} +1 -1
- package/dist/bundle/chunks/{chunk-PT6JJUN2.js → chunk-XMNPK472.js} +1 -1
- package/dist/bundle/chunks/{client-WTYEICLH.js → chunk-Y3TMJV3J.js} +3 -3
- package/dist/bundle/chunks/{chunk-GSSD3R5X.js → chunk-Z6BREXV3.js} +1 -1
- package/dist/bundle/chunks/{chunk-KXB5WIS5.js → chunk-Z6SAQ5O3.js} +1 -1
- package/dist/bundle/chunks/{chunk-LOIF6PHI.js → chunk-ZAUVY6ZC.js} +3 -3
- package/dist/bundle/chunks/{chunk-7CNOCJCN.js → chunk-ZP6JJDYV.js} +1 -1
- package/dist/bundle/chunks/cli-main-Q2GA53XM.js +3 -0
- package/dist/bundle/chunks/client-LOS6GSEW.js +2 -0
- package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-K5H6BJP3.js → cloudflare-workers-ai-system-one-WDHT7BBV.js} +1 -1
- package/dist/bundle/chunks/cursor-agent.js +3 -3
- package/dist/bundle/chunks/devin-agent.js +3 -3
- package/dist/bundle/chunks/dispatch-5R3TYAYB.js +9 -0
- package/dist/bundle/chunks/google-generative-ai-FHYFXKLA.js +2 -0
- package/dist/bundle/chunks/google-vertex-5DWE5U5K.js +2 -0
- package/dist/bundle/chunks/{help-fast-path-3Z26DQSV.js → help-fast-path-FETLIF3W.js} +1 -1
- package/dist/bundle/chunks/host-command-XEB7SHT3.js +2 -0
- package/dist/bundle/chunks/{host-lifecycle-3VHHIGDL.js → host-lifecycle-HX3EGRRW.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +2 -2
- package/dist/bundle/chunks/{host-session-command-56XF6ACS.js → host-session-command-FFN52LXJ.js} +1 -1
- package/dist/bundle/chunks/{host-socket-request-QL2WEZTN.js → host-socket-request-K4LCUOUD.js} +1 -1
- package/dist/bundle/chunks/interactive-mode-5DEKY3YW.js +2 -0
- package/dist/bundle/chunks/{mcp-presenter-bootstrap-XUSCQVRC.js → mcp-presenter-bootstrap-FOMKF4TU.js} +1 -1
- package/dist/bundle/chunks/{mistral-conversations-DH44NOYV.js → mistral-conversations-I2PI7DDF.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-Z2CW4SDM.js → multi-session-host-OPR5VBFO.js} +6 -7
- package/dist/bundle/chunks/{openai-codex-responses-SERAFKAS.js → openai-codex-responses-WSEX6SH7.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-BZB5O45A.js → openai-completions-YCBHTBSS.js} +1 -1
- package/dist/bundle/chunks/openai-responses-GXNSQF4A.js +3 -0
- package/dist/bundle/chunks/{package-manager-cli-N55U6PEO.js → package-manager-cli-W55E3LHP.js} +1 -1
- package/dist/bundle/chunks/{pi-messages-VXATX45B.js → pi-messages-O6GISIRW.js} +2 -2
- package/dist/bundle/chunks/{role-JVSBNKGE.js → role-SHIZQKK4.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-CBGCBYHV.js → rotation-stream-2PCZWNKF.js} +1 -1
- package/dist/bundle/chunks/rpc-mode-IDUJTSYS.js +2 -0
- package/dist/bundle/chunks/{rpc-monitor-source-AE3C6EQV.js → rpc-monitor-source-DRZXJHTL.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-VS7CZC2J.js → schedule-command-B7RRSANU.js} +1 -1
- package/dist/bundle/chunks/session-control-endpoint-LMZH5JLH.js +3 -0
- package/dist/bundle/chunks/{session-picker-E4KUJDLO.js → session-picker-DTGBOXDR.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +214 -205
- package/dist/bundle/chunks/{typesafe-system-one-P75WJ767.js → typesafe-system-one-XGYJJVSE.js} +1 -1
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.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/cli/host-command-args.d.ts +1 -0
- package/dist/cli/host-command-args.js +5 -0
- package/dist/cli/host-command.js +7 -1
- package/dist/cli.js +21 -3
- package/dist/core/agent-session.d.ts +11 -1
- package/dist/core/agent-session.js +19 -2
- package/dist/core/extensions/builtin/compaction/index.js +7 -1
- package/dist/core/extensions/builtin/herdr/index.js +9 -5
- package/dist/core/extensions/builtin/mcp/auth/oauth-issuer.d.ts +6 -0
- package/dist/core/extensions/builtin/mcp/auth/oauth-issuer.js +25 -0
- package/dist/core/extensions/builtin/mcp/auth/oauth-provider.d.ts +3 -3
- package/dist/core/extensions/builtin/mcp/auth/oauth-provider.js +50 -19
- package/dist/core/extensions/builtin/mcp/auth/oauth-refresh.js +4 -3
- package/dist/core/extensions/builtin/mcp/auth/oauth.js +19 -12
- package/dist/core/extensions/builtin/mcp/catalog-cache.d.ts +2 -1
- package/dist/core/extensions/builtin/mcp/catalog-cache.js +19 -6
- package/dist/core/extensions/builtin/mcp/catalog.d.ts +3 -2
- package/dist/core/extensions/builtin/mcp/catalog.js +20 -3
- package/dist/core/extensions/builtin/mcp/expose/call.d.ts +2 -1
- package/dist/core/extensions/builtin/mcp/expose/call.js +2 -1
- package/dist/core/extensions/builtin/mcp/expose/register.js +1 -1
- package/dist/core/extensions/builtin/mcp/expose/schema-compat.d.ts +2 -2
- package/dist/core/extensions/builtin/mcp/expose/schema-compat.js +11 -1
- package/dist/core/extensions/builtin/mcp/invocation.js +16 -2
- package/dist/core/extensions/builtin/mcp/modern/dispatch.js +1 -0
- package/dist/core/extensions/builtin/mcp/modern/parameter-headers.d.ts +4 -1
- package/dist/core/extensions/builtin/mcp/modern/parameter-headers.js +33 -35
- package/dist/core/extensions/builtin/mcp/modern/request.d.ts +1 -1
- package/dist/core/extensions/builtin/mcp/modern/request.js +4 -1
- package/dist/core/extensions/builtin/mcp/modern/sdk-bridge.js +18 -3
- package/dist/core/extensions/builtin/mcp/modern/stdio-probe.js +23 -0
- package/dist/core/extensions/builtin/mcp/modern/subscriptions.d.ts +14 -0
- package/dist/core/extensions/builtin/mcp/modern/subscriptions.js +226 -0
- package/dist/core/extensions/builtin/mcp/modern/tool-schema.d.ts +13 -0
- package/dist/core/extensions/builtin/mcp/modern/tool-schema.js +75 -0
- package/dist/core/extensions/builtin/mcp/modern/tools.d.ts +107 -0
- package/dist/core/extensions/builtin/mcp/modern/tools.js +53 -0
- package/dist/core/extensions/builtin/mcp/modern/transport.d.ts +2 -0
- package/dist/core/extensions/builtin/mcp/modern/transport.js +4 -2
- package/dist/core/extensions/builtin/mcp/resources.js +4 -0
- package/dist/core/extensions/builtin/mcp/tool-client.d.ts +13 -0
- package/dist/core/extensions/builtin/mcp/tool-client.js +17 -0
- package/dist/core/extensions/builtin/mcp/tool-contracts.d.ts +19 -0
- package/dist/core/extensions/builtin/mcp/tool-contracts.js +2 -0
- package/dist/core/extensions/builtin/mcp/wrap.js +2 -2
- package/dist/core/extensions/builtin/permission-system/bash-command-segments.d.ts +37 -0
- package/dist/core/extensions/builtin/permission-system/bash-command-segments.js +899 -0
- package/dist/core/extensions/builtin/permission-system/parsers.d.ts +2 -0
- package/dist/core/extensions/builtin/permission-system/parsers.js +44 -10
- package/dist/core/extensions/builtin/terminal/extension-state.js +2 -1
- package/dist/core/extensions/builtin/vertex-model-garden/auth.d.ts +9 -0
- package/dist/core/extensions/builtin/vertex-model-garden/auth.js +17 -1
- package/dist/core/extensions/builtin/websearch/websearch/providers/google.d.ts +6 -0
- package/dist/core/extensions/builtin/websearch/websearch/providers/google.js +6 -1
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/lifecycle-children.d.ts +3 -1
- package/dist/core/lifecycle-children.js +79 -15
- package/dist/core/lifecycle-record.js +1 -24
- package/dist/core/lifecycle-session-binding.js +2 -1
- package/dist/core/lifecycle-wait-items.d.ts +17 -0
- package/dist/core/lifecycle-wait-items.js +72 -0
- package/dist/core/model-runtime.js +6 -1
- package/dist/core/provider-api-key-auth.d.ts +6 -1
- package/dist/core/provider-api-key-auth.js +11 -4
- package/dist/core/provider-composer.d.ts +8 -1
- package/dist/core/provider-composer.js +7 -3
- package/dist/core/sdk.js +4 -1
- package/dist/core/session-activity.js +2 -0
- package/dist/core/session-lifecycle-types.d.ts +20 -4
- package/dist/core/session-lifecycle.js +35 -4
- package/dist/core/structured-session-lane.d.ts +33 -0
- package/dist/core/structured-session-lane.js +62 -0
- package/dist/core/work-custody-record.d.ts +2 -1
- package/dist/core/work-custody-record.js +2 -0
- package/dist/core/work-obligations.d.ts +1 -1
- package/dist/core/work-obligations.js +8 -2
- package/dist/modes/interactive/session-control-commands.js +21 -4
- package/dist/modes/interactive/session-control-rpc-commands.d.ts +1 -1
- package/dist/modes/interactive/session-control-rpc-commands.js +19 -0
- package/dist/modes/json-event.d.ts +79 -1
- package/dist/modes/json-event.js +79 -1
- package/dist/modes/rpc/compact-content-index.d.ts +85 -0
- package/dist/modes/rpc/compact-content-index.js +254 -0
- package/dist/modes/rpc/compact-content-store.d.ts +59 -0
- package/dist/modes/rpc/compact-content-store.js +134 -0
- package/dist/modes/rpc/compact-index-pages.d.ts +12 -0
- package/dist/modes/rpc/compact-index-pages.js +31 -0
- package/dist/modes/rpc/compact-session-state.d.ts +83 -0
- package/dist/modes/rpc/compact-session-state.js +197 -0
- package/dist/modes/rpc/compact-spool-dir.d.ts +8 -0
- package/dist/modes/rpc/compact-spool-dir.js +94 -0
- package/dist/modes/rpc/compact-spool-storage.d.ts +53 -0
- package/dist/modes/rpc/compact-spool-storage.js +162 -0
- package/dist/modes/rpc/compact-storage-io.d.ts +28 -0
- package/dist/modes/rpc/compact-storage-io.js +25 -0
- package/dist/modes/rpc/compact-transition.d.ts +41 -0
- package/dist/modes/rpc/compact-transition.js +12 -0
- package/dist/modes/rpc/connection-handler.d.ts +4 -0
- package/dist/modes/rpc/connection-handler.js +51 -13
- package/dist/modes/rpc/connection-question-bridge.d.ts +2 -1
- package/dist/modes/rpc/connection-question-bridge.js +6 -2
- package/dist/modes/rpc/extension-ui-response.d.ts +7 -2
- package/dist/modes/rpc/extension-ui-response.js +27 -7
- package/dist/modes/rpc/get-snapshot.d.ts +18 -0
- package/dist/modes/rpc/get-snapshot.js +43 -0
- package/dist/modes/rpc/host-capabilities.js +3 -0
- package/dist/modes/rpc/host-ensure-start.js +6 -3
- package/dist/modes/rpc/host-ensure-types.d.ts +2 -0
- package/dist/modes/rpc/host-ensure.js +1 -0
- package/dist/modes/rpc/host-handoff.d.ts +2 -0
- package/dist/modes/rpc/host-handover-request.d.ts +1 -1
- package/dist/modes/rpc/host-handover-request.js +4 -3
- package/dist/modes/rpc/host-handover-wire.js +6 -0
- package/dist/modes/rpc/host-idle-handover.d.ts +2 -0
- package/dist/modes/rpc/host-idle-handover.js +3 -1
- package/dist/modes/rpc/host-observe-request.js +1 -0
- package/dist/modes/rpc/host-runner.d.ts +1 -0
- package/dist/modes/rpc/host-runner.js +9 -7
- package/dist/modes/rpc/host-successor.js +4 -0
- package/dist/modes/rpc/json-normal-value.d.ts +6 -0
- package/dist/modes/rpc/json-normal-value.js +100 -0
- package/dist/modes/rpc/mcp-presenter-bootstrap.js +5 -0
- package/dist/modes/rpc/media-placeholders.d.ts +9 -3
- package/dist/modes/rpc/media-placeholders.js +12 -4
- package/dist/modes/rpc/rpc-host-command-types.d.ts +2 -0
- package/dist/modes/rpc/rpc-question-types.d.ts +1 -0
- package/dist/modes/rpc/rpc-read-response-types.d.ts +7 -0
- package/dist/modes/rpc/rpc-session-command-types.d.ts +6 -0
- package/dist/modes/rpc/rpc-session-state-types.d.ts +3 -0
- package/dist/modes/rpc/rpc-session-state.js +2 -0
- package/dist/modes/rpc/rpc-types.d.ts +1 -0
- package/dist/modes/rpc/security-presentations.js +2 -1
- package/dist/modes/rpc/session-attachment-gate.js +1 -0
- package/dist/modes/rpc/session-binding.js +30 -17
- package/dist/modes/rpc/session-command-activity.js +1 -0
- package/dist/modes/rpc/session-event-fanout.d.ts +1 -1
- package/dist/modes/rpc/session-event-fanout.js +17 -9
- package/dist/modes/rpc/session-event-writer.d.ts +2 -0
- package/dist/modes/rpc/session-event-writer.js +24 -5
- package/dist/modes/rpc/session-extension-ui-requests.d.ts +2 -1
- package/dist/modes/rpc/session-extension-ui-requests.js +15 -10
- package/dist/modes/rpc/session-held.js +1 -0
- package/dist/modes/rpc/session-record-stream.d.ts +3 -3
- package/dist/modes/rpc/session-record-stream.js +3 -3
- package/dist/modes/rpc/session-status-stream.d.ts +2 -1
- package/dist/modes/rpc/session-status-stream.js +8 -2
- package/dist/modes/rpc/session-status-subscriptions.d.ts +2 -1
- package/dist/modes/rpc/session-status-subscriptions.js +4 -0
- package/dist/modes/rpc/session-structured-lanes.d.ts +12 -0
- package/dist/modes/rpc/session-structured-lanes.js +24 -0
- package/dist/modes/rpc/session-worker-client.js +6 -5
- package/dist/modes/rpc/session-worker.js +5 -2
- package/dist/modes/rpc/snapshot-types.d.ts +29 -0
- package/dist/modes/rpc/snapshot-types.js +2 -0
- package/dist/modes/rpc/structured-session-records.d.ts +12 -0
- package/dist/modes/rpc/structured-session-records.js +88 -0
- package/dist/modes/rpc/ui-answer-ledger.d.ts +13 -0
- package/dist/modes/rpc/ui-answer-ledger.js +34 -0
- package/dist/senpi +21 -3
- package/docs/extensions.md +7 -1
- package/docs/mcp.md +20 -0
- package/docs/rpc.md +61 -2
- package/package.json +7 -6
- package/dist/bundle/chunks/azure-openai-responses-7I45DI72.js +0 -2
- package/dist/bundle/chunks/chunk-DMI55M2N.js +0 -2
- package/dist/bundle/chunks/chunk-DODH3N6U.js +0 -410
- package/dist/bundle/chunks/chunk-J37GRED2.js +0 -5
- package/dist/bundle/chunks/chunk-TBU6VYHN.js +0 -13
- package/dist/bundle/chunks/cli-main-YYH3IBC6.js +0 -3
- package/dist/bundle/chunks/dispatch-MXG5YWLV.js +0 -9
- package/dist/bundle/chunks/google-generative-ai-UM5Y7T6B.js +0 -2
- package/dist/bundle/chunks/google-vertex-OKU2VQHL.js +0 -2
- package/dist/bundle/chunks/host-command-TDLLHXVI.js +0 -2
- package/dist/bundle/chunks/interactive-mode-OEPULLZK.js +0 -2
- package/dist/bundle/chunks/openai-responses-TNHQ6SJS.js +0 -3
- package/dist/bundle/chunks/rpc-mode-ETXQWEB2.js +0 -2
- package/dist/bundle/chunks/session-control-endpoint-4LEIDIVI.js +0 -3
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* `AgentSession.isSessionBusy` instead of testing individual flags, so a source
|
|
17
17
|
* added later cannot be silently missed by one call site.
|
|
18
18
|
*/
|
|
19
|
+
import { normalizeWaitItems, wakeSourceItems } from "./lifecycle-wait-items.js";
|
|
19
20
|
/** Live counts of extension-published wake sources, keyed by source name. */
|
|
20
21
|
export class WakeSourceTracker {
|
|
21
22
|
constructor() {
|
|
@@ -39,6 +40,7 @@ export class WakeSourceTracker {
|
|
|
39
40
|
this.counts.set(source, {
|
|
40
41
|
activeCount,
|
|
41
42
|
kind: "kind" in data && data.kind === "children" ? "children" : "background",
|
|
43
|
+
...normalizeWaitItems(wakeSourceItems(data)),
|
|
42
44
|
});
|
|
43
45
|
else
|
|
44
46
|
this.counts.delete(source);
|
|
@@ -9,13 +9,26 @@ export interface HumanWait {
|
|
|
9
9
|
readonly childLabel?: string;
|
|
10
10
|
readonly since: string;
|
|
11
11
|
}
|
|
12
|
+
export interface LifecycleWaitItem {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly label?: string;
|
|
15
|
+
readonly startedAt?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface LifecycleWaitSource {
|
|
18
|
+
readonly source: string;
|
|
19
|
+
readonly activeCount: number;
|
|
20
|
+
readonly items?: readonly LifecycleWaitItem[];
|
|
21
|
+
readonly omittedItems?: number;
|
|
22
|
+
}
|
|
12
23
|
export interface LifecycleWaits {
|
|
13
24
|
readonly children: number;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
/** Named detail can be incomplete even without truncation: custody need not have a named report. */
|
|
26
|
+
readonly childSources?: readonly LifecycleWaitSource[];
|
|
27
|
+
readonly childReports?: readonly Pick<ChildLifecycleReport, "taskId" | "childSessionId" | "runEpoch" | "state" | "label" | "since">[];
|
|
28
|
+
readonly childReportsOmitted?: number;
|
|
29
|
+
readonly background: readonly (LifecycleWaitSource & {
|
|
17
30
|
readonly retryAtMs?: number;
|
|
18
|
-
}[];
|
|
31
|
+
})[];
|
|
19
32
|
readonly human: readonly HumanWait[];
|
|
20
33
|
}
|
|
21
34
|
export interface LifecycleHold {
|
|
@@ -83,6 +96,9 @@ export interface ChildLifecycleReport {
|
|
|
83
96
|
readonly runEpoch: number;
|
|
84
97
|
readonly generation: number;
|
|
85
98
|
readonly state: SessionLifecycleState;
|
|
99
|
+
readonly label?: string;
|
|
100
|
+
/** The child's own state-entry time, not the parent's evaluation time. */
|
|
101
|
+
readonly since?: string;
|
|
86
102
|
readonly waitingOn?: LifecycleWaits;
|
|
87
103
|
readonly terminal?: "completed" | "error" | "lost" | "interrupted" | "cancelled";
|
|
88
104
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { effectiveWakes } from "./extensions/builtin/goal/turn-end-liveness.js";
|
|
2
2
|
import { LifecycleChildren } from "./lifecycle-children.js";
|
|
3
3
|
import { LifecycleLedger } from "./lifecycle-ledger.js";
|
|
4
|
+
import { projectWaitItems } from "./lifecycle-wait-items.js";
|
|
4
5
|
import { sameStop, stopDetail } from "./lifecycle-stop.js";
|
|
5
6
|
import { lifecycleState, lifecycleTerminal } from "./session-lifecycle-reducer.js";
|
|
6
7
|
import { SessionWorkObligations } from "./work-obligations.js";
|
|
@@ -189,11 +190,34 @@ export class SessionLifecycleController {
|
|
|
189
190
|
evaluate() {
|
|
190
191
|
const runtime = this.options.readRuntime();
|
|
191
192
|
const active = this.obligations.active;
|
|
192
|
-
const childRecords = this.children.reports
|
|
193
|
+
const childRecords = this.children.reports
|
|
194
|
+
.filter((report) => report.childSessionId !== this.options.sessionId && report.terminal === undefined)
|
|
195
|
+
.sort((a, b) => (a.taskId < b.taskId ? -1 : a.taskId > b.taskId ? 1 : 0));
|
|
196
|
+
const childReports = childRecords
|
|
197
|
+
.slice(0, 32)
|
|
198
|
+
.map(({ taskId, childSessionId, runEpoch, state, label, since }) => ({
|
|
199
|
+
taskId,
|
|
200
|
+
childSessionId,
|
|
201
|
+
runEpoch,
|
|
202
|
+
state,
|
|
203
|
+
...(label === undefined ? {} : { label }),
|
|
204
|
+
...(since === undefined ? {} : { since }),
|
|
205
|
+
}));
|
|
206
|
+
const childSources = active
|
|
207
|
+
.filter((record) => record.kind === "children")
|
|
208
|
+
.map((record) => ({
|
|
209
|
+
source: record.source ?? record.key,
|
|
210
|
+
activeCount: record.activeCount ?? 1,
|
|
211
|
+
...projectWaitItems(record),
|
|
212
|
+
}));
|
|
193
213
|
const background = active
|
|
194
214
|
.filter((record) => record.kind === "background")
|
|
195
|
-
.map((record) => ({
|
|
196
|
-
|
|
215
|
+
.map((record) => ({
|
|
216
|
+
source: record.source ?? record.key,
|
|
217
|
+
activeCount: record.activeCount ?? 1,
|
|
218
|
+
...projectWaitItems(record),
|
|
219
|
+
}));
|
|
220
|
+
const children = Math.max(childRecords.length, active
|
|
197
221
|
.filter((record) => record.kind === "children")
|
|
198
222
|
.reduce((sum, record) => sum + (record.activeCount ?? 1), 0));
|
|
199
223
|
const input = this.liveness;
|
|
@@ -297,7 +321,14 @@ export class SessionLifecycleController {
|
|
|
297
321
|
runEpoch: this.ownTask.runEpoch,
|
|
298
322
|
}
|
|
299
323
|
: undefined;
|
|
300
|
-
const waits = {
|
|
324
|
+
const waits = {
|
|
325
|
+
children,
|
|
326
|
+
background,
|
|
327
|
+
human,
|
|
328
|
+
...(childSources.length ? { childSources } : {}),
|
|
329
|
+
...(childReports.length ? { childReports } : {}),
|
|
330
|
+
...(childRecords.length > 32 ? { childReportsOmitted: childRecords.length - 32 } : {}),
|
|
331
|
+
};
|
|
301
332
|
const lastStop = this.lastStop(input, synthetic.some((wait) => wait.kind === "stalled"));
|
|
302
333
|
const state = lifecycleState({
|
|
303
334
|
role: this.ledger.snapshot.role,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { InternalAgentChannel } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import { type AssistantProgress } from "@earendil-works/pi-ai";
|
|
3
|
+
import type { AgentSessionEvent } from "./agent-session.ts";
|
|
4
|
+
/** One record of a session's internal structured lane: a session event or a block control, in session order. */
|
|
5
|
+
export type AgentSessionStructuredRecord = AgentSessionEvent | AssistantProgress;
|
|
6
|
+
type StructuredListener = (record: AgentSessionStructuredRecord) => void;
|
|
7
|
+
export declare class StructuredLaneUnavailableError extends Error {
|
|
8
|
+
constructor();
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The AgentSession end of the internal-only agent channel (senpi#4272, R3.C6.2). While a structured listener is
|
|
12
|
+
* attached, it holds the channel's capture subscription; block controls enter the session's own event queue, so they
|
|
13
|
+
* keep their position among the ordinary events. Extension listeners, `session.subscribe` and every legacy
|
|
14
|
+
* destination never see a control.
|
|
15
|
+
*
|
|
16
|
+
* The capture subscription is module-wide (`subscribeAssistantCapture`): while it is held, every capture-enabled
|
|
17
|
+
* provider stream in the process that first pushes afterwards builds capture records, including streams of sessions
|
|
18
|
+
* with no structured listener, which drop them at their public iterator.
|
|
19
|
+
*/
|
|
20
|
+
export declare class StructuredSessionLane {
|
|
21
|
+
#private;
|
|
22
|
+
private readonly listeners;
|
|
23
|
+
private releaseChannel;
|
|
24
|
+
constructor(channel: InternalAgentChannel | undefined, enqueue: (deliver: () => void) => void);
|
|
25
|
+
get active(): boolean;
|
|
26
|
+
subscribe(listener: StructuredListener): () => void;
|
|
27
|
+
/** Publishes a session event with the provider capture of its `source` agent event. */
|
|
28
|
+
emitEvent(event: AgentSessionEvent, source: object): void;
|
|
29
|
+
dispose(): void;
|
|
30
|
+
private emit;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=structured-session-lane.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { carryAssistantCapture } from "@earendil-works/pi-ai";
|
|
2
|
+
export class StructuredLaneUnavailableError extends Error {
|
|
3
|
+
constructor() {
|
|
4
|
+
super("Structured lane unavailable: Agent was constructed outside the session layer");
|
|
5
|
+
this.name = "StructuredLaneUnavailableError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The AgentSession end of the internal-only agent channel (senpi#4272, R3.C6.2). While a structured listener is
|
|
10
|
+
* attached, it holds the channel's capture subscription; block controls enter the session's own event queue, so they
|
|
11
|
+
* keep their position among the ordinary events. Extension listeners, `session.subscribe` and every legacy
|
|
12
|
+
* destination never see a control.
|
|
13
|
+
*
|
|
14
|
+
* The capture subscription is module-wide (`subscribeAssistantCapture`): while it is held, every capture-enabled
|
|
15
|
+
* provider stream in the process that first pushes afterwards builds capture records, including streams of sessions
|
|
16
|
+
* with no structured listener, which drop them at their public iterator.
|
|
17
|
+
*/
|
|
18
|
+
export class StructuredSessionLane {
|
|
19
|
+
#channel;
|
|
20
|
+
#enqueue;
|
|
21
|
+
constructor(channel, enqueue) {
|
|
22
|
+
this.listeners = new Set();
|
|
23
|
+
this.#channel = channel;
|
|
24
|
+
this.#enqueue = enqueue;
|
|
25
|
+
}
|
|
26
|
+
get active() {
|
|
27
|
+
return this.listeners.size > 0;
|
|
28
|
+
}
|
|
29
|
+
subscribe(listener) {
|
|
30
|
+
if (!this.#channel)
|
|
31
|
+
throw new StructuredLaneUnavailableError();
|
|
32
|
+
this.listeners.add(listener);
|
|
33
|
+
this.releaseChannel ??= this.#channel.subscribe((record) => {
|
|
34
|
+
if ("progress" in record)
|
|
35
|
+
this.#enqueue(() => this.emit(record.progress));
|
|
36
|
+
});
|
|
37
|
+
return () => {
|
|
38
|
+
this.listeners.delete(listener);
|
|
39
|
+
if (this.listeners.size === 0)
|
|
40
|
+
this.dispose();
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Publishes a session event with the provider capture of its `source` agent event. */
|
|
44
|
+
emitEvent(event, source) {
|
|
45
|
+
const message = (event.type === "message_start" || event.type === "message_end") && event.message.role === "assistant"
|
|
46
|
+
? event.message
|
|
47
|
+
: undefined;
|
|
48
|
+
// A user-facing description replaced the engine message, so the capture's frozen message must follow it.
|
|
49
|
+
const described = message && "message" in source && source.message !== message ? message : undefined;
|
|
50
|
+
this.emit(carryAssistantCapture(source, event, described));
|
|
51
|
+
}
|
|
52
|
+
dispose() {
|
|
53
|
+
this.listeners.clear();
|
|
54
|
+
this.releaseChannel?.();
|
|
55
|
+
this.releaseChannel = undefined;
|
|
56
|
+
}
|
|
57
|
+
emit(record) {
|
|
58
|
+
for (const listener of [...this.listeners])
|
|
59
|
+
listener(record);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=structured-session-lane.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CustomMessage } from "./messages.ts";
|
|
2
|
+
import { type WaitSourceItems } from "./lifecycle-wait-items.ts";
|
|
2
3
|
import type { ObligationKind } from "./session-lifecycle-types.ts";
|
|
3
4
|
export interface CustodyPayload {
|
|
4
5
|
readonly message: Pick<CustomMessage, "customType" | "content" | "display" | "details">;
|
|
@@ -7,7 +8,7 @@ export interface CustodyPayload {
|
|
|
7
8
|
readonly itemIds?: readonly string[];
|
|
8
9
|
}
|
|
9
10
|
/** Mutable only by the registry; every replacement is appended before installation. */
|
|
10
|
-
export interface WorkCustodyRecord {
|
|
11
|
+
export interface WorkCustodyRecord extends WaitSourceItems {
|
|
11
12
|
readonly id: string;
|
|
12
13
|
readonly key: string;
|
|
13
14
|
readonly kind: ObligationKind;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeWaitItems } from "./lifecycle-wait-items.js";
|
|
1
2
|
export function isRecord(value) {
|
|
2
3
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
4
|
}
|
|
@@ -25,6 +26,7 @@ export function readWorkCustody(value) {
|
|
|
25
26
|
key: value.key,
|
|
26
27
|
kind: value.kind,
|
|
27
28
|
state: value.state,
|
|
29
|
+
...normalizeWaitItems(value.items, value.omittedItems),
|
|
28
30
|
...(typeof value.source === "string" ? { source: value.source } : {}),
|
|
29
31
|
...(typeof value.activeCount === "number" ? { activeCount: value.activeCount } : {}),
|
|
30
32
|
...(typeof value.detail === "string" ? { detail: value.detail } : {}),
|
|
@@ -36,7 +36,7 @@ export declare class SessionWorkObligations implements WorkObligations {
|
|
|
36
36
|
get activeCount(): number;
|
|
37
37
|
get persisted(): boolean;
|
|
38
38
|
open(key: string, kind: ObligationKind, detail?: string): ObligationToken;
|
|
39
|
-
syncSource(source: string, kind: ObligationKind, activeCount: number): void;
|
|
39
|
+
syncSource(source: string, kind: ObligationKind, activeCount: number, items?: unknown): void;
|
|
40
40
|
/** After a restart, a restored wake source stays open only if its producer published again. */
|
|
41
41
|
retireRestoredSources(): void;
|
|
42
42
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeWaitItems, waitItemSignature } from "./lifecycle-wait-items.js";
|
|
1
2
|
import { custodyIsOpen, readWorkCustody } from "./work-custody-record.js";
|
|
2
3
|
/** Custody keys the engine opens itself (senpi#3986): queued deliveries and published wake sources. */
|
|
3
4
|
export const ENGINE_DELIVERY_KEY_PREFIX = "delivery:";
|
|
@@ -59,7 +60,7 @@ export class SessionWorkObligations {
|
|
|
59
60
|
this.store.changed();
|
|
60
61
|
return this.token(record.id);
|
|
61
62
|
}
|
|
62
|
-
syncSource(source, kind, activeCount) {
|
|
63
|
+
syncSource(source, kind, activeCount, items) {
|
|
63
64
|
const key = `${WAKE_SOURCE_KEY_PREFIX}${source}`;
|
|
64
65
|
this.publishedSources.add(key);
|
|
65
66
|
const current = this.active.find((record) => record.key === key);
|
|
@@ -68,7 +69,10 @@ export class SessionWorkObligations {
|
|
|
68
69
|
this.close(current.id, "passive");
|
|
69
70
|
return;
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
+
const detail = normalizeWaitItems(items);
|
|
73
|
+
if (current?.activeCount === activeCount &&
|
|
74
|
+
current.kind === kind &&
|
|
75
|
+
waitItemSignature(current) === waitItemSignature(detail))
|
|
72
76
|
return;
|
|
73
77
|
this.install({
|
|
74
78
|
...current,
|
|
@@ -77,6 +81,8 @@ export class SessionWorkObligations {
|
|
|
77
81
|
source,
|
|
78
82
|
kind,
|
|
79
83
|
activeCount,
|
|
84
|
+
items: detail.items,
|
|
85
|
+
omittedItems: detail.omittedItems,
|
|
80
86
|
state: current?.state ?? "open",
|
|
81
87
|
});
|
|
82
88
|
this.store.changed();
|
|
@@ -13,6 +13,7 @@ import { ENTRIES_TAIL_CAPABILITY, OBSERVE_READS_CAPABILITY, SESSION_STATUS_CAPAB
|
|
|
13
13
|
import { answerGetEntries } from "../rpc/get-entries-command.js";
|
|
14
14
|
import { answeredUiRequestId, settledQuestionStatus, unansweredQuestionIds } from "../rpc/extension-ui-response.js";
|
|
15
15
|
import { buildRpcSessionState } from "../rpc/rpc-session-state.js";
|
|
16
|
+
import { sessionUiAnswerLedger } from "../rpc/ui-answer-ledger.js";
|
|
16
17
|
import { runTuiRpcCommand, TUI_RPC_COMMANDS } from "./session-control-rpc-commands.js";
|
|
17
18
|
import { failure, success } from "./session-control-server.js";
|
|
18
19
|
import { runSessionControlCommand, SESSION_CONTROL_COMMANDS, } from "./session-control-session-commands.js";
|
|
@@ -45,6 +46,8 @@ export async function runControlCommand(context, connection, command) {
|
|
|
45
46
|
TUI_OBSERVER_CAPABILITY,
|
|
46
47
|
OBSERVE_READS_CAPABILITY,
|
|
47
48
|
ENTRIES_TAIL_CAPABILITY,
|
|
49
|
+
"snapshot_cursor",
|
|
50
|
+
"ui_answer_ledger",
|
|
48
51
|
],
|
|
49
52
|
mode: "tui",
|
|
50
53
|
endpoint_kind: "tui",
|
|
@@ -89,7 +92,7 @@ export async function runControlCommand(context, connection, command) {
|
|
|
89
92
|
return success(id, type, { admitted: result.admitted ?? [] });
|
|
90
93
|
}
|
|
91
94
|
case "extension_ui_response":
|
|
92
|
-
return answerQuestion(context
|
|
95
|
+
return answerQuestion(context, command);
|
|
93
96
|
default: {
|
|
94
97
|
const rpc = await runTuiRpcCommand(context, connection, command);
|
|
95
98
|
if (rpc !== undefined)
|
|
@@ -121,12 +124,25 @@ function sessionRow(session) {
|
|
|
121
124
|
* settles by the host's rule (`settledQuestionStatus`), so the same frame reaches the model as the same
|
|
122
125
|
* message on either surface.
|
|
123
126
|
*/
|
|
124
|
-
function answerQuestion(
|
|
127
|
+
function answerQuestion(context, command) {
|
|
128
|
+
const { surface, session } = context;
|
|
129
|
+
const ledger = sessionUiAnswerLedger(session);
|
|
130
|
+
const answerId = command.answerId;
|
|
131
|
+
if (answerId !== undefined && (typeof answerId !== "string" || answerId.length < 1 || answerId.length > 256))
|
|
132
|
+
return failure(command.id, "extension_ui_response", "invalid_answer_id");
|
|
125
133
|
const frameId = command.id;
|
|
126
134
|
const requestId = answeredUiRequestId(command);
|
|
135
|
+
const receipt = requestId === undefined || answerId === undefined ? undefined : ledger.lookup(requestId, answerId);
|
|
136
|
+
if (receipt === "replay")
|
|
137
|
+
return { ...success(frameId, "extension_ui_response"), disposition: receipt };
|
|
138
|
+
if (receipt === "already_answered")
|
|
139
|
+
return { ...failure(frameId, "extension_ui_response", "already_answered"), disposition: receipt };
|
|
127
140
|
const request = requestId === undefined ? undefined : surface.pendingQuestion(requestId);
|
|
128
141
|
if (requestId === undefined || request === undefined) {
|
|
129
|
-
return
|
|
142
|
+
return {
|
|
143
|
+
...failure(frameId, "extension_ui_response", answerId === undefined ? "unknown_request" : "unknown_extension_ui_request"),
|
|
144
|
+
disposition: "unknown",
|
|
145
|
+
};
|
|
130
146
|
}
|
|
131
147
|
const response = questionResponse(command, request.questions);
|
|
132
148
|
if (response === "question_incomplete")
|
|
@@ -134,7 +150,8 @@ function answerQuestion(surface, command) {
|
|
|
134
150
|
if (response === undefined || !surface.answerQuestion(requestId, response)) {
|
|
135
151
|
return failure(frameId, "extension_ui_response", "invalid_response");
|
|
136
152
|
}
|
|
137
|
-
|
|
153
|
+
ledger.record(requestId, answerId);
|
|
154
|
+
return { ...success(frameId, "extension_ui_response"), disposition: "applied" };
|
|
138
155
|
}
|
|
139
156
|
function questionResponse(command, questions) {
|
|
140
157
|
// Another client's cancel (the desktop's Remove) is the user's; the builtin settles it from its own draft.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentSession } from "../../core/agent-session.ts";
|
|
2
2
|
import { type ControlAttachments } from "./session-control-attach.ts";
|
|
3
3
|
import { type ControlCommand, type ControlConnection } from "./session-control-server.ts";
|
|
4
|
-
export declare const TUI_RPC_COMMANDS: readonly ["open_session", "subscribe_sessions", "unsubscribe_sessions", "steer", "follow_up", "prompt", "get_effect_status", "set_client_info", "attach_session", "release_attachment", "abort"];
|
|
4
|
+
export declare const TUI_RPC_COMMANDS: readonly ["open_session", "get_snapshot", "subscribe_sessions", "unsubscribe_sessions", "steer", "follow_up", "prompt", "get_effect_status", "set_client_info", "attach_session", "release_attachment", "abort"];
|
|
5
5
|
export interface RpcCommandContext {
|
|
6
6
|
/** This endpoint's instance id: the `expectedHostInstance` an `attach_session` may name. */
|
|
7
7
|
readonly instanceId: string;
|
|
@@ -17,11 +17,13 @@ import { CONNECTION_ROLE_FIXED } from "../rpc/connection-roles.js";
|
|
|
17
17
|
import { INTERACTIVE_USER_CAPABILITY } from "../rpc/custom-capability.js";
|
|
18
18
|
import { runAbort, runGetEffectStatus } from "../rpc/effect-commands.js";
|
|
19
19
|
import { buildRpcSessionState } from "../rpc/rpc-session-state.js";
|
|
20
|
+
import { getSnapshot } from "../rpc/get-snapshot.js";
|
|
20
21
|
import { answerSubscribeSessions, answerUnsubscribeSessions, refusal } from "../rpc/session-status-commands.js";
|
|
21
22
|
import { keyOf } from "./session-control-attach.js";
|
|
22
23
|
import { failure, success } from "./session-control-server.js";
|
|
23
24
|
export const TUI_RPC_COMMANDS = [
|
|
24
25
|
"open_session",
|
|
26
|
+
"get_snapshot",
|
|
25
27
|
"subscribe_sessions",
|
|
26
28
|
"unsubscribe_sessions",
|
|
27
29
|
"steer",
|
|
@@ -38,6 +40,23 @@ const STOP_REQUIRES_INTERACTIVE_CLIENT = "stop_requires_interactive_client: decl
|
|
|
38
40
|
/** `null` = answered on the writer already; `undefined` = not a command this file owns. */
|
|
39
41
|
export async function runTuiRpcCommand(context, connection, command) {
|
|
40
42
|
switch (command.type) {
|
|
43
|
+
case "get_snapshot": {
|
|
44
|
+
const { attachments, session } = context;
|
|
45
|
+
if (command.sessionId !== undefined && command.sessionId !== attachments.handle)
|
|
46
|
+
return {
|
|
47
|
+
id: command.id,
|
|
48
|
+
type: "response",
|
|
49
|
+
command: command.type,
|
|
50
|
+
success: false,
|
|
51
|
+
error: "unknown_session",
|
|
52
|
+
};
|
|
53
|
+
const snapshot = getSnapshot(session, { tail: command.tail, maxBytes: command.maxBytes }, {
|
|
54
|
+
enqueue: (markerId) => attachments.run(connection, () => attachments.writer.enqueue(attachments.handle, { type: "snapshot_marker", markerId })),
|
|
55
|
+
});
|
|
56
|
+
return "error" in snapshot
|
|
57
|
+
? { id: command.id, type: "response", command: command.type, success: false, error: snapshot.error }
|
|
58
|
+
: answered(idOf(command), command.type, snapshot.data);
|
|
59
|
+
}
|
|
41
60
|
case "open_session":
|
|
42
61
|
return openSession(context, connection, command);
|
|
43
62
|
case "subscribe_sessions":
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AssistantMessage, getAssistantCapture, type TextContent, type ThinkingContent, type ToolCall, type Usage } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { AgentSessionEvent } from "../core/agent-session.ts";
|
|
3
3
|
type WithoutPartial<T> = T extends {
|
|
4
4
|
partial: unknown;
|
|
@@ -13,6 +13,7 @@ type ToJsonAssistantMessageEvent<T> = T extends {
|
|
|
13
13
|
type MessageUpdateEvent = Extract<AgentSessionEvent, {
|
|
14
14
|
type: "message_update";
|
|
15
15
|
}>;
|
|
16
|
+
type AssistantCapture = NonNullable<ReturnType<typeof getAssistantCapture>>;
|
|
16
17
|
type JsonMessageUpdateEvent = {
|
|
17
18
|
type: "message_update";
|
|
18
19
|
usage: Usage;
|
|
@@ -23,6 +24,82 @@ type JsonMessageUpdateEvent = {
|
|
|
23
24
|
export type JsonAgentSessionEvent = Exclude<AgentSessionEvent, {
|
|
24
25
|
type: "message_update";
|
|
25
26
|
}> | JsonMessageUpdateEvent;
|
|
27
|
+
/** The engine-staged block-seed projection (senpi#4272, R3.C6.2); no public destination selects it before S17. */
|
|
28
|
+
export interface BlockSeedOptions {
|
|
29
|
+
readonly blockSeeds: 1;
|
|
30
|
+
}
|
|
31
|
+
type SeededAssistantEvent = {
|
|
32
|
+
type: "start";
|
|
33
|
+
seed: {
|
|
34
|
+
message: AssistantMessage;
|
|
35
|
+
};
|
|
36
|
+
} | {
|
|
37
|
+
type: "text_start";
|
|
38
|
+
contentIndex: number;
|
|
39
|
+
seed: {
|
|
40
|
+
block: TextContent;
|
|
41
|
+
coveredCodeUnits: number;
|
|
42
|
+
};
|
|
43
|
+
} | {
|
|
44
|
+
type: "thinking_start";
|
|
45
|
+
contentIndex: number;
|
|
46
|
+
seed: {
|
|
47
|
+
block: ThinkingContent;
|
|
48
|
+
coveredCodeUnits: number;
|
|
49
|
+
};
|
|
50
|
+
} | {
|
|
51
|
+
type: "toolcall_start";
|
|
52
|
+
contentIndex: number;
|
|
53
|
+
id: string;
|
|
54
|
+
toolName: string;
|
|
55
|
+
seed: {
|
|
56
|
+
block: ToolCall;
|
|
57
|
+
rawArgumentPrefix: string;
|
|
58
|
+
parsedThrough: number;
|
|
59
|
+
coveredCodeUnits: number;
|
|
60
|
+
};
|
|
61
|
+
} | {
|
|
62
|
+
type: "text_delta" | "thinking_delta";
|
|
63
|
+
contentIndex: number;
|
|
64
|
+
delta: string;
|
|
65
|
+
offset: number;
|
|
66
|
+
} | {
|
|
67
|
+
type: "toolcall_delta";
|
|
68
|
+
contentIndex: number;
|
|
69
|
+
delta: string;
|
|
70
|
+
offset: number;
|
|
71
|
+
parsedThrough: number;
|
|
72
|
+
} | {
|
|
73
|
+
type: "text_end";
|
|
74
|
+
contentIndex: number;
|
|
75
|
+
content: string;
|
|
76
|
+
block: TextContent;
|
|
77
|
+
} | {
|
|
78
|
+
type: "thinking_end";
|
|
79
|
+
contentIndex: number;
|
|
80
|
+
content: string;
|
|
81
|
+
block: ThinkingContent;
|
|
82
|
+
} | {
|
|
83
|
+
type: "toolcall_end";
|
|
84
|
+
contentIndex: number;
|
|
85
|
+
toolCall: ToolCall;
|
|
86
|
+
} | {
|
|
87
|
+
type: "done";
|
|
88
|
+
reason: string;
|
|
89
|
+
message: AssistantMessage;
|
|
90
|
+
} | {
|
|
91
|
+
type: "error";
|
|
92
|
+
reason: string;
|
|
93
|
+
error: AssistantMessage;
|
|
94
|
+
};
|
|
95
|
+
export type SeededJsonMessageUpdateEvent = Omit<MessageUpdateEvent, "message" | "assistantMessageEvent"> & {
|
|
96
|
+
usage: Usage;
|
|
97
|
+
messageMetadata?: AssistantCapture["metadata"];
|
|
98
|
+
assistantMessageEvent: SeededAssistantEvent;
|
|
99
|
+
};
|
|
100
|
+
export type SeededJsonAgentSessionEvent = Exclude<AgentSessionEvent, {
|
|
101
|
+
type: "message_update";
|
|
102
|
+
}> | SeededJsonMessageUpdateEvent;
|
|
26
103
|
/**
|
|
27
104
|
* Remove cumulative assistant snapshots from streaming wire events.
|
|
28
105
|
* `message_start` provides the initial message, deltas build it, and
|
|
@@ -31,5 +108,6 @@ export type JsonAgentSessionEvent = Exclude<AgentSessionEvent, {
|
|
|
31
108
|
*/
|
|
32
109
|
export declare function toJsonEvent(event: MessageUpdateEvent): JsonMessageUpdateEvent;
|
|
33
110
|
export declare function toJsonEvent(event: AgentSessionEvent): JsonAgentSessionEvent;
|
|
111
|
+
export declare function toJsonEvent(event: AgentSessionEvent, options: BlockSeedOptions): SeededJsonAgentSessionEvent | undefined;
|
|
34
112
|
export {};
|
|
35
113
|
//# sourceMappingURL=json-event.d.ts.map
|
package/dist/modes/json-event.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getAssistantCapture, } from "@earendil-works/pi-ai";
|
|
1
2
|
function toJsonAssistantMessageEvent(event) {
|
|
2
3
|
if (event.type === "toolcall_start") {
|
|
3
4
|
const toolCall = event.partial.content[event.contentIndex];
|
|
@@ -13,7 +14,84 @@ function toJsonAssistantMessageEvent(event) {
|
|
|
13
14
|
const { partial: _partial, ...deltaEvent } = event;
|
|
14
15
|
return deltaEvent;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Builds a seeded assistant event from the producer-time capture only: an ordinary delta reads its index, its
|
|
19
|
+
* delta string and the capture, never the shared partial, the block or the parsed arguments.
|
|
20
|
+
*/
|
|
21
|
+
function toSeededAssistantEvent(event, capture) {
|
|
22
|
+
if (event.type === "start")
|
|
23
|
+
return capture.message && { type: "start", seed: { message: capture.message } };
|
|
24
|
+
if (event.type === "done")
|
|
25
|
+
return { type: "done", reason: event.reason, message: event.message };
|
|
26
|
+
if (event.type === "error")
|
|
27
|
+
return { type: "error", reason: event.reason, error: event.error };
|
|
28
|
+
const contentIndex = capture.contentIndex ?? event.contentIndex;
|
|
29
|
+
if (event.type === "text_delta" || event.type === "thinking_delta" || event.type === "toolcall_delta") {
|
|
30
|
+
const { offset, parsedThrough } = capture;
|
|
31
|
+
if (offset === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
if (event.type !== "toolcall_delta")
|
|
34
|
+
return { type: event.type, contentIndex, delta: event.delta, offset };
|
|
35
|
+
if (parsedThrough === undefined)
|
|
36
|
+
return undefined;
|
|
37
|
+
return { type: event.type, contentIndex, delta: event.delta, offset, parsedThrough };
|
|
38
|
+
}
|
|
39
|
+
const { block, coveredCodeUnits } = capture;
|
|
40
|
+
if (event.type === "toolcall_end")
|
|
41
|
+
return block?.type === "toolCall" ? { type: event.type, contentIndex, toolCall: block } : undefined;
|
|
42
|
+
if (event.type === "text_end")
|
|
43
|
+
return block?.type === "text" ? { type: event.type, contentIndex, content: event.content, block } : undefined;
|
|
44
|
+
if (event.type === "thinking_end")
|
|
45
|
+
return block?.type === "thinking" ? { type: event.type, contentIndex, content: event.content, block } : undefined;
|
|
46
|
+
if (coveredCodeUnits === undefined)
|
|
47
|
+
return undefined;
|
|
48
|
+
if (event.type === "text_start")
|
|
49
|
+
return block?.type === "text" ? { type: event.type, contentIndex, seed: { block, coveredCodeUnits } } : undefined;
|
|
50
|
+
if (event.type === "thinking_start")
|
|
51
|
+
return block?.type === "thinking"
|
|
52
|
+
? { type: event.type, contentIndex, seed: { block, coveredCodeUnits } }
|
|
53
|
+
: undefined;
|
|
54
|
+
const { rawArgumentPrefix, parsedThrough } = capture;
|
|
55
|
+
if (block?.type !== "toolCall" || rawArgumentPrefix === undefined || parsedThrough === undefined)
|
|
56
|
+
return undefined;
|
|
57
|
+
return {
|
|
58
|
+
type: event.type,
|
|
59
|
+
contentIndex,
|
|
60
|
+
id: block.id,
|
|
61
|
+
toolName: block.name,
|
|
62
|
+
seed: { block, rawArgumentPrefix, parsedThrough, coveredCodeUnits },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* An assistant record with no capture has no seeded form (`undefined`): its producer captured nothing, so any
|
|
67
|
+
* seed would be read from the live partial and could already hold later bytes. Identity is never invented.
|
|
68
|
+
*/
|
|
69
|
+
function toSeededJsonEvent(event) {
|
|
70
|
+
if ((event.type === "message_start" || event.type === "message_end") && event.message.role === "assistant") {
|
|
71
|
+
const message = getAssistantCapture(event)?.message;
|
|
72
|
+
if (message)
|
|
73
|
+
return { ...event, message };
|
|
74
|
+
// The terminal message is complete when emitted; only an uncaptured start may already hold later bytes.
|
|
75
|
+
return event.type === "message_end" ? event : undefined;
|
|
76
|
+
}
|
|
77
|
+
if (event.type !== "message_update")
|
|
78
|
+
return event;
|
|
79
|
+
const capture = getAssistantCapture(event);
|
|
80
|
+
const assistantMessageEvent = capture && toSeededAssistantEvent(event.assistantMessageEvent, capture);
|
|
81
|
+
if (!capture || !assistantMessageEvent)
|
|
82
|
+
return undefined;
|
|
83
|
+
const { message: _message, assistantMessageEvent: _event, ...outer } = event;
|
|
84
|
+
const changed = capture.metadata !== undefined && Object.keys(capture.metadata).length > 0;
|
|
85
|
+
return {
|
|
86
|
+
...outer,
|
|
87
|
+
usage: capture.usage,
|
|
88
|
+
...(changed ? { messageMetadata: capture.metadata } : {}),
|
|
89
|
+
assistantMessageEvent,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export function toJsonEvent(event, options) {
|
|
93
|
+
if (options)
|
|
94
|
+
return toSeededJsonEvent(event);
|
|
17
95
|
if (event.type !== "message_update") {
|
|
18
96
|
return event;
|
|
19
97
|
}
|