@narumitw/pi-subagents 2.1.4 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -1228
- package/dist/child-communication-bridge.ts +136 -0
- package/dist/child-communication-bridge.ts.map +7 -0
- package/dist/chunks/chunk-UKTWUQRM.js +667 -0
- package/dist/chunks/chunk-UKTWUQRM.js.map +7 -0
- package/dist/index.ts +1448 -1614
- package/dist/index.ts.map +4 -4
- package/docs/design-principles.md +31 -0
- package/docs/ipc-transport-idea.md +103 -0
- package/docs/tools.md +109 -0
- package/package.json +11 -19
- package/src/broker-credentials.ts +71 -0
- package/src/child-communication-bridge.ts +153 -0
- package/src/child-communication-tools.ts +147 -0
- package/src/completion-renderer.ts +60 -0
- package/src/index.ts +1 -1
- package/src/message-broker.ts +628 -0
- package/src/model-output.ts +42 -0
- package/src/process.ts +688 -0
- package/src/runtime.ts +538 -0
- package/src/subagents.ts +33 -34
- package/src/tools.ts +416 -0
- package/src/types.ts +85 -0
- package/src/widget.ts +130 -0
- package/dist/chunks/auto-transport-FUUKFDIG.ts +0 -109
- package/dist/chunks/auto-transport-FUUKFDIG.ts.map +0 -7
- package/dist/chunks/capability-grant-PR72SWWS.ts +0 -19
- package/dist/chunks/capability-grant-PR72SWWS.ts.map +0 -7
- package/dist/chunks/child-peer-bridge.ts +0 -108
- package/dist/chunks/child-peer-bridge.ts.map +0 -7
- package/dist/chunks/chunk-2LMJU25E.ts +0 -1641
- package/dist/chunks/chunk-2LMJU25E.ts.map +0 -7
- package/dist/chunks/chunk-47SK2QYC.ts +0 -56
- package/dist/chunks/chunk-47SK2QYC.ts.map +0 -7
- package/dist/chunks/chunk-4AQSF7AS.ts +0 -29
- package/dist/chunks/chunk-4AQSF7AS.ts.map +0 -7
- package/dist/chunks/chunk-5DGRMKNV.ts +0 -126
- package/dist/chunks/chunk-5DGRMKNV.ts.map +0 -7
- package/dist/chunks/chunk-6H6TBBED.ts +0 -108
- package/dist/chunks/chunk-6H6TBBED.ts.map +0 -7
- package/dist/chunks/chunk-6KJ34M6S.ts +0 -159
- package/dist/chunks/chunk-6KJ34M6S.ts.map +0 -7
- package/dist/chunks/chunk-6NSJVPXX.ts +0 -480
- package/dist/chunks/chunk-6NSJVPXX.ts.map +0 -7
- package/dist/chunks/chunk-7AAJEUSL.ts +0 -238
- package/dist/chunks/chunk-7AAJEUSL.ts.map +0 -7
- package/dist/chunks/chunk-BFK2Z4ZF.ts +0 -189
- package/dist/chunks/chunk-BFK2Z4ZF.ts.map +0 -7
- package/dist/chunks/chunk-BOAXY55Y.ts +0 -153
- package/dist/chunks/chunk-BOAXY55Y.ts.map +0 -7
- package/dist/chunks/chunk-D4CR7T73.ts +0 -353
- package/dist/chunks/chunk-D4CR7T73.ts.map +0 -7
- package/dist/chunks/chunk-FEVPWRMU.ts +0 -300
- package/dist/chunks/chunk-FEVPWRMU.ts.map +0 -7
- package/dist/chunks/chunk-G6VZTCFH.ts +0 -70
- package/dist/chunks/chunk-G6VZTCFH.ts.map +0 -7
- package/dist/chunks/chunk-H3FP6DLR.ts +0 -160
- package/dist/chunks/chunk-H3FP6DLR.ts.map +0 -7
- package/dist/chunks/chunk-HA36LPCO.ts +0 -130
- package/dist/chunks/chunk-HA36LPCO.ts.map +0 -7
- package/dist/chunks/chunk-HOP5FXDT.ts +0 -27
- package/dist/chunks/chunk-HOP5FXDT.ts.map +0 -7
- package/dist/chunks/chunk-IGAMVWFN.ts +0 -139
- package/dist/chunks/chunk-IGAMVWFN.ts.map +0 -7
- package/dist/chunks/chunk-ILEQ27AL.ts +0 -45
- package/dist/chunks/chunk-ILEQ27AL.ts.map +0 -7
- package/dist/chunks/chunk-ITVWPNU4.ts +0 -819
- package/dist/chunks/chunk-ITVWPNU4.ts.map +0 -7
- package/dist/chunks/chunk-IWC32VPY.ts +0 -172
- package/dist/chunks/chunk-IWC32VPY.ts.map +0 -7
- package/dist/chunks/chunk-JSZIP73U.ts +0 -362
- package/dist/chunks/chunk-JSZIP73U.ts.map +0 -7
- package/dist/chunks/chunk-JU6LUNLP.ts +0 -380
- package/dist/chunks/chunk-JU6LUNLP.ts.map +0 -7
- package/dist/chunks/chunk-KMGKCEO4.ts +0 -38
- package/dist/chunks/chunk-KMGKCEO4.ts.map +0 -7
- package/dist/chunks/chunk-LASD73CM.ts +0 -339
- package/dist/chunks/chunk-LASD73CM.ts.map +0 -7
- package/dist/chunks/chunk-LEOYDZI3.ts +0 -22
- package/dist/chunks/chunk-LEOYDZI3.ts.map +0 -7
- package/dist/chunks/chunk-LL4LP2T7.ts +0 -737
- package/dist/chunks/chunk-LL4LP2T7.ts.map +0 -7
- package/dist/chunks/chunk-N2T5IN4X.ts +0 -18
- package/dist/chunks/chunk-N2T5IN4X.ts.map +0 -7
- package/dist/chunks/chunk-N7BLVXKK.ts +0 -73
- package/dist/chunks/chunk-N7BLVXKK.ts.map +0 -7
- package/dist/chunks/chunk-NLT67IZS.ts +0 -322
- package/dist/chunks/chunk-NLT67IZS.ts.map +0 -7
- package/dist/chunks/chunk-NTRPLF46.ts +0 -63
- package/dist/chunks/chunk-NTRPLF46.ts.map +0 -7
- package/dist/chunks/chunk-ONDTY4EL.ts +0 -91
- package/dist/chunks/chunk-ONDTY4EL.ts.map +0 -7
- package/dist/chunks/chunk-OVPHFGKO.ts +0 -1769
- package/dist/chunks/chunk-OVPHFGKO.ts.map +0 -7
- package/dist/chunks/chunk-P7OH4XMF.ts +0 -60
- package/dist/chunks/chunk-P7OH4XMF.ts.map +0 -7
- package/dist/chunks/chunk-PBZMBTNJ.ts +0 -422
- package/dist/chunks/chunk-PBZMBTNJ.ts.map +0 -7
- package/dist/chunks/chunk-PGLSFLYW.ts +0 -52
- package/dist/chunks/chunk-PGLSFLYW.ts.map +0 -7
- package/dist/chunks/chunk-RRR66UWR.ts +0 -28
- package/dist/chunks/chunk-RRR66UWR.ts.map +0 -7
- package/dist/chunks/chunk-RSUXZD6S.ts +0 -275
- package/dist/chunks/chunk-RSUXZD6S.ts.map +0 -7
- package/dist/chunks/chunk-RTCVYIZA.ts +0 -221
- package/dist/chunks/chunk-RTCVYIZA.ts.map +0 -7
- package/dist/chunks/chunk-RY2AEGMZ.ts +0 -34
- package/dist/chunks/chunk-RY2AEGMZ.ts.map +0 -7
- package/dist/chunks/chunk-SWGQLFSD.ts +0 -60
- package/dist/chunks/chunk-SWGQLFSD.ts.map +0 -7
- package/dist/chunks/chunk-TM2R67J3.ts +0 -52
- package/dist/chunks/chunk-TM2R67J3.ts.map +0 -7
- package/dist/chunks/chunk-TMZRHIIK.ts +0 -497
- package/dist/chunks/chunk-TMZRHIIK.ts.map +0 -7
- package/dist/chunks/chunk-TZ34IQ3M.ts +0 -59
- package/dist/chunks/chunk-TZ34IQ3M.ts.map +0 -7
- package/dist/chunks/chunk-UMBPMVJW.ts +0 -22
- package/dist/chunks/chunk-UMBPMVJW.ts.map +0 -7
- package/dist/chunks/chunk-VDG7LTYE.ts +0 -80
- package/dist/chunks/chunk-VDG7LTYE.ts.map +0 -7
- package/dist/chunks/chunk-X4NMONPE.ts +0 -73
- package/dist/chunks/chunk-X4NMONPE.ts.map +0 -7
- package/dist/chunks/chunk-YPJEN6NU.ts +0 -65
- package/dist/chunks/chunk-YPJEN6NU.ts.map +0 -7
- package/dist/chunks/chunk-YU53SHA7.ts +0 -328
- package/dist/chunks/chunk-YU53SHA7.ts.map +0 -7
- package/dist/chunks/completion-delivery-RSJU6BXL.ts +0 -17
- package/dist/chunks/completion-delivery-RSJU6BXL.ts.map +0 -7
- package/dist/chunks/config-status-FKGDECZ3.ts +0 -35
- package/dist/chunks/config-status-FKGDECZ3.ts.map +0 -7
- package/dist/chunks/config-ui-ABHYNGQ7.ts +0 -1212
- package/dist/chunks/config-ui-ABHYNGQ7.ts.map +0 -7
- package/dist/chunks/consult-LJU3IQY5.ts +0 -519
- package/dist/chunks/consult-LJU3IQY5.ts.map +0 -7
- package/dist/chunks/context-QDKLVQXE.ts +0 -11
- package/dist/chunks/context-QDKLVQXE.ts.map +0 -7
- package/dist/chunks/create-stateful-transport-JWC2EFYL.ts +0 -130
- package/dist/chunks/create-stateful-transport-JWC2EFYL.ts.map +0 -7
- package/dist/chunks/cwd-policy-NB6XZ5GF.ts +0 -17
- package/dist/chunks/cwd-policy-NB6XZ5GF.ts.map +0 -7
- package/dist/chunks/delegation-contract-LA56I5DT.ts +0 -24
- package/dist/chunks/delegation-contract-LA56I5DT.ts.map +0 -7
- package/dist/chunks/discovery-MIFB2U4Y.ts +0 -12
- package/dist/chunks/discovery-MIFB2U4Y.ts.map +0 -7
- package/dist/chunks/execution-Q2JZLKJA.ts +0 -4037
- package/dist/chunks/execution-Q2JZLKJA.ts.map +0 -7
- package/dist/chunks/in-process-transport-HJ6TZXC3.ts +0 -39
- package/dist/chunks/in-process-transport-HJ6TZXC3.ts.map +0 -7
- package/dist/chunks/inspect-UH2TKH6E.ts +0 -634
- package/dist/chunks/inspect-UH2TKH6E.ts.map +0 -7
- package/dist/chunks/peer-communication-KL36Z6CO.ts +0 -294
- package/dist/chunks/peer-communication-KL36Z6CO.ts.map +0 -7
- package/dist/chunks/persistence-UY3PY6E5.ts +0 -348
- package/dist/chunks/persistence-UY3PY6E5.ts.map +0 -7
- package/dist/chunks/registry-BT54L6CY.ts +0 -1445
- package/dist/chunks/registry-BT54L6CY.ts.map +0 -7
- package/dist/chunks/retained-semantic-state-GM75FZGE.ts +0 -81
- package/dist/chunks/retained-semantic-state-GM75FZGE.ts.map +0 -7
- package/dist/chunks/rpc-transport-7R7DVCEB.ts +0 -1222
- package/dist/chunks/rpc-transport-7R7DVCEB.ts.map +0 -7
- package/dist/chunks/runtime-policy-5YELCOVC.ts +0 -15
- package/dist/chunks/runtime-policy-5YELCOVC.ts.map +0 -7
- package/dist/chunks/semantic-snapshot-WPJ3UAFW.ts +0 -19
- package/dist/chunks/semantic-snapshot-WPJ3UAFW.ts.map +0 -7
- package/dist/chunks/spawn-idempotency-BNHOSMZW.ts +0 -13
- package/dist/chunks/spawn-idempotency-BNHOSMZW.ts.map +0 -7
- package/dist/chunks/stateful-lifecycle-JAR6K55H.ts +0 -15
- package/dist/chunks/stateful-lifecycle-JAR6K55H.ts.map +0 -7
- package/dist/chunks/subprocess-transport-VHZJRBTW.ts +0 -160
- package/dist/chunks/subprocess-transport-VHZJRBTW.ts.map +0 -7
- package/dist/chunks/usage-recording-store-CW3EH2SZ.ts +0 -164
- package/dist/chunks/usage-recording-store-CW3EH2SZ.ts.map +0 -7
- package/dist/chunks/workspace-WDKLN72J.ts +0 -11
- package/dist/chunks/workspace-WDKLN72J.ts.map +0 -7
- package/docs/async-runtime-protocol.md +0 -84
- package/docs/implementation-notes/pi-subagents-capability-matrix.md +0 -62
- package/docs/implementation-notes/pi-subagents-current-direction.md +0 -99
- package/docs/implementation-notes/pi-subagents-rpc-v1.md +0 -139
- package/docs/pi-subagents-diagrams.md +0 -183
- package/src/adaptive-scheduler.ts +0 -224
- package/src/admission-policy.ts +0 -78
- package/src/agent-projection.ts +0 -53
- package/src/agents/built-ins.ts +0 -71
- package/src/agents/catalog.ts +0 -241
- package/src/agents/discovery.ts +0 -265
- package/src/agents/types.ts +0 -100
- package/src/agents.ts +0 -51
- package/src/auto-transport.ts +0 -121
- package/src/blocking-status.ts +0 -63
- package/src/cached-module-loader.ts +0 -18
- package/src/capabilities.ts +0 -145
- package/src/capability-grant.ts +0 -115
- package/src/capability-router.ts +0 -107
- package/src/child-peer-bridge.ts +0 -124
- package/src/child-peer-tools.ts +0 -132
- package/src/completion-delivery.ts +0 -409
- package/src/completion-render.ts +0 -190
- package/src/completion-requirement.ts +0 -479
- package/src/completion-routing.ts +0 -24
- package/src/config-registration.ts +0 -114
- package/src/config-status.ts +0 -217
- package/src/config-ui.ts +0 -983
- package/src/consult-policy.ts +0 -15
- package/src/consult-registration.ts +0 -125
- package/src/consult-render.ts +0 -194
- package/src/consult-resources.ts +0 -51
- package/src/consult-tool.ts +0 -95
- package/src/consult.ts +0 -566
- package/src/context.ts +0 -126
- package/src/create-stateful-transport.ts +0 -157
- package/src/cwd-policy.ts +0 -183
- package/src/delegation-contract.ts +0 -463
- package/src/execution/budget.ts +0 -56
- package/src/execution/runtime-policy.ts +0 -19
- package/src/execution-plan.ts +0 -322
- package/src/execution-ui.ts +0 -259
- package/src/execution.ts +0 -1679
- package/src/in-process-transport.ts +0 -941
- package/src/inspect-registration.ts +0 -64
- package/src/inspect-render.ts +0 -334
- package/src/inspect-tool.ts +0 -45
- package/src/inspect.ts +0 -769
- package/src/integration-controller.ts +0 -98
- package/src/limits.ts +0 -75
- package/src/orchestration-metrics.ts +0 -116
- package/src/outcome.ts +0 -61
- package/src/panel-child-group.ts +0 -35
- package/src/panel-contract.ts +0 -343
- package/src/panel-evidence.ts +0 -59
- package/src/panel-execution.ts +0 -769
- package/src/panel-failure.ts +0 -56
- package/src/panel-planning.ts +0 -175
- package/src/panel-presets.ts +0 -3
- package/src/panel-prompts.ts +0 -132
- package/src/panel-reconciliation.ts +0 -57
- package/src/panel-render.ts +0 -103
- package/src/parallel-limit-ui.ts +0 -113
- package/src/params.ts +0 -278
- package/src/peer-communication.ts +0 -352
- package/src/peer-transport.ts +0 -49
- package/src/persistence.ts +0 -522
- package/src/pi-args.ts +0 -43
- package/src/pi-invocation.ts +0 -168
- package/src/process-control.ts +0 -43
- package/src/prompt-resources.ts +0 -38
- package/src/prompt-source-safety.ts +0 -48
- package/src/protocol.ts +0 -76
- package/src/registry-types.ts +0 -204
- package/src/registry.ts +0 -1698
- package/src/render-common.ts +0 -252
- package/src/render.ts +0 -704
- package/src/result-contract.ts +0 -431
- package/src/retained-semantic-state.ts +0 -100
- package/src/rpc-timeout-finalization.ts +0 -207
- package/src/rpc-transport-metadata.ts +0 -65
- package/src/rpc-transport.ts +0 -1035
- package/src/rpc-turn-capture.ts +0 -217
- package/src/runner-outcome.ts +0 -31
- package/src/runner-result.ts +0 -55
- package/src/runner-types.ts +0 -102
- package/src/runner-usage.ts +0 -48
- package/src/runner.ts +0 -866
- package/src/safe-text.ts +0 -67
- package/src/semantic-snapshot.ts +0 -214
- package/src/session-guidance-contract.ts +0 -399
- package/src/settings/inspection.ts +0 -302
- package/src/settings/schema.ts +0 -195
- package/src/settings-reader.ts +0 -215
- package/src/settings.ts +0 -452
- package/src/spawn-idempotency.ts +0 -68
- package/src/stateful-agent-view.ts +0 -85
- package/src/stateful-config.ts +0 -13
- package/src/stateful-guidance.ts +0 -29
- package/src/stateful-lifecycle.ts +0 -74
- package/src/stateful-limit-ui.ts +0 -249
- package/src/stateful-limits.ts +0 -96
- package/src/stateful-prompt.ts +0 -49
- package/src/stateful-registration.ts +0 -1320
- package/src/stateful-render.ts +0 -318
- package/src/stateful-safety.ts +0 -47
- package/src/stateful-tool-params.ts +0 -215
- package/src/stateful.ts +0 -12
- package/src/subagent-details.ts +0 -43
- package/src/subagents-extension.ts +0 -372
- package/src/subprocess-transport.ts +0 -145
- package/src/supervision.ts +0 -104
- package/src/task-path.ts +0 -65
- package/src/timeout-checkpoint.ts +0 -305
- package/src/timeout-finalization.ts +0 -75
- package/src/tool-schema-compatibility.ts +0 -73
- package/src/transport-types.ts +0 -74
- package/src/transport-ui.ts +0 -135
- package/src/transport.ts +0 -43
- package/src/turn-budget.ts +0 -109
- package/src/usage-format.ts +0 -42
- package/src/usage-recording-config.ts +0 -13
- package/src/usage-recording-store.ts +0 -183
- package/src/usage-recording.ts +0 -478
- package/src/verification-harness.ts +0 -516
- package/src/verification-policy.ts +0 -67
- package/src/verification-receipt.ts +0 -275
- package/src/verified-execution-benchmark.ts +0 -86
- package/src/verified-execution-contract.ts +0 -191
- package/src/verified-execution-schema.ts +0 -32
- package/src/work-item-ledger.ts +0 -1404
- package/src/work-item-persistence.ts +0 -254
- package/src/workflow-completion-controller.ts +0 -397
- package/src/workflow-planning.ts +0 -172
- package/src/workflow-tree-identity.ts +0 -289
- package/src/workflow-ui.ts +0 -69
- package/src/workflow-verification.ts +0 -296
- package/src/workspace.ts +0 -174
package/src/usage-recording.ts
DELETED
|
@@ -1,478 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { type ExtensionAPI, getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
import type { AgentTurnCompletion, ManagedAgent } from "./registry-types.js";
|
|
5
|
-
import type { TransportUsage } from "./transport-types.js";
|
|
6
|
-
import {
|
|
7
|
-
USAGE_RECORDING_DIRECTORY,
|
|
8
|
-
USAGE_RECORDING_RETENTION_DAYS,
|
|
9
|
-
USAGE_RECORDING_STUDY_ID,
|
|
10
|
-
} from "./usage-recording-config.js";
|
|
11
|
-
import type { UsageEventStorePort } from "./usage-recording-store.js";
|
|
12
|
-
|
|
13
|
-
const SHUTDOWN_FLUSH_MS = 2_500;
|
|
14
|
-
|
|
15
|
-
const SUBAGENT_TOOLS = new Set([
|
|
16
|
-
"subagent",
|
|
17
|
-
"subagent_spawn",
|
|
18
|
-
"subagent_send",
|
|
19
|
-
"subagent_manage",
|
|
20
|
-
"subagent_mailbox",
|
|
21
|
-
"subagent_inspect",
|
|
22
|
-
"subagent_consult",
|
|
23
|
-
"subagent_await",
|
|
24
|
-
]);
|
|
25
|
-
|
|
26
|
-
export type UsageSurfaceArm = "all" | "async-only" | "blocking-only" | "disabled";
|
|
27
|
-
|
|
28
|
-
type UsageEventType =
|
|
29
|
-
| "study_exposure"
|
|
30
|
-
| "parent_turn_start"
|
|
31
|
-
| "parent_turn_end"
|
|
32
|
-
| "tool_start"
|
|
33
|
-
| "tool_end"
|
|
34
|
-
| "child_run_start"
|
|
35
|
-
| "child_run_end"
|
|
36
|
-
| "completion_transition"
|
|
37
|
-
| "lifecycle";
|
|
38
|
-
|
|
39
|
-
interface UsageEvent {
|
|
40
|
-
schemaVersion: 1;
|
|
41
|
-
studyId: typeof USAGE_RECORDING_STUDY_ID;
|
|
42
|
-
surfaceArm: UsageSurfaceArm;
|
|
43
|
-
logicalSession: string;
|
|
44
|
-
runtimeInstance: string;
|
|
45
|
-
branchEpoch: number;
|
|
46
|
-
turnId?: string;
|
|
47
|
-
eventSequence: number;
|
|
48
|
-
monotonicOffsetMs: number;
|
|
49
|
-
eventType: UsageEventType;
|
|
50
|
-
data: Record<string, boolean | number | string>;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface UsageRecordingStatus {
|
|
54
|
-
enabled: boolean;
|
|
55
|
-
initialized: boolean;
|
|
56
|
-
retentionDays: number;
|
|
57
|
-
path: string;
|
|
58
|
-
recordedEvents: number;
|
|
59
|
-
writeFailure: boolean;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface UsageRecordingController {
|
|
63
|
-
startSession(input: {
|
|
64
|
-
enabled: boolean;
|
|
65
|
-
surfaceArm: UsageSurfaceArm;
|
|
66
|
-
reason: "startup" | "reload" | "new" | "resume" | "fork";
|
|
67
|
-
onWarning?: (message: string) => void;
|
|
68
|
-
}): Promise<void>;
|
|
69
|
-
shutdown(reason: "quit" | "reload" | "new" | "resume" | "fork"): Promise<void>;
|
|
70
|
-
setEnabled(value: boolean): Promise<void>;
|
|
71
|
-
getStatus(): UsageRecordingStatus;
|
|
72
|
-
observeAgents(agents: readonly ManagedAgent[]): void;
|
|
73
|
-
recordChildCompletion(completion: AgentTurnCompletion): void;
|
|
74
|
-
recordCompletionDeliveryAttempt(
|
|
75
|
-
completion: AgentTurnCompletion,
|
|
76
|
-
input: {
|
|
77
|
-
delivery: "steer" | "nextTurn";
|
|
78
|
-
triggerTurn: boolean;
|
|
79
|
-
outcome: "accepted" | "failed";
|
|
80
|
-
},
|
|
81
|
-
): void;
|
|
82
|
-
recordCompletionVisible(completion: AgentTurnCompletion): void;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export interface UsageRecordingDependencies {
|
|
86
|
-
createId(): string;
|
|
87
|
-
monotonicNow(): number;
|
|
88
|
-
getAgentDir(): string;
|
|
89
|
-
loadStore(): Promise<{
|
|
90
|
-
UsageEventStore: new (path: string) => UsageEventStorePort;
|
|
91
|
-
}>;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function registerUsageRecording(
|
|
95
|
-
pi: ExtensionAPI,
|
|
96
|
-
dependencies: Partial<UsageRecordingDependencies> = {},
|
|
97
|
-
): UsageRecordingController {
|
|
98
|
-
const deps: UsageRecordingDependencies = {
|
|
99
|
-
createId: dependencies.createId ?? randomUUID,
|
|
100
|
-
monotonicNow: dependencies.monotonicNow ?? performance.now.bind(performance),
|
|
101
|
-
getAgentDir: dependencies.getAgentDir ?? getAgentDir,
|
|
102
|
-
loadStore: dependencies.loadStore ?? (() => import("./usage-recording-store.js")),
|
|
103
|
-
};
|
|
104
|
-
const pathValue = path.join(deps.getAgentDir(), USAGE_RECORDING_DIRECTORY);
|
|
105
|
-
const runtimeInstance = deps.createId();
|
|
106
|
-
let logicalSession = deps.createId();
|
|
107
|
-
let branchEpoch = 0;
|
|
108
|
-
let surfaceArm: UsageSurfaceArm = "disabled";
|
|
109
|
-
let sessionStartedAt = deps.monotonicNow();
|
|
110
|
-
let enabled = false;
|
|
111
|
-
let eventSequence = 0;
|
|
112
|
-
let recordedEvents = 0;
|
|
113
|
-
let writeFailure = false;
|
|
114
|
-
let warningActive = false;
|
|
115
|
-
let onWarning: ((message: string) => void) | undefined;
|
|
116
|
-
let storePromise: Promise<UsageEventStorePort> | undefined;
|
|
117
|
-
let writeGeneration = 0;
|
|
118
|
-
let writeTail: Promise<void> = Promise.resolve();
|
|
119
|
-
let transitionTail: Promise<void> = Promise.resolve();
|
|
120
|
-
let currentTurnId: string | undefined;
|
|
121
|
-
let turnOrdinal = 0;
|
|
122
|
-
let operationOrdinal = 0;
|
|
123
|
-
let childOrdinal = 0;
|
|
124
|
-
let runOrdinal = 0;
|
|
125
|
-
let completionOrdinal = 0;
|
|
126
|
-
const operations = new Map<string, { id: string; startedAt: number }>();
|
|
127
|
-
const children = new Map<string, string>();
|
|
128
|
-
const runs = new Map<string, string>();
|
|
129
|
-
const completions = new Map<string, string>();
|
|
130
|
-
const agentStates = new Map<string, string>();
|
|
131
|
-
const activeRuns = new Map<string, string>();
|
|
132
|
-
|
|
133
|
-
pi.on("agent_start", () => record("lifecycle", { phase: "parent_agent_start" }));
|
|
134
|
-
pi.on("agent_settled", () => record("lifecycle", { phase: "parent_agent_settled" }));
|
|
135
|
-
pi.on("turn_start", () => {
|
|
136
|
-
currentTurnId = `turn-${++turnOrdinal}`;
|
|
137
|
-
record("parent_turn_start", { turnOrdinal }, currentTurnId);
|
|
138
|
-
});
|
|
139
|
-
pi.on("turn_end", (event) => {
|
|
140
|
-
record(
|
|
141
|
-
"parent_turn_end",
|
|
142
|
-
{
|
|
143
|
-
turnOrdinal,
|
|
144
|
-
...usageNumbers(event.message.role === "assistant" ? event.message.usage : undefined),
|
|
145
|
-
},
|
|
146
|
-
currentTurnId,
|
|
147
|
-
);
|
|
148
|
-
currentTurnId = undefined;
|
|
149
|
-
});
|
|
150
|
-
pi.on("tool_execution_start", (event) => {
|
|
151
|
-
if (!SUBAGENT_TOOLS.has(event.toolName)) return;
|
|
152
|
-
const operationId = `tool-${++operationOrdinal}`;
|
|
153
|
-
operations.set(event.toolCallId, { id: operationId, startedAt: offset() });
|
|
154
|
-
record("tool_start", { operationId, tool: event.toolName }, currentTurnId);
|
|
155
|
-
});
|
|
156
|
-
pi.on("tool_execution_end", (event) => {
|
|
157
|
-
if (!SUBAGENT_TOOLS.has(event.toolName)) return;
|
|
158
|
-
const operation = operations.get(event.toolCallId);
|
|
159
|
-
operations.delete(event.toolCallId);
|
|
160
|
-
record(
|
|
161
|
-
"tool_end",
|
|
162
|
-
{
|
|
163
|
-
operationId: operation?.id ?? `tool-${++operationOrdinal}`,
|
|
164
|
-
tool: event.toolName,
|
|
165
|
-
isError: event.isError,
|
|
166
|
-
...(operation ? { durationMs: Math.max(0, offset() - operation.startedAt) } : {}),
|
|
167
|
-
...usageNumbers(event.result?.usage),
|
|
168
|
-
},
|
|
169
|
-
currentTurnId,
|
|
170
|
-
);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const controller: UsageRecordingController = {
|
|
174
|
-
startSession(input) {
|
|
175
|
-
return serializeTransition(async () => {
|
|
176
|
-
enabled = false;
|
|
177
|
-
await closeStore();
|
|
178
|
-
logicalSession = deps.createId();
|
|
179
|
-
branchEpoch += 1;
|
|
180
|
-
surfaceArm = input.surfaceArm;
|
|
181
|
-
sessionStartedAt = deps.monotonicNow();
|
|
182
|
-
eventSequence = 0;
|
|
183
|
-
recordedEvents = 0;
|
|
184
|
-
writeFailure = false;
|
|
185
|
-
warningActive = false;
|
|
186
|
-
onWarning = input.onWarning;
|
|
187
|
-
currentTurnId = undefined;
|
|
188
|
-
turnOrdinal = 0;
|
|
189
|
-
operationOrdinal = 0;
|
|
190
|
-
childOrdinal = 0;
|
|
191
|
-
runOrdinal = 0;
|
|
192
|
-
completionOrdinal = 0;
|
|
193
|
-
operations.clear();
|
|
194
|
-
children.clear();
|
|
195
|
-
runs.clear();
|
|
196
|
-
completions.clear();
|
|
197
|
-
agentStates.clear();
|
|
198
|
-
activeRuns.clear();
|
|
199
|
-
enabled = input.enabled;
|
|
200
|
-
if (!enabled) return;
|
|
201
|
-
record("study_exposure", { reason: input.reason });
|
|
202
|
-
record("lifecycle", { phase: "session_start", reason: input.reason });
|
|
203
|
-
enqueue(async (store) => store.prune(USAGE_RECORDING_RETENTION_DAYS));
|
|
204
|
-
await writeTail;
|
|
205
|
-
});
|
|
206
|
-
},
|
|
207
|
-
shutdown(reason) {
|
|
208
|
-
return serializeTransition(async () => {
|
|
209
|
-
if (enabled) record("lifecycle", { phase: "session_shutdown", reason });
|
|
210
|
-
enabled = false;
|
|
211
|
-
await flushWithin(SHUTDOWN_FLUSH_MS);
|
|
212
|
-
await closeStore();
|
|
213
|
-
});
|
|
214
|
-
},
|
|
215
|
-
setEnabled(value) {
|
|
216
|
-
return serializeTransition(async () => {
|
|
217
|
-
if (value === enabled) return;
|
|
218
|
-
if (value) {
|
|
219
|
-
enabled = true;
|
|
220
|
-
record("study_exposure", { reason: "enabled_in_settings" });
|
|
221
|
-
record("lifecycle", { phase: "recording_enabled" });
|
|
222
|
-
enqueue(async (store) => store.prune(USAGE_RECORDING_RETENTION_DAYS));
|
|
223
|
-
await writeTail;
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
record("lifecycle", { phase: "recording_disabled" });
|
|
227
|
-
enabled = false;
|
|
228
|
-
await flushWithin(SHUTDOWN_FLUSH_MS);
|
|
229
|
-
await closeStore();
|
|
230
|
-
});
|
|
231
|
-
},
|
|
232
|
-
getStatus() {
|
|
233
|
-
return {
|
|
234
|
-
enabled,
|
|
235
|
-
initialized: storePromise !== undefined,
|
|
236
|
-
retentionDays: USAGE_RECORDING_RETENTION_DAYS,
|
|
237
|
-
path: pathValue,
|
|
238
|
-
recordedEvents,
|
|
239
|
-
writeFailure,
|
|
240
|
-
};
|
|
241
|
-
},
|
|
242
|
-
observeAgents(agents) {
|
|
243
|
-
if (!enabled) return;
|
|
244
|
-
for (const agent of agents) {
|
|
245
|
-
const childId = localChildId(agent.id);
|
|
246
|
-
if (agentStates.get(agent.id) !== agent.state) {
|
|
247
|
-
agentStates.set(agent.id, agent.state);
|
|
248
|
-
record("lifecycle", { phase: "child_state", childId, state: agent.state });
|
|
249
|
-
}
|
|
250
|
-
if (agent.currentRunId && activeRuns.get(agent.id) !== agent.currentRunId) {
|
|
251
|
-
activeRuns.set(agent.id, agent.currentRunId);
|
|
252
|
-
record("child_run_start", {
|
|
253
|
-
childId,
|
|
254
|
-
runId: localRunId(agent.currentRunId),
|
|
255
|
-
generation: agent.currentTurnGeneration ?? agent.turnGeneration ?? 0,
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
},
|
|
260
|
-
recordChildCompletion(completion) {
|
|
261
|
-
if (!enabled) return;
|
|
262
|
-
const childId = localChildId(completion.agent.id);
|
|
263
|
-
const runId = localRunId(completion.runId);
|
|
264
|
-
const timing = completion.agent.telemetry?.timing;
|
|
265
|
-
record("child_run_end", {
|
|
266
|
-
childId,
|
|
267
|
-
runId,
|
|
268
|
-
generation: completion.generation,
|
|
269
|
-
state: completion.agent.state,
|
|
270
|
-
...(completion.agent.outcome?.status
|
|
271
|
-
? { outcomeStatus: completion.agent.outcome.status }
|
|
272
|
-
: {}),
|
|
273
|
-
...(completion.agent.termination?.reason
|
|
274
|
-
? { terminationReason: completion.agent.termination.reason }
|
|
275
|
-
: {}),
|
|
276
|
-
...(completion.agent.telemetry?.budgetSource
|
|
277
|
-
? {
|
|
278
|
-
timeoutBudgetSource: completion.agent.telemetry.budgetSource.timeout,
|
|
279
|
-
idleTimeoutBudgetSource: completion.agent.telemetry.budgetSource.idleTimeout,
|
|
280
|
-
turnLimitBudgetSource: completion.agent.telemetry.budgetSource.turnLimit,
|
|
281
|
-
toolCallLimitBudgetSource: completion.agent.telemetry.budgetSource.toolCallLimit,
|
|
282
|
-
}
|
|
283
|
-
: {}),
|
|
284
|
-
...(timing?.startedAt !== undefined && timing.settledAt !== undefined
|
|
285
|
-
? { durationMs: Math.max(0, timing.settledAt - timing.startedAt) }
|
|
286
|
-
: {}),
|
|
287
|
-
...transportUsageNumbers(completion.agent.telemetry?.usage),
|
|
288
|
-
});
|
|
289
|
-
recordCompletion(completion, "persisted");
|
|
290
|
-
},
|
|
291
|
-
recordCompletionDeliveryAttempt(completion, input) {
|
|
292
|
-
recordCompletion(completion, "delivery_attempt", {
|
|
293
|
-
delivery: input.delivery,
|
|
294
|
-
triggerTurn: input.triggerTurn,
|
|
295
|
-
outcome: input.outcome,
|
|
296
|
-
});
|
|
297
|
-
},
|
|
298
|
-
recordCompletionVisible(completion) {
|
|
299
|
-
recordCompletion(completion, "visible");
|
|
300
|
-
},
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
return controller;
|
|
304
|
-
|
|
305
|
-
function record(
|
|
306
|
-
eventType: UsageEventType,
|
|
307
|
-
data: UsageEvent["data"],
|
|
308
|
-
turnId = currentTurnId,
|
|
309
|
-
): void {
|
|
310
|
-
if (!enabled) return;
|
|
311
|
-
const event: UsageEvent = {
|
|
312
|
-
schemaVersion: 1,
|
|
313
|
-
studyId: USAGE_RECORDING_STUDY_ID,
|
|
314
|
-
surfaceArm,
|
|
315
|
-
logicalSession,
|
|
316
|
-
runtimeInstance,
|
|
317
|
-
branchEpoch,
|
|
318
|
-
...(turnId ? { turnId } : {}),
|
|
319
|
-
eventSequence: ++eventSequence,
|
|
320
|
-
monotonicOffsetMs: offset(),
|
|
321
|
-
eventType,
|
|
322
|
-
data,
|
|
323
|
-
};
|
|
324
|
-
enqueue(async (store) => store.append(event), true);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function recordCompletion(
|
|
328
|
-
completion: AgentTurnCompletion,
|
|
329
|
-
transition: "persisted" | "delivery_attempt" | "visible",
|
|
330
|
-
extra: UsageEvent["data"] = {},
|
|
331
|
-
): void {
|
|
332
|
-
if (!enabled) return;
|
|
333
|
-
record("completion_transition", {
|
|
334
|
-
completionId: localCompletionId(completion.completionId),
|
|
335
|
-
childId: localChildId(completion.agent.id),
|
|
336
|
-
runId: localRunId(completion.runId),
|
|
337
|
-
generation: completion.generation,
|
|
338
|
-
transition,
|
|
339
|
-
...extra,
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function enqueue(
|
|
344
|
-
operation: (store: UsageEventStorePort) => Promise<void>,
|
|
345
|
-
countsAsEvent = false,
|
|
346
|
-
): void {
|
|
347
|
-
const generation = writeGeneration;
|
|
348
|
-
const task = writeTail.then(async () => {
|
|
349
|
-
if (generation !== writeGeneration) return false;
|
|
350
|
-
await operation(await ensureStore());
|
|
351
|
-
return true;
|
|
352
|
-
});
|
|
353
|
-
writeTail = task.then(
|
|
354
|
-
(completed) => {
|
|
355
|
-
if (completed && countsAsEvent) recordedEvents += 1;
|
|
356
|
-
writeFailure = false;
|
|
357
|
-
warningActive = false;
|
|
358
|
-
},
|
|
359
|
-
() => {
|
|
360
|
-
writeFailure = true;
|
|
361
|
-
if (!warningActive) {
|
|
362
|
-
warningActive = true;
|
|
363
|
-
safeWarn("Local subagent usage recording could not save an event; recording will retry.");
|
|
364
|
-
}
|
|
365
|
-
},
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
async function ensureStore(): Promise<UsageEventStorePort> {
|
|
370
|
-
storePromise ??= deps
|
|
371
|
-
.loadStore()
|
|
372
|
-
.then(({ UsageEventStore }) => new UsageEventStore(pathValue))
|
|
373
|
-
.catch((error: unknown) => {
|
|
374
|
-
storePromise = undefined;
|
|
375
|
-
throw error;
|
|
376
|
-
});
|
|
377
|
-
return storePromise;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function serializeTransition(operation: () => Promise<void>): Promise<void> {
|
|
381
|
-
const result = transitionTail.then(operation, operation);
|
|
382
|
-
transitionTail = result.catch(() => undefined);
|
|
383
|
-
return result;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
async function flushWithin(timeoutMs: number): Promise<void> {
|
|
387
|
-
let timer: NodeJS.Timeout | undefined;
|
|
388
|
-
try {
|
|
389
|
-
await Promise.race([
|
|
390
|
-
writeTail,
|
|
391
|
-
new Promise<void>((resolve) => {
|
|
392
|
-
timer = setTimeout(resolve, timeoutMs);
|
|
393
|
-
}),
|
|
394
|
-
]);
|
|
395
|
-
} finally {
|
|
396
|
-
if (timer) clearTimeout(timer);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
async function closeStore(): Promise<void> {
|
|
401
|
-
writeGeneration += 1;
|
|
402
|
-
const active = storePromise;
|
|
403
|
-
storePromise = undefined;
|
|
404
|
-
if (active) await active.then((store) => store.close()).catch(() => undefined);
|
|
405
|
-
await writeTail;
|
|
406
|
-
writeTail = Promise.resolve();
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
function localChildId(value: string): string {
|
|
410
|
-
return localId(children, value, "child", () => ++childOrdinal);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function localRunId(value: string): string {
|
|
414
|
-
return localId(runs, value, "run", () => ++runOrdinal);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
function localCompletionId(value: string): string {
|
|
418
|
-
return localId(completions, value, "completion", () => ++completionOrdinal);
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function offset(): number {
|
|
422
|
-
return Math.max(0, Math.round(deps.monotonicNow() - sessionStartedAt));
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
function safeWarn(message: string): void {
|
|
426
|
-
try {
|
|
427
|
-
onWarning?.(message);
|
|
428
|
-
} catch {
|
|
429
|
-
// A replaced UI cannot receive storage feedback.
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
function localId(
|
|
435
|
-
values: Map<string, string>,
|
|
436
|
-
raw: string,
|
|
437
|
-
prefix: string,
|
|
438
|
-
next: () => number,
|
|
439
|
-
): string {
|
|
440
|
-
const existing = values.get(raw);
|
|
441
|
-
if (existing) return existing;
|
|
442
|
-
const created = `${prefix}-${next()}`;
|
|
443
|
-
values.set(raw, created);
|
|
444
|
-
return created;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
function usageNumbers(value: unknown): Record<string, number> {
|
|
448
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
449
|
-
const record = value as Record<string, unknown>;
|
|
450
|
-
return numericFields(record, ["input", "output", "cacheRead", "cacheWrite"]);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
function transportUsageNumbers(value: TransportUsage | undefined): Record<string, number> {
|
|
454
|
-
if (!value) return {};
|
|
455
|
-
return numericFields(value as unknown as Record<string, unknown>, [
|
|
456
|
-
"input",
|
|
457
|
-
"output",
|
|
458
|
-
"cacheRead",
|
|
459
|
-
"cacheWrite",
|
|
460
|
-
"totalTokens",
|
|
461
|
-
"cost",
|
|
462
|
-
"turns",
|
|
463
|
-
]);
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
function numericFields(
|
|
467
|
-
record: Record<string, unknown>,
|
|
468
|
-
fields: readonly string[],
|
|
469
|
-
): Record<string, number> {
|
|
470
|
-
return Object.fromEntries(
|
|
471
|
-
fields.flatMap((field) => {
|
|
472
|
-
const value = record[field];
|
|
473
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0
|
|
474
|
-
? [[field, value] as const]
|
|
475
|
-
: [];
|
|
476
|
-
}),
|
|
477
|
-
);
|
|
478
|
-
}
|