@loucompanion/forge-bridge 0.1.3-dev.9bc5014a2270 → 0.1.3-dev.a58d7cd1092f
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 +127 -0
- package/dist/bridge/bridge.base.d.ts +8 -1
- package/dist/bridge/bridge.service.d.ts +93 -3
- package/dist/bridge/bridge.service.js +1358 -47
- package/dist/bridge/bridge.types.d.ts +202 -1
- package/dist/bridge/runner-host-capabilities.d.ts +15 -0
- package/dist/bridge/runner-host-capabilities.js +93 -0
- package/dist/cleanup/cleanup.service.d.ts +14 -2
- package/dist/cleanup/cleanup.service.js +496 -3
- package/dist/cleanup/cleanup.types.d.ts +10 -0
- package/dist/cleanup/index.d.ts +1 -1
- package/dist/cleanup/index.js +1 -1
- package/dist/cleanup/internals.d.ts +2 -2
- package/dist/cleanup/internals.js +1 -1
- package/dist/cli/cli.help.js +47 -1
- package/dist/cli/cli.service.d.ts +45 -2
- package/dist/cli/cli.service.js +378 -26
- package/dist/cli/local-config.d.ts +7 -0
- package/dist/cli/local-config.js +51 -3
- package/dist/runtime/aspnet-runtime-prebuild.d.ts +36 -0
- package/dist/runtime/aspnet-runtime-prebuild.js +340 -0
- package/dist/runtime/attempt-node-runtime-launcher.d.ts +17 -0
- package/dist/runtime/attempt-node-runtime-launcher.js +105 -0
- package/dist/runtime/attempt-process-supervisor-registry.d.ts +20 -0
- package/dist/runtime/attempt-process-supervisor-registry.js +64 -0
- package/dist/runtime/attempt-process-supervisor.d.ts +97 -0
- package/dist/runtime/attempt-process-supervisor.js +386 -0
- package/dist/runtime/docker-engine-probe.d.ts +83 -0
- package/dist/runtime/docker-engine-probe.js +300 -0
- package/dist/runtime/generated-output-reset.d.ts +10 -0
- package/dist/runtime/generated-output-reset.js +103 -0
- package/dist/runtime/host-listener-inspector.d.ts +46 -0
- package/dist/runtime/host-listener-inspector.js +349 -0
- package/dist/runtime/host-port-broker.d.ts +76 -0
- package/dist/runtime/host-port-broker.js +333 -0
- package/dist/runtime/host-runtime-contract.d.ts +47 -0
- package/dist/runtime/host-runtime-contract.js +700 -0
- package/dist/runtime/host-runtime-lease.d.ts +197 -0
- package/dist/runtime/host-runtime-lease.js +2203 -0
- package/dist/runtime/host-runtime-promotion.d.ts +23 -0
- package/dist/runtime/host-runtime-promotion.js +159 -0
- package/dist/runtime/memory-capacity.d.ts +68 -0
- package/dist/runtime/memory-capacity.js +121 -0
- package/dist/runtime/node-host-runtime-adapter.d.ts +54 -0
- package/dist/runtime/node-host-runtime-adapter.js +284 -0
- package/dist/runtime/playwright-host-runtime-adapter.d.ts +21 -0
- package/dist/runtime/playwright-host-runtime-adapter.js +231 -0
- package/dist/runtime/runtime-isolation-lease.d.ts +67 -0
- package/dist/runtime/runtime-isolation-lease.js +158 -0
- package/dist/runtime/workspace-resource-estimator.d.ts +17 -0
- package/dist/runtime/workspace-resource-estimator.js +174 -0
- package/dist/sandbox/command-runner.d.ts +4 -0
- package/dist/sandbox/command-runner.js +47 -0
- package/dist/sandbox/contract.d.ts +5 -0
- package/dist/sandbox/contract.js +276 -0
- package/dist/sandbox/event-budget.d.ts +11 -0
- package/dist/sandbox/event-budget.js +27 -0
- package/dist/sandbox/image-policy.d.ts +35 -0
- package/dist/sandbox/image-policy.js +247 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +5 -0
- package/dist/sandbox/lease-watchdog.d.ts +18 -0
- package/dist/sandbox/lease-watchdog.js +67 -0
- package/dist/sandbox/preflight.d.ts +84 -0
- package/dist/sandbox/preflight.js +521 -0
- package/dist/sandbox/process.d.ts +20 -0
- package/dist/sandbox/process.js +209 -0
- package/dist/sandbox/provider-auth/codex.d.ts +26 -0
- package/dist/sandbox/provider-auth/codex.js +212 -0
- package/dist/sandbox/repository-lock.d.ts +5 -0
- package/dist/sandbox/repository-lock.js +121 -0
- package/dist/sandbox/runtime.d.ts +297 -0
- package/dist/sandbox/runtime.js +2338 -0
- package/dist/sandbox/sandbox.types.d.ts +93 -0
- package/dist/sandbox/sandbox.types.js +1 -0
- package/dist/sandbox/smoke.d.ts +76 -0
- package/dist/sandbox/smoke.js +380 -0
- package/dist/sandbox/worker-supervisor.d.ts +13 -0
- package/dist/sandbox/worker-supervisor.js +36 -0
- package/dist/sandbox/worker.d.ts +1 -0
- package/dist/sandbox/worker.js +225 -0
- package/dist/sandbox/workspace.service.d.ts +13 -0
- package/dist/sandbox/workspace.service.js +72 -0
- package/dist/session/managed-attempt-tools.d.ts +21 -0
- package/dist/session/managed-attempt-tools.js +912 -0
- package/dist/session/managed-build-coordinator.d.ts +5 -0
- package/dist/session/managed-build-coordinator.js +105 -0
- package/dist/session/managed-build-receipt.d.ts +21 -0
- package/dist/session/managed-build-receipt.js +335 -0
- package/dist/session/phase-completion.artifacts.d.ts +17 -0
- package/dist/session/phase-completion.artifacts.js +256 -26
- package/dist/session/phase-completion.d.ts +12 -2
- package/dist/session/phase-completion.helpers.d.ts +5 -0
- package/dist/session/phase-completion.helpers.js +51 -10
- package/dist/session/phase-completion.js +14 -3
- package/dist/session/phase-completion.prompts.d.ts +3 -3
- package/dist/session/phase-completion.prompts.js +24 -8
- package/dist/session/phase-completion.runtime.d.ts +13 -1
- package/dist/session/phase-completion.runtime.js +189 -8
- package/dist/session/phase-completion.schemas.js +117 -4
- package/dist/session/phase-completion.validation.d.ts +4 -1
- package/dist/session/phase-completion.validation.js +153 -22
- package/dist/session/pre-publication-validation.d.ts +46 -0
- package/dist/session/pre-publication-validation.js +208 -0
- package/dist/session/provider-cli/ci-repair-readiness.d.ts +16 -0
- package/dist/session/provider-cli/ci-repair-readiness.js +110 -0
- package/dist/session/provider-cli/provider-cli.artifacts.d.ts +3 -2
- package/dist/session/provider-cli/provider-cli.artifacts.js +65 -7
- package/dist/session/provider-cli/provider-cli.base.d.ts +1 -0
- package/dist/session/provider-cli/provider-cli.deterministic.d.ts +2 -0
- package/dist/session/provider-cli/provider-cli.deterministic.js +66 -9
- package/dist/session/provider-cli/provider-cli.process.d.ts +26 -0
- package/dist/session/provider-cli/provider-cli.process.js +474 -23
- package/dist/session/provider-cli/provider-cli.prompts.d.ts +16 -2
- package/dist/session/provider-cli/provider-cli.prompts.js +224 -24
- package/dist/session/provider-cli/provider-cli.qa-sidecars.js +1 -0
- package/dist/session/provider-cli/provider-cli.runtime.d.ts +1 -1
- package/dist/session/provider-cli/provider-cli.runtime.js +6 -3
- package/dist/session/provider-cli/provider-cli.service.d.ts +26 -3
- package/dist/session/provider-cli/provider-cli.service.js +646 -90
- package/dist/session/provider-cli/provider-cli.types.d.ts +5 -0
- package/dist/session/provider-cli/provider-output-state.d.ts +2 -0
- package/dist/session/provider-cli/provider-output-state.js +91 -16
- package/dist/session/provider-cli/provider-usage.d.ts +7 -0
- package/dist/session/provider-cli/provider-usage.js +28 -5
- package/dist/session/session-redaction.d.ts +3 -0
- package/dist/session/session-redaction.js +38 -0
- package/dist/session/session.base.d.ts +6 -1
- package/dist/session/session.service.d.ts +8 -2
- package/dist/session/session.service.js +530 -42
- package/dist/session/session.types.d.ts +124 -1
- package/dist/session/session.types.js +231 -4
- package/dist/shared/format/format-bytes.d.ts +1 -0
- package/dist/shared/format/format-bytes.js +9 -0
- package/dist/shared/path/path.d.ts +1 -0
- package/dist/shared/path/path.js +21 -1
- package/dist/shared/process/dotnet-toolchain.d.ts +14 -0
- package/dist/shared/process/dotnet-toolchain.js +179 -0
- package/dist/shared/process/host-process-recovery.d.ts +12 -0
- package/dist/shared/process/host-process-recovery.js +78 -0
- package/dist/shared/process/host-process-supervisor.d.ts +59 -0
- package/dist/shared/process/host-process-supervisor.js +330 -0
- package/dist/shared/process/process.d.ts +1 -0
- package/dist/shared/process/process.js +1 -0
- package/dist/shared/process/windows-launch.d.ts +1 -1
- package/dist/shared/process/windows-launch.js +6 -3
- package/dist/shared/provider-capabilities.d.ts +1 -0
- package/dist/shared/provider-capabilities.js +3 -0
- package/dist/shared/redaction/redaction.js +16 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worktree/artifact-injector.d.ts +3 -2
- package/dist/worktree/artifact-injector.js +43 -4
- package/dist/worktree/dependency-warmer.d.ts +36 -2
- package/dist/worktree/dependency-warmer.js +347 -11
- package/dist/worktree/index.d.ts +2 -1
- package/dist/worktree/index.js +1 -0
- package/dist/worktree/prior-phase-artifact-hydrator.d.ts +2 -0
- package/dist/worktree/prior-phase-artifact-hydrator.js +136 -0
- package/dist/worktree/worktree-paths.d.ts +4 -0
- package/dist/worktree/worktree-paths.js +30 -0
- package/dist/worktree/worktree.base.d.ts +3 -0
- package/dist/worktree/worktree.service.d.ts +13 -2
- package/dist/worktree/worktree.service.js +238 -47
- package/dist/worktree/worktree.types.d.ts +5 -1
- package/package.json +8 -4
- package/runtime/windows-job-supervisor.ps1 +444 -0
- package/runtime/windows-listener-owner.ps1 +33 -0
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import type { RunOnceDispatchPacket, RunnerDispatchArtifact, RunnerDispatchEvent, RunnerDispatchSpec } from "../session.types.js";
|
|
2
2
|
import type { WorktreeHandle } from "../../worktree/worktree.types.js";
|
|
3
|
+
import type { ProviderProcessRunner } from "./provider-cli.process.js";
|
|
3
4
|
export interface ProviderCliRunContext {
|
|
4
5
|
readonly dispatch: RunOnceDispatchPacket;
|
|
5
6
|
readonly worktree: WorktreeHandle;
|
|
7
|
+
readonly runtimeEnvironment?: Readonly<Record<string, string>>;
|
|
8
|
+
readonly processRunner?: ProviderProcessRunner;
|
|
6
9
|
readonly signal?: AbortSignal;
|
|
7
10
|
emit(event: RunnerDispatchEvent): Promise<void>;
|
|
8
11
|
}
|
|
9
12
|
export interface ProviderCliDraftContext {
|
|
10
13
|
readonly dispatch: RunOnceDispatchPacket;
|
|
11
14
|
readonly worktree: WorktreeHandle;
|
|
15
|
+
readonly runtimeEnvironment?: Readonly<Record<string, string>>;
|
|
16
|
+
readonly processRunner?: ProviderProcessRunner;
|
|
12
17
|
readonly signal?: AbortSignal;
|
|
13
18
|
emit(event: RunnerDispatchEvent): Promise<void>;
|
|
14
19
|
}
|
|
@@ -5,6 +5,8 @@ export declare function clip(value: string, maxLength: number): string;
|
|
|
5
5
|
export interface ProviderOutputState {
|
|
6
6
|
readonly sessionLabel: string | null;
|
|
7
7
|
finalMessage: string | null;
|
|
8
|
+
/** True only while the provider has reported a tool/command start without a matching completion. */
|
|
9
|
+
readonly hasActiveToolCall: boolean;
|
|
8
10
|
/** Accumulated provider-reported token usage for this run, or null when none was reported. */
|
|
9
11
|
readonly usage: ProviderUsage | null;
|
|
10
12
|
consume(line: string): readonly RunnerDispatchEvent[];
|
|
@@ -25,12 +25,16 @@ class CursorStreamJsonState {
|
|
|
25
25
|
finalMessage = null;
|
|
26
26
|
emittedSession = false;
|
|
27
27
|
accumulatedUsage = null;
|
|
28
|
+
activeToolCallCount = 0;
|
|
28
29
|
get sessionLabel() {
|
|
29
30
|
return this.sessionId ? `session ${this.sessionId}` : null;
|
|
30
31
|
}
|
|
31
32
|
get usage() {
|
|
32
33
|
return this.accumulatedUsage;
|
|
33
34
|
}
|
|
35
|
+
get hasActiveToolCall() {
|
|
36
|
+
return this.activeToolCallCount > 0;
|
|
37
|
+
}
|
|
34
38
|
consume(line) {
|
|
35
39
|
const event = parseJsonLine(line);
|
|
36
40
|
if (!event) {
|
|
@@ -45,7 +49,8 @@ class CursorStreamJsonState {
|
|
|
45
49
|
role: "runner",
|
|
46
50
|
kind: "checkpoint",
|
|
47
51
|
content: `Cursor session started: ${this.sessionId}.`,
|
|
48
|
-
eventType: "provider_thread_started"
|
|
52
|
+
eventType: "provider_thread_started",
|
|
53
|
+
data: JSON.stringify({ threadId: this.sessionId })
|
|
49
54
|
}];
|
|
50
55
|
}
|
|
51
56
|
}
|
|
@@ -65,6 +70,7 @@ class CursorStreamJsonState {
|
|
|
65
70
|
const subtype = stringField(event, "subtype");
|
|
66
71
|
const toolCall = objectField(event, "tool_call");
|
|
67
72
|
if (subtype === "started") {
|
|
73
|
+
this.activeToolCallCount += 1;
|
|
68
74
|
const summary = formatCursorToolCallStarted(toolCall);
|
|
69
75
|
if (summary) {
|
|
70
76
|
return [{
|
|
@@ -76,6 +82,7 @@ class CursorStreamJsonState {
|
|
|
76
82
|
}
|
|
77
83
|
}
|
|
78
84
|
if (subtype === "completed") {
|
|
85
|
+
this.activeToolCallCount = Math.max(0, this.activeToolCallCount - 1);
|
|
79
86
|
const completed = formatCursorToolCallCompleted(toolCall);
|
|
80
87
|
if (completed) {
|
|
81
88
|
return [{
|
|
@@ -110,13 +117,19 @@ class CursorStreamJsonState {
|
|
|
110
117
|
if (Object.keys(usage).length === 0 && durationMs === 0) {
|
|
111
118
|
return;
|
|
112
119
|
}
|
|
120
|
+
const uncachedInputTokens = readUsageNumber(usage, "inputTokens");
|
|
121
|
+
const cacheReadTokens = readUsageNumber(usage, "cacheReadTokens");
|
|
122
|
+
const cacheCreationTokens = readUsageNumber(usage, "cacheWriteTokens");
|
|
113
123
|
this.accumulatedUsage = addUsage(this.accumulatedUsage ?? emptyUsage("provider_reported"), {
|
|
114
|
-
inputTokens:
|
|
124
|
+
inputTokens: uncachedInputTokens + cacheReadTokens + cacheCreationTokens,
|
|
125
|
+
uncachedInputTokens,
|
|
115
126
|
outputTokens: readUsageNumber(usage, "outputTokens"),
|
|
116
|
-
cacheReadTokens
|
|
117
|
-
cacheCreationTokens
|
|
127
|
+
cacheReadTokens,
|
|
128
|
+
cacheCreationTokens,
|
|
118
129
|
providerDurationMs: durationMs > 0 ? durationMs : null,
|
|
119
|
-
source: "provider_reported"
|
|
130
|
+
source: "provider_reported",
|
|
131
|
+
inputTokenSemantics: "excludes_cache_tokens",
|
|
132
|
+
rawUsage: [{ provider: "cursor", usage }]
|
|
120
133
|
});
|
|
121
134
|
}
|
|
122
135
|
}
|
|
@@ -224,18 +237,23 @@ class CodexJsonState {
|
|
|
224
237
|
finalMessage = null;
|
|
225
238
|
emittedThread = false;
|
|
226
239
|
accumulatedUsage = null;
|
|
240
|
+
activeToolCallCount = 0;
|
|
227
241
|
get sessionLabel() {
|
|
228
242
|
return this.threadId ? `thread ${this.threadId}` : null;
|
|
229
243
|
}
|
|
230
244
|
get usage() {
|
|
231
245
|
return this.accumulatedUsage;
|
|
232
246
|
}
|
|
247
|
+
get hasActiveToolCall() {
|
|
248
|
+
return this.activeToolCallCount > 0;
|
|
249
|
+
}
|
|
233
250
|
consume(line) {
|
|
234
251
|
const event = parseJsonLine(line);
|
|
235
252
|
if (!event) {
|
|
236
253
|
return [];
|
|
237
254
|
}
|
|
238
255
|
const type = stringField(event, "type") ?? "";
|
|
256
|
+
this.trackToolActivity(type, event);
|
|
239
257
|
if (type === "thread.started") {
|
|
240
258
|
this.threadId = stringField(event, "thread_id");
|
|
241
259
|
if (this.threadId && !this.emittedThread) {
|
|
@@ -244,7 +262,8 @@ class CodexJsonState {
|
|
|
244
262
|
role: "runner",
|
|
245
263
|
kind: "checkpoint",
|
|
246
264
|
content: `Codex thread started: ${this.threadId}.`,
|
|
247
|
-
eventType: "provider_thread_started"
|
|
265
|
+
eventType: "provider_thread_started",
|
|
266
|
+
data: JSON.stringify({ threadId: this.threadId })
|
|
248
267
|
}];
|
|
249
268
|
}
|
|
250
269
|
}
|
|
@@ -265,7 +284,7 @@ class CodexJsonState {
|
|
|
265
284
|
eventType: "provider_cli_error"
|
|
266
285
|
}];
|
|
267
286
|
}
|
|
268
|
-
if (type === "item.completed" || type === "item.updated") {
|
|
287
|
+
if (type === "item.started" || type === "item.completed" || type === "item.updated") {
|
|
269
288
|
const item = objectField(event, "item");
|
|
270
289
|
const itemType = stringField(item, "type");
|
|
271
290
|
if (itemType === "agent_message") {
|
|
@@ -287,7 +306,7 @@ class CodexJsonState {
|
|
|
287
306
|
return [{
|
|
288
307
|
role: "worker",
|
|
289
308
|
kind: "checkpoint",
|
|
290
|
-
content: `Codex command ${status || "completed"}: ${clip(command, 500)}`,
|
|
309
|
+
content: `Codex command ${status || (type === "item.started" ? "started" : "completed")}: ${clip(command, 500)}`,
|
|
291
310
|
eventType: "provider_command"
|
|
292
311
|
}];
|
|
293
312
|
}
|
|
@@ -299,17 +318,39 @@ class CodexJsonState {
|
|
|
299
318
|
}
|
|
300
319
|
return [];
|
|
301
320
|
}
|
|
321
|
+
trackToolActivity(type, event) {
|
|
322
|
+
if (type !== "item.started" && type !== "item.completed") {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const item = objectField(event, "item");
|
|
326
|
+
const itemType = (stringField(item, "type") ?? "").toLowerCase();
|
|
327
|
+
const toolName = mcpToolName(item);
|
|
328
|
+
const isTool = itemType === "command_execution"
|
|
329
|
+
|| itemType.includes("mcp")
|
|
330
|
+
|| Boolean(toolName);
|
|
331
|
+
if (!isTool) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
this.activeToolCallCount = type === "item.started"
|
|
335
|
+
? this.activeToolCallCount + 1
|
|
336
|
+
: Math.max(0, this.activeToolCallCount - 1);
|
|
337
|
+
}
|
|
302
338
|
accumulateUsage(event) {
|
|
303
339
|
const usage = objectField(event, "usage");
|
|
304
340
|
if (Object.keys(usage).length === 0) {
|
|
305
341
|
return;
|
|
306
342
|
}
|
|
343
|
+
const inputTokens = readUsageNumber(usage, "input_tokens");
|
|
344
|
+
const cacheReadTokens = readUsageNumber(usage, "cached_input_tokens");
|
|
307
345
|
this.accumulatedUsage = addUsage(this.accumulatedUsage ?? emptyUsage("provider_reported"), {
|
|
308
|
-
inputTokens
|
|
346
|
+
inputTokens,
|
|
347
|
+
uncachedInputTokens: Math.max(0, inputTokens - cacheReadTokens),
|
|
309
348
|
outputTokens: readUsageNumber(usage, "output_tokens"),
|
|
310
|
-
cacheReadTokens
|
|
349
|
+
cacheReadTokens,
|
|
311
350
|
reasoningOutputTokens: readUsageNumber(usage, "reasoning_output_tokens"),
|
|
312
|
-
source: "provider_reported"
|
|
351
|
+
source: "provider_reported",
|
|
352
|
+
inputTokenSemantics: "includes_cached_input",
|
|
353
|
+
rawUsage: [{ provider: "codex", usage }]
|
|
313
354
|
});
|
|
314
355
|
}
|
|
315
356
|
}
|
|
@@ -397,11 +438,45 @@ function mcpErrorSummary(item) {
|
|
|
397
438
|
if (direct) {
|
|
398
439
|
return clip(direct, 600);
|
|
399
440
|
}
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
441
|
+
const messages = uniqueErrorMessages([
|
|
442
|
+
item.error,
|
|
443
|
+
item.result,
|
|
444
|
+
item.content,
|
|
445
|
+
]);
|
|
446
|
+
return messages.length > 0 ? clip(messages.join(" Caused by: "), 600) : null;
|
|
447
|
+
}
|
|
448
|
+
function uniqueErrorMessages(values) {
|
|
449
|
+
const messages = [];
|
|
450
|
+
const seenMessages = new Set();
|
|
451
|
+
const seenObjects = new Set();
|
|
452
|
+
const visit = (value, depth) => {
|
|
453
|
+
if (depth > 8 || value === null || value === undefined)
|
|
454
|
+
return;
|
|
455
|
+
if (typeof value === "string") {
|
|
456
|
+
const message = value.trim();
|
|
457
|
+
if (message.length > 0 && !seenMessages.has(message)) {
|
|
458
|
+
seenMessages.add(message);
|
|
459
|
+
messages.push(message);
|
|
460
|
+
}
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (typeof value !== "object" || seenObjects.has(value))
|
|
464
|
+
return;
|
|
465
|
+
seenObjects.add(value);
|
|
466
|
+
if (Array.isArray(value)) {
|
|
467
|
+
for (const entry of value)
|
|
468
|
+
visit(entry, depth + 1);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
const record = value;
|
|
472
|
+
for (const key of ["message", "summary", "error", "cause", "data", "details", "result", "content"]) {
|
|
473
|
+
if (key in record)
|
|
474
|
+
visit(record[key], depth + 1);
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
for (const value of values)
|
|
478
|
+
visit(value, 0);
|
|
479
|
+
return messages;
|
|
405
480
|
}
|
|
406
481
|
function safeProviderMcpData(item, serverName, toolName, status) {
|
|
407
482
|
const elapsedMs = numericField(item, "elapsed_ms") ?? numericField(item, "duration_ms");
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import type { RunOnceDispatchPacket, RunnerDispatchEvent } from "../session.types.js";
|
|
2
2
|
export type UsageSource = "provider_reported" | "cli_reported" | "estimated" | "unknown";
|
|
3
|
+
export type InputTokenSemantics = "includes_cached_input" | "excludes_cache_tokens" | "unknown";
|
|
4
|
+
export declare const PROVIDER_USAGE_SCHEMA_VERSION = 1;
|
|
3
5
|
/**
|
|
4
6
|
* Normalized, provider-agnostic token usage accumulated for a dispatch. Cost is never computed
|
|
5
7
|
* here; the API recomputes cost from these tokens x model rates (ADR-0006).
|
|
6
8
|
*/
|
|
7
9
|
export interface ProviderUsage {
|
|
10
|
+
/** Normalized total input. Cached input is a subset, never an additive peer. */
|
|
8
11
|
readonly inputTokens: number;
|
|
12
|
+
readonly uncachedInputTokens: number | null;
|
|
9
13
|
readonly outputTokens: number;
|
|
10
14
|
readonly cacheReadTokens: number;
|
|
11
15
|
readonly cacheCreationTokens: number;
|
|
12
16
|
readonly reasoningOutputTokens: number;
|
|
13
17
|
readonly providerDurationMs: number | null;
|
|
14
18
|
readonly source: UsageSource;
|
|
19
|
+
readonly inputTokenSemantics: InputTokenSemantics;
|
|
20
|
+
/** Exact provider usage objects retained for audit/re-normalization. */
|
|
21
|
+
readonly rawUsage: readonly Record<string, unknown>[];
|
|
15
22
|
}
|
|
16
23
|
export declare function emptyUsage(source?: UsageSource): ProviderUsage;
|
|
17
24
|
export declare function addUsage(base: ProviderUsage, next: Partial<ProviderUsage>): ProviderUsage;
|
|
@@ -1,27 +1,38 @@
|
|
|
1
|
+
export const PROVIDER_USAGE_SCHEMA_VERSION = 1;
|
|
1
2
|
export function emptyUsage(source = "unknown") {
|
|
2
3
|
return {
|
|
3
4
|
inputTokens: 0,
|
|
5
|
+
uncachedInputTokens: 0,
|
|
4
6
|
outputTokens: 0,
|
|
5
7
|
cacheReadTokens: 0,
|
|
6
8
|
cacheCreationTokens: 0,
|
|
7
9
|
reasoningOutputTokens: 0,
|
|
8
10
|
providerDurationMs: null,
|
|
9
|
-
source
|
|
11
|
+
source,
|
|
12
|
+
inputTokenSemantics: "unknown",
|
|
13
|
+
rawUsage: []
|
|
10
14
|
};
|
|
11
15
|
}
|
|
12
16
|
export function addUsage(base, next) {
|
|
17
|
+
const nextUncached = next.uncachedInputTokens;
|
|
18
|
+
const uncachedInputTokens = base.uncachedInputTokens === null || nextUncached === null
|
|
19
|
+
? null
|
|
20
|
+
: base.uncachedInputTokens + nonNegative(nextUncached);
|
|
13
21
|
return {
|
|
14
22
|
inputTokens: base.inputTokens + nonNegative(next.inputTokens),
|
|
23
|
+
uncachedInputTokens,
|
|
15
24
|
outputTokens: base.outputTokens + nonNegative(next.outputTokens),
|
|
16
25
|
cacheReadTokens: base.cacheReadTokens + nonNegative(next.cacheReadTokens),
|
|
17
26
|
cacheCreationTokens: base.cacheCreationTokens + nonNegative(next.cacheCreationTokens),
|
|
18
27
|
reasoningOutputTokens: base.reasoningOutputTokens + nonNegative(next.reasoningOutputTokens),
|
|
19
28
|
providerDurationMs: next.providerDurationMs ?? base.providerDurationMs,
|
|
20
|
-
source: next.source ?? base.source
|
|
29
|
+
source: next.source ?? base.source,
|
|
30
|
+
inputTokenSemantics: mergeSemantics(base.inputTokenSemantics, next.inputTokenSemantics),
|
|
31
|
+
rawUsage: [...base.rawUsage, ...(next.rawUsage ?? [])]
|
|
21
32
|
};
|
|
22
33
|
}
|
|
23
34
|
export function totalTokens(usage) {
|
|
24
|
-
return usage.inputTokens + usage.outputTokens
|
|
35
|
+
return usage.inputTokens + usage.outputTokens;
|
|
25
36
|
}
|
|
26
37
|
export function hasUsage(usage) {
|
|
27
38
|
return usage !== null && totalTokens(usage) > 0;
|
|
@@ -37,20 +48,26 @@ export function buildProviderUsageEvent(dispatch, usage) {
|
|
|
37
48
|
lane: dispatch.execution.lane,
|
|
38
49
|
phase: dispatch.cycleRun.phase,
|
|
39
50
|
attempt: dispatch.cycleRun.attempt,
|
|
51
|
+
usage_schema_version: PROVIDER_USAGE_SCHEMA_VERSION,
|
|
52
|
+
input_token_semantics: usage.inputTokenSemantics,
|
|
40
53
|
input_tokens: usage.inputTokens,
|
|
54
|
+
uncached_input_tokens: usage.uncachedInputTokens,
|
|
41
55
|
output_tokens: usage.outputTokens,
|
|
42
56
|
cache_read_tokens: usage.cacheReadTokens,
|
|
43
57
|
cache_creation_tokens: usage.cacheCreationTokens,
|
|
44
58
|
reasoning_output_tokens: usage.reasoningOutputTokens,
|
|
45
59
|
metered: dispatch.execution.authKind === "api_key",
|
|
46
60
|
usage_source: usage.source,
|
|
47
|
-
provider_duration_ms: usage.providerDurationMs
|
|
61
|
+
provider_duration_ms: usage.providerDurationMs,
|
|
62
|
+
normalized_total_tokens: totalTokens(usage),
|
|
63
|
+
normalized_total_formula: "total_input + output; cached_input is a subset of total_input",
|
|
64
|
+
raw_usage: usage.rawUsage
|
|
48
65
|
};
|
|
49
66
|
const total = totalTokens(usage);
|
|
50
67
|
return {
|
|
51
68
|
role: "runner",
|
|
52
69
|
kind: "checkpoint",
|
|
53
|
-
content: `Provider usage: ${total} tokens (${usage.inputTokens} in / ${usage.outputTokens} out) for ${dispatch.execution.model}.`,
|
|
70
|
+
content: `Provider usage: ${total} tokens (${usage.inputTokens} total in, including ${usage.cacheReadTokens} cached / ${usage.outputTokens} out) for ${dispatch.execution.model}.`,
|
|
54
71
|
eventType: "provider_usage",
|
|
55
72
|
data: JSON.stringify(data)
|
|
56
73
|
};
|
|
@@ -62,3 +79,9 @@ export function readUsageNumber(source, key) {
|
|
|
62
79
|
function nonNegative(value) {
|
|
63
80
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
64
81
|
}
|
|
82
|
+
function mergeSemantics(base, next) {
|
|
83
|
+
if (!next || next === "unknown") {
|
|
84
|
+
return base;
|
|
85
|
+
}
|
|
86
|
+
return base === "unknown" || base === next ? next : "unknown";
|
|
87
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { RunOnceResultPacket, RunnerDispatchEvent } from "./session.types.js";
|
|
2
|
+
export declare function redactRunnerDispatchEvent(event: RunnerDispatchEvent, exactSecrets?: readonly string[]): RunnerDispatchEvent;
|
|
3
|
+
export declare function redactRunOnceResultPacket(result: RunOnceResultPacket, exactSecrets?: readonly string[]): RunOnceResultPacket;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { redactSecrets } from "../shared/redaction/redaction.js";
|
|
2
|
+
const integrityProtectedEventDataTypes = new Set(["sandbox_started"]);
|
|
3
|
+
export function redactRunnerDispatchEvent(event, exactSecrets = []) {
|
|
4
|
+
if (!event.data || !integrityProtectedEventDataTypes.has(event.eventType)) {
|
|
5
|
+
return redactSecrets(event, exactSecrets);
|
|
6
|
+
}
|
|
7
|
+
// sandbox_started data is runner-authored protocol metadata. Its runtime
|
|
8
|
+
// lease repeats the dispatch fence so the API can validate ownership. The
|
|
9
|
+
// transcript redactor treats any serialized `*Token` field as a secret and
|
|
10
|
+
// must not rewrite that identity before transport or result persistence.
|
|
11
|
+
const { data, ...transcript } = event;
|
|
12
|
+
return {
|
|
13
|
+
...redactSecrets(transcript, exactSecrets),
|
|
14
|
+
data,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function redactRunOnceResultPacket(result, exactSecrets = []) {
|
|
18
|
+
const { events, artifact, artifacts, ...payload } = result;
|
|
19
|
+
return {
|
|
20
|
+
...redactSecrets(payload, exactSecrets),
|
|
21
|
+
...(artifact !== undefined
|
|
22
|
+
? { artifact: artifact === null ? null : redactArtifact(artifact, exactSecrets) }
|
|
23
|
+
: {}),
|
|
24
|
+
...(artifacts !== undefined
|
|
25
|
+
? { artifacts: artifacts === null ? null : artifacts.map(item => redactArtifact(item, exactSecrets)) }
|
|
26
|
+
: {}),
|
|
27
|
+
events: events.map(event => redactRunnerDispatchEvent(event, exactSecrets)),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function redactArtifact(artifact, exactSecrets) {
|
|
31
|
+
const { sidecars, ...payload } = artifact;
|
|
32
|
+
return {
|
|
33
|
+
...redactSecrets(payload, exactSecrets),
|
|
34
|
+
// These bytes already passed the QA path/hash/size checks. The generic
|
|
35
|
+
// redactor strips contentBase64 fields and must not corrupt the payload.
|
|
36
|
+
...(sidecars !== undefined ? { sidecars } : {}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import type { RunOnceDispatchPacket, RunOnceResultPacket, RunnerDispatchEvent } from "./session.types.js";
|
|
1
|
+
import type { HostRuntimeReadinessProbeRequest, HostRuntimeReadinessProbeResult, RunOnceDispatchPacket, RunOnceResultPacket, RunnerDispatchEvent } from "./session.types.js";
|
|
2
|
+
import type { HostRuntimeCapacitySnapshot, HostRuntimeReapOptions, HostRuntimeReapReport } from "../runtime/host-runtime-lease.js";
|
|
2
3
|
export interface SessionEventSink {
|
|
3
4
|
emit(event: RunnerDispatchEvent): Promise<void>;
|
|
4
5
|
}
|
|
5
6
|
export interface SessionService {
|
|
6
7
|
runOnce(dispatch: RunOnceDispatchPacket, sink: SessionEventSink, signal?: AbortSignal): Promise<RunOnceResultPacket>;
|
|
8
|
+
updateLease?(dispatchAttemptId: string, fencingToken: string, expiresAt: string): Promise<void>;
|
|
9
|
+
reapHostRuntime?(options: HostRuntimeReapOptions): Promise<HostRuntimeReapReport | null>;
|
|
10
|
+
runtimeCapacity?(): HostRuntimeCapacitySnapshot | null;
|
|
11
|
+
probeHostRuntime?(request: HostRuntimeReadinessProbeRequest, signal?: AbortSignal): Promise<HostRuntimeReadinessProbeResult>;
|
|
7
12
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { ProviderCliService } from "./provider-cli/provider-cli.base.js";
|
|
2
2
|
import type { SessionEventSink, SessionService } from "./session.base.js";
|
|
3
|
-
import type { RunOnceDispatchPacket, RunOnceResultPacket } from "./session.types.js";
|
|
3
|
+
import type { HostRuntimeReadinessProbeRequest, HostRuntimeReadinessProbeResult, RunOnceDispatchPacket, RunOnceResultPacket } from "./session.types.js";
|
|
4
4
|
import type { WorktreeService } from "../worktree/worktree.base.js";
|
|
5
|
+
import { type HostRuntimeCapacitySnapshot, type HostRuntimeLeaseRuntime, type HostRuntimeReapOptions, type HostRuntimeReapReport } from "../runtime/host-runtime-lease.js";
|
|
5
6
|
export declare class BridgeSessionService implements SessionService {
|
|
6
7
|
private readonly worktrees;
|
|
7
8
|
private readonly providerCli;
|
|
8
|
-
|
|
9
|
+
private readonly hostRuntime?;
|
|
10
|
+
constructor(worktrees?: WorktreeService, providerCli?: ProviderCliService, hostRuntime?: HostRuntimeLeaseRuntime | undefined);
|
|
11
|
+
updateLease(dispatchAttemptId: string, fencingToken: string, expiresAt: string): Promise<void>;
|
|
12
|
+
reapHostRuntime(options: HostRuntimeReapOptions): Promise<HostRuntimeReapReport | null>;
|
|
13
|
+
runtimeCapacity(): HostRuntimeCapacitySnapshot | null;
|
|
14
|
+
probeHostRuntime(request: HostRuntimeReadinessProbeRequest, signal?: AbortSignal): Promise<HostRuntimeReadinessProbeResult>;
|
|
9
15
|
runOnce(dispatch: RunOnceDispatchPacket, sink: SessionEventSink, signal?: AbortSignal): Promise<RunOnceResultPacket>;
|
|
10
16
|
}
|