condukt 0.26.0 → 0.27.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.
Files changed (83) hide show
  1. package/dist/runtimes/claude/bridge-cache.d.ts +58 -0
  2. package/dist/runtimes/claude/bridge-cache.d.ts.map +1 -0
  3. package/dist/runtimes/claude/bridge-cache.js +257 -0
  4. package/dist/runtimes/claude/bridge-cache.js.map +1 -0
  5. package/dist/runtimes/claude/claude-runtime.d.ts +30 -0
  6. package/dist/runtimes/claude/claude-runtime.d.ts.map +1 -0
  7. package/dist/runtimes/claude/claude-runtime.js +88 -0
  8. package/dist/runtimes/claude/claude-runtime.js.map +1 -0
  9. package/dist/runtimes/claude/claude-session.d.ts +154 -0
  10. package/dist/runtimes/claude/claude-session.d.ts.map +1 -0
  11. package/dist/runtimes/claude/claude-session.js +851 -0
  12. package/dist/runtimes/claude/claude-session.js.map +1 -0
  13. package/dist/runtimes/claude/config-mapper.d.ts +69 -0
  14. package/dist/runtimes/claude/config-mapper.d.ts.map +1 -0
  15. package/dist/runtimes/claude/config-mapper.js +458 -0
  16. package/dist/runtimes/claude/config-mapper.js.map +1 -0
  17. package/dist/runtimes/claude/epoch-store.d.ts +28 -0
  18. package/dist/runtimes/claude/epoch-store.d.ts.map +1 -0
  19. package/dist/runtimes/claude/epoch-store.js +199 -0
  20. package/dist/runtimes/claude/epoch-store.js.map +1 -0
  21. package/dist/runtimes/claude/fallback-runtime.d.ts +14 -0
  22. package/dist/runtimes/claude/fallback-runtime.d.ts.map +1 -0
  23. package/dist/runtimes/claude/fallback-runtime.js +64 -0
  24. package/dist/runtimes/claude/fallback-runtime.js.map +1 -0
  25. package/dist/runtimes/claude/index.d.ts +24 -0
  26. package/dist/runtimes/claude/index.d.ts.map +1 -0
  27. package/dist/runtimes/claude/index.js +61 -0
  28. package/dist/runtimes/claude/index.js.map +1 -0
  29. package/dist/runtimes/claude/message-mapper.d.ts +135 -0
  30. package/dist/runtimes/claude/message-mapper.d.ts.map +1 -0
  31. package/dist/runtimes/claude/message-mapper.js +504 -0
  32. package/dist/runtimes/claude/message-mapper.js.map +1 -0
  33. package/dist/runtimes/claude/one-shot.d.ts +48 -0
  34. package/dist/runtimes/claude/one-shot.d.ts.map +1 -0
  35. package/dist/runtimes/claude/one-shot.js +186 -0
  36. package/dist/runtimes/claude/one-shot.js.map +1 -0
  37. package/dist/runtimes/claude/protocol-bridge.d.ts +138 -0
  38. package/dist/runtimes/claude/protocol-bridge.d.ts.map +1 -0
  39. package/dist/runtimes/claude/protocol-bridge.js +1170 -0
  40. package/dist/runtimes/claude/protocol-bridge.js.map +1 -0
  41. package/dist/runtimes/claude/protocol-router.d.ts +113 -0
  42. package/dist/runtimes/claude/protocol-router.d.ts.map +1 -0
  43. package/dist/runtimes/claude/protocol-router.js +514 -0
  44. package/dist/runtimes/claude/protocol-router.js.map +1 -0
  45. package/dist/runtimes/claude/session-epoch.d.ts +156 -0
  46. package/dist/runtimes/claude/session-epoch.d.ts.map +1 -0
  47. package/dist/runtimes/claude/session-epoch.js +365 -0
  48. package/dist/runtimes/claude/session-epoch.js.map +1 -0
  49. package/dist/runtimes/claude/session-recovery.d.ts +78 -0
  50. package/dist/runtimes/claude/session-recovery.d.ts.map +1 -0
  51. package/dist/runtimes/claude/session-recovery.js +259 -0
  52. package/dist/runtimes/claude/session-recovery.js.map +1 -0
  53. package/dist/runtimes/claude/sse.d.ts +16 -0
  54. package/dist/runtimes/claude/sse.d.ts.map +1 -0
  55. package/dist/runtimes/claude/sse.js +46 -0
  56. package/dist/runtimes/claude/sse.js.map +1 -0
  57. package/dist/runtimes/claude/translate-chat.d.ts +106 -0
  58. package/dist/runtimes/claude/translate-chat.d.ts.map +1 -0
  59. package/dist/runtimes/claude/translate-chat.js +857 -0
  60. package/dist/runtimes/claude/translate-chat.js.map +1 -0
  61. package/dist/runtimes/claude/translate-responses.d.ts +76 -0
  62. package/dist/runtimes/claude/translate-responses.d.ts.map +1 -0
  63. package/dist/runtimes/claude/translate-responses.js +625 -0
  64. package/dist/runtimes/claude/translate-responses.js.map +1 -0
  65. package/dist/runtimes/claude/usage-ledger.d.ts +108 -0
  66. package/dist/runtimes/claude/usage-ledger.d.ts.map +1 -0
  67. package/dist/runtimes/claude/usage-ledger.js +189 -0
  68. package/dist/runtimes/claude/usage-ledger.js.map +1 -0
  69. package/dist/runtimes/copilot/sdk-backend.d.ts.map +1 -1
  70. package/dist/runtimes/copilot/sdk-backend.js +15 -104
  71. package/dist/runtimes/copilot/sdk-backend.js.map +1 -1
  72. package/dist/runtimes/mcp-env.d.ts +24 -0
  73. package/dist/runtimes/mcp-env.d.ts.map +1 -0
  74. package/dist/runtimes/mcp-env.js +81 -0
  75. package/dist/runtimes/mcp-env.js.map +1 -0
  76. package/dist/src/session-recovery-policy.d.ts +19 -0
  77. package/dist/src/session-recovery-policy.d.ts.map +1 -0
  78. package/dist/src/session-recovery-policy.js +43 -0
  79. package/dist/src/session-recovery-policy.js.map +1 -0
  80. package/dist/src/types.d.ts +45 -0
  81. package/dist/src/types.d.ts.map +1 -1
  82. package/dist/src/types.js.map +1 -1
  83. package/package.json +20 -4
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Token accounting for the Claude Agent SDK.
3
+ *
4
+ * The SDK exposes three usage surfaces, and only one is authoritative:
5
+ *
6
+ * - `assistant.message.usage` — the API's non-final, per-block snapshot. It
7
+ * must never be summed (doing so double-counts every streamed turn) and it
8
+ * carries no subagent attribution.
9
+ * - `result.usage` — the main agent loop only, excluding subagents, sidechains,
10
+ * compaction and Workflow calls.
11
+ * - `result.modelUsage` — per-model totals for every call made through the
12
+ * query pipeline, subagents included. These totals are **cumulative**: each
13
+ * result carries the running total for the session so far, and a resumed or
14
+ * forked session continues from the totals its transcript saved.
15
+ *
16
+ * condukt's usage events are per-turn charges (the scheduler sums them), so
17
+ * this ledger differences successive cumulative snapshots. It also seeds a
18
+ * baseline when the first result after a resume arrives with no earlier
19
+ * snapshot in this process — the transcript, not this process, holds the
20
+ * earlier turns, and reporting the whole cumulative total as one turn would
21
+ * overstate the node by the entire session.
22
+ */
23
+ import type { ModelUsage } from '@anthropic-ai/claude-agent-sdk';
24
+ /** Per-model token counts in condukt's vocabulary. */
25
+ export interface TokenCounts {
26
+ /** Prompt tokens, including cache reads and cache writes. */
27
+ readonly inputTokens: number;
28
+ readonly outputTokens: number;
29
+ readonly cacheReadTokens: number;
30
+ readonly cacheWriteTokens: number;
31
+ }
32
+ /**
33
+ * One `node:usage` payload. Extends the emitter's `Record<string, unknown>`
34
+ * contract so `agent.ts` can consume it without a cast.
35
+ */
36
+ export interface ClaudeUsageRecord extends Record<string, unknown> {
37
+ readonly inputTokens: number;
38
+ readonly outputTokens: number;
39
+ readonly totalTokens: number;
40
+ readonly cacheReadTokens: number;
41
+ readonly cacheWriteTokens: number;
42
+ readonly model: string;
43
+ readonly apiCallId: string;
44
+ /** Wall-clock duration of the whole turn, in milliseconds (result-level). */
45
+ readonly duration?: number;
46
+ }
47
+ export interface ModelUsageObservation {
48
+ /** `result.uuid`; combined with the model for a stable dedupe key. */
49
+ readonly uuid: string;
50
+ /** `result.duration_ms`. The SDK does not break duration down per model. */
51
+ readonly durationMs?: number;
52
+ /** `result.modelUsage` (camelCase, cumulative). */
53
+ readonly modelUsage: Readonly<Record<string, Partial<ModelUsage>>> | undefined;
54
+ /** `result.usage` (snake_case, main loop only, per turn). */
55
+ readonly mainLoopUsage: Readonly<Record<string, unknown>> | undefined;
56
+ /** Model of the latest assistant frame, when one was seen. */
57
+ readonly mainLoopModel?: string;
58
+ }
59
+ export interface ModelUsageObservationContext {
60
+ /**
61
+ * Whether this turn continued an existing session (`resume`). Only used for
62
+ * the very first observation, where it decides between "this snapshot is the
63
+ * turn" and "this snapshot is the session baseline".
64
+ */
65
+ readonly resumed: boolean;
66
+ }
67
+ /**
68
+ * Differences the SDK's cumulative `modelUsage` snapshots into per-turn usage.
69
+ *
70
+ * One ledger lives for the whole session: turn N's delta is turn N's snapshot
71
+ * minus turn N-1's. A zeroed/empty error result never overwrites the baseline,
72
+ * so a crash cannot resurrect already-billed tokens on the next turn.
73
+ */
74
+ export declare class ModelUsageLedger {
75
+ private snapshot;
76
+ /**
77
+ * Turns that billed each model. The session cannot derive this from the
78
+ * snapshot alone, and reporting the session's total turn count against
79
+ * every model would claim requests a model never served.
80
+ */
81
+ private readonly requestCounts;
82
+ private readonly fallbackModel;
83
+ constructor(options?: {
84
+ readonly fallbackModel?: string;
85
+ });
86
+ /**
87
+ * Records one result and returns the usage records for the turn it closed.
88
+ *
89
+ * - Fresh session, first result: the snapshot *is* this turn.
90
+ * - Resumed session with no earlier snapshot (process restart): seed the
91
+ * baseline from the snapshot and report only the main-loop usage, which is
92
+ * per-turn. Subagent tokens from this one turn stay unattributed until the
93
+ * next result's delta; the plan records this gap rather than inventing a
94
+ * number.
95
+ * - Later results: per-model deltas, clamped at zero so a mid-session
96
+ * `/clear` (which resets the running total) cannot produce negative usage.
97
+ */
98
+ observe(observation: ModelUsageObservation, context: ModelUsageObservationContext): ClaudeUsageRecord[];
99
+ /** Cumulative per-model totals as of the last non-zeroed result. */
100
+ getSnapshot(): ReadonlyMap<string, TokenCounts>;
101
+ /** Turns that produced usage for each model. */
102
+ getRequestCounts(): ReadonlyMap<string, number>;
103
+ /** True once at least one result with real usage has been observed. */
104
+ hasUsage(): boolean;
105
+ private record;
106
+ private attributeMainLoop;
107
+ }
108
+ //# sourceMappingURL=usage-ledger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-ledger.d.ts","sourceRoot":"","sources":["../../../runtimes/claude/usage-ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAEjE,sDAAsD;AACtD,MAAM,WAAW,WAAW;IAC1B,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAkB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAChE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,mDAAmD;IACnD,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAC/E,6DAA6D;IAC7D,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IACtE,8DAA8D;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AA0ED;;;;;;GAMG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAyC;IACzD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAE3B,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE;IAIzD;;;;;;;;;;;OAWG;IACH,OAAO,CACL,WAAW,EAAE,qBAAqB,EAClC,OAAO,EAAE,4BAA4B,GACpC,iBAAiB,EAAE;IA2DtB,oEAAoE;IACpE,WAAW,IAAI,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC;IAI/C,gDAAgD;IAChD,gBAAgB,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAI/C,uEAAuE;IACvE,QAAQ,IAAI,OAAO;IAInB,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,iBAAiB;CAW1B"}
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ /**
3
+ * Token accounting for the Claude Agent SDK.
4
+ *
5
+ * The SDK exposes three usage surfaces, and only one is authoritative:
6
+ *
7
+ * - `assistant.message.usage` — the API's non-final, per-block snapshot. It
8
+ * must never be summed (doing so double-counts every streamed turn) and it
9
+ * carries no subagent attribution.
10
+ * - `result.usage` — the main agent loop only, excluding subagents, sidechains,
11
+ * compaction and Workflow calls.
12
+ * - `result.modelUsage` — per-model totals for every call made through the
13
+ * query pipeline, subagents included. These totals are **cumulative**: each
14
+ * result carries the running total for the session so far, and a resumed or
15
+ * forked session continues from the totals its transcript saved.
16
+ *
17
+ * condukt's usage events are per-turn charges (the scheduler sums them), so
18
+ * this ledger differences successive cumulative snapshots. It also seeds a
19
+ * baseline when the first result after a resume arrives with no earlier
20
+ * snapshot in this process — the transcript, not this process, holds the
21
+ * earlier turns, and reporting the whole cumulative total as one turn would
22
+ * overstate the node by the entire session.
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.ModelUsageLedger = void 0;
26
+ const ZERO = Object.freeze({
27
+ inputTokens: 0,
28
+ outputTokens: 0,
29
+ cacheReadTokens: 0,
30
+ cacheWriteTokens: 0,
31
+ });
32
+ let fallbackSequence = 0;
33
+ function count(value) {
34
+ return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : 0;
35
+ }
36
+ function totalOf(counts) {
37
+ return counts.inputTokens + counts.outputTokens;
38
+ }
39
+ function countsFromModelUsage(usage) {
40
+ return {
41
+ // ModelUsage.inputTokens excludes cached prompt tokens; condukt's
42
+ // `inputTokens` is the whole prompt.
43
+ inputTokens: count(usage?.inputTokens)
44
+ + count(usage?.cacheReadInputTokens)
45
+ + count(usage?.cacheCreationInputTokens),
46
+ outputTokens: count(usage?.outputTokens),
47
+ cacheReadTokens: count(usage?.cacheReadInputTokens),
48
+ cacheWriteTokens: count(usage?.cacheCreationInputTokens),
49
+ };
50
+ }
51
+ /** Reads the main-loop `result.usage`, accepting either spelling. */
52
+ function countsFromMainLoop(usage) {
53
+ if (usage === undefined)
54
+ return ZERO;
55
+ const cacheRead = count(usage['cache_read_input_tokens'] ?? usage['cacheReadTokens']);
56
+ const cacheWrite = count(usage['cache_creation_input_tokens'] ?? usage['cacheWriteTokens']);
57
+ return {
58
+ inputTokens: count(usage['input_tokens'] ?? usage['inputTokens']) + cacheRead + cacheWrite,
59
+ outputTokens: count(usage['output_tokens'] ?? usage['outputTokens']),
60
+ cacheReadTokens: cacheRead,
61
+ cacheWriteTokens: cacheWrite,
62
+ };
63
+ }
64
+ function subtractClamped(cumulative, previous) {
65
+ return {
66
+ inputTokens: Math.max(0, cumulative.inputTokens - previous.inputTokens),
67
+ outputTokens: Math.max(0, cumulative.outputTokens - previous.outputTokens),
68
+ cacheReadTokens: Math.max(0, cumulative.cacheReadTokens - previous.cacheReadTokens),
69
+ cacheWriteTokens: Math.max(0, cumulative.cacheWriteTokens - previous.cacheWriteTokens),
70
+ };
71
+ }
72
+ function toRecord(model, counts, uuid, durationMs) {
73
+ const callId = uuid.length > 0 ? `${uuid}:${model}` : `claude-${Date.now().toString(36)}-${++fallbackSequence}`;
74
+ return {
75
+ inputTokens: counts.inputTokens,
76
+ outputTokens: counts.outputTokens,
77
+ totalTokens: counts.inputTokens + counts.outputTokens,
78
+ cacheReadTokens: counts.cacheReadTokens,
79
+ cacheWriteTokens: counts.cacheWriteTokens,
80
+ model,
81
+ apiCallId: callId,
82
+ ...(durationMs !== undefined ? { duration: durationMs } : {}),
83
+ };
84
+ }
85
+ /**
86
+ * Differences the SDK's cumulative `modelUsage` snapshots into per-turn usage.
87
+ *
88
+ * One ledger lives for the whole session: turn N's delta is turn N's snapshot
89
+ * minus turn N-1's. A zeroed/empty error result never overwrites the baseline,
90
+ * so a crash cannot resurrect already-billed tokens on the next turn.
91
+ */
92
+ class ModelUsageLedger {
93
+ snapshot = null;
94
+ /**
95
+ * Turns that billed each model. The session cannot derive this from the
96
+ * snapshot alone, and reporting the session's total turn count against
97
+ * every model would claim requests a model never served.
98
+ */
99
+ requestCounts = new Map();
100
+ fallbackModel;
101
+ constructor(options) {
102
+ this.fallbackModel = options?.fallbackModel ?? 'claude';
103
+ }
104
+ /**
105
+ * Records one result and returns the usage records for the turn it closed.
106
+ *
107
+ * - Fresh session, first result: the snapshot *is* this turn.
108
+ * - Resumed session with no earlier snapshot (process restart): seed the
109
+ * baseline from the snapshot and report only the main-loop usage, which is
110
+ * per-turn. Subagent tokens from this one turn stay unattributed until the
111
+ * next result's delta; the plan records this gap rather than inventing a
112
+ * number.
113
+ * - Later results: per-model deltas, clamped at zero so a mid-session
114
+ * `/clear` (which resets the running total) cannot produce negative usage.
115
+ */
116
+ observe(observation, context) {
117
+ const cumulative = new Map();
118
+ for (const [model, usage] of Object.entries(observation.modelUsage ?? {})) {
119
+ cumulative.set(model, countsFromModelUsage(usage));
120
+ }
121
+ const snapshotHasUsage = [...cumulative.values()].some((counts) => totalOf(counts) > 0);
122
+ const mainLoop = countsFromMainLoop(observation.mainLoopUsage);
123
+ const mainLoopHasUsage = totalOf(mainLoop) > 0;
124
+ if (this.snapshot === null) {
125
+ if (snapshotHasUsage) {
126
+ this.snapshot = cumulative;
127
+ if (context.resumed) {
128
+ return mainLoopHasUsage
129
+ ? [this.record(this.attributeMainLoop(observation.mainLoopModel, cumulative), mainLoop, observation.uuid, observation.durationMs)]
130
+ : [];
131
+ }
132
+ return [...cumulative.entries()]
133
+ .filter(([, counts]) => totalOf(counts) > 0)
134
+ .map(([model, counts]) => this.record(model, counts, observation.uuid, observation.durationMs));
135
+ }
136
+ // No per-model snapshot at all: the main loop is the only accounting
137
+ // left. Do not seed anything — the next result's cumulative total will
138
+ // still be baselined on its own first observation.
139
+ return mainLoopHasUsage
140
+ ? [this.record(this.attributeMainLoop(observation.mainLoopModel, cumulative), mainLoop, observation.uuid, observation.durationMs)]
141
+ : [];
142
+ }
143
+ if (!snapshotHasUsage) {
144
+ // Crash / startup-error results may carry a zeroed snapshot. Treating it
145
+ // as real would reset the baseline and re-bill every earlier turn.
146
+ return [];
147
+ }
148
+ const records = [];
149
+ for (const [model, counts] of cumulative) {
150
+ const previous = this.snapshot.get(model) ?? ZERO;
151
+ this.snapshot.set(model, counts);
152
+ const delta = subtractClamped(counts, previous);
153
+ if (totalOf(delta) > 0) {
154
+ records.push(this.record(model, delta, observation.uuid, observation.durationMs));
155
+ }
156
+ }
157
+ // Models absent from this snapshot keep their last-seen totals: they may
158
+ // return in a later turn, and their earlier usage is already accounted.
159
+ return records;
160
+ }
161
+ /** Cumulative per-model totals as of the last non-zeroed result. */
162
+ getSnapshot() {
163
+ return this.snapshot ?? new Map();
164
+ }
165
+ /** Turns that produced usage for each model. */
166
+ getRequestCounts() {
167
+ return this.requestCounts;
168
+ }
169
+ /** True once at least one result with real usage has been observed. */
170
+ hasUsage() {
171
+ return this.snapshot !== null && [...this.snapshot.values()].some((counts) => totalOf(counts) > 0);
172
+ }
173
+ record(model, counts, uuid, durationMs) {
174
+ this.requestCounts.set(model, (this.requestCounts.get(model) ?? 0) + 1);
175
+ return toRecord(model, counts, uuid, durationMs);
176
+ }
177
+ attributeMainLoop(observedModel, cumulative) {
178
+ if (observedModel !== undefined && observedModel.length > 0)
179
+ return observedModel;
180
+ if (cumulative.size === 1) {
181
+ const only = cumulative.keys().next();
182
+ if (!only.done)
183
+ return only.value;
184
+ }
185
+ return this.fallbackModel;
186
+ }
187
+ }
188
+ exports.ModelUsageLedger = ModelUsageLedger;
189
+ //# sourceMappingURL=usage-ledger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-ledger.js","sourceRoot":"","sources":["../../../runtimes/claude/usage-ledger.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sdk-backend.d.ts","sourceRoot":"","sources":["../../../runtimes/copilot/sdk-backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAmBH,OAAO,KAAK,EAEV,MAAM,EAKP,MAAM,iBAAiB,CAAC;AAMzB,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,aAAa,EACb,sBAAsB,EAQvB,MAAM,mBAAmB,CAAC;AAU3B,OAAO,KAAK,EACV,wBAAwB,EACxB,cAAc,EACd,cAAc,EACf,MAAM,aAAa,CAAC;AAMrB,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AACvF,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAmC9D,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD,uFAAuF;IACvF,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,gFAAgF;IAChF,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,kFAAkF;IAClF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,0GAA0G;IAC1G,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,GAAG,KAAK,CAAC;IACjD,0FAA0F;IAC1F,QAAQ,CAAC,wBAAwB,CAAC,EAAE,wBAAwB,CAAC;IAC7D,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAC5C,qFAAqF;IACrF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CAC9C;AAwvCD;;;;;;GAMG;AACH,qBAAa,UAAW,YAAW,cAAc;IAC/C,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,YAAY;;;;OAIT;IACZ,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqC;IACpE,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA2B;IACpE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAqB;IAC/D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA+B;IAChE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,OAAO,GAAE,iBAAsB;IAgBrC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAY/B,aAAa,CACjB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,cAAc,CAAC;CAoB3B"}
1
+ {"version":3,"file":"sdk-backend.d.ts","sourceRoot":"","sources":["../../../runtimes/copilot/sdk-backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAmBH,OAAO,KAAK,EAEV,MAAM,EAKP,MAAM,iBAAiB,CAAC;AAWzB,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,aAAa,EACb,sBAAsB,EAQvB,MAAM,mBAAmB,CAAC;AAU3B,OAAO,KAAK,EACV,wBAAwB,EACxB,cAAc,EACd,cAAc,EACf,MAAM,aAAa,CAAC;AAMrB,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AACvF,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAmC9D,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD,uFAAuF;IACvF,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,gFAAgF;IAChF,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,kFAAkF;IAClF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,0GAA0G;IAC1G,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,GAAG,KAAK,CAAC;IACjD,0FAA0F;IAC1F,QAAQ,CAAC,wBAAwB,CAAC,EAAE,wBAAwB,CAAC;IAC7D,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAC5C,qFAAqF;IACrF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CAC9C;AA4nCD;;;;;;GAMG;AACH,qBAAa,UAAW,YAAW,cAAc;IAC/C,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,YAAY;;;;OAIT;IACZ,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqC;IACpE,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA2B;IACpE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAqB;IAC/D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA+B;IAChE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,OAAO,GAAE,iBAAsB;IAgBrC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAY/B,aAAa,CACjB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,cAAc,CAAC;CAoB3B"}
@@ -51,6 +51,8 @@ const fs = __importStar(require("fs"));
51
51
  const path = __importStar(require("path"));
52
52
  const node_crypto_1 = require("node:crypto");
53
53
  const types_1 = require("../../src/types");
54
+ const session_recovery_policy_1 = require("../../src/session-recovery-policy");
55
+ const mcp_env_1 = require("../mcp-env");
54
56
  const lifecycle_events_1 = require("./lifecycle-events");
55
57
  const subagents_1 = require("./subagents");
56
58
  const SEVERITY_RANK = {
@@ -81,36 +83,6 @@ function writeDiagnosticStderr(severity, message, configuredLevel) {
81
83
  /* closed stream */
82
84
  }
83
85
  }
84
- const MAX_SESSION_RECOVERY_CONTINUATIONS = 23;
85
- function positiveIntegerOr(value, fallback) {
86
- return value !== undefined && Number.isFinite(value) && value > 0
87
- ? Math.trunc(value)
88
- : fallback;
89
- }
90
- function nonNegativeOr(value, fallback) {
91
- return value !== undefined && Number.isFinite(value) && value >= 0
92
- ? value
93
- : fallback;
94
- }
95
- function effectiveSessionRecoveryPolicy(policy) {
96
- if (policy === false)
97
- return undefined;
98
- const configured = policy ?? {};
99
- return {
100
- maxContinuations: Math.min(MAX_SESSION_RECOVERY_CONTINUATIONS, positiveIntegerOr(configured.maxContinuations, types_1.DEFAULT_SESSION_RECOVERY_POLICY.maxContinuations)),
101
- budgetMs: nonNegativeOr(configured.budgetMs, types_1.DEFAULT_SESSION_RECOVERY_POLICY.budgetMs),
102
- backoffBaseMs: positiveIntegerOr(configured.backoffBaseMs, types_1.DEFAULT_SESSION_RECOVERY_POLICY.backoffBaseMs),
103
- backoffMaxMs: positiveIntegerOr(configured.backoffMaxMs, types_1.DEFAULT_SESSION_RECOVERY_POLICY.backoffMaxMs),
104
- jitter: configured.jitter ?? types_1.DEFAULT_SESSION_RECOVERY_POLICY.jitter,
105
- nativeRetryGraceMs: nonNegativeOr(configured.nativeRetryGraceMs, types_1.DEFAULT_SESSION_RECOVERY_POLICY.nativeRetryGraceMs),
106
- };
107
- }
108
- function recoveryDelayMs(policy, failedContinuation) {
109
- const exponent = Math.min(52, Math.max(0, failedContinuation));
110
- const capped = Math.min(policy.backoffMaxMs, policy.backoffBaseMs * (2 ** exponent));
111
- const delayed = policy.jitter ? Math.random() * capped : capped;
112
- return Math.max(100, Number.isFinite(delayed) ? delayed : 100);
113
- }
114
86
  /**
115
87
  * A failed reconnect step, tagged with the stage that threw so an `exhausted`
116
88
  * event can name it.
@@ -975,72 +947,6 @@ function parseMcpConfig(configPath, mcpServerWorkingDirectory, terminalLogLevel)
975
947
  return null;
976
948
  }
977
949
  }
978
- const ENV_REFERENCE = /^\$\{([A-Z_][A-Z0-9_]*(?:\|[A-Z_][A-Z0-9_]*)*)\}$/;
979
- /**
980
- * Resolves ${NAME} and ${NAME|FALLBACK|...}, taking the first variable that is set.
981
- *
982
- * The fallback chain exists because there is no single conventional name for a GitHub
983
- * token: the Copilot CLI itself reads COPILOT_GITHUB_TOKEN, then GH_TOKEN, then
984
- * GITHUB_TOKEN. A default that insisted on one spelling would silently ship an
985
- * unauthenticated server in any environment that chose a different one.
986
- */
987
- function resolveMcpEnvironmentValue(value) {
988
- const match = ENV_REFERENCE.exec(value);
989
- if (!match)
990
- return value;
991
- for (const name of match[1].split('|')) {
992
- const resolved = process.env[name];
993
- if (resolved !== undefined && resolved !== '')
994
- return resolved;
995
- }
996
- return undefined;
997
- }
998
- function resolveMcpEnvironmentRecord(values) {
999
- if (values === undefined)
1000
- return undefined;
1001
- const resolved = {};
1002
- for (const [key, value] of Object.entries(values)) {
1003
- const environmentValue = resolveMcpEnvironmentValue(value);
1004
- if (environmentValue !== undefined)
1005
- resolved[key] = environmentValue;
1006
- }
1007
- return Object.keys(resolved).length > 0 ? resolved : undefined;
1008
- }
1009
- // Embedded references, so `Bearer ${A|B}` resolves rather than only a bare `${A|B}`. The
1010
- // fallback alternatives must be part of the pattern: a reference matcher without them finds
1011
- // nothing in `${A|B}`, leaves the value untouched, and emits the placeholder as a literal
1012
- // header — an unauthenticated server that reports no error and simply returns no tools.
1013
- const HEADER_ENV_REFERENCE = /\$\{([A-Z_][A-Z0-9_]*(?:\|[A-Z_][A-Z0-9_]*)*)\}/g;
1014
- function resolveMcpHeaders(headers, terminalLogLevel) {
1015
- if (headers === undefined)
1016
- return undefined;
1017
- const resolved = {};
1018
- for (const [key, value] of Object.entries(headers)) {
1019
- const references = [...value.matchAll(HEADER_ENV_REFERENCE)];
1020
- let resolvedValue = value;
1021
- let complete = true;
1022
- for (const reference of references) {
1023
- const names = reference[1].split('|');
1024
- const environmentValue = names
1025
- .map((name) => process.env[name])
1026
- .find((candidate) => candidate !== undefined && candidate !== '');
1027
- if (environmentValue === undefined) {
1028
- // Dropping the header is deliberate — a missing credential must not abort a run — but
1029
- // it is invisible at the server, which just answers with nothing.
1030
- try {
1031
- writeDiagnosticStderr('warning', `[SdkBackend] MCP header ${key} dropped: none of ${names.join(', ')} is set\n`, terminalLogLevel);
1032
- }
1033
- catch { /* diagnostics must not break configuration */ }
1034
- complete = false;
1035
- break;
1036
- }
1037
- resolvedValue = resolvedValue.replace(reference[0], environmentValue);
1038
- }
1039
- if (complete)
1040
- resolved[key] = resolvedValue;
1041
- }
1042
- return Object.keys(resolved).length > 0 ? resolved : undefined;
1043
- }
1044
950
  function toSdkMcpServers(servers, terminalLogLevel) {
1045
951
  if (servers === undefined || servers === false)
1046
952
  return servers;
@@ -1050,14 +956,19 @@ function toSdkMcpServers(servers, terminalLogLevel) {
1050
956
  if (!parsed)
1051
957
  continue;
1052
958
  if ('url' in parsed) {
1053
- const headers = resolveMcpHeaders(parsed.headers, terminalLogLevel);
959
+ const headers = (0, mcp_env_1.resolveMcpHeaders)(parsed.headers, ({ header, names }) => {
960
+ try {
961
+ writeDiagnosticStderr('warning', `[SdkBackend] MCP header ${header} dropped: none of ${names.join(', ')} is set\n`, terminalLogLevel);
962
+ }
963
+ catch { /* diagnostics must not break configuration */ }
964
+ });
1054
965
  converted[name] = {
1055
966
  ...parsed,
1056
967
  ...(headers !== undefined ? { headers } : { headers: undefined }),
1057
968
  };
1058
969
  }
1059
970
  else {
1060
- const env = resolveMcpEnvironmentRecord(parsed.env);
971
+ const env = (0, mcp_env_1.resolveMcpEnvironmentRecord)(parsed.env);
1061
972
  converted[name] = {
1062
973
  ...parsed,
1063
974
  ...(env !== undefined ? { env } : { env: undefined }),
@@ -2036,7 +1947,7 @@ class SdkSession {
2036
1947
  });
2037
1948
  }
2038
1949
  scheduleRecovery(failedHandle, error, data, eventId, options = {}) {
2039
- const policy = effectiveSessionRecoveryPolicy(this.config.sessionRecovery);
1950
+ const policy = (0, session_recovery_policy_1.effectiveSessionRecoveryPolicy)(this.config.sessionRecovery);
2040
1951
  if (!policy) {
2041
1952
  const eventType = data?.failureKind === 'session-progress-timeout'
2042
1953
  ? 'session.progress_timeout'
@@ -2068,7 +1979,7 @@ class SdkSession {
2068
1979
  }
2069
1980
  this.recoveryStartedAt ??= Date.now();
2070
1981
  this.recoveryDeadlineMs ??= Math.min(this.sessionDeadlineMs ?? Number.POSITIVE_INFINITY, this.recoveryStartedAt + policy.budgetMs);
2071
- const delayMs = recoveryDelayMs(policy, this.recoveryContinuation);
1982
+ const delayMs = (0, session_recovery_policy_1.recoveryDelayMs)(policy, this.recoveryContinuation);
2072
1983
  this.emitRecovery('scheduled', policy, this.recoveryContinuation + 1, sessionId, {
2073
1984
  delayMs,
2074
1985
  ...this.recoveryMetadata(data),
@@ -2137,7 +2048,7 @@ class SdkSession {
2137
2048
  this.exhaustRecovery(policy, sessionId, originalError, failed.message, data, failed.stage);
2138
2049
  return;
2139
2050
  }
2140
- const retryDelayMs = recoveryDelayMs(policy, this.recoveryContinuation);
2051
+ const retryDelayMs = (0, session_recovery_policy_1.recoveryDelayMs)(policy, this.recoveryContinuation);
2141
2052
  this.emitRecovery('scheduled', policy, this.recoveryContinuation + 1, sessionId, {
2142
2053
  delayMs: retryDelayMs,
2143
2054
  ...this.recoveryMetadata(data),
@@ -2550,7 +2461,7 @@ class SdkSession {
2550
2461
  // rather than the attempt's first turn, so the recovery bookkeeping (and
2551
2462
  // its `recovered` event) does not apply to it.
2552
2463
  const isContinuation = this.settleWaiters.length > 0;
2553
- const policy = effectiveSessionRecoveryPolicy(this.config.sessionRecovery);
2464
+ const policy = (0, session_recovery_policy_1.effectiveSessionRecoveryPolicy)(this.config.sessionRecovery);
2554
2465
  if (!isContinuation && policy && this.recoveryContinuation > 0 && this.sessionId) {
2555
2466
  this.emitRecovery('recovered', policy, this.recoveryContinuation, this.sessionId);
2556
2467
  }
@@ -2707,7 +2618,7 @@ class SdkSession {
2707
2618
  if (!e.agentId && this.nativeRetryGraceTimer) {
2708
2619
  clearTimeout(this.nativeRetryGraceTimer);
2709
2620
  this.nativeRetryGraceTimer = null;
2710
- const policy = effectiveSessionRecoveryPolicy(this.config.sessionRecovery);
2621
+ const policy = (0, session_recovery_policy_1.effectiveSessionRecoveryPolicy)(this.config.sessionRecovery);
2711
2622
  if (policy && this.sessionId) {
2712
2623
  this.emitRecovery('native-retry', policy, this.recoveryContinuation, this.sessionId);
2713
2624
  }
@@ -2954,7 +2865,7 @@ class SdkSession {
2954
2865
  // genuinely running subagent read is abandoned and re-issued by the model.
2955
2866
  // For the read-only work recovery is opted into for, that is the right
2956
2867
  // trade against failing the node; a mutating node opts out of recovery.
2957
- const policy = effectiveSessionRecoveryPolicy(this.config.sessionRecovery);
2868
+ const policy = (0, session_recovery_policy_1.effectiveSessionRecoveryPolicy)(this.config.sessionRecovery);
2958
2869
  const hasPendingWork = this.activeToolCalls.size > 0 || this.pendingExternalRequests.size > 0;
2959
2870
  if (!policy) {
2960
2871
  if (hasPendingWork) {