@jmanuelcorral/openteam 0.27.0 → 0.28.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/.opencode/openteam.example.json +7 -1
- package/README.es.md +22 -4
- package/README.md +28 -4
- package/dist/certificates/graph-release-certificate.json +2 -2
- package/dist/certificates/graph-shadow-certificate.json +2 -2
- package/dist/certificates/opencode-2.0.5/graph-release-certificate.json +2 -2
- package/dist/certificates/opencode-2.0.5/graph-shadow-certificate.json +2 -2
- package/dist/cli/opencodeVersion.d.ts.map +1 -1
- package/dist/cli.js +1641 -258
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/config/errors.d.ts.map +1 -1
- package/dist/config/graphFeatureGate.d.ts +3 -3
- package/dist/config/schema.d.ts +18 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/console/agentView.d.ts +13 -0
- package/dist/console/agentView.d.ts.map +1 -0
- package/dist/console/assets.d.ts.map +1 -1
- package/dist/console/inspector.d.ts.map +1 -1
- package/dist/console/refresh.d.ts +1 -1
- package/dist/console/refresh.d.ts.map +1 -1
- package/dist/console/render.d.ts +1 -0
- package/dist/console/render.d.ts.map +1 -1
- package/dist/contract/opencode.d.ts +13 -12
- package/dist/contract/opencode.d.ts.map +1 -1
- package/dist/graph/certificate.d.ts.map +1 -1
- package/dist/graph/schema.d.ts +6 -0
- package/dist/graph/schema.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1260 -434
- package/dist/lifecycle/contracts.d.ts +2 -2
- package/dist/lifecycle/contracts.d.ts.map +1 -1
- package/dist/lifecycle/schema.d.ts +6 -0
- package/dist/lifecycle/schema.d.ts.map +1 -1
- package/dist/local/concurrency.d.ts +1 -1
- package/dist/local/concurrency.d.ts.map +1 -1
- package/dist/messages/agentView.d.ts +77 -0
- package/dist/messages/agentView.d.ts.map +1 -0
- package/dist/messages/consoleDetail.d.ts +9 -0
- package/dist/messages/consoleDetail.d.ts.map +1 -1
- package/dist/messages/nativeHost.d.ts +1 -0
- package/dist/messages/nativeHost.d.ts.map +1 -1
- package/dist/messages/orchestration.d.ts +26 -0
- package/dist/messages/orchestration.d.ts.map +1 -1
- package/dist/opencodeArtifacts/orchestratorAgent.d.ts.map +1 -1
- package/dist/orchestrator/coordinator.d.ts +13 -1
- package/dist/orchestrator/coordinator.d.ts.map +1 -1
- package/dist/orchestrator/outputContract.d.ts +3 -0
- package/dist/orchestrator/outputContract.d.ts.map +1 -1
- package/dist/orchestrator/reportDelivery.d.ts +13 -0
- package/dist/orchestrator/reportDelivery.d.ts.map +1 -0
- package/dist/orchestrator/subsessions.d.ts +5 -0
- package/dist/orchestrator/subsessions.d.ts.map +1 -1
- package/dist/orchestrator/taskEffort.d.ts +39 -0
- package/dist/orchestrator/taskEffort.d.ts.map +1 -0
- package/dist/plugin/capture.d.ts +3 -0
- package/dist/plugin/capture.d.ts.map +1 -1
- package/dist/plugin/nativeHost.d.ts.map +1 -1
- package/dist/plugin/nativeHostContext.d.ts +1 -1
- package/dist/plugin/nativeHostContext.d.ts.map +1 -1
- package/dist/plugin/nativeSessions.d.ts +9 -0
- package/dist/plugin/nativeSessions.d.ts.map +1 -1
- package/dist/plugin/orchestrateTool.d.ts +6 -0
- package/dist/plugin/orchestrateTool.d.ts.map +1 -1
- package/dist/plugin/reportTool.d.ts +4 -0
- package/dist/plugin/reportTool.d.ts.map +1 -0
- package/dist/plugin/runtimeContext.d.ts +14 -0
- package/dist/plugin/runtimeContext.d.ts.map +1 -1
- package/dist/plugin/toolcalls.d.ts +9 -1
- package/dist/plugin/toolcalls.d.ts.map +1 -1
- package/dist/storage/scopedArtifacts.d.ts +7 -0
- package/dist/storage/scopedArtifacts.d.ts.map +1 -0
- package/dist/telemetry/aggregate.d.ts +7 -0
- package/dist/telemetry/aggregate.d.ts.map +1 -1
- package/dist/telemetry/events.d.ts +68 -2
- package/dist/telemetry/events.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { exec, execFile as execFile4 } from "node:child_process";
|
|
|
7
7
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
8
8
|
import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile2 } from "node:fs/promises";
|
|
9
9
|
import { createRequire as createRequire2 } from "node:module";
|
|
10
|
-
import { dirname as
|
|
10
|
+
import { dirname as dirname12, resolve as resolve19 } from "node:path";
|
|
11
11
|
import { promisify as promisify3 } from "node:util";
|
|
12
12
|
import {
|
|
13
13
|
confirm as clackConfirm,
|
|
@@ -577,6 +577,15 @@ function migrateConfig(raw) {
|
|
|
577
577
|
var consoleDetailMessages = {
|
|
578
578
|
runtimeStateCleanupFailed: "The Console runtime state could not be published and its staging file could not be removed.",
|
|
579
579
|
requestFailed: "The local opencode request failed.",
|
|
580
|
+
usageUnavailable: "Unavailable / partial",
|
|
581
|
+
usageCaution: "The host did not report trustworthy usage for every message. Counters are not confirmed totals; no token rate or real savings can be inferred.",
|
|
582
|
+
timingUnknown: "Unknown",
|
|
583
|
+
estimatedCost: "Estimated cost",
|
|
584
|
+
estimatedBaseline: "Estimated baseline",
|
|
585
|
+
estimatedSavings: "Estimated savings",
|
|
586
|
+
estimatedInput: "Estimated tokens in",
|
|
587
|
+
estimatedOutput: "Estimated tokens out",
|
|
588
|
+
estimatesNotUsage: "Routing estimates are separate from host-reported usage; they are not measured spend or proven savings.",
|
|
580
589
|
nativeToolFailed: "The native tool execution failed.",
|
|
581
590
|
follow: "Follow new activity",
|
|
582
591
|
metadataOnly: "Lifecycle and telemetry stay metadata-only.",
|
|
@@ -832,7 +841,13 @@ var OrchestratorConfigSchema = z2.object({
|
|
|
832
841
|
roles: OrchestratorRolesSchema,
|
|
833
842
|
primary: AgentExecutionPolicySchema.optional(),
|
|
834
843
|
maxRetries: z2.number().int().min(0).optional(),
|
|
835
|
-
maxModelsPerNode: z2.number().int().positive().optional()
|
|
844
|
+
maxModelsPerNode: z2.number().int().positive().optional(),
|
|
845
|
+
taskBudget: z2.object({
|
|
846
|
+
maxBatches: z2.number().int().min(1).max(1000).optional(),
|
|
847
|
+
maxAttempts: z2.number().int().min(1).max(1e4).optional(),
|
|
848
|
+
maxDurationMs: z2.number().int().min(1000).max(86400000).optional(),
|
|
849
|
+
maxDepth: z2.number().int().min(0).max(32).optional()
|
|
850
|
+
}).strict().optional()
|
|
836
851
|
}).strict();
|
|
837
852
|
var defaultFrontierModel = {
|
|
838
853
|
providerID: "google",
|
|
@@ -1497,6 +1512,32 @@ function withReportedModelSlots(runtime, reported, aliases) {
|
|
|
1497
1512
|
}
|
|
1498
1513
|
|
|
1499
1514
|
// src/messages/orchestration.ts
|
|
1515
|
+
var reportDeliveryMessages = {
|
|
1516
|
+
description: "Submit the active worker's substantive findings to its assigned durable report. No arbitrary paths or other sessions are accepted. This does not replace the coordinator's completion checks.",
|
|
1517
|
+
status: "Whether the assigned work is done or needs another bounded pass.",
|
|
1518
|
+
findings: "Concrete findings, changes, evidence and remaining work; at most 32768 characters.",
|
|
1519
|
+
assignmentConflict: "A report assignment is already active for this session.",
|
|
1520
|
+
noAssignment: "No active coordinator-owned report assignment exists for this session.",
|
|
1521
|
+
invalidReport: "Report delivery requires substantive findings and a valid done/continue status within 32768 characters.",
|
|
1522
|
+
unsafePath: "The private artifact path is unavailable, linked or outside the allowed boundary.",
|
|
1523
|
+
workspaceMismatch: "Orchestration directory must match the trusted host workspace; a model-authored directory cannot change report or session scope.",
|
|
1524
|
+
submitted: (path) => `Report persisted at ${path}. The coordinator will independently validate current, substantive completion.`
|
|
1525
|
+
};
|
|
1526
|
+
var taskEffortMessages = {
|
|
1527
|
+
cancelled: "Task execution was cancelled; no replacement attempt was dispatched.",
|
|
1528
|
+
createDeadline: "task-budget-exhausted: duration. Session creation did not settle before the deadline; no prompt was dispatched and retry is disabled.",
|
|
1529
|
+
ledgerInvalid: "The cumulative task-effort ledger is invalid or unavailable; orchestration is stopped rather than resetting its allowance.",
|
|
1530
|
+
exhausted: (reason) => `task-budget-exhausted: ${reason}. Keep existing work and reports. Another batch or worker cannot reset this task's allowance; a new root user turn starts a new task.`,
|
|
1531
|
+
summary: (batches, attempts, remainingMs, remainingBatches, remainingAttempts) => `Task effort: ${batches} batch(es), ${attempts} attempt(s), ${Math.max(0, Math.floor(remainingMs / 1000))}s remaining; ${remainingBatches} batch(es) and ${remainingAttempts} attempt(s) available.`
|
|
1532
|
+
};
|
|
1533
|
+
var executionPhaseMessages = {
|
|
1534
|
+
"model-request": "Model request",
|
|
1535
|
+
"tool-input": "Preparing tool input",
|
|
1536
|
+
"tool-execution": "Executing a tool",
|
|
1537
|
+
"report-validation": "Validating durable report",
|
|
1538
|
+
idle: "Session idle",
|
|
1539
|
+
unknown: "Session phase unavailable"
|
|
1540
|
+
};
|
|
1500
1541
|
var HOST_SESSION_REQUIRED = "Orchestration requires a nonempty host ToolContext sessionID.";
|
|
1501
1542
|
var PARENT_OVERRIDE_IGNORED = "parentSessionID override ignored: the trusted host ToolContext session owns this orchestration and its children. Programmatic callers must supply their parent as the ToolContext sessionID.";
|
|
1502
1543
|
var PARENT_SESSION_DESCRIPTION = "Legacy parent reference. Omit it: the trusted host ToolContext session is the parent. A differing payload value is ignored with an advisory.";
|
|
@@ -2359,15 +2400,29 @@ var MessageEventSchema = EventBaseSchema.extend({
|
|
|
2359
2400
|
tokensReasoning: z5.number().int().min(0),
|
|
2360
2401
|
tokensCacheRead: z5.number().int().min(0),
|
|
2361
2402
|
tokensCacheWrite: z5.number().int().min(0),
|
|
2362
|
-
durationMs: z5.number().int().min(0)
|
|
2403
|
+
durationMs: z5.number().int().min(0),
|
|
2404
|
+
usageStatus: z5.enum(["reported", "missing", "zero-unverified"]).optional(),
|
|
2405
|
+
costStatus: z5.enum(["reported", "unavailable"]).optional(),
|
|
2406
|
+
finish: z5.enum([
|
|
2407
|
+
"stop",
|
|
2408
|
+
"length",
|
|
2409
|
+
"tool-calls",
|
|
2410
|
+
"content-filter",
|
|
2411
|
+
"error",
|
|
2412
|
+
"unknown"
|
|
2413
|
+
]).optional(),
|
|
2414
|
+
truncatedToolCall: z5.boolean().optional()
|
|
2363
2415
|
});
|
|
2364
2416
|
var ToolcallEventSchema = EventBaseSchema.extend({
|
|
2365
2417
|
type: z5.literal("toolcall"),
|
|
2366
2418
|
tool: z5.string().min(1),
|
|
2367
2419
|
callID: z5.string().min(1),
|
|
2368
2420
|
agent: z5.string().min(1).optional(),
|
|
2369
|
-
durationMs: z5.number().int().min(0),
|
|
2421
|
+
durationMs: z5.number().int().min(0).nullable(),
|
|
2370
2422
|
ok: z5.boolean(),
|
|
2423
|
+
executed: z5.boolean().optional(),
|
|
2424
|
+
providerExecuted: z5.boolean().optional(),
|
|
2425
|
+
failureKind: z5.enum(["input-invalid", "execution", "unknown"]).optional(),
|
|
2371
2426
|
title: z5.string().optional()
|
|
2372
2427
|
});
|
|
2373
2428
|
var MeetingEventSchema = EventBaseSchema.extend({
|
|
@@ -2397,7 +2452,15 @@ var ActivityEventSchema = EventBaseSchema.extend({
|
|
|
2397
2452
|
type: z5.literal("activity"),
|
|
2398
2453
|
kind: z5.enum(["route", "agent", "decision", "commit"]),
|
|
2399
2454
|
agent: z5.string().min(1).optional(),
|
|
2400
|
-
summary: z5.string().min(1)
|
|
2455
|
+
summary: z5.string().min(1),
|
|
2456
|
+
phase: z5.enum([
|
|
2457
|
+
"model-request",
|
|
2458
|
+
"tool-input",
|
|
2459
|
+
"tool-execution",
|
|
2460
|
+
"report-validation",
|
|
2461
|
+
"idle",
|
|
2462
|
+
"unknown"
|
|
2463
|
+
]).optional()
|
|
2401
2464
|
});
|
|
2402
2465
|
var SessionEndpointEventSchema = EventBaseSchema.extend({
|
|
2403
2466
|
type: z5.literal("session-endpoint"),
|
|
@@ -2860,11 +2923,17 @@ function reportHasSubstance(text) {
|
|
|
2860
2923
|
function roleReportPath(batchID, roleID) {
|
|
2861
2924
|
return `${ROLE_REPORTS_ROOT}/${reportPathSegment(batchID)}/${reportPathSegment(roleID)}.md`;
|
|
2862
2925
|
}
|
|
2863
|
-
function outputContractInstruction(reportPath) {
|
|
2926
|
+
function outputContractInstruction(reportPath, structuredReport) {
|
|
2864
2927
|
return [
|
|
2865
2928
|
"## Output contract (openteam)",
|
|
2866
2929
|
"",
|
|
2867
|
-
|
|
2930
|
+
...structuredReport ? [
|
|
2931
|
+
"Prefer `openteam-submit-report` with substantive `findings` and `status`",
|
|
2932
|
+
"(`done` or `continue`): openteam persists only your assigned report and",
|
|
2933
|
+
"confirms the write. Keep submissions concise; split large work into small",
|
|
2934
|
+
"tool calls. If that tool is unavailable, write your complete findings"
|
|
2935
|
+
] : ["Write your complete findings"],
|
|
2936
|
+
"to the report file below using the `write`",
|
|
2868
2937
|
"tool (create parent directories as needed), and keep it updated with",
|
|
2869
2938
|
"`edit` as you progress. This file is the ONLY channel your work reaches",
|
|
2870
2939
|
"the coordinator: anything you do not write there is discarded and lost,",
|
|
@@ -2907,9 +2976,33 @@ function composeSubsessionPrompt(input) {
|
|
|
2907
2976
|
].join(`
|
|
2908
2977
|
`) : "";
|
|
2909
2978
|
return {
|
|
2910
|
-
prompt: `${input.prompt}${handoff}
|
|
2979
|
+
prompt: `${input.prompt}${handoff}${input.truncated !== true ? "" : [
|
|
2980
|
+
"",
|
|
2981
|
+
"",
|
|
2982
|
+
"## Truncated tool-call recovery",
|
|
2983
|
+
"",
|
|
2984
|
+
"The previous response ended at the output limit and a tool call was invalid",
|
|
2985
|
+
"before execution. Use smaller, bounded tool calls and concise findings.",
|
|
2986
|
+
"Inspect the existing workspace and assigned report before continuing.",
|
|
2987
|
+
"Never repair and execute the malformed JSON. Produce a fresh, complete",
|
|
2988
|
+
"call only for work that is still necessary. Do not increase model limits",
|
|
2989
|
+
"or change the execution domain. This continuation uses the same pass budget."
|
|
2990
|
+
].join(`
|
|
2991
|
+
`)}${input.repair === undefined ? "" : [
|
|
2992
|
+
"",
|
|
2993
|
+
"",
|
|
2994
|
+
"## Report delivery repair",
|
|
2995
|
+
"",
|
|
2996
|
+
`Previous pass did not prove completion: ${input.repair}.`,
|
|
2997
|
+
"Continue the SAME goal and existing workspace, not a new orchestration.",
|
|
2998
|
+
"Read the assigned report and inspect the existing work first. Do not redo",
|
|
2999
|
+
"completed implementation merely because its delivery failed. Persist the",
|
|
3000
|
+
input.structuredReport === false ? "missing findings in the assigned report; do not just promise a report." : "missing findings with openteam-submit-report; do not just promise a report.",
|
|
3001
|
+
"This repair consumes the existing node pass allowance."
|
|
3002
|
+
].join(`
|
|
3003
|
+
`)}
|
|
2911
3004
|
|
|
2912
|
-
${outputContractInstruction(reportPath)}`,
|
|
3005
|
+
${outputContractInstruction(reportPath, input.structuredReport !== false)}`,
|
|
2913
3006
|
reportPath
|
|
2914
3007
|
};
|
|
2915
3008
|
}
|
|
@@ -3286,15 +3379,21 @@ function promptArgs(sessionID, req, signal) {
|
|
|
3286
3379
|
}
|
|
3287
3380
|
return args;
|
|
3288
3381
|
}
|
|
3289
|
-
async function withTimeout(promise, timeoutMs) {
|
|
3290
|
-
if (timeoutMs === undefined) {
|
|
3382
|
+
async function withTimeout(promise, timeoutMs, signal) {
|
|
3383
|
+
if (timeoutMs === undefined && signal === undefined) {
|
|
3291
3384
|
return { kind: "settled", value: await promise };
|
|
3292
3385
|
}
|
|
3293
3386
|
let timeoutID;
|
|
3387
|
+
let abortListener;
|
|
3294
3388
|
const timeout = new Promise((resolve) => {
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3389
|
+
if (timeoutMs !== undefined)
|
|
3390
|
+
timeoutID = setTimeout(() => {
|
|
3391
|
+
resolve({ kind: "timeout" });
|
|
3392
|
+
}, timeoutMs);
|
|
3393
|
+
abortListener = () => resolve({ kind: "aborted" });
|
|
3394
|
+
signal?.addEventListener("abort", abortListener, { once: true });
|
|
3395
|
+
if (signal?.aborted)
|
|
3396
|
+
abortListener();
|
|
3298
3397
|
});
|
|
3299
3398
|
try {
|
|
3300
3399
|
return await Promise.race([
|
|
@@ -3303,6 +3402,8 @@ async function withTimeout(promise, timeoutMs) {
|
|
|
3303
3402
|
]);
|
|
3304
3403
|
} finally {
|
|
3305
3404
|
clearTimeout(timeoutID);
|
|
3405
|
+
if (abortListener !== undefined)
|
|
3406
|
+
signal?.removeEventListener("abort", abortListener);
|
|
3306
3407
|
}
|
|
3307
3408
|
}
|
|
3308
3409
|
async function beforeDeadline(request, deadline, deps) {
|
|
@@ -3424,7 +3525,35 @@ async function confirmPromptRequestSettled(isSettled, deps, deadline) {
|
|
|
3424
3525
|
async function runSubsession(client, req, deps) {
|
|
3425
3526
|
let sessionID;
|
|
3426
3527
|
try {
|
|
3427
|
-
|
|
3528
|
+
deps.signal?.throwIfAborted();
|
|
3529
|
+
const createController = new AbortController;
|
|
3530
|
+
const createSignal = deps.signal === undefined ? createController.signal : AbortSignal.any([deps.signal, createController.signal]);
|
|
3531
|
+
const remaining = deps.deadlineAt === undefined ? undefined : Math.max(0, deps.deadlineAt - deps.now());
|
|
3532
|
+
if (remaining === 0)
|
|
3533
|
+
return {
|
|
3534
|
+
success: false,
|
|
3535
|
+
roleID: req.roleID,
|
|
3536
|
+
model: req.model,
|
|
3537
|
+
failureStage: "create",
|
|
3538
|
+
failureReason: taskEffortMessages.createDeadline,
|
|
3539
|
+
retrySafe: false
|
|
3540
|
+
};
|
|
3541
|
+
const createOutcome = await withTimeout(req.existingSessionID === undefined ? client.session.create(remaining === undefined && deps.signal === undefined ? createArgs(req) : { ...createArgs(req), signal: createSignal }) : Promise.resolve({
|
|
3542
|
+
data: { id: req.existingSessionID },
|
|
3543
|
+
error: undefined
|
|
3544
|
+
}), remaining, deps.signal);
|
|
3545
|
+
if (createOutcome.kind !== "settled") {
|
|
3546
|
+
createController.abort();
|
|
3547
|
+
return {
|
|
3548
|
+
success: false,
|
|
3549
|
+
roleID: req.roleID,
|
|
3550
|
+
model: req.model,
|
|
3551
|
+
failureStage: "create",
|
|
3552
|
+
failureReason: createOutcome.kind === "timeout" ? taskEffortMessages.createDeadline : taskEffortMessages.cancelled,
|
|
3553
|
+
retrySafe: false
|
|
3554
|
+
};
|
|
3555
|
+
}
|
|
3556
|
+
const created = createOutcome.value;
|
|
3428
3557
|
if (created.error !== undefined) {
|
|
3429
3558
|
const normalizedFailure = isNormalizedSessionFailure(created.error) ? created.error : undefined;
|
|
3430
3559
|
return {
|
|
@@ -3451,19 +3580,32 @@ async function runSubsession(client, req, deps) {
|
|
|
3451
3580
|
try {
|
|
3452
3581
|
await deps.onSessionCreated?.(sessionID);
|
|
3453
3582
|
} catch {}
|
|
3583
|
+
await deps.prepareSession?.(sessionID);
|
|
3584
|
+
deps.signal?.throwIfAborted();
|
|
3585
|
+
if (deps.deadlineAt !== undefined && deps.now() >= deps.deadlineAt)
|
|
3586
|
+
return {
|
|
3587
|
+
success: false,
|
|
3588
|
+
sessionID,
|
|
3589
|
+
roleID: req.roleID,
|
|
3590
|
+
model: req.model,
|
|
3591
|
+
failureStage: "create",
|
|
3592
|
+
failureReason: taskEffortMessages.createDeadline,
|
|
3593
|
+
retrySafe: false
|
|
3594
|
+
};
|
|
3454
3595
|
} catch (error) {
|
|
3455
3596
|
return {
|
|
3456
3597
|
success: false,
|
|
3457
3598
|
roleID: req.roleID,
|
|
3458
3599
|
model: req.model,
|
|
3459
3600
|
failureStage: "create",
|
|
3460
|
-
failureReason: errorReason(error),
|
|
3461
|
-
retrySafe: true
|
|
3601
|
+
failureReason: deps.signal?.aborted ? taskEffortMessages.cancelled : errorReason(error),
|
|
3602
|
+
retrySafe: deps.signal?.aborted !== true
|
|
3462
3603
|
};
|
|
3463
3604
|
}
|
|
3464
3605
|
const promptController = new AbortController;
|
|
3606
|
+
const promptSignal = deps.signal === undefined ? promptController.signal : AbortSignal.any([deps.signal, promptController.signal]);
|
|
3465
3607
|
let promptSettled = false;
|
|
3466
|
-
const promptPromise = client.session.prompt(promptArgs(sessionID, req,
|
|
3608
|
+
const promptPromise = client.session.prompt(promptArgs(sessionID, req, promptSignal)).then((value) => {
|
|
3467
3609
|
promptSettled = true;
|
|
3468
3610
|
return value;
|
|
3469
3611
|
}, (error) => {
|
|
@@ -3471,8 +3613,9 @@ async function runSubsession(client, req, deps) {
|
|
|
3471
3613
|
throw error;
|
|
3472
3614
|
});
|
|
3473
3615
|
try {
|
|
3474
|
-
const
|
|
3475
|
-
|
|
3616
|
+
const timeoutMs = deps.deadlineAt === undefined ? deps.timeoutMs : Math.min(deps.timeoutMs ?? Infinity, Math.max(0, deps.deadlineAt - deps.now()));
|
|
3617
|
+
const outcome = await withTimeout(promptPromise, timeoutMs, deps.signal);
|
|
3618
|
+
if (outcome.kind !== "settled") {
|
|
3476
3619
|
promptController.abort();
|
|
3477
3620
|
const stopDeadline = deps.now() + Math.max(0, deps.abortGraceMs);
|
|
3478
3621
|
const stopped = await confirmSessionStopped(client, sessionID, req.directory, deps, stopDeadline);
|
|
@@ -3483,8 +3626,8 @@ async function runSubsession(client, req, deps) {
|
|
|
3483
3626
|
roleID: req.roleID,
|
|
3484
3627
|
model: req.model,
|
|
3485
3628
|
failureStage: "prompt",
|
|
3486
|
-
failureReason: !stopped.confirmed ? promptStopUnconfirmed(stopped.cause) : requestSettled ? promptTimedOut(deps.timeoutMs ?? 0) : promptStopUnconfirmed("request-unsettled"),
|
|
3487
|
-
retrySafe: stopped.confirmed && requestSettled
|
|
3629
|
+
failureReason: !stopped.confirmed ? promptStopUnconfirmed(stopped.cause) : requestSettled ? deps.deadlineAt !== undefined && deps.now() >= deps.deadlineAt ? taskEffortMessages.exhausted("duration") : outcome.kind === "aborted" ? taskEffortMessages.cancelled : promptTimedOut(deps.timeoutMs ?? 0) : promptStopUnconfirmed("request-unsettled"),
|
|
3630
|
+
retrySafe: stopped.confirmed && requestSettled && outcome.kind !== "aborted" && (deps.deadlineAt === undefined || deps.now() < deps.deadlineAt)
|
|
3488
3631
|
};
|
|
3489
3632
|
}
|
|
3490
3633
|
const prompted = outcome.value;
|
|
@@ -3517,8 +3660,8 @@ async function runSubsession(client, req, deps) {
|
|
|
3517
3660
|
roleID: req.roleID,
|
|
3518
3661
|
model: req.model,
|
|
3519
3662
|
failureStage: "prompt",
|
|
3520
|
-
failureReason: stopped.confirmed ? errorReason(error) : promptStopUnconfirmed(stopped.cause),
|
|
3521
|
-
retrySafe: stopped.confirmed
|
|
3663
|
+
failureReason: stopped.confirmed ? deps.signal?.aborted ? taskEffortMessages.cancelled : errorReason(error) : promptStopUnconfirmed(stopped.cause),
|
|
3664
|
+
retrySafe: stopped.confirmed && deps.signal?.aborted !== true
|
|
3522
3665
|
};
|
|
3523
3666
|
}
|
|
3524
3667
|
}
|
|
@@ -3714,12 +3857,15 @@ var TelemetryFailureClassSchema = z7.enum([
|
|
|
3714
3857
|
"prompt-auth",
|
|
3715
3858
|
"prompt-content-filter",
|
|
3716
3859
|
"prompt-context-length",
|
|
3860
|
+
"prompt-output-truncated",
|
|
3861
|
+
"budget-exhausted",
|
|
3717
3862
|
"prompt-validation",
|
|
3718
3863
|
"prompt-connection",
|
|
3719
3864
|
"prompt-server",
|
|
3720
3865
|
"unknown"
|
|
3721
3866
|
]);
|
|
3722
3867
|
var FAILURE_CAUSE_RULES = [
|
|
3868
|
+
[["prompt-output-truncated"], "prompt-output-truncated"],
|
|
3723
3869
|
[
|
|
3724
3870
|
[
|
|
3725
3871
|
"rate limit",
|
|
@@ -3822,6 +3968,8 @@ function matchFailureCause(lowerReason) {
|
|
|
3822
3968
|
}
|
|
3823
3969
|
function classifyFailureForTelemetry(failureReason, failureStage) {
|
|
3824
3970
|
const lower = failureReason.toLowerCase();
|
|
3971
|
+
if (lower.startsWith("task-budget-exhausted:"))
|
|
3972
|
+
return "budget-exhausted";
|
|
3825
3973
|
if (TIMEOUT_NEEDLES.some((needle) => lower.includes(needle))) {
|
|
3826
3974
|
return "prompt-timeout";
|
|
3827
3975
|
}
|
|
@@ -3900,6 +4048,8 @@ async function recordLifecycle(lifecycle, event) {
|
|
|
3900
4048
|
await lifecycle.recorder.append(event);
|
|
3901
4049
|
}
|
|
3902
4050
|
function lifecycleFailureFor(subsession) {
|
|
4051
|
+
if (subsession.failureReason?.startsWith("task-budget-exhausted:"))
|
|
4052
|
+
return { class: "budget-exhausted", retryable: false };
|
|
3903
4053
|
const normalized = subsession.normalizedFailure;
|
|
3904
4054
|
if (normalized !== undefined) {
|
|
3905
4055
|
return {
|
|
@@ -3969,7 +4119,7 @@ function buildNodeBudgetExhaustedEvent(roleID, passCount, sessionID, ts) {
|
|
|
3969
4119
|
passCount
|
|
3970
4120
|
};
|
|
3971
4121
|
}
|
|
3972
|
-
async function runRoleTaskWithCorrelation(input, deps, correlation, batch, routed, handoff, reportBatchID, attemptLifecycle) {
|
|
4122
|
+
async function runRoleTaskWithCorrelation(input, deps, correlation, batch, routed, handoff, reportBatchID, attemptLifecycle, repair, truncated, existingSessionID) {
|
|
3973
4123
|
const role = roleFor(input);
|
|
3974
4124
|
if (routed.routeKind === "blocked") {
|
|
3975
4125
|
throw new Error(coordinatorRoutingBlocked(input.roleID, routed.blockReason));
|
|
@@ -3980,13 +4130,18 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
3980
4130
|
prompt: input.prompt,
|
|
3981
4131
|
roleID: input.roleID,
|
|
3982
4132
|
batchID: reportBatchID,
|
|
3983
|
-
handoff
|
|
4133
|
+
handoff,
|
|
4134
|
+
structuredReport: deps.reportDelivery !== undefined,
|
|
4135
|
+
...repair === undefined ? {} : { repair },
|
|
4136
|
+
...truncated === true ? { truncated: true } : {}
|
|
3984
4137
|
});
|
|
3985
4138
|
const request = {
|
|
3986
4139
|
roleID: input.roleID,
|
|
3987
4140
|
model: decision2.selected,
|
|
3988
4141
|
prompt: composed.prompt
|
|
3989
4142
|
};
|
|
4143
|
+
if (existingSessionID !== undefined)
|
|
4144
|
+
request.existingSessionID = existingSessionID;
|
|
3990
4145
|
if (input.parentSessionID !== undefined) {
|
|
3991
4146
|
request.parentSessionID = input.parentSessionID;
|
|
3992
4147
|
}
|
|
@@ -4004,11 +4159,17 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
4004
4159
|
if (input.directory !== undefined) {
|
|
4005
4160
|
request.directory = input.directory;
|
|
4006
4161
|
}
|
|
4162
|
+
let reportLease;
|
|
4007
4163
|
const subsessionDeps = {
|
|
4008
4164
|
abortGraceMs: deps.abortGraceMs,
|
|
4009
4165
|
statusPollMs: deps.statusPollMs,
|
|
4010
4166
|
now: deps.now,
|
|
4011
4167
|
delay: deps.delay,
|
|
4168
|
+
prepareSession: async (sessionID) => {
|
|
4169
|
+
if (deps.taskEffort !== undefined)
|
|
4170
|
+
deps.taskEffort.ledger.bindChild(deps.taskEffort.ref, sessionID);
|
|
4171
|
+
reportLease = deps.reportDelivery?.open(sessionID, reportBatchID, input.roleID);
|
|
4172
|
+
},
|
|
4012
4173
|
...deps.timeoutMs === undefined ? {} : { timeoutMs: deps.timeoutMs },
|
|
4013
4174
|
...attemptLifecycle === undefined ? {} : {
|
|
4014
4175
|
onSessionCreated: (sessionID) => recordLifecycle(attemptLifecycle.lifecycle, {
|
|
@@ -4053,27 +4214,66 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
4053
4214
|
}
|
|
4054
4215
|
let release;
|
|
4055
4216
|
let queueObservation;
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
const
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
const acquisition = await limiter.acquire(poolKey, priority);
|
|
4066
|
-
release = acquisition.release;
|
|
4067
|
-
waitedMs = acquisition.waitedMs;
|
|
4068
|
-
}
|
|
4069
|
-
queueObservation = {
|
|
4070
|
-
runtimeId,
|
|
4071
|
-
waitedMs,
|
|
4072
|
-
activeCount: limiter.activeCount(poolKey),
|
|
4073
|
-
queuedCount: limiter.queuedCount(poolKey)
|
|
4217
|
+
const admission = deps.taskEffort?.ledger.check(deps.taskEffort.ref);
|
|
4218
|
+
async function denied(reason) {
|
|
4219
|
+
const subsession = {
|
|
4220
|
+
roleID: input.roleID,
|
|
4221
|
+
model: decision2.selected,
|
|
4222
|
+
success: false,
|
|
4223
|
+
failureStage: "create",
|
|
4224
|
+
retrySafe: false,
|
|
4225
|
+
failureReason: reason
|
|
4074
4226
|
};
|
|
4227
|
+
const record = buildRecord(input, decision2, subsession, deps, correlation.decisionID, correlation.batchID);
|
|
4228
|
+
await safeEmit(deps.sink, correlatedCostRecordToRouteEvent(record));
|
|
4229
|
+
return { decision: decision2, subsession, record, reportPath: composed.reportPath };
|
|
4075
4230
|
}
|
|
4231
|
+
if (admission?.ok === false)
|
|
4232
|
+
return denied(taskEffortMessages.exhausted(admission.reason));
|
|
4233
|
+
if (deps.signal?.aborted)
|
|
4234
|
+
return denied(taskEffortMessages.cancelled);
|
|
4235
|
+
const queueController = new AbortController;
|
|
4236
|
+
const queueSignal = deps.signal === undefined ? queueController.signal : AbortSignal.any([deps.signal, queueController.signal]);
|
|
4237
|
+
const queueDeadline = admission?.ok === true ? setTimeout(() => queueController.abort(), admission.remainingMs) : undefined;
|
|
4076
4238
|
try {
|
|
4239
|
+
if (runtimeId !== undefined && deps.runtimeLimiter !== undefined) {
|
|
4240
|
+
const limiter = deps.runtimeLimiter;
|
|
4241
|
+
const priority = priorityForRole(role);
|
|
4242
|
+
const dispatchRuntime = configuredRuntime(runtimeId, input.config) ?? { id: runtimeId };
|
|
4243
|
+
const aliases = localModelAliases(decision2.selected.providerID, input.availableModels);
|
|
4244
|
+
const poolKey = slotPoolKey(withReportedModelSlots(dispatchRuntime, deps.reportedModelSlots?.(runtimeId), aliases), aliases.get(decision2.selected.modelID) ?? decision2.selected.modelID);
|
|
4245
|
+
release = limiter.tryAcquire(poolKey, priority);
|
|
4246
|
+
let waitedMs = 0;
|
|
4247
|
+
if (release === undefined) {
|
|
4248
|
+
let acquisition;
|
|
4249
|
+
try {
|
|
4250
|
+
acquisition = await limiter.acquire(poolKey, priority, queueSignal);
|
|
4251
|
+
} catch (error) {
|
|
4252
|
+
if (!queueSignal.aborted)
|
|
4253
|
+
throw error;
|
|
4254
|
+
return denied(queueController.signal.aborted ? taskEffortMessages.exhausted("duration") : taskEffortMessages.cancelled);
|
|
4255
|
+
}
|
|
4256
|
+
release = acquisition.release;
|
|
4257
|
+
waitedMs = acquisition.waitedMs;
|
|
4258
|
+
}
|
|
4259
|
+
queueObservation = {
|
|
4260
|
+
runtimeId,
|
|
4261
|
+
waitedMs,
|
|
4262
|
+
activeCount: limiter.activeCount(poolKey),
|
|
4263
|
+
queuedCount: limiter.queuedCount(poolKey)
|
|
4264
|
+
};
|
|
4265
|
+
}
|
|
4266
|
+
clearTimeout(queueDeadline);
|
|
4267
|
+
const effort = deps.taskEffort?.ledger.attempt(deps.taskEffort.ref);
|
|
4268
|
+
if (effort?.ok === false) {
|
|
4269
|
+
return denied(taskEffortMessages.exhausted(effort.reason));
|
|
4270
|
+
}
|
|
4271
|
+
if (effort?.ok === true) {
|
|
4272
|
+
subsessionDeps.timeoutMs = Math.min(subsessionDeps.timeoutMs ?? Infinity, effort.remainingMs);
|
|
4273
|
+
subsessionDeps.deadlineAt = deps.now() + effort.remainingMs;
|
|
4274
|
+
}
|
|
4275
|
+
if (deps.signal !== undefined)
|
|
4276
|
+
subsessionDeps.signal = deps.signal;
|
|
4077
4277
|
if (attemptLifecycle !== undefined) {
|
|
4078
4278
|
await recordLifecycle(attemptLifecycle.lifecycle, {
|
|
4079
4279
|
type: "attempt.started",
|
|
@@ -4101,8 +4301,17 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
4101
4301
|
await safeEmit(deps.sink, buildQueueEvent(queueObservation, sessionID, deps.now(), queueCorrelation));
|
|
4102
4302
|
}
|
|
4103
4303
|
}
|
|
4104
|
-
|
|
4304
|
+
const reportSubmitted = await reportLease?.close();
|
|
4305
|
+
return {
|
|
4306
|
+
decision: decision2,
|
|
4307
|
+
subsession,
|
|
4308
|
+
record,
|
|
4309
|
+
reportPath: composed.reportPath,
|
|
4310
|
+
...reportSubmitted === undefined ? {} : { reportSubmitted }
|
|
4311
|
+
};
|
|
4105
4312
|
} finally {
|
|
4313
|
+
clearTimeout(queueDeadline);
|
|
4314
|
+
await reportLease?.close();
|
|
4106
4315
|
release?.();
|
|
4107
4316
|
}
|
|
4108
4317
|
}
|
|
@@ -4214,15 +4423,19 @@ async function assessCurrentAttemptReport(input, before, result, deps) {
|
|
|
4214
4423
|
done: false
|
|
4215
4424
|
};
|
|
4216
4425
|
}
|
|
4217
|
-
if (after === before) {
|
|
4426
|
+
if (after === before && result.reportSubmitted !== true) {
|
|
4218
4427
|
return {
|
|
4219
4428
|
result: withFailure(gated, REPORT_STALE_REASON, "report"),
|
|
4220
4429
|
done: false
|
|
4221
4430
|
};
|
|
4222
4431
|
}
|
|
4432
|
+
const done = parseReportStatus(after) === "done" && reportHasSubstance(after);
|
|
4223
4433
|
return {
|
|
4224
4434
|
result: gated,
|
|
4225
|
-
done
|
|
4435
|
+
done,
|
|
4436
|
+
...!done ? {
|
|
4437
|
+
repairReason: !reportHasSubstance(after) ? "report-without-substance" : parseReportStatus(after) === "continue" ? "report-continue" : "report-status-missing"
|
|
4438
|
+
} : {}
|
|
4226
4439
|
};
|
|
4227
4440
|
}
|
|
4228
4441
|
function failedPassDisposition(subsession) {
|
|
@@ -4233,6 +4446,8 @@ function failedPassDisposition(subsession) {
|
|
|
4233
4446
|
if (subsession.failureStage === "report")
|
|
4234
4447
|
return "retry-incomplete";
|
|
4235
4448
|
if (subsession.normalizedFailure !== undefined) {
|
|
4449
|
+
if (subsession.normalizedFailure.failureClass === "prompt-output-truncated")
|
|
4450
|
+
return "retry-incomplete";
|
|
4236
4451
|
return subsession.normalizedFailure.retryable ? "retry-transport" : "terminal";
|
|
4237
4452
|
}
|
|
4238
4453
|
const failureReason = subsession.failureReason ?? "";
|
|
@@ -4332,6 +4547,7 @@ async function runNodeWithIteration(input, deps, correlation, batch, lifecycle)
|
|
|
4332
4547
|
let totalPasses = 0;
|
|
4333
4548
|
let spend = { usd: 0, frontierTokens: 0 };
|
|
4334
4549
|
let lastResult;
|
|
4550
|
+
let reportRepairReason;
|
|
4335
4551
|
let escalationReason;
|
|
4336
4552
|
const reportBatchID = correlation.batchID ?? correlation.decisionID;
|
|
4337
4553
|
modelLoop:
|
|
@@ -4404,14 +4620,19 @@ async function runNodeWithIteration(input, deps, correlation, batch, lifecycle)
|
|
|
4404
4620
|
retryIndex: pass - 1,
|
|
4405
4621
|
selectionCause: lifecycleSelectionCause(totalPasses, modelIndex, retryReason, escalationReason)
|
|
4406
4622
|
};
|
|
4407
|
-
let result = await runRoleTaskWithCorrelation(input, deps, attemptCorrelation, batch, attemptDecision, modelIndex > 0, reportBatchID, attemptLifecycle);
|
|
4623
|
+
let result = await runRoleTaskWithCorrelation(input, deps, attemptCorrelation, batch, attemptDecision, modelIndex > 0, reportBatchID, attemptLifecycle, reportRepairReason, lastResult?.subsession.normalizedFailure?.failureClass === "prompt-output-truncated", pass > 1 && reportRepairReason !== undefined && (lastResult?.subsession.success || lastResult?.subsession.failureStage === "report") && lastResult?.subsession.retrySafe !== false ? lastResult?.subsession.sessionID : undefined);
|
|
4408
4624
|
totalPasses += 1;
|
|
4409
4625
|
spend = {
|
|
4410
4626
|
usd: attemptDecision.estimatedCostUSD === null ? spend.usd : spend.usd + attemptDecision.estimatedCostUSD,
|
|
4411
4627
|
frontierTokens: spend.frontierTokens + (attemptDecision.routeKind === "frontier" ? (input.task.estimatedInputTokens ?? 0) + (input.task.estimatedOutputTokens ?? 0) : 0)
|
|
4412
4628
|
};
|
|
4629
|
+
if (result.subsession.sessionID !== undefined)
|
|
4630
|
+
await deps.sessionPhase?.(result.subsession.sessionID, "report-validation");
|
|
4413
4631
|
const assessment = await assessCurrentAttemptReport(input, before, result, deps);
|
|
4632
|
+
if (result.subsession.sessionID !== undefined)
|
|
4633
|
+
await deps.sessionPhase?.(result.subsession.sessionID, "idle");
|
|
4414
4634
|
result = assessment.result;
|
|
4635
|
+
reportRepairReason = assessment.repairReason ?? (result.subsession.failureStage === "report" ? result.subsession.failureReason : undefined);
|
|
4415
4636
|
lastResult = result;
|
|
4416
4637
|
if (assessment.done) {
|
|
4417
4638
|
await recordAttemptTerminal(attemptLifecycle, result, "none", true);
|
|
@@ -4497,13 +4718,28 @@ async function runRoleTasks(inputs, deps, options = {}) {
|
|
|
4497
4718
|
});
|
|
4498
4719
|
}
|
|
4499
4720
|
}
|
|
4500
|
-
const
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4721
|
+
const waveController = deps.taskEffort === undefined ? undefined : new AbortController;
|
|
4722
|
+
const waveDeps = waveController === undefined ? deps : {
|
|
4723
|
+
...deps,
|
|
4724
|
+
signal: deps.signal === undefined ? waveController.signal : AbortSignal.any([deps.signal, waveController.signal])
|
|
4725
|
+
};
|
|
4726
|
+
const waveTasks = runnable.map(async (input) => {
|
|
4727
|
+
try {
|
|
4728
|
+
const correlation = correlationByRole.get(input.roleID);
|
|
4729
|
+
if (correlation === undefined) {
|
|
4730
|
+
throw new Error(`missing correlation for ${input.roleID}`);
|
|
4731
|
+
}
|
|
4732
|
+
return await runNodeWithIteration(input, waveDeps, correlation, batch, lifecycle);
|
|
4733
|
+
} catch (error) {
|
|
4734
|
+
waveController?.abort();
|
|
4735
|
+
throw error;
|
|
4504
4736
|
}
|
|
4505
|
-
|
|
4506
|
-
|
|
4737
|
+
});
|
|
4738
|
+
const waveResults = waveController === undefined ? await Promise.all(waveTasks) : (await Promise.allSettled(waveTasks)).map((outcome) => {
|
|
4739
|
+
if (outcome.status === "rejected")
|
|
4740
|
+
throw outcome.reason;
|
|
4741
|
+
return outcome.value;
|
|
4742
|
+
});
|
|
4507
4743
|
for (const result of waveResults) {
|
|
4508
4744
|
allResults.push(result);
|
|
4509
4745
|
if (result.subsession.success) {
|
|
@@ -5720,6 +5956,11 @@ function applyRoute(session2, event) {
|
|
|
5720
5956
|
}
|
|
5721
5957
|
function applyMessage(session2, event) {
|
|
5722
5958
|
session2.messageCount += 1;
|
|
5959
|
+
const unknownUsage = event.usageStatus === undefined ? event.tokensIn + event.tokensOut + event.tokensReasoning + event.tokensCacheRead + event.tokensCacheWrite === 0 : event.usageStatus !== "reported";
|
|
5960
|
+
if (unknownUsage)
|
|
5961
|
+
session2.unavailableUsageMessages = (session2.unavailableUsageMessages ?? 0) + 1;
|
|
5962
|
+
if (event.costStatus === "unavailable" || event.costStatus === undefined && unknownUsage && event.costUSD === 0)
|
|
5963
|
+
session2.unavailableCostMessages = (session2.unavailableCostMessages ?? 0) + 1;
|
|
5723
5964
|
session2.realCostUSD += event.costUSD;
|
|
5724
5965
|
session2.tokensIn += event.tokensIn;
|
|
5725
5966
|
session2.tokensOut += event.tokensOut;
|
|
@@ -5731,7 +5972,9 @@ function applyMessage(session2, event) {
|
|
|
5731
5972
|
}
|
|
5732
5973
|
function applyToolUsage(stats, event) {
|
|
5733
5974
|
stats.count += 1;
|
|
5734
|
-
stats.totalDurationMs += event.durationMs;
|
|
5975
|
+
stats.totalDurationMs += event.durationMs ?? 0;
|
|
5976
|
+
if (event.durationMs === null)
|
|
5977
|
+
stats.unknownDurationCount = (stats.unknownDurationCount ?? 0) + 1;
|
|
5735
5978
|
if (event.ok) {
|
|
5736
5979
|
stats.ok += 1;
|
|
5737
5980
|
} else {
|
|
@@ -5774,6 +6017,8 @@ function mergeTool(target, source) {
|
|
|
5774
6017
|
target.ok += source.ok;
|
|
5775
6018
|
target.failed += source.failed;
|
|
5776
6019
|
target.totalDurationMs += source.totalDurationMs;
|
|
6020
|
+
if (source.unknownDurationCount !== undefined)
|
|
6021
|
+
target.unknownDurationCount = (target.unknownDurationCount ?? 0) + source.unknownDurationCount;
|
|
5777
6022
|
}
|
|
5778
6023
|
function accumulateTotals(totals, session2) {
|
|
5779
6024
|
totals.sessions += 1;
|
|
@@ -5784,6 +6029,10 @@ function accumulateTotals(totals, session2) {
|
|
|
5784
6029
|
totals.estimatedSavingsUSD = addEstimate(totals.estimatedSavingsUSD, session2.estimatedSavingsUSD);
|
|
5785
6030
|
totals.realCostUSD += session2.realCostUSD;
|
|
5786
6031
|
totals.messageCount += session2.messageCount;
|
|
6032
|
+
if (session2.unavailableUsageMessages !== undefined)
|
|
6033
|
+
totals.unavailableUsageMessages = (totals.unavailableUsageMessages ?? 0) + session2.unavailableUsageMessages;
|
|
6034
|
+
if (session2.unavailableCostMessages !== undefined)
|
|
6035
|
+
totals.unavailableCostMessages = (totals.unavailableCostMessages ?? 0) + session2.unavailableCostMessages;
|
|
5787
6036
|
totals.tokensIn += session2.tokensIn;
|
|
5788
6037
|
totals.tokensOut += session2.tokensOut;
|
|
5789
6038
|
totals.tokensReasoning += session2.tokensReasoning;
|
|
@@ -5850,6 +6099,7 @@ function aggregateEvents(events) {
|
|
|
5850
6099
|
const decisions = [];
|
|
5851
6100
|
const meetings = [];
|
|
5852
6101
|
const activity = [];
|
|
6102
|
+
const calls = new Map;
|
|
5853
6103
|
const sessionFor = (sessionID, ts) => {
|
|
5854
6104
|
const existing = sessions.get(sessionID);
|
|
5855
6105
|
if (existing === undefined) {
|
|
@@ -5870,7 +6120,13 @@ function aggregateEvents(events) {
|
|
|
5870
6120
|
applyMessage(sessionFor(event.sessionID, event.ts), event);
|
|
5871
6121
|
break;
|
|
5872
6122
|
case "toolcall":
|
|
5873
|
-
|
|
6123
|
+
{
|
|
6124
|
+
const key = `${event.sessionID}\x00${event.callID}`;
|
|
6125
|
+
const previous = calls.get(key);
|
|
6126
|
+
if (previous === undefined || previous.ok && !event.ok || previous.ok === event.ok && (event.durationMs ?? -1) > (previous.durationMs ?? -1)) {
|
|
6127
|
+
calls.set(key, event);
|
|
6128
|
+
}
|
|
6129
|
+
}
|
|
5874
6130
|
break;
|
|
5875
6131
|
case "session-endpoint":
|
|
5876
6132
|
applyEndpoint(sessionFor(event.sessionID, event.ts), event);
|
|
@@ -5883,9 +6139,19 @@ function aggregateEvents(events) {
|
|
|
5883
6139
|
break;
|
|
5884
6140
|
case "activity":
|
|
5885
6141
|
activity.push(toActivity(event));
|
|
6142
|
+
if (event.phase !== undefined) {
|
|
6143
|
+
const session2 = sessionFor(event.sessionID, event.ts);
|
|
6144
|
+
if (event.ts >= (session2.phaseAt ?? -Infinity)) {
|
|
6145
|
+
session2.phase = event.phase;
|
|
6146
|
+
session2.phaseAt = event.ts;
|
|
6147
|
+
}
|
|
6148
|
+
}
|
|
5886
6149
|
break;
|
|
5887
6150
|
}
|
|
5888
6151
|
}
|
|
6152
|
+
for (const event of calls.values()) {
|
|
6153
|
+
applyToolcall(sessionFor(event.sessionID, event.ts), event);
|
|
6154
|
+
}
|
|
5889
6155
|
const totals = {
|
|
5890
6156
|
sessions: 0,
|
|
5891
6157
|
routeCount: 0,
|
|
@@ -6176,8 +6442,15 @@ var KNOWN_CONFIG_KEYS_BY_PATH = new Map([
|
|
|
6176
6442
|
["graph.worktrees", ["enabled"]],
|
|
6177
6443
|
["lifecycle", ["root", "retention"]],
|
|
6178
6444
|
["lifecycle.retention", ["maxTerminalRuns", "maxAgeDays", "maxBytes"]],
|
|
6179
|
-
[
|
|
6445
|
+
[
|
|
6446
|
+
"orchestrator",
|
|
6447
|
+
["roles", "primary", "maxRetries", "maxModelsPerNode", "taskBudget"]
|
|
6448
|
+
],
|
|
6180
6449
|
["orchestrator.primary", ["executionMode", "model", "fallbacks"]],
|
|
6450
|
+
[
|
|
6451
|
+
"orchestrator.taskBudget",
|
|
6452
|
+
["maxBatches", "maxAttempts", "maxDurationMs", "maxDepth"]
|
|
6453
|
+
],
|
|
6181
6454
|
["orchestrator.primary.fallbacks[]", MODEL_REF_KEYS]
|
|
6182
6455
|
]);
|
|
6183
6456
|
function isUnrecognizedKeysIssue(issue) {
|
|
@@ -7466,6 +7739,488 @@ async function handleLifecycleHistoryRoute(request, response, url, deps) {
|
|
|
7466
7739
|
return true;
|
|
7467
7740
|
}
|
|
7468
7741
|
|
|
7742
|
+
// src/messages/agentView.ts
|
|
7743
|
+
var agentViewMessages = {
|
|
7744
|
+
title: "Agent workspace",
|
|
7745
|
+
graph: "Graph",
|
|
7746
|
+
chronology: "Chronology",
|
|
7747
|
+
filters: "Filters",
|
|
7748
|
+
search: "Search operations",
|
|
7749
|
+
searchHint: "Alias, role, model or operation ID",
|
|
7750
|
+
allRoles: "All roles",
|
|
7751
|
+
allStates: "All states",
|
|
7752
|
+
role: "Role",
|
|
7753
|
+
state: "State",
|
|
7754
|
+
matches: "Matching operations",
|
|
7755
|
+
noMatches: "No operations match these filters.",
|
|
7756
|
+
filterNote: "Filtered operations stay dimmed to preserve context.",
|
|
7757
|
+
hierarchy: "Hierarchy",
|
|
7758
|
+
dependency: "Prerequisite",
|
|
7759
|
+
legend: "Solid: parent/child. Dashed: prerequisite. Neither implies model activity.",
|
|
7760
|
+
inspector: "Operation inspector",
|
|
7761
|
+
root: "Select coordinator",
|
|
7762
|
+
isolate: "Isolate hierarchy branch",
|
|
7763
|
+
clearIsolation: "Show all branches",
|
|
7764
|
+
selectedFiltered: "The selected operation is outside the current filters.",
|
|
7765
|
+
zoomIn: "Zoom in",
|
|
7766
|
+
zoomOut: "Zoom out",
|
|
7767
|
+
fit: "Fit graph",
|
|
7768
|
+
reset: "Reset view",
|
|
7769
|
+
canvas: "Agent graph. Select an operation with Enter or Space. Arrow keys pan the canvas; plus and minus zoom.",
|
|
7770
|
+
play: "Play recorded events",
|
|
7771
|
+
pause: "Pause replay",
|
|
7772
|
+
previous: "Previous event",
|
|
7773
|
+
next: "Next event",
|
|
7774
|
+
speed: "Events per second",
|
|
7775
|
+
replayNote: "Replay uses recorded event prefixes. Current conversations and telemetry are never shown at historical cursors.",
|
|
7776
|
+
noEvents: "No recorded events at this cursor.",
|
|
7777
|
+
eventWindow: "Showing the most recent 1,000 events in this prefix. Use the cursor to inspect earlier history.",
|
|
7778
|
+
attempts: "Attempts",
|
|
7779
|
+
failures: "Failed attempts",
|
|
7780
|
+
noModel: "Model not recorded",
|
|
7781
|
+
noSession: "No session created",
|
|
7782
|
+
phase: "Observed phase",
|
|
7783
|
+
phaseUnknown: "Session phase unavailable",
|
|
7784
|
+
historicalMetrics: "Live phase and usage are unavailable in historical replay.",
|
|
7785
|
+
usage: "Reported input / output tokens",
|
|
7786
|
+
usageUnavailable: "Usage unavailable / partial",
|
|
7787
|
+
cost: "Reported cost",
|
|
7788
|
+
costUnavailable: "Cost unavailable / partial",
|
|
7789
|
+
tools: "Tool calls / failures",
|
|
7790
|
+
noTools: "No tool outcomes observed",
|
|
7791
|
+
related: "Related batches",
|
|
7792
|
+
relatedNote: "Same task, or a batch whose root session is this operation's child session. Outcomes remain independent.",
|
|
7793
|
+
relatedFailed: "Related failed batches",
|
|
7794
|
+
missing: "Unresolved references",
|
|
7795
|
+
states: {
|
|
7796
|
+
waiting: "Waiting",
|
|
7797
|
+
selected: "Selected",
|
|
7798
|
+
queued: "Queued",
|
|
7799
|
+
running: "Running",
|
|
7800
|
+
succeeded: "Succeeded",
|
|
7801
|
+
failed: "Failed",
|
|
7802
|
+
blocked: "Blocked",
|
|
7803
|
+
cancelled: "Cancelled",
|
|
7804
|
+
interrupted: "Interrupted",
|
|
7805
|
+
unknown: "Unknown"
|
|
7806
|
+
},
|
|
7807
|
+
events: {
|
|
7808
|
+
"run.started": "Batch started",
|
|
7809
|
+
"operation.queued": "Operation queued",
|
|
7810
|
+
"attempt.model-selected": "Model selected",
|
|
7811
|
+
"attempt.queued": "Attempt queued",
|
|
7812
|
+
"attempt.started": "Attempt started",
|
|
7813
|
+
"session.created": "Session created",
|
|
7814
|
+
"attempt.terminal": "Attempt finished",
|
|
7815
|
+
"operation.terminal": "Operation finished",
|
|
7816
|
+
"run.terminal": "Batch finished"
|
|
7817
|
+
}
|
|
7818
|
+
};
|
|
7819
|
+
|
|
7820
|
+
// src/console/agentView.ts
|
|
7821
|
+
function layoutAgentOperations(operations) {
|
|
7822
|
+
const byID = new Map(operations.map((operation) => [operation.operationID, operation]));
|
|
7823
|
+
const rows = new Map;
|
|
7824
|
+
const nodes = [];
|
|
7825
|
+
let width = 256;
|
|
7826
|
+
let height = 152;
|
|
7827
|
+
for (const operation of byID.values()) {
|
|
7828
|
+
const seen = new Set([operation.operationID]);
|
|
7829
|
+
let parent = operation.parentOperationID;
|
|
7830
|
+
let depth = 0;
|
|
7831
|
+
while (parent !== undefined && byID.has(parent) && !seen.has(parent)) {
|
|
7832
|
+
seen.add(parent);
|
|
7833
|
+
depth++;
|
|
7834
|
+
parent = byID.get(parent)?.parentOperationID;
|
|
7835
|
+
}
|
|
7836
|
+
const row = rows.get(depth) ?? 0;
|
|
7837
|
+
rows.set(depth, row + 1);
|
|
7838
|
+
const x = 28 + depth * 268;
|
|
7839
|
+
const y = 28 + row * 148;
|
|
7840
|
+
nodes.push({ id: operation.operationID, x, y });
|
|
7841
|
+
width = Math.max(width, x + 256);
|
|
7842
|
+
height = Math.max(height, y + 144);
|
|
7843
|
+
}
|
|
7844
|
+
return { nodes, width, height };
|
|
7845
|
+
}
|
|
7846
|
+
var AGENT_VIEW_CLIENT_JS = `
|
|
7847
|
+
var layoutAgentOperations=${layoutAgentOperations.toString()};
|
|
7848
|
+
function createAgentViewer(host,options){
|
|
7849
|
+
var msg=${JSON.stringify(agentViewMessages)},phases=${JSON.stringify(executionPhaseMessages)};
|
|
7850
|
+
var source=null,selected=null,isolated=null,run=null,mode='graph',playing=false,playTimer=null,pendingCursor=null;
|
|
7851
|
+
var scale=1,offsetX=24,offsetY=24,positioned=false,drag=null,summaries=new Map((document.__consoleTelemetry||[]).map(function(item){return [item.sessionID,item]})),nodes=new Map(),layout=null;
|
|
7852
|
+
var metricsKey='',relatedKey='';
|
|
7853
|
+
var namespace='http://www.w3.org/2000/svg',byID=new Map(),tree=null,filtered=new Set(),openDetails=new Map();
|
|
7854
|
+
function element(tag,text,className){var node=document.createElement(tag);if(text!==undefined){node.textContent=text}if(className){node.className=className}return node}
|
|
7855
|
+
function button(label,action,marker){
|
|
7856
|
+
var node=element('button',label);node.type='button';node.setAttribute('aria-label',label);
|
|
7857
|
+
if(marker){node.setAttribute('data-agent-'+marker,'')}
|
|
7858
|
+
node.addEventListener('click',action);return node;
|
|
7859
|
+
}
|
|
7860
|
+
function svgElement(tag,attributes,text){
|
|
7861
|
+
var node=document.createElementNS(namespace,tag);
|
|
7862
|
+
Object.keys(attributes||{}).forEach(function(key){node.setAttribute(key,String(attributes[key]))});
|
|
7863
|
+
if(text!==undefined){node.textContent=text}return node;
|
|
7864
|
+
}
|
|
7865
|
+
function label(text,input){var node=element('label',text);node.appendChild(input);return node}
|
|
7866
|
+
function option(select,value,text){var node=element('option',text);node.value=value;select.appendChild(node)}
|
|
7867
|
+
var shell=element('section',undefined,'av-workspace');shell.setAttribute('aria-label',msg.title);
|
|
7868
|
+
var tools=element('div',undefined,'av-toolbar');
|
|
7869
|
+
var graphButton=button(msg.graph,function(){setMode('graph')},'graph');
|
|
7870
|
+
var chronologyButton=button(msg.chronology,function(){setMode('chronology')},'chronology');
|
|
7871
|
+
tools.append(graphButton,chronologyButton);
|
|
7872
|
+
tools.appendChild(button(msg.previous,function(){pause();seek(Math.max(0,source.cursor-1),true)},'previous'));
|
|
7873
|
+
var playButton=button(msg.play,togglePlayback,'play');tools.appendChild(playButton);
|
|
7874
|
+
tools.appendChild(button(msg.next,function(){pause();seek(Math.min(source.head,source.cursor+1),true)},'next'));
|
|
7875
|
+
var speed=element('select');speed.setAttribute('aria-label',msg.speed);
|
|
7876
|
+
[1,2,5].forEach(function(value){option(speed,String(value),String(value))});
|
|
7877
|
+
tools.appendChild(label(msg.speed,speed));
|
|
7878
|
+
var count=element('span',undefined,'av-count');count.setAttribute('role','status');tools.appendChild(count);
|
|
7879
|
+
shell.appendChild(tools);
|
|
7880
|
+
var body=element('div',undefined,'av-body'),filters=element('aside',undefined,'av-filters');
|
|
7881
|
+
filters.appendChild(element('h3',msg.filters));
|
|
7882
|
+
var search=element('input');search.type='search';search.placeholder=msg.searchHint;search.setAttribute('data-agent-search','');
|
|
7883
|
+
filters.appendChild(label(msg.search,search));
|
|
7884
|
+
var role=element('select');role.setAttribute('data-agent-role','');option(role,'',msg.allRoles);
|
|
7885
|
+
filters.appendChild(label(msg.role,role));
|
|
7886
|
+
var status=element('select');status.setAttribute('data-agent-state','');option(status,'',msg.allStates);
|
|
7887
|
+
Object.keys(msg.states).forEach(function(key){option(status,key,msg.states[key])});
|
|
7888
|
+
filters.appendChild(label(msg.state,status));
|
|
7889
|
+
var isolate=button(msg.isolate,function(){isolated=isolated?null:selected;applyFilters()},'isolate');
|
|
7890
|
+
filters.appendChild(isolate);
|
|
7891
|
+
filters.appendChild(button(msg.root,function(){select(source.rootOperationID)},'root'));
|
|
7892
|
+
filters.appendChild(element('p',msg.filterNote));
|
|
7893
|
+
var legend=element('div',undefined,'av-legend');legend.appendChild(element('p',msg.hierarchy,'av-solid'));
|
|
7894
|
+
legend.appendChild(element('p',msg.dependency,'av-dashed'));legend.appendChild(element('p',msg.legend));filters.appendChild(legend);
|
|
7895
|
+
var unresolved=element('p');unresolved.setAttribute('data-agent-unresolved','');filters.appendChild(unresolved);
|
|
7896
|
+
body.appendChild(filters);
|
|
7897
|
+
var center=element('div',undefined,'av-center');
|
|
7898
|
+
var canvas=element('div',undefined,'av-canvas');
|
|
7899
|
+
var zoomTools=element('div',undefined,'av-zoom');
|
|
7900
|
+
zoomTools.append(button(msg.zoomIn,function(){zoom(1.2)},'zoom-in'),button(msg.zoomOut,function(){zoom(1/1.2)},'zoom-out'),
|
|
7901
|
+
button(msg.fit,fit,'fit'),button(msg.reset,function(){scale=1;offsetX=24;offsetY=24;transform()},'reset'));
|
|
7902
|
+
canvas.appendChild(zoomTools);
|
|
7903
|
+
var svg=svgElement('svg',{'class':'av-graph','role':'group','aria-label':msg.canvas,tabindex:0});
|
|
7904
|
+
var viewport=svgElement('g',{'class':'av-viewport'});svg.appendChild(viewport);canvas.appendChild(svg);
|
|
7905
|
+
center.appendChild(canvas);
|
|
7906
|
+
var chronology=element('ol',undefined,'av-chronology');chronology.hidden=true;chronology.setAttribute('aria-label',msg.chronology);
|
|
7907
|
+
center.appendChild(chronology);
|
|
7908
|
+
var empty=element('p',msg.noMatches,'av-empty');empty.hidden=true;center.appendChild(empty);
|
|
7909
|
+
body.appendChild(center);
|
|
7910
|
+
var inspector=element('aside',undefined,'av-inspector');
|
|
7911
|
+
inspector.setAttribute('aria-label',msg.inspector);inspector.appendChild(element('h3',msg.inspector));
|
|
7912
|
+
var notice=element('p',msg.selectedFiltered);notice.hidden=true;inspector.appendChild(notice);
|
|
7913
|
+
var metrics=element('div',undefined,'av-metrics');metrics.setAttribute('data-agent-metrics','');inspector.appendChild(metrics);
|
|
7914
|
+
var inspectorTree=element('div');inspectorTree.setAttribute('data-agent-inspector-tree','');inspector.appendChild(inspectorTree);
|
|
7915
|
+
var related=element('section',undefined,'av-related');inspector.appendChild(related);
|
|
7916
|
+
body.appendChild(inspector);shell.appendChild(body);
|
|
7917
|
+
var replayNote=element('p',msg.replayNote,'av-replay-note');shell.appendChild(replayNote);
|
|
7918
|
+
host.replaceChildren(shell);
|
|
7919
|
+
host.classList.add('av-host');
|
|
7920
|
+
function setMode(value){
|
|
7921
|
+
mode=value;canvas.hidden=value!=='graph';chronology.hidden=value!=='chronology';
|
|
7922
|
+
graphButton.setAttribute('aria-pressed',String(value==='graph'));chronologyButton.setAttribute('aria-pressed',String(value==='chronology'));
|
|
7923
|
+
if(value==='graph'&&!positioned){fit()}
|
|
7924
|
+
}
|
|
7925
|
+
function transform(){
|
|
7926
|
+
viewport.setAttribute('transform','translate('+offsetX+' '+offsetY+') scale('+scale+')');
|
|
7927
|
+
svg.setAttribute('data-agent-scale',String(scale));
|
|
7928
|
+
}
|
|
7929
|
+
function fit(){
|
|
7930
|
+
if(!layout){return}
|
|
7931
|
+
var bounds=svg.getBoundingClientRect();if(!bounds.width||!bounds.height){return}
|
|
7932
|
+
scale=Math.max(.06,Math.min(1.25,(bounds.width-48)/layout.width,(bounds.height-92)/layout.height));
|
|
7933
|
+
offsetX=(bounds.width-layout.width*scale)/2;offsetY=60;positioned=true;transform();
|
|
7934
|
+
}
|
|
7935
|
+
function zoom(factor,x,y){
|
|
7936
|
+
var bounds=svg.getBoundingClientRect(),cx=x===undefined?bounds.width/2:x,cy=y===undefined?bounds.height/2:y;
|
|
7937
|
+
var next=Math.max(.06,Math.min(3,scale*factor));
|
|
7938
|
+
offsetX=cx-(cx-offsetX)*next/scale;offsetY=cy-(cy-offsetY)*next/scale;scale=next;positioned=true;transform();
|
|
7939
|
+
}
|
|
7940
|
+
svg.addEventListener('wheel',function(event){
|
|
7941
|
+
if(!event.ctrlKey&&!event.metaKey){return}
|
|
7942
|
+
event.preventDefault();var bounds=svg.getBoundingClientRect();zoom(event.deltaY>0?1/1.15:1.15,event.clientX-bounds.left,event.clientY-bounds.top);
|
|
7943
|
+
},{passive:false});
|
|
7944
|
+
svg.addEventListener('pointerdown',function(event){
|
|
7945
|
+
if(event.button!==0||event.target.closest('[data-agent-operation]')){return}
|
|
7946
|
+
drag={x:event.clientX,y:event.clientY,left:offsetX,top:offsetY,id:event.pointerId};
|
|
7947
|
+
svg.setPointerCapture(event.pointerId);
|
|
7948
|
+
});
|
|
7949
|
+
svg.addEventListener('pointermove',function(event){
|
|
7950
|
+
if(!drag||event.pointerId!==drag.id){return}
|
|
7951
|
+
offsetX=drag.left+event.clientX-drag.x;offsetY=drag.top+event.clientY-drag.y;positioned=true;transform();
|
|
7952
|
+
});
|
|
7953
|
+
function endDrag(){drag=null}
|
|
7954
|
+
svg.addEventListener('pointerup',endDrag);svg.addEventListener('pointercancel',endDrag);svg.addEventListener('lostpointercapture',endDrag);
|
|
7955
|
+
svg.addEventListener('keydown',function(event){
|
|
7956
|
+
if(event.key==='+'||event.key==='='){event.preventDefault();zoom(1.2)}
|
|
7957
|
+
else if(event.key==='-'){event.preventDefault();zoom(1/1.2)}
|
|
7958
|
+
else if(['ArrowLeft','ArrowRight','ArrowUp','ArrowDown'].includes(event.key)){
|
|
7959
|
+
event.preventDefault();offsetX+=event.key==='ArrowLeft'?40:event.key==='ArrowRight'?-40:0;
|
|
7960
|
+
offsetY+=event.key==='ArrowUp'?40:event.key==='ArrowDown'?-40:0;positioned=true;transform();
|
|
7961
|
+
}
|
|
7962
|
+
});
|
|
7963
|
+
function lastAttempt(operation){var attempts=operation.attempts||[];return attempts[attempts.length-1]}
|
|
7964
|
+
function phaseFor(operation){
|
|
7965
|
+
if(operation.state!=='running'){return msg.states[operation.state]||msg.states.unknown}
|
|
7966
|
+
if(!options.isLive()){return msg.phaseUnknown}
|
|
7967
|
+
var attempt=lastAttempt(operation),summary=summaries.get(attempt&&attempt.sessionID||options.rootSessionID(operation.operationID));
|
|
7968
|
+
return summary&&phases[summary.phase]||msg.phaseUnknown;
|
|
7969
|
+
}
|
|
7970
|
+
function appendMetric(name,value){var row=element('p');row.append(element('span',name),element('strong',String(value)));metrics.appendChild(row)}
|
|
7971
|
+
function updateMetrics(){
|
|
7972
|
+
if(!source){return}
|
|
7973
|
+
nodes.forEach(function(node,id){var phase=phaseFor(byID.get(id));if(node.phase.textContent!==phase){node.phase.textContent=phase}});
|
|
7974
|
+
var operation=byID.get(selected),attempt=operation&&lastAttempt(operation);
|
|
7975
|
+
var session=attempt&&attempt.sessionID||options.rootSessionID(operation&&operation.operationID),summary=summaries.get(session);
|
|
7976
|
+
var key=JSON.stringify([source.runID,selected,options.isLive(),operation&&phaseFor(operation),summary]);
|
|
7977
|
+
if(metricsKey===key){return}metricsKey=key;
|
|
7978
|
+
metrics.replaceChildren();
|
|
7979
|
+
if(!options.isLive()){metrics.appendChild(element('p',msg.historicalMetrics));return}
|
|
7980
|
+
if(!operation){return}
|
|
7981
|
+
appendMetric(msg.phase,phaseFor(operation));
|
|
7982
|
+
var hasUsage=summary&&summary.messageCount>0&&!(summary.unavailableUsageMessages>0);
|
|
7983
|
+
appendMetric(msg.usage,hasUsage?summary.tokensIn+' / '+summary.tokensOut:msg.usageUnavailable);
|
|
7984
|
+
appendMetric(msg.cost,summary&&summary.messageCount>0&&!(summary.unavailableCostMessages>0)?'$'+summary.realCostUSD.toFixed(5):msg.costUnavailable);
|
|
7985
|
+
appendMetric(msg.tools,summary&&summary.toolcalls.count?summary.toolcalls.count+' / '+summary.toolcalls.failed:msg.noTools);
|
|
7986
|
+
}
|
|
7987
|
+
function updateRelated(){
|
|
7988
|
+
if(!source){return}
|
|
7989
|
+
var current=(options.runs()||[]).find(function(item){return item.runID===source.runID});
|
|
7990
|
+
var operation=byID.get(selected),sessions=new Set((operation&&operation.attempts||[]).map(function(attempt){return attempt.sessionID}).filter(Boolean));
|
|
7991
|
+
var others=(options.isLive()?options.runs():[]).filter(function(item){return item.runID!==source.runID&&
|
|
7992
|
+
(current&&item.rootTaskID===current.rootTaskID||item.rootSessionID&&sessions.has(item.rootSessionID))});
|
|
7993
|
+
var key=JSON.stringify([source.runID,selected,others]);if(relatedKey===key){return}relatedKey=key;
|
|
7994
|
+
related.replaceChildren();
|
|
7995
|
+
if(!others.length){return}
|
|
7996
|
+
related.appendChild(element('h4',msg.related));related.appendChild(element('p',msg.relatedNote));
|
|
7997
|
+
var failed=others.filter(function(item){return item.terminalOutcome==='failed'}).length;
|
|
7998
|
+
if(failed){related.appendChild(element('p',msg.relatedFailed+': '+failed,'av-warning'))}
|
|
7999
|
+
others.forEach(function(item){
|
|
8000
|
+
var link=element('a',item.runID+' · '+(msg.states[item.terminalOutcome]||msg.states.unknown));
|
|
8001
|
+
var url=new URL(window.location.href);url.searchParams.set('run',item.runID);url.searchParams.delete('cursor');link.href=url.href;
|
|
8002
|
+
link.setAttribute('data-agent-related-run',item.runID);link.setAttribute('data-state',item.terminalOutcome||'unknown');related.appendChild(link);
|
|
8003
|
+
});
|
|
8004
|
+
}
|
|
8005
|
+
function select(id,quiet){
|
|
8006
|
+
if(!byID.has(id)){selected=null;shell.removeAttribute('data-agent-selected');updateMetrics();updateRelated();return}
|
|
8007
|
+
selected=id;shell.setAttribute('data-agent-selected',id);
|
|
8008
|
+
nodes.forEach(function(node,key){node.group.setAttribute('aria-pressed',String(key===id))});
|
|
8009
|
+
inspectorTree.querySelectorAll('.lct-operation-card').forEach(function(card){
|
|
8010
|
+
card.hidden=card.parentElement.getAttribute('data-lifecycle-operation-id')!==id;
|
|
8011
|
+
});
|
|
8012
|
+
notice.hidden=!filtered.has(id);
|
|
8013
|
+
inspector.scrollTop=quiet?inspector.scrollTop:0;
|
|
8014
|
+
updateMetrics();updateRelated();
|
|
8015
|
+
if(!quiet){document.dispatchEvent(new CustomEvent('console-conversation-selection'))}
|
|
8016
|
+
}
|
|
8017
|
+
function applyFilters(){
|
|
8018
|
+
if(!source){return}
|
|
8019
|
+
var term=search.value.trim().toLowerCase(),branch=null;
|
|
8020
|
+
if(isolated&&byID.has(isolated)){
|
|
8021
|
+
branch=new Set([isolated]);var parent=byID.get(isolated).parentOperationID;
|
|
8022
|
+
while(parent&&byID.has(parent)&&!branch.has(parent)){branch.add(parent);parent=byID.get(parent).parentOperationID}
|
|
8023
|
+
var descend=new Set([isolated]),changed=true;
|
|
8024
|
+
while(changed){changed=false;byID.forEach(function(op,id){if(descend.has(op.parentOperationID)&&!descend.has(id)){descend.add(id);changed=true}})}
|
|
8025
|
+
descend.forEach(function(id){branch.add(id)});
|
|
8026
|
+
}
|
|
8027
|
+
filtered=new Set();
|
|
8028
|
+
byID.forEach(function(op,id){
|
|
8029
|
+
var models=(op.attempts||[]).map(function(a){return a.model?a.model.providerID+'/'+a.model.modelID:''}).join(' ');
|
|
8030
|
+
var match=(!term||[id,op.agentID||'',op.roleID,models].join(' ').toLowerCase().includes(term))&&
|
|
8031
|
+
(!role.value||op.roleID===role.value)&&(!status.value||op.state===status.value)&&(!branch||branch.has(id));
|
|
8032
|
+
if(!match){filtered.add(id)}
|
|
8033
|
+
var node=nodes.get(id);if(node){node.group.setAttribute('data-filtered',String(!match));node.group.setAttribute('tabindex',match?'0':'-1')}
|
|
8034
|
+
});
|
|
8035
|
+
viewport.querySelectorAll('[data-edge-from]').forEach(function(edge){
|
|
8036
|
+
edge.setAttribute('data-filtered',String(filtered.has(edge.getAttribute('data-edge-from'))||filtered.has(edge.getAttribute('data-edge-to'))));
|
|
8037
|
+
});
|
|
8038
|
+
chronology.querySelectorAll('[data-event-operation]').forEach(function(row){row.hidden=filtered.has(row.getAttribute('data-event-operation'))});
|
|
8039
|
+
count.textContent=msg.matches+': '+(byID.size-filtered.size)+' / '+byID.size;
|
|
8040
|
+
empty.hidden=filtered.size!==byID.size||byID.size===0;
|
|
8041
|
+
notice.hidden=!filtered.has(selected);isolate.textContent=isolated?msg.clearIsolation:msg.isolate;
|
|
8042
|
+
isolate.setAttribute('aria-pressed',String(!!isolated));
|
|
8043
|
+
}
|
|
8044
|
+
search.addEventListener('input',applyFilters);role.addEventListener('change',applyFilters);status.addEventListener('change',applyFilters);
|
|
8045
|
+
function buildGraph(){
|
|
8046
|
+
var focus=document.activeElement&&document.activeElement.getAttribute('data-agent-operation');
|
|
8047
|
+
viewport.replaceChildren();nodes.clear();layout=layoutAgentOperations(Array.from(byID.values()));
|
|
8048
|
+
var positions=new Map(layout.nodes.map(function(node){return [node.id,node]}));
|
|
8049
|
+
var defs=svgElement('defs'),marker=svgElement('marker',{id:'agent-dependency-arrow',viewBox:'0 0 8 8',refX:7,refY:4,markerWidth:6,markerHeight:6,orient:'auto'});
|
|
8050
|
+
marker.appendChild(svgElement('path',{d:'M0 0 L8 4 L0 8 Z',fill:'#8a777e'}));defs.appendChild(marker);viewport.appendChild(defs);
|
|
8051
|
+
var missing=0;
|
|
8052
|
+
function edge(from,to,kind){
|
|
8053
|
+
var a=positions.get(from),b=positions.get(to);if(!a||!b){missing++;return}
|
|
8054
|
+
var x1=a.x+228,y1=a.y+56,x2=b.x,y2=b.y+56,middle=(x1+x2)/2;
|
|
8055
|
+
var path=svgElement('path',{'class':'av-edge','data-kind':kind,'data-edge-from':from,'data-edge-to':to,
|
|
8056
|
+
d:'M'+x1+' '+y1+' C'+middle+' '+y1+' '+middle+' '+y2+' '+x2+' '+y2});
|
|
8057
|
+
if(kind==='dependency'){path.setAttribute('marker-end','url(#agent-dependency-arrow)')}
|
|
8058
|
+
path.appendChild(svgElement('title',{},(kind==='hierarchy'?msg.hierarchy:msg.dependency)+': '+from+' -> '+to));viewport.appendChild(path);
|
|
8059
|
+
}
|
|
8060
|
+
byID.forEach(function(operation){
|
|
8061
|
+
if(operation.parentOperationID){edge(operation.parentOperationID,operation.operationID,'hierarchy')}
|
|
8062
|
+
(operation.dependsOnOperationIDs||[]).forEach(function(id){edge(id,operation.operationID,'dependency')});
|
|
8063
|
+
});
|
|
8064
|
+
unresolved.textContent=msg.missing+': '+missing;unresolved.hidden=missing===0;
|
|
8065
|
+
layout.nodes.forEach(function(position){
|
|
8066
|
+
var operation=byID.get(position.id),attempt=lastAttempt(operation),identity=operation.agentID||operation.roleID;
|
|
8067
|
+
var group=svgElement('g',{'class':'av-node',transform:'translate('+position.x+' '+position.y+')','data-agent-operation':position.id,
|
|
8068
|
+
'data-state':operation.state,role:'button',tabindex:0,'aria-label':identity+' · '+operation.roleID+' · '+(msg.states[operation.state]||msg.states.unknown)});
|
|
8069
|
+
group.appendChild(svgElement('rect',{width:228,height:120,rx:12}));
|
|
8070
|
+
group.appendChild(svgElement('title',{},identity+' · '+position.id));
|
|
8071
|
+
group.appendChild(svgElement('text',{x:14,y:23,'class':'av-role'},operation.roleID.slice(0,31)));
|
|
8072
|
+
group.appendChild(svgElement('text',{x:14,y:45,'class':'av-name'},identity.slice(0,28)));
|
|
8073
|
+
var model=attempt&&attempt.model?attempt.model.providerID+'/'+attempt.model.modelID:msg.noModel;
|
|
8074
|
+
group.appendChild(svgElement('text',{x:14,y:64,'class':'av-model'},model.slice(0,32)));
|
|
8075
|
+
var phase=svgElement('text',{x:14,y:84,'class':'av-phase'},phaseFor(operation));group.appendChild(phase);
|
|
8076
|
+
var failures=(operation.attempts||[]).filter(function(a){return ['failed','interrupted','cancelled'].includes(a.state)}).length;
|
|
8077
|
+
group.appendChild(svgElement('text',{x:14,y:105,'class':'av-attempts'},msg.attempts+': '+operation.attempts.length+' · '+msg.failures+': '+failures));
|
|
8078
|
+
group.addEventListener('click',function(){select(position.id)});
|
|
8079
|
+
group.addEventListener('keydown',function(event){if(event.key==='Enter'||event.key===' '){event.preventDefault();select(position.id)}});
|
|
8080
|
+
nodes.set(position.id,{group:group,phase:phase});viewport.appendChild(group);
|
|
8081
|
+
});
|
|
8082
|
+
transform();if(!positioned){fit()}
|
|
8083
|
+
if(focus&&nodes.has(focus)){nodes.get(focus).group.focus({preventScroll:true})}
|
|
8084
|
+
}
|
|
8085
|
+
function buildChronology(){
|
|
8086
|
+
var top=chronology.scrollTop;chronology.replaceChildren();var events=source.timeline||[];
|
|
8087
|
+
if(!events.length){chronology.appendChild(element('li',msg.noEvents))}
|
|
8088
|
+
if(events.length>1000){chronology.appendChild(element('li',msg.eventWindow))}
|
|
8089
|
+
events.slice(-1000).forEach(function(event){
|
|
8090
|
+
var id=event.operationID||event.root&&event.root.operationID||source.rootOperationID,op=byID.get(id);
|
|
8091
|
+
var row=element('li');row.setAttribute('data-event-operation',id);row.setAttribute('data-event-seq',String(event.seq));
|
|
8092
|
+
var item=button('',function(){pause();select(id);seek(event.seq+1,true)});
|
|
8093
|
+
item.appendChild(element('time',new Date(event.at).toISOString()));
|
|
8094
|
+
item.appendChild(element('strong',msg.events[event.type]||event.type));
|
|
8095
|
+
item.appendChild(element('span',(op&&(op.agentID||op.roleID)||id)+(event.outcome?' · '+(msg.states[event.outcome]||event.outcome):'')));
|
|
8096
|
+
row.appendChild(item);chronology.appendChild(row);
|
|
8097
|
+
});chronology.scrollTop=top;
|
|
8098
|
+
}
|
|
8099
|
+
function seek(cursor,push){pendingCursor=cursor;options.seek(cursor,push)}
|
|
8100
|
+
function pause(){playing=false;clearTimeout(playTimer);playTimer=null;playButton.textContent=msg.play;playButton.setAttribute('aria-label',msg.play);playButton.setAttribute('aria-pressed','false')}
|
|
8101
|
+
function tick(){
|
|
8102
|
+
if(!playing||!source){return}
|
|
8103
|
+
if(document.hidden||!shell.isConnected){pause();return}
|
|
8104
|
+
if(pendingCursor===null||source.cursor===pendingCursor){
|
|
8105
|
+
if(source.cursor>=source.head){pause();return}
|
|
8106
|
+
seek(source.cursor+1,false);
|
|
8107
|
+
}
|
|
8108
|
+
playTimer=setTimeout(tick,1000/Number(speed.value));
|
|
8109
|
+
}
|
|
8110
|
+
function togglePlayback(){
|
|
8111
|
+
if(playing){pause();return}if(!source||source.head===0){return}
|
|
8112
|
+
playing=true;playButton.textContent=msg.pause;playButton.setAttribute('aria-label',msg.pause);playButton.setAttribute('aria-pressed','true');
|
|
8113
|
+
seek(source.cursor>=source.head?0:source.cursor,true);playTimer=setTimeout(tick,1000/Number(speed.value));
|
|
8114
|
+
}
|
|
8115
|
+
function rememberDetails(){
|
|
8116
|
+
if(!tree){return}
|
|
8117
|
+
tree.querySelectorAll('[data-lifecycle-operation-id]').forEach(function(article){
|
|
8118
|
+
var card=article.querySelector('.lct-operation-card');if(!card){return}
|
|
8119
|
+
card.querySelectorAll('details:not(.lc-conversation details)').forEach(function(detail,index){
|
|
8120
|
+
openDetails.set(article.getAttribute('data-lifecycle-operation-id')+':'+index,detail.open);
|
|
8121
|
+
});
|
|
8122
|
+
});
|
|
8123
|
+
}
|
|
8124
|
+
function update(projection,nextTree){
|
|
8125
|
+
var changedRun=run!==projection.runID;
|
|
8126
|
+
if(changedRun){pause();selected=projection.rootOperationID;isolated=null;positioned=false;openDetails.clear()}
|
|
8127
|
+
else{rememberDetails()}
|
|
8128
|
+
run=projection.runID;source=projection;
|
|
8129
|
+
byID=new Map((projection.operations||[]).map(function(op){return [op.operationID,op]}));
|
|
8130
|
+
if(!byID.has(selected)){selected=byID.has(projection.rootOperationID)?projection.rootOperationID:byID.keys().next().value}
|
|
8131
|
+
var oldRole=role.value;role.replaceChildren();option(role,'',msg.allRoles);
|
|
8132
|
+
Array.from(new Set(Array.from(byID.values()).map(function(op){return op.roleID}))).sort().forEach(function(value){option(role,value,value)});
|
|
8133
|
+
if(Array.from(role.options).some(function(item){return item.value===oldRole})){role.value=oldRole}
|
|
8134
|
+
var top=inspector.scrollTop;tree=nextTree;inspectorTree.replaceChildren(tree);
|
|
8135
|
+
tree.querySelectorAll('[data-lifecycle-operation-id]').forEach(function(article){
|
|
8136
|
+
var card=article.querySelector('.lct-operation-card');if(!card){return}
|
|
8137
|
+
card.querySelectorAll('details').forEach(function(detail,index){
|
|
8138
|
+
var saved=openDetails.get(article.getAttribute('data-lifecycle-operation-id')+':'+index);if(saved!==undefined){detail.open=saved}
|
|
8139
|
+
});
|
|
8140
|
+
});
|
|
8141
|
+
isolate.disabled=byID.size===0;
|
|
8142
|
+
buildGraph();buildChronology();applyFilters();select(selected,true);setMode(mode);inspector.scrollTop=changedRun?0:top;
|
|
8143
|
+
}
|
|
8144
|
+
function onTelemetry(event){
|
|
8145
|
+
summaries=new Map((event.detail&&event.detail.sessions||[]).map(function(item){return [item.sessionID,item]}));
|
|
8146
|
+
if(shell.isConnected){updateMetrics()}
|
|
8147
|
+
}
|
|
8148
|
+
function onVisibility(){if(document.hidden){pause()}}
|
|
8149
|
+
document.addEventListener('console-telemetry',onTelemetry);
|
|
8150
|
+
document.addEventListener('visibilitychange',onVisibility);
|
|
8151
|
+
window.addEventListener('pagehide',pause);
|
|
8152
|
+
return {update:update,pause:pause,connected:function(){return shell.isConnected},refresh:function(){updateMetrics();updateRelated();if(!positioned&&mode==='graph'){fit()}},
|
|
8153
|
+
dispose:function(){pause();document.removeEventListener('console-telemetry',onTelemetry);document.removeEventListener('visibilitychange',onVisibility);
|
|
8154
|
+
window.removeEventListener('pagehide',pause);host.classList.remove('av-host')}};
|
|
8155
|
+
}
|
|
8156
|
+
`;
|
|
8157
|
+
var AGENT_VIEW_STYLE = `
|
|
8158
|
+
#screen-tree:has(.av-workspace){max-width:none}
|
|
8159
|
+
.av-host{max-height:none;padding:0;overflow:visible}
|
|
8160
|
+
.av-workspace{--av-bg:#121012;--av-text:#f3edef;--av-muted:#b7aab0;--av-line:#3b3036;--av-accent:#c9184c;--cp-bg:#121012;--cp-surface:#1d181c;--cp-surface-soft:#262026;--cp-text:#f3edef;--cp-text-muted:#b7aab0;--cp-border:#3b3036;--cp-border-strong:#79646d;--cp-accent:#f47b9e;--cp-success:#77c491;--cp-danger:#ff8699;color:var(--av-text);background:var(--av-bg);border:1px solid var(--av-line);border-radius:14px;overflow:hidden}
|
|
8161
|
+
.av-workspace [hidden]{display:none!important}
|
|
8162
|
+
.av-workspace button,.av-workspace input,.av-workspace select{font:inherit;color:inherit;background:#211b20;border:1px solid var(--av-line);border-radius:7px;padding:6px 9px}
|
|
8163
|
+
.av-workspace button:hover,.av-workspace button[aria-pressed="true"]{border-color:#ee7399;color:#ffa2be}
|
|
8164
|
+
.av-workspace :focus-visible{outline:2px solid #ec5282;outline-offset:3px}
|
|
8165
|
+
.av-toolbar{display:flex;align-items:center;gap:7px;flex-wrap:wrap;padding:12px;border-bottom:1px solid var(--av-line);font-size:12px}
|
|
8166
|
+
.av-toolbar label{display:flex;align-items:center;gap:6px}.av-count{margin-left:auto;color:var(--av-muted)}
|
|
8167
|
+
.av-body{display:grid;grid-template-columns:180px minmax(300px,1fr) minmax(280px,360px);height:min(78vh,860px);min-height:520px}
|
|
8168
|
+
.av-filters{padding:16px 12px;border-right:1px solid var(--av-line);overflow:auto;font-size:12px}
|
|
8169
|
+
.av-filters h3,.av-inspector>h3{color:var(--av-text);font-size:12px;letter-spacing:.06em;text-transform:uppercase;margin-bottom:14px}
|
|
8170
|
+
.av-filters label{display:grid;gap:6px;margin-bottom:14px;color:var(--av-muted)}
|
|
8171
|
+
.av-filters input,.av-filters select{width:100%;min-width:0;color:var(--av-text)}
|
|
8172
|
+
.av-filters>button{display:block;width:100%;margin:9px 0;font-size:12px;text-align:left}
|
|
8173
|
+
.av-filters p,.av-related p{margin:10px 0;color:var(--av-muted);line-height:1.5;font-size:11px}
|
|
8174
|
+
.av-legend{margin-top:24px;border-top:1px solid var(--av-line);padding-top:8px}
|
|
8175
|
+
.av-solid:before,.av-dashed:before{content:"";display:inline-block;width:24px;border-top:2px solid #b7aab0;margin-right:7px;vertical-align:middle}.av-dashed:before{border-top-style:dashed}
|
|
8176
|
+
.av-center{position:relative;min-width:0;background:#fdfbf6;color:#30272d}
|
|
8177
|
+
.av-canvas{position:relative;height:100%;min-height:380px;overflow:hidden;background-image:radial-gradient(#e3d9db .8px,transparent .8px);background-size:20px 20px}
|
|
8178
|
+
.av-zoom{position:absolute;display:flex;gap:5px;top:12px;left:12px;z-index:2;flex-wrap:wrap}
|
|
8179
|
+
.av-zoom button{background:#fdfbf6;color:#342c30;border-color:#d6c5cb;font-size:11px;box-shadow:0 1px 3px #0001}
|
|
8180
|
+
.av-zoom button:hover{color:#a50e3c}
|
|
8181
|
+
.av-graph{width:100%;height:100%;display:block;cursor:grab;touch-action:none}
|
|
8182
|
+
.av-node{cursor:pointer;outline:none}.av-node rect{fill:#fffdf9;stroke:#d2c5ca;stroke-width:1.5}
|
|
8183
|
+
.av-node:hover rect,.av-node:focus-visible rect{stroke:#69434f;stroke-width:2}
|
|
8184
|
+
.av-node[aria-pressed="true"] rect{stroke:#c9184c;stroke-width:2.5}
|
|
8185
|
+
.av-node[data-state="failed"] rect,.av-node[data-state="interrupted"] rect{fill:#fff0f1;stroke:#bf3150}
|
|
8186
|
+
.av-node[data-state="succeeded"] rect{fill:#f4faf3;stroke:#79a186}
|
|
8187
|
+
.av-node text{fill:#362b31;font:11px var(--font-sans);pointer-events:none}
|
|
8188
|
+
.av-node .av-role{fill:#755f69;font-size:10px;letter-spacing:.04em}
|
|
8189
|
+
.av-node .av-name{font-size:16px;font-weight:650}
|
|
8190
|
+
.av-node .av-model,.av-node .av-attempts{fill:#6d5a63;font-size:10px;font-family:var(--font-mono)}
|
|
8191
|
+
.av-node .av-phase{fill:#9d234b;font-size:11px}
|
|
8192
|
+
.av-node[data-filtered="true"]{opacity:.22}
|
|
8193
|
+
.av-edge{fill:none;stroke:#a6969c;stroke-width:1.5}
|
|
8194
|
+
.av-edge[data-kind="dependency"]{stroke:#bd5776;stroke-dasharray:5 5}
|
|
8195
|
+
.av-edge[data-filtered="true"]{opacity:.12}
|
|
8196
|
+
.av-empty{position:absolute;bottom:18px;left:18px;right:18px;background:#fdfbf6;padding:10px;border:1px solid #d6c5cb;border-radius:7px;font-size:12px}
|
|
8197
|
+
.av-inspector{overflow:auto;min-width:0;padding:16px 14px;border-left:1px solid var(--av-line);overflow-anchor:none}
|
|
8198
|
+
.av-inspector .lct-tree,.av-inspector .lct-operation{min-width:0;margin:0;padding:0;max-width:100%}
|
|
8199
|
+
.av-inspector .lct-operation-children{margin:0;padding:0;border:0}
|
|
8200
|
+
.av-inspector .lct-operation-card{border-left-width:3px;box-shadow:none;border-radius:8px;padding:12px}
|
|
8201
|
+
.av-inspector .lct-operation-meta,.av-inspector .lct-attempt-meta{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
|
|
8202
|
+
.av-inspector .lct-operation-head,.av-inspector .lct-attempt-head{flex-wrap:wrap}
|
|
8203
|
+
.av-inspector .lct-session{display:block}.av-inspector code,.av-inspector dd{overflow-wrap:anywhere;word-break:break-word}
|
|
8204
|
+
.av-inspector .lc-conversation{padding:9px}.av-inspector .lc-conversation pre{padding:8px;font-size:11px}
|
|
8205
|
+
.av-inspector .lct-attempt{padding:10px;min-width:0}
|
|
8206
|
+
.av-inspector .lct-times{display:block;font-size:10px}
|
|
8207
|
+
.av-inspector .lct-unlinked>h4,.av-inspector .lct-unlinked>p,.av-inspector .lct-no-attempts{font-size:11px}
|
|
8208
|
+
.av-metrics{margin-bottom:14px;font-size:11px;border-bottom:1px solid var(--av-line);padding-bottom:10px}
|
|
8209
|
+
.av-metrics p{display:flex;flex-wrap:wrap;gap:3px 8px;justify-content:space-between;margin:5px 0}.av-metrics span{color:var(--av-muted)}
|
|
8210
|
+
.av-related{margin-top:18px}.av-related a{display:block;color:#f59fba;overflow-wrap:anywhere;font-size:11px;margin:8px 0}
|
|
8211
|
+
.av-related a[data-state="failed"],.av-warning{color:#ff8699!important}
|
|
8212
|
+
.av-chronology{list-style:none;margin:0;padding:18px;height:100%;overflow:auto}
|
|
8213
|
+
.av-chronology li{border-left:2px solid #d2c5ca;padding:0 0 12px 16px}
|
|
8214
|
+
.av-chronology button{display:grid;gap:7px;text-align:left;width:100%;background:#fffdf9;color:#30272d;border-color:#d2c5ca;padding:12px}
|
|
8215
|
+
.av-chronology button:hover{border-color:#c9184c;color:#9d234b}
|
|
8216
|
+
.av-chronology time{font:10px var(--font-mono);color:#725e68}.av-chronology span{font-size:11px;overflow-wrap:anywhere}
|
|
8217
|
+
.av-replay-note{padding:10px 14px;margin:0;border-top:1px solid var(--av-line);color:var(--av-muted);font-size:11px}
|
|
8218
|
+
@media(max-width:1280px){.av-body{grid-template-columns:145px minmax(250px,1fr) 300px}.av-toolbar{gap:5px}}
|
|
8219
|
+
@media(max-width:1050px){.av-body{grid-template-columns:minmax(250px,1fr) 300px}.av-filters{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:10px;align-items:center;border-bottom:1px solid var(--av-line);max-height:150px}.av-filters label{width:150px;margin:0}.av-filters>button{width:auto}.av-filters h3,.av-filters>p,.av-legend{display:none}.av-body{height:auto}.av-center,.av-inspector{height:620px}}
|
|
8220
|
+
@media(max-width:740px){.av-body{display:block}.av-center{height:430px}.av-inspector{height:auto;max-height:650px;border-left:0;border-top:1px solid var(--av-line)}.av-count{width:100%;margin:0}.av-filters{max-height:none}.av-toolbar{font-size:11px}}
|
|
8221
|
+
@media(prefers-reduced-motion:reduce){.av-workspace *{animation:none!important;transition:none!important}}
|
|
8222
|
+
`;
|
|
8223
|
+
|
|
7469
8224
|
// src/console/inspector.ts
|
|
7470
8225
|
var CONVERSATION_CLIENT_JS = `
|
|
7471
8226
|
function wireConversationInspector(){
|
|
@@ -7708,7 +8463,9 @@ function wireConversationInspector(){
|
|
|
7708
8463
|
});
|
|
7709
8464
|
document.addEventListener('conversation-tree-replacing',function(){
|
|
7710
8465
|
var scroll=document.querySelector('.scroll'),tree=mount&&mount.querySelector('[data-lifecycle-tree-mount]');
|
|
7711
|
-
|
|
8466
|
+
var inspector=mount&&mount.querySelector('.av-inspector');
|
|
8467
|
+
retained={focus:document.activeElement,scroll:scroll,scrollTop:scroll&&scroll.scrollTop,treeTop:tree&&tree.scrollTop,
|
|
8468
|
+
inspector:inspector,inspectorTop:inspector&&inspector.scrollTop,positions:[]};
|
|
7712
8469
|
records.forEach(function(record){
|
|
7713
8470
|
[record.body].concat(Array.from(record.panel.querySelectorAll('pre'))).forEach(function(node){
|
|
7714
8471
|
retained.positions.push([node,node.scrollTop,node.scrollLeft]);
|
|
@@ -7723,6 +8480,7 @@ function wireConversationInspector(){
|
|
|
7723
8480
|
var tree=mount&&mount.querySelector('[data-lifecycle-tree-mount]');
|
|
7724
8481
|
if(tree&&retained.treeTop!==null){tree.scrollTop=retained.treeTop}
|
|
7725
8482
|
if(retained.scroll){retained.scroll.scrollTop=retained.scrollTop}
|
|
8483
|
+
if(retained.inspector&&retained.inspector.isConnected){retained.inspector.scrollTop=retained.inspectorTop}
|
|
7726
8484
|
if(retained.focus&&retained.focus.isConnected&&retained.focus!==document.activeElement&&
|
|
7727
8485
|
(!document.activeElement||document.activeElement===document.body||document.activeElement===document.documentElement)){
|
|
7728
8486
|
retained.focus.focus({preventScroll:true});
|
|
@@ -7877,6 +8635,8 @@ var CONSOLE_REFRESH_JS = `
|
|
|
7877
8635
|
if(viewStopped||viewRequest!==controller||!result){return}
|
|
7878
8636
|
if(typeof result.data.routing!=='string'||typeof result.data.logs!=='string'){return}
|
|
7879
8637
|
latestView=result.data;viewRevision=result.revision;
|
|
8638
|
+
document.__consoleTelemetry=latestView.sessionSummaries||[];
|
|
8639
|
+
document.dispatchEvent(new CustomEvent('console-telemetry',{detail:{sessions:latestView.sessionSummaries||[]}}));
|
|
7880
8640
|
var updated=document.querySelector('.token-chip b');
|
|
7881
8641
|
if(updated&&typeof latestView.updatedAt==='string'){updated.textContent=latestView.updatedAt}
|
|
7882
8642
|
if(Number.isInteger(latestView.refreshMs)&&latestView.refreshMs>=250&&latestView.refreshMs!==ms){
|
|
@@ -8515,6 +9275,7 @@ var LIFECYCLE_THEME_BOOT = `
|
|
|
8515
9275
|
})();
|
|
8516
9276
|
`;
|
|
8517
9277
|
var LIFECYCLE_CLIENT_JS = `
|
|
9278
|
+
${AGENT_VIEW_CLIENT_JS}
|
|
8518
9279
|
function wireLifecycleTimeline(){
|
|
8519
9280
|
var mount=document.getElementById('lifecycle-timeline-mount');
|
|
8520
9281
|
if(!mount){return}
|
|
@@ -8553,6 +9314,11 @@ function wireLifecycleTimeline(){
|
|
|
8553
9314
|
lastSseHead:new Map()
|
|
8554
9315
|
};
|
|
8555
9316
|
var projectionKey='';
|
|
9317
|
+
var agentViewer=null,agentRuns=[],agentRootOperationID=null;
|
|
9318
|
+
function clearAgentViewer(){
|
|
9319
|
+
if(agentViewer){agentViewer.dispose();agentViewer=null}
|
|
9320
|
+
var note=mount.querySelector('[data-agent-degraded]');if(note){note.remove()}
|
|
9321
|
+
}
|
|
8556
9322
|
var committedRun=mount.getAttribute('data-lifecycle-run')||null,committedCursor=urlCursor();
|
|
8557
9323
|
|
|
8558
9324
|
function invalidateConversation(){
|
|
@@ -8687,6 +9453,7 @@ function wireLifecycleTimeline(){
|
|
|
8687
9453
|
if(sliderWired||!slider){return}
|
|
8688
9454
|
sliderWired=true;
|
|
8689
9455
|
slider.addEventListener('input',function(){
|
|
9456
|
+
if(agentViewer){agentViewer.pause()}
|
|
8690
9457
|
var c=parseInt(slider.value,10);
|
|
8691
9458
|
if(!scrubInProgress){
|
|
8692
9459
|
history.pushState(null,'',window.location.href);
|
|
@@ -8829,6 +9596,7 @@ function wireLifecycleTimeline(){
|
|
|
8829
9596
|
function renderView(d,requestedCursor){
|
|
8830
9597
|
ensureViewControls();
|
|
8831
9598
|
state.runID=d.selection.runID;
|
|
9599
|
+
agentRuns=d.runs||[];
|
|
8832
9600
|
state.head=d.selection.head;
|
|
8833
9601
|
state.cursor=d.selection.cursor;
|
|
8834
9602
|
state.followLive=requestedCursor===null;
|
|
@@ -8905,6 +9673,7 @@ function wireLifecycleTimeline(){
|
|
|
8905
9673
|
}
|
|
8906
9674
|
|
|
8907
9675
|
function renderLegacy(d){
|
|
9676
|
+
clearAgentViewer();
|
|
8908
9677
|
ensureViewControls();
|
|
8909
9678
|
state.runID=d.selection.runID;
|
|
8910
9679
|
state.head=0;
|
|
@@ -8943,19 +9712,37 @@ function wireLifecycleTimeline(){
|
|
|
8943
9712
|
|
|
8944
9713
|
function renderProjection(proj,recording){
|
|
8945
9714
|
if(!proj||!treeMountEl){return}
|
|
9715
|
+
agentRootOperationID=proj.rootOperationID;
|
|
8946
9716
|
var degraded=recording&&recording.state==='degraded';
|
|
8947
9717
|
var option=runSelect&&Array.from(runSelect.options).find(function(o){return o.value===proj.runID});
|
|
8948
9718
|
var key=JSON.stringify([proj.runID,proj.cursor,proj.rootOperationID,proj.operations,degraded,option&&option.getAttribute('data-run-session')]);
|
|
8949
|
-
if(key===projectionKey){return}
|
|
9719
|
+
if(key===projectionKey){if(agentViewer){agentViewer.refresh()}return}
|
|
8950
9720
|
projectionKey=key;
|
|
8951
9721
|
document.dispatchEvent(new CustomEvent('conversation-tree-replacing'));
|
|
8952
|
-
|
|
9722
|
+
if(!agentViewer||!agentViewer.connected()){
|
|
9723
|
+
if(agentViewer){agentViewer.dispose()}
|
|
9724
|
+
agentViewer=createAgentViewer(treeMountEl,{
|
|
9725
|
+
isLive:function(){return state.followLive},
|
|
9726
|
+
runs:function(){return agentRuns},
|
|
9727
|
+
rootSessionID:function(id){
|
|
9728
|
+
if(id!==agentRootOperationID){return undefined}
|
|
9729
|
+
var option=runSelect&&Array.from(runSelect.options).find(function(o){return o.value===state.runID});
|
|
9730
|
+
return option&&option.getAttribute('data-run-session')||undefined;
|
|
9731
|
+
},
|
|
9732
|
+
seek:function(cursor,push){
|
|
9733
|
+
if(push){pushUrl(state.runID,cursor)}else{replaceUrl(state.runID,cursor)}
|
|
9734
|
+
navigateFromUrl(false);
|
|
9735
|
+
}
|
|
9736
|
+
});
|
|
9737
|
+
}
|
|
9738
|
+
var priorNote=mount.querySelector('[data-agent-degraded]');if(priorNote){priorNote.remove()}
|
|
8953
9739
|
if(degraded){
|
|
8954
9740
|
var note=makeElement('div','lc-partial-note',message('partial-tail'));
|
|
9741
|
+
note.setAttribute('data-agent-degraded','');
|
|
8955
9742
|
note.setAttribute('role','status');
|
|
8956
|
-
treeMountEl.
|
|
9743
|
+
treeMountEl.before(note);
|
|
8957
9744
|
}
|
|
8958
|
-
|
|
9745
|
+
agentViewer.update(proj,buildOperationTree(proj));
|
|
8959
9746
|
}
|
|
8960
9747
|
|
|
8961
9748
|
function makeElement(tag,className,text){
|
|
@@ -9288,6 +10075,7 @@ function wireLifecycleTimeline(){
|
|
|
9288
10075
|
}
|
|
9289
10076
|
|
|
9290
10077
|
function showError(){
|
|
10078
|
+
clearAgentViewer();
|
|
9291
10079
|
invalidateConversation();
|
|
9292
10080
|
projectionKey='';
|
|
9293
10081
|
mount.setAttribute('data-lifecycle-state','error');
|
|
@@ -9304,6 +10092,7 @@ function wireLifecycleTimeline(){
|
|
|
9304
10092
|
}
|
|
9305
10093
|
|
|
9306
10094
|
function showApiError(err){
|
|
10095
|
+
clearAgentViewer();
|
|
9307
10096
|
projectionKey='';
|
|
9308
10097
|
mount.setAttribute('data-lifecycle-state','error');
|
|
9309
10098
|
updateScreenCopy('unavailable',false,null);
|
|
@@ -9320,6 +10109,7 @@ function wireLifecycleTimeline(){
|
|
|
9320
10109
|
}
|
|
9321
10110
|
|
|
9322
10111
|
function showDisabled(d){
|
|
10112
|
+
clearAgentViewer();
|
|
9323
10113
|
projectionKey='';
|
|
9324
10114
|
mount.setAttribute('data-lifecycle-state','disabled');
|
|
9325
10115
|
updateScreenCopy('unavailable',false,null);
|
|
@@ -9337,6 +10127,7 @@ function wireLifecycleTimeline(){
|
|
|
9337
10127
|
}
|
|
9338
10128
|
|
|
9339
10129
|
function showEmpty(){
|
|
10130
|
+
clearAgentViewer();
|
|
9340
10131
|
projectionKey='';
|
|
9341
10132
|
mount.setAttribute('data-lifecycle-state','empty');
|
|
9342
10133
|
updateScreenCopy('empty',false,null);
|
|
@@ -9355,6 +10146,7 @@ function wireLifecycleTimeline(){
|
|
|
9355
10146
|
// --- Run selector change ---
|
|
9356
10147
|
if(runSelect){
|
|
9357
10148
|
runSelect.addEventListener('change',function(){
|
|
10149
|
+
if(agentViewer){agentViewer.pause()}
|
|
9358
10150
|
var newRun=runSelect.value;
|
|
9359
10151
|
pushUrl(newRun,null); // committed selection → traversable entry
|
|
9360
10152
|
navigateFromUrl(false);
|
|
@@ -9369,6 +10161,7 @@ function wireLifecycleTimeline(){
|
|
|
9369
10161
|
// --- Live / Return to live ---
|
|
9370
10162
|
if(liveBtn){
|
|
9371
10163
|
liveBtn.addEventListener('click',function(){
|
|
10164
|
+
if(agentViewer){agentViewer.pause()}
|
|
9372
10165
|
pushUrl(state.explicitRun,null); // return-to-live preserves automatic run selection
|
|
9373
10166
|
navigateFromUrl(false);
|
|
9374
10167
|
});
|
|
@@ -9393,6 +10186,7 @@ function wireLifecycleTimeline(){
|
|
|
9393
10186
|
|
|
9394
10187
|
// --- Browser back/forward ---
|
|
9395
10188
|
window.addEventListener('popstate',function(){
|
|
10189
|
+
if(agentViewer){agentViewer.pause()}
|
|
9396
10190
|
navigateFromUrl(false);
|
|
9397
10191
|
});
|
|
9398
10192
|
|
|
@@ -9447,7 +10241,11 @@ function ms(value) {
|
|
|
9447
10241
|
return value >= 1000 ? `${(value / 1000).toFixed(2)}s` : `${Math.round(value)}ms`;
|
|
9448
10242
|
}
|
|
9449
10243
|
function avgMs(stats) {
|
|
9450
|
-
|
|
10244
|
+
const known = stats.count - (stats.unknownDurationCount ?? 0);
|
|
10245
|
+
return stats.count === 0 ? "—" : known === 0 ? consoleDetailMessages.timingUnknown : ms(stats.totalDurationMs / known);
|
|
10246
|
+
}
|
|
10247
|
+
function measured(value, unavailable) {
|
|
10248
|
+
return (unavailable ?? 0) === 0 ? String(value) : `<span title="${escapeHtml(consoleDetailMessages.usageCaution)}">${escapeHtml(consoleDetailMessages.usageUnavailable)}</span>`;
|
|
9451
10249
|
}
|
|
9452
10250
|
function agentModel(agent) {
|
|
9453
10251
|
return agent.model === undefined ? "inherits default" : `${agent.model.providerID}/${agent.model.modelID}`;
|
|
@@ -9462,15 +10260,16 @@ function summaryPanel(cost) {
|
|
|
9462
10260
|
return [
|
|
9463
10261
|
'<section class="panel" id="panel-summary">',
|
|
9464
10262
|
"<h2>Routing summary</h2>",
|
|
10263
|
+
`<p class="muted">${escapeHtml(consoleDetailMessages.estimatesNotUsage)}</p>`,
|
|
9465
10264
|
'<div class="grid">',
|
|
9466
10265
|
`<div class="stat"><span class="k">Decisions</span><span class="v">${cost.count}</span></div>`,
|
|
9467
10266
|
`<div class="stat"><span class="k">Local</span><span class="v">${cost.localCount}</span></div>`,
|
|
9468
10267
|
`<div class="stat"><span class="k">Frontier</span><span class="v">${cost.frontierCount}</span></div>`,
|
|
9469
|
-
`<div class="stat"><span class="k"
|
|
9470
|
-
`<div class="stat"><span class="k"
|
|
9471
|
-
`<div class="stat"><span class="k"
|
|
9472
|
-
`<div class="stat"><span class="k"
|
|
9473
|
-
`<div class="stat"><span class="k"
|
|
10268
|
+
`<div class="stat"><span class="k">${escapeHtml(consoleDetailMessages.estimatedCost)}</span><span class="v">${usd(cost.totalEstimatedUSD)}</span></div>`,
|
|
10269
|
+
`<div class="stat"><span class="k">${escapeHtml(consoleDetailMessages.estimatedBaseline)}</span><span class="v">${usd(cost.totalBaselineUSD)}</span></div>`,
|
|
10270
|
+
`<div class="stat"><span class="k">${escapeHtml(consoleDetailMessages.estimatedSavings)}</span><span class="v good">${usd(cost.totalSavingsUSD)} (${pct(cost.savingsPct)})</span></div>`,
|
|
10271
|
+
`<div class="stat"><span class="k">${escapeHtml(consoleDetailMessages.estimatedInput)}</span><span class="v">${cost.tokensIn}</span></div>`,
|
|
10272
|
+
`<div class="stat"><span class="k">${escapeHtml(consoleDetailMessages.estimatedOutput)}</span><span class="v">${cost.tokensOut}</span></div>`,
|
|
9474
10273
|
"</div>",
|
|
9475
10274
|
"</section>"
|
|
9476
10275
|
].join("");
|
|
@@ -9585,12 +10384,12 @@ function totalsPanel(totals) {
|
|
|
9585
10384
|
'<div class="grid">',
|
|
9586
10385
|
`<div class="stat"><span class="k">Sessions</span><span class="v">${totals.sessions}</span></div>`,
|
|
9587
10386
|
`<div class="stat"><span class="k">Messages</span><span class="v">${totals.messageCount}</span></div>`,
|
|
9588
|
-
`<div class="stat"><span class="k">Real cost</span><span class="v">${usd(totals.realCostUSD)}</span></div>`,
|
|
10387
|
+
`<div class="stat"><span class="k">Real cost</span><span class="v">${measured(usd(totals.realCostUSD), totals.unavailableCostMessages)}</span></div>`,
|
|
9589
10388
|
`<div class="stat"><span class="k">Est. savings</span><span class="v good">${usd(totals.estimatedSavingsUSD)}</span></div>`,
|
|
9590
|
-
`<div class="stat"><span class="k">Tokens in</span><span class="v">${totals.tokensIn}</span></div>`,
|
|
9591
|
-
`<div class="stat"><span class="k">Tokens out</span><span class="v">${totals.tokensOut}</span></div>`,
|
|
9592
|
-
`<div class="stat"><span class="k">Reasoning</span><span class="v">${totals.tokensReasoning}</span></div>`,
|
|
9593
|
-
`<div class="stat"><span class="k">Cache r/w</span><span class="v">${totals.tokensCacheRead}/${totals.tokensCacheWrite}</span></div>`,
|
|
10389
|
+
`<div class="stat"><span class="k">Tokens in</span><span class="v">${measured(totals.tokensIn, totals.unavailableUsageMessages)}</span></div>`,
|
|
10390
|
+
`<div class="stat"><span class="k">Tokens out</span><span class="v">${measured(totals.tokensOut, totals.unavailableUsageMessages)}</span></div>`,
|
|
10391
|
+
`<div class="stat"><span class="k">Reasoning</span><span class="v">${measured(totals.tokensReasoning, totals.unavailableUsageMessages)}</span></div>`,
|
|
10392
|
+
`<div class="stat"><span class="k">Cache r/w</span><span class="v">${measured(`${totals.tokensCacheRead}/${totals.tokensCacheWrite}`, totals.unavailableUsageMessages)}</span></div>`,
|
|
9594
10393
|
`<div class="stat"><span class="k">Toolcalls</span><span class="v">${t.count} <span class="good">${t.ok}✓</span> <span class="frontier">${t.failed}✗</span></span></div>`,
|
|
9595
10394
|
`<div class="stat"><span class="k">Avg tool dur.</span><span class="v">${avgMs(t)}</span></div>`,
|
|
9596
10395
|
"</div>",
|
|
@@ -9613,8 +10412,8 @@ function sessionRow(session2) {
|
|
|
9613
10412
|
`<td>${sessionNameHtml(session2.sessionID, sessionName(session2))}<br>${observedTimeHtml(session2)}<br><code>${escapeHtml(session2.sessionID)}</code></td>`,
|
|
9614
10413
|
`<td>${models}</td>`,
|
|
9615
10414
|
`<td><span class="local">${session2.localCount}</span>/<span class="frontier">${session2.frontierCount}</span></td>`,
|
|
9616
|
-
`<td>${usd(session2.realCostUSD)}</td>`,
|
|
9617
|
-
`<td>${session2.tokensIn}/${session2.tokensOut}</td>`,
|
|
10415
|
+
`<td>${measured(usd(session2.realCostUSD), session2.unavailableCostMessages)}</td>`,
|
|
10416
|
+
`<td>${measured(`${session2.tokensIn}/${session2.tokensOut}`, session2.unavailableUsageMessages)}</td>`,
|
|
9618
10417
|
`<td>${session2.toolcalls.count} (${avgMs(session2.toolcalls)})</td>`,
|
|
9619
10418
|
"</tr>"
|
|
9620
10419
|
].join("");
|
|
@@ -9751,8 +10550,8 @@ function sessionHeaderPanel(tab) {
|
|
|
9751
10550
|
`<div class="stat"><span class="k">Endpoint</span><span class="v">${endpoint}</span></div>`,
|
|
9752
10551
|
dir,
|
|
9753
10552
|
title,
|
|
9754
|
-
`<div class="stat"><span class="k">Real cost</span><span class="v">${usd(s.realCostUSD)}</span></div>`,
|
|
9755
|
-
`<div class="stat"><span class="k">Tokens in/out</span><span class="v">${s.tokensIn}/${s.tokensOut}</span></div>`,
|
|
10553
|
+
`<div class="stat"><span class="k">Real cost</span><span class="v">${measured(usd(s.realCostUSD), s.unavailableCostMessages)}</span></div>`,
|
|
10554
|
+
`<div class="stat"><span class="k">Tokens in/out</span><span class="v">${measured(`${s.tokensIn}/${s.tokensOut}`, s.unavailableUsageMessages)}</span></div>`,
|
|
9756
10555
|
`<div class="stat"><span class="k">Local/Frontier</span><span class="v"><span class="local">${s.localCount}</span>/<span class="frontier">${s.frontierCount}</span></span></div>`,
|
|
9757
10556
|
`<div class="stat"><span class="k">Toolcalls</span><span class="v">${s.toolcalls.count} (${avgMs(s.toolcalls)})</span></div>`,
|
|
9758
10557
|
"</div>",
|
|
@@ -10653,7 +11452,7 @@ function renderConsoleHtml(state, options = {}) {
|
|
|
10653
11452
|
'<meta name="viewport" content="width=device-width,initial-scale=1">',
|
|
10654
11453
|
"<title>openteam console</title>",
|
|
10655
11454
|
lifecycleEnabled ? `<script>${LIFECYCLE_THEME_BOOT}</script>` : "",
|
|
10656
|
-
`<style>${CONSOLE_STYLE}${CONVERSATION_STYLE}${graphOptionProvided ? GRAPH_STYLE : ""}${lifecycleEnabled ? LIFECYCLE_STYLE : ""}</style>`,
|
|
11455
|
+
`<style>${CONSOLE_STYLE}${CONVERSATION_STYLE}${graphOptionProvided ? GRAPH_STYLE : ""}${lifecycleEnabled ? LIFECYCLE_STYLE + AGENT_VIEW_STYLE : ""}</style>`,
|
|
10657
11456
|
"</head>",
|
|
10658
11457
|
"<body>",
|
|
10659
11458
|
'<div class="app">',
|
|
@@ -10683,6 +11482,7 @@ function renderConsoleUpdate(state, options = {}) {
|
|
|
10683
11482
|
routing: routingScreenBody(state),
|
|
10684
11483
|
logs: logsScreenBody(state, options.terminalEnabled === true, options.ptyEnabled === true),
|
|
10685
11484
|
sessionCount: state.sessionsDetail.length,
|
|
11485
|
+
sessionSummaries: state.sessions,
|
|
10686
11486
|
...options.graphView ? {
|
|
10687
11487
|
tree: treeGraphPanel(options.graphView.projection, options.drilldownEnabled === true, false, options.graphView.mode ?? "active")
|
|
10688
11488
|
} : {}
|
|
@@ -12618,6 +13418,7 @@ var lifecycleFailureSchema = z13.object({
|
|
|
12618
13418
|
"prompt-auth",
|
|
12619
13419
|
"prompt-content-filter",
|
|
12620
13420
|
"prompt-context-length",
|
|
13421
|
+
"prompt-output-truncated",
|
|
12621
13422
|
"prompt-validation",
|
|
12622
13423
|
"prompt-connection",
|
|
12623
13424
|
"prompt-server",
|
|
@@ -13662,6 +14463,8 @@ var NodeFailureClassSchema = z17.enum([
|
|
|
13662
14463
|
"prompt-auth",
|
|
13663
14464
|
"prompt-content-filter",
|
|
13664
14465
|
"prompt-context-length",
|
|
14466
|
+
"prompt-output-truncated",
|
|
14467
|
+
"budget-exhausted",
|
|
13665
14468
|
"prompt-validation",
|
|
13666
14469
|
"prompt-connection",
|
|
13667
14470
|
"prompt-server",
|
|
@@ -17776,7 +18579,7 @@ function createMigrateAdapter(root) {
|
|
|
17776
18579
|
}
|
|
17777
18580
|
|
|
17778
18581
|
// src/cli/opencodeVersion.ts
|
|
17779
|
-
var SEMVER_PATTERN = /(\d+\.\d+\.\d+)/;
|
|
18582
|
+
var SEMVER_PATTERN = /(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)/;
|
|
17780
18583
|
function normalizeVersion(raw) {
|
|
17781
18584
|
if (raw === undefined) {
|
|
17782
18585
|
return;
|
|
@@ -18170,7 +18973,15 @@ function buildOrchestratorAgent(model, options = {}) {
|
|
|
18170
18973
|
" `title` is optional and only for readability.",
|
|
18171
18974
|
"- `parentSessionID` (optional): the current session, so that the subsessions",
|
|
18172
18975
|
" link as children.",
|
|
18173
|
-
"- `directory` (optional):
|
|
18976
|
+
"- `directory` (optional): omit it to use the trusted host workspace. A different",
|
|
18977
|
+
" directory is rejected; this argument cannot authorize another workspace.",
|
|
18978
|
+
"",
|
|
18979
|
+
"Related and nested batches share a cumulative task budget, not a fresh allowance",
|
|
18980
|
+
"per call. On `task-budget-exhausted`, stop delegation and summarize preserved",
|
|
18981
|
+
"work and remaining tasks. Never create another batch/session or edit effort",
|
|
18982
|
+
"state to reset that allowance. Only a genuinely new root user turn starts a new task.",
|
|
18983
|
+
"Workers should use `openteam-submit-report` for their assigned report, retaining",
|
|
18984
|
+
"operator permission checks. Do not broaden file or shell permissions to deliver it.",
|
|
18174
18985
|
"",
|
|
18175
18986
|
"The tool returns a per-role summary: selected model, success or",
|
|
18176
18987
|
"failure, the created session, and — for each role — a `report` file path",
|
|
@@ -21728,7 +22539,8 @@ var nativeHostMessages = {
|
|
|
21728
22539
|
setupPolicyQuestion: (paths, providers) => `Remove exact project-local provider.use deny rules for ${providers.join(", ")} from ${paths.join(", ")}? Older setup added these rules, but they may also be operator limits. Confirm only if you intend to enable the guarded native transport.`,
|
|
21729
22540
|
setupPolicyPreserved: "Setup stopped. Provider-denial rules were preserved and no files were written.",
|
|
21730
22541
|
setupPolicyNotice: "Only the explicitly reviewed project rules were removed. Wildcard, scoped, unrelated and global provider denials remain authoritative.",
|
|
21731
|
-
unsupportedVersion: (version) => `openteam
|
|
22542
|
+
unsupportedVersion: (version) => `openteam does not support native opencode ${version}. The supported stable native range is >=2.0.5 <3.0.0.`,
|
|
22543
|
+
certificateVersionMismatch: (certified, live) => `certified for "${certified}", running "${live}" — evidence is outside the supported host compatibility range`,
|
|
21732
22544
|
missingBindings: "The native opencode execution context is unavailable. No child session or privileged operation was started.",
|
|
21733
22545
|
missingVersion: "The opencode host did not provide an authoritative version or server endpoint.",
|
|
21734
22546
|
workspaceMismatch: "The native opencode session does not belong to this workspace.",
|
|
@@ -21746,7 +22558,7 @@ var nativeHostMessages = {
|
|
|
21746
22558
|
// package.json
|
|
21747
22559
|
var package_default = {
|
|
21748
22560
|
name: "@jmanuelcorral/openteam",
|
|
21749
|
-
version: "0.
|
|
22561
|
+
version: "0.28.0",
|
|
21750
22562
|
packageManager: "bun@1.3.14",
|
|
21751
22563
|
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
21752
22564
|
license: "MIT",
|
|
@@ -22041,10 +22853,31 @@ function parseSemver(version) {
|
|
|
22041
22853
|
patch: Number(match[3])
|
|
22042
22854
|
};
|
|
22043
22855
|
}
|
|
22856
|
+
function compareSemver2(a, b) {
|
|
22857
|
+
if (a.major !== b.major) {
|
|
22858
|
+
return a.major < b.major ? -1 : 1;
|
|
22859
|
+
}
|
|
22860
|
+
if (a.minor !== b.minor) {
|
|
22861
|
+
return a.minor < b.minor ? -1 : 1;
|
|
22862
|
+
}
|
|
22863
|
+
if (a.patch !== b.patch) {
|
|
22864
|
+
return a.patch < b.patch ? -1 : 1;
|
|
22865
|
+
}
|
|
22866
|
+
return 0;
|
|
22867
|
+
}
|
|
22868
|
+
function isSupportedNativeOpencodeVersion(version) {
|
|
22869
|
+
if (version === undefined || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.test(version))
|
|
22870
|
+
return false;
|
|
22871
|
+
const live = parseSemver(version);
|
|
22872
|
+
const minimum = parseSemver(NATIVE_OPENCODE_VERSION);
|
|
22873
|
+
return Object.values(live).every(Number.isSafeInteger) && live.major === minimum.major && compareSemver2(live, minimum) >= 0;
|
|
22874
|
+
}
|
|
22044
22875
|
function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
22045
22876
|
if (certifiedVersion === liveVersion) {
|
|
22046
22877
|
return true;
|
|
22047
22878
|
}
|
|
22879
|
+
if (isSupportedNativeOpencodeVersion(certifiedVersion) && isSupportedNativeOpencodeVersion(liveVersion))
|
|
22880
|
+
return compareSemver2(parseSemver(liveVersion), parseSemver(certifiedVersion)) >= 0;
|
|
22048
22881
|
let certified;
|
|
22049
22882
|
let live;
|
|
22050
22883
|
try {
|
|
@@ -22609,7 +23442,7 @@ function orchestratorAgentModel(answers) {
|
|
|
22609
23442
|
}
|
|
22610
23443
|
function buildOpencodeConfig(answers) {
|
|
22611
23444
|
assertSetupResidency(answers);
|
|
22612
|
-
const policies = answers.opencodeVersion
|
|
23445
|
+
const policies = isSupportedNativeOpencodeVersion(answers.opencodeVersion) ? [] : residentV2Policies(answers.runtimes.filter((choice) => choice.enabled && runtimeRequiresModelResidency(localRuntimeKind(choice))).map(choiceProviderID));
|
|
22613
23446
|
const provider = {};
|
|
22614
23447
|
const providerOwner = new Map;
|
|
22615
23448
|
for (const choice of answers.runtimes) {
|
|
@@ -24153,7 +24986,7 @@ async function runSetup(deps) {
|
|
|
24153
24986
|
try {
|
|
24154
24987
|
existingOpenTeamConfig = await readExistingOpenTeamConfig(openTeamPath, deps);
|
|
24155
24988
|
existingOpencodeFiles = await readExistingOpencodeConfigFiles(opencodeConfigPaths, deps);
|
|
24156
|
-
if (opencodeVersion
|
|
24989
|
+
if (isSupportedNativeOpencodeVersion(opencodeVersion)) {
|
|
24157
24990
|
existingOpencodeFiles = existingOpencodeFiles.map((file) => {
|
|
24158
24991
|
nativeDocuments.set(file.path, file.raw);
|
|
24159
24992
|
return { ...file, raw: nativeSetupView(file.raw) };
|
|
@@ -24198,7 +25031,7 @@ async function runSetup(deps) {
|
|
|
24198
25031
|
throw new Error(finalOpenTeamConfig.local.runtimes.some((runtime) => runtime.defaultModel.providerID === providerID && localRuntimeKind(runtime) === "lemonade") ? executionSetupMessages.lemonadeRetainedProviderUnprotected(providerID) : executionSetupMessages.retainedResidencyProviderUnprotected(providerID));
|
|
24199
25032
|
}
|
|
24200
25033
|
const nativePolicyMigrations = new Set;
|
|
24201
|
-
if (opencodeVersion
|
|
25034
|
+
if (isSupportedNativeOpencodeVersion(opencodeVersion)) {
|
|
24202
25035
|
const providers = new Set(effectiveOpenTeamConfig.local.runtimes.filter((runtime) => runtime.enabled && runtimeRequiresModelResidency(localRuntimeKind(runtime))).map((runtime) => runtime.defaultModel.providerID));
|
|
24203
25036
|
const planned = existingOpencodeFiles.map((file) => {
|
|
24204
25037
|
const raw = withoutReviewedNativeDenials(file.raw, providers);
|
|
@@ -24217,7 +25050,7 @@ async function runSetup(deps) {
|
|
|
24217
25050
|
prompt.note(nativeHostMessages.setupPolicyNotice);
|
|
24218
25051
|
}
|
|
24219
25052
|
}
|
|
24220
|
-
const v2Denials = opencodeVersion
|
|
25053
|
+
const v2Denials = isSupportedNativeOpencodeVersion(opencodeVersion) ? [] : residentV2Policies([
|
|
24221
25054
|
...opencodeConfig.experimental?.policies.map((policy) => policy.resource) ?? [],
|
|
24222
25055
|
...effectiveOpenTeamConfig.local.runtimes.filter((runtime) => runtimeRequiresModelResidency(localRuntimeKind(runtime))).map((runtime) => runtime.defaultModel.providerID)
|
|
24223
25056
|
]);
|
|
@@ -24360,7 +25193,7 @@ async function runSetup(deps) {
|
|
|
24360
25193
|
await verifyResidencyBeforeWrite(deps, answers, effectiveOpenTeamConfig, effectivePlannedOpencode);
|
|
24361
25194
|
const serializedOpencodePlan = [...opencodeWritePlan].map(([path2, contents]) => [
|
|
24362
25195
|
path2,
|
|
24363
|
-
serializeOpencodeConfig(opencodeVersion
|
|
25196
|
+
serializeOpencodeConfig(isSupportedNativeOpencodeVersion(opencodeVersion) ? restoreNativeSetupConfig(contents, nativeDocuments.get(path2)) : contents)
|
|
24364
25197
|
]);
|
|
24365
25198
|
await deps.writeFile(openTeamPath, serializeOpenTeamConfig(finalOpenTeamConfig));
|
|
24366
25199
|
for (const [path2, contents] of serializedOpencodePlan) {
|
|
@@ -27850,7 +28683,7 @@ function planStartupHygieneMigration(exists) {
|
|
|
27850
28683
|
|
|
27851
28684
|
// src/index.ts
|
|
27852
28685
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
27853
|
-
import { basename as basename4, dirname as
|
|
28686
|
+
import { basename as basename4, dirname as dirname11, resolve as resolve18 } from "node:path";
|
|
27854
28687
|
|
|
27855
28688
|
// src/graph/certificate.ts
|
|
27856
28689
|
import { z as z29 } from "zod";
|
|
@@ -28017,7 +28850,7 @@ function parseShadowCertificate(value, opencodeVersion) {
|
|
|
28017
28850
|
throw new ShadowCertificateError("digest-mismatch", "certificate digest does not cover the presented evidence");
|
|
28018
28851
|
}
|
|
28019
28852
|
if (!isCertificateVersionCompatible(certificate.opencodeVersion, opencodeVersion)) {
|
|
28020
|
-
throw new ShadowCertificateError("opencode-mismatch",
|
|
28853
|
+
throw new ShadowCertificateError("opencode-mismatch", nativeHostMessages.certificateVersionMismatch(certificate.opencodeVersion, opencodeVersion));
|
|
28021
28854
|
}
|
|
28022
28855
|
return certificate;
|
|
28023
28856
|
}
|
|
@@ -28202,7 +29035,7 @@ function parseReleaseCertificate(value, opencodeVersion, expectedShadowDigest) {
|
|
|
28202
29035
|
throw new ReleaseCertificateError("digest-mismatch", "certificate digest does not cover the presented evidence");
|
|
28203
29036
|
}
|
|
28204
29037
|
if (!isCertificateVersionCompatible(certificate.opencodeVersion, opencodeVersion)) {
|
|
28205
|
-
throw new ReleaseCertificateError("opencode-mismatch",
|
|
29038
|
+
throw new ReleaseCertificateError("opencode-mismatch", nativeHostMessages.certificateVersionMismatch(certificate.opencodeVersion, opencodeVersion));
|
|
28206
29039
|
}
|
|
28207
29040
|
return certificate;
|
|
28208
29041
|
}
|
|
@@ -29020,17 +29853,31 @@ function createRuntimeConcurrencyLimiter(options) {
|
|
|
29020
29853
|
}
|
|
29021
29854
|
return {
|
|
29022
29855
|
tryAcquire,
|
|
29023
|
-
acquire(runtimeId, priority = "worker") {
|
|
29856
|
+
async acquire(runtimeId, priority = "worker", signal) {
|
|
29857
|
+
signal?.throwIfAborted();
|
|
29024
29858
|
const immediate = tryAcquire(runtimeId, priority);
|
|
29025
29859
|
if (immediate !== undefined) {
|
|
29026
29860
|
return Promise.resolve({ release: immediate, waitedMs: 0 });
|
|
29027
29861
|
}
|
|
29028
29862
|
const state = stateFor(runtimeId);
|
|
29029
29863
|
const queuedAt = options.now();
|
|
29030
|
-
return new Promise((resolve13) => {
|
|
29031
|
-
|
|
29864
|
+
return new Promise((resolve13, reject) => {
|
|
29865
|
+
const waiter = (release) => {
|
|
29866
|
+
signal?.removeEventListener("abort", cancel2);
|
|
29032
29867
|
resolve13({ release, waitedMs: options.now() - queuedAt });
|
|
29033
|
-
}
|
|
29868
|
+
};
|
|
29869
|
+
function cancel2() {
|
|
29870
|
+
const index = state.queues[priority].indexOf(waiter);
|
|
29871
|
+
if (index < 0)
|
|
29872
|
+
return;
|
|
29873
|
+
state.queues[priority].splice(index, 1);
|
|
29874
|
+
signal?.removeEventListener("abort", cancel2);
|
|
29875
|
+
reject(signal?.reason);
|
|
29876
|
+
}
|
|
29877
|
+
state.queues[priority].push(waiter);
|
|
29878
|
+
signal?.addEventListener("abort", cancel2, { once: true });
|
|
29879
|
+
if (signal?.aborted)
|
|
29880
|
+
cancel2();
|
|
29034
29881
|
});
|
|
29035
29882
|
},
|
|
29036
29883
|
activeCount(runtimeId) {
|
|
@@ -29071,6 +29918,192 @@ var readReportArtifact = async (reportPath) => {
|
|
|
29071
29918
|
}
|
|
29072
29919
|
};
|
|
29073
29920
|
|
|
29921
|
+
// src/orchestrator/reportDelivery.ts
|
|
29922
|
+
import { z as z30 } from "zod";
|
|
29923
|
+
var Submission = z30.object({
|
|
29924
|
+
status: z30.enum(["done", "continue"]),
|
|
29925
|
+
findings: z30.string().min(1).max(32768)
|
|
29926
|
+
}).strict();
|
|
29927
|
+
function createReportDelivery(deps) {
|
|
29928
|
+
const active = new Map;
|
|
29929
|
+
return {
|
|
29930
|
+
open(sessionID, batchID, roleID) {
|
|
29931
|
+
if (active.has(sessionID))
|
|
29932
|
+
throw new Error(reportDeliveryMessages.assignmentConflict);
|
|
29933
|
+
const lease = {
|
|
29934
|
+
path: roleReportPath(batchID, roleID),
|
|
29935
|
+
open: true,
|
|
29936
|
+
submitted: false,
|
|
29937
|
+
pending: Promise.resolve()
|
|
29938
|
+
};
|
|
29939
|
+
active.set(sessionID, lease);
|
|
29940
|
+
return {
|
|
29941
|
+
async close() {
|
|
29942
|
+
lease.open = false;
|
|
29943
|
+
await lease.pending;
|
|
29944
|
+
if (active.get(sessionID) === lease)
|
|
29945
|
+
active.delete(sessionID);
|
|
29946
|
+
return lease.submitted;
|
|
29947
|
+
}
|
|
29948
|
+
};
|
|
29949
|
+
},
|
|
29950
|
+
path(sessionID) {
|
|
29951
|
+
const lease = active.get(sessionID);
|
|
29952
|
+
if (lease?.open !== true)
|
|
29953
|
+
throw new Error(reportDeliveryMessages.noAssignment);
|
|
29954
|
+
return lease.path;
|
|
29955
|
+
},
|
|
29956
|
+
async submit(sessionID, input) {
|
|
29957
|
+
const payload = Submission.safeParse(input);
|
|
29958
|
+
if (!payload.success || !reportHasSubstance(payload.data.findings))
|
|
29959
|
+
throw new Error(reportDeliveryMessages.invalidReport);
|
|
29960
|
+
const lease = active.get(sessionID);
|
|
29961
|
+
if (lease?.open !== true)
|
|
29962
|
+
throw new Error(reportDeliveryMessages.noAssignment);
|
|
29963
|
+
const content = `${payload.data.findings.trim()}
|
|
29964
|
+
|
|
29965
|
+
openteam-status: ${payload.data.status}
|
|
29966
|
+
`;
|
|
29967
|
+
if (parseReportStatus(content) !== payload.data.status)
|
|
29968
|
+
throw new Error(reportDeliveryMessages.invalidReport);
|
|
29969
|
+
const write = lease.pending.then(async () => {
|
|
29970
|
+
if (!lease.open)
|
|
29971
|
+
throw new Error(reportDeliveryMessages.noAssignment);
|
|
29972
|
+
await deps.write(lease.path, content);
|
|
29973
|
+
lease.submitted = true;
|
|
29974
|
+
});
|
|
29975
|
+
lease.pending = write.then(() => {}, () => {});
|
|
29976
|
+
await write;
|
|
29977
|
+
return lease.path;
|
|
29978
|
+
}
|
|
29979
|
+
};
|
|
29980
|
+
}
|
|
29981
|
+
|
|
29982
|
+
// src/orchestrator/taskEffort.ts
|
|
29983
|
+
import { z as z31 } from "zod";
|
|
29984
|
+
var Binding = z31.object({
|
|
29985
|
+
taskID: z31.string().regex(/^[a-f0-9]{64}$/),
|
|
29986
|
+
depth: z31.number().int().min(0).max(128),
|
|
29987
|
+
worker: z31.boolean()
|
|
29988
|
+
}).strict();
|
|
29989
|
+
var Record = z31.object({
|
|
29990
|
+
v: z31.literal(1),
|
|
29991
|
+
startedAt: z31.number().finite(),
|
|
29992
|
+
batches: z31.number().int().min(0),
|
|
29993
|
+
attempts: z31.number().int().min(0),
|
|
29994
|
+
maxBatches: z31.number().int().positive(),
|
|
29995
|
+
maxAttempts: z31.number().int().positive(),
|
|
29996
|
+
maxDurationMs: z31.number().int().positive(),
|
|
29997
|
+
maxDepth: z31.number().int().min(0)
|
|
29998
|
+
}).strict();
|
|
29999
|
+
function decode(schema, raw) {
|
|
30000
|
+
let value;
|
|
30001
|
+
try {
|
|
30002
|
+
value = JSON.parse(raw ?? "null");
|
|
30003
|
+
} catch {
|
|
30004
|
+
throw new Error(taskEffortMessages.ledgerInvalid);
|
|
30005
|
+
}
|
|
30006
|
+
const parsed = schema.safeParse(value);
|
|
30007
|
+
if (!parsed.success)
|
|
30008
|
+
throw new Error(taskEffortMessages.ledgerInvalid);
|
|
30009
|
+
return parsed.data;
|
|
30010
|
+
}
|
|
30011
|
+
function createTaskEffort(deps) {
|
|
30012
|
+
const limits = {
|
|
30013
|
+
maxBatches: deps.limits?.maxBatches ?? 8,
|
|
30014
|
+
maxAttempts: deps.limits?.maxAttempts ?? 32,
|
|
30015
|
+
maxDurationMs: deps.limits?.maxDurationMs ?? 7200000,
|
|
30016
|
+
maxDepth: deps.limits?.maxDepth ?? 3
|
|
30017
|
+
};
|
|
30018
|
+
const bindingPath = (sessionID) => `sessions/${sha256Hex(sessionID)}.json`;
|
|
30019
|
+
const taskPath = (taskID) => `tasks/${taskID}.json`;
|
|
30020
|
+
function initialize(sessionID, messageID) {
|
|
30021
|
+
const taskID = sha256Hex(`${sessionID}\x00${messageID}`);
|
|
30022
|
+
deps.store.update(taskPath(taskID), (previous) => {
|
|
30023
|
+
if (previous !== undefined) {
|
|
30024
|
+
decode(Record, previous);
|
|
30025
|
+
return previous;
|
|
30026
|
+
}
|
|
30027
|
+
return JSON.stringify({
|
|
30028
|
+
v: 1,
|
|
30029
|
+
startedAt: deps.now(),
|
|
30030
|
+
batches: 0,
|
|
30031
|
+
attempts: 0,
|
|
30032
|
+
...limits
|
|
30033
|
+
});
|
|
30034
|
+
});
|
|
30035
|
+
const binding = { taskID, depth: 0, worker: false };
|
|
30036
|
+
deps.store.write(bindingPath(sessionID), JSON.stringify(binding));
|
|
30037
|
+
return binding;
|
|
30038
|
+
}
|
|
30039
|
+
function bindChild(parent, sessionID) {
|
|
30040
|
+
if (parent.depth >= 128)
|
|
30041
|
+
throw new Error(taskEffortMessages.ledgerInvalid);
|
|
30042
|
+
deps.store.write(bindingPath(sessionID), JSON.stringify({
|
|
30043
|
+
taskID: parent.taskID,
|
|
30044
|
+
depth: parent.depth + 1,
|
|
30045
|
+
worker: true
|
|
30046
|
+
}));
|
|
30047
|
+
}
|
|
30048
|
+
async function forSession(sessionID, ancestors = new Set) {
|
|
30049
|
+
if (ancestors.has(sessionID) || ancestors.size >= 128)
|
|
30050
|
+
throw new Error(taskEffortMessages.ledgerInvalid);
|
|
30051
|
+
const stored = deps.store.read(bindingPath(sessionID));
|
|
30052
|
+
if (stored !== undefined)
|
|
30053
|
+
return decode(Binding, stored);
|
|
30054
|
+
ancestors.add(sessionID);
|
|
30055
|
+
const parentID = await deps.parentSession?.(sessionID);
|
|
30056
|
+
if (parentID !== undefined) {
|
|
30057
|
+
const parent = await forSession(parentID, ancestors);
|
|
30058
|
+
bindChild(parent, sessionID);
|
|
30059
|
+
return { taskID: parent.taskID, depth: parent.depth + 1 };
|
|
30060
|
+
}
|
|
30061
|
+
return initialize(sessionID, "restored-session");
|
|
30062
|
+
}
|
|
30063
|
+
function consume(ref, kind) {
|
|
30064
|
+
let result = { ok: false, reason: "duration" };
|
|
30065
|
+
deps.store.update(taskPath(ref.taskID), (raw) => {
|
|
30066
|
+
const record3 = decode(Record, raw);
|
|
30067
|
+
const remainingMs = Math.min(record3.maxDurationMs, limits.maxDurationMs) - Math.max(0, deps.now() - record3.startedAt);
|
|
30068
|
+
const reason = ref.depth > Math.min(record3.maxDepth, limits.maxDepth) ? "depth" : remainingMs <= 0 ? "duration" : kind === "batches" && record3.batches >= Math.min(record3.maxBatches, limits.maxBatches) ? "batches" : kind === "attempts" && record3.attempts >= Math.min(record3.maxAttempts, limits.maxAttempts) ? "attempts" : undefined;
|
|
30069
|
+
if (reason !== undefined)
|
|
30070
|
+
result = { ok: false, reason };
|
|
30071
|
+
else {
|
|
30072
|
+
if (kind !== "check")
|
|
30073
|
+
record3[kind] += 1;
|
|
30074
|
+
result = {
|
|
30075
|
+
ok: true,
|
|
30076
|
+
remainingMs,
|
|
30077
|
+
batches: record3.batches,
|
|
30078
|
+
attempts: record3.attempts,
|
|
30079
|
+
remainingBatches: Math.max(0, Math.min(record3.maxBatches, limits.maxBatches) - record3.batches),
|
|
30080
|
+
remainingAttempts: Math.max(0, Math.min(record3.maxAttempts, limits.maxAttempts) - record3.attempts)
|
|
30081
|
+
};
|
|
30082
|
+
}
|
|
30083
|
+
return JSON.stringify(record3);
|
|
30084
|
+
});
|
|
30085
|
+
return result;
|
|
30086
|
+
}
|
|
30087
|
+
return {
|
|
30088
|
+
async userTurn(sessionID, messageID) {
|
|
30089
|
+
const stored = deps.store.read(bindingPath(sessionID));
|
|
30090
|
+
if (stored !== undefined && decode(Binding, stored).worker)
|
|
30091
|
+
return;
|
|
30092
|
+
const parentID = await deps.parentSession?.(sessionID);
|
|
30093
|
+
if (parentID !== undefined) {
|
|
30094
|
+
bindChild(await forSession(parentID), sessionID);
|
|
30095
|
+
return;
|
|
30096
|
+
}
|
|
30097
|
+
initialize(sessionID, messageID);
|
|
30098
|
+
},
|
|
30099
|
+
forSession,
|
|
30100
|
+
bindChild,
|
|
30101
|
+
batch: (ref) => consume(ref, "batches"),
|
|
30102
|
+
attempt: (ref) => consume(ref, "attempts"),
|
|
30103
|
+
check: (ref) => consume(ref, "check")
|
|
30104
|
+
};
|
|
30105
|
+
}
|
|
30106
|
+
|
|
29074
30107
|
// src/plugin/availability.ts
|
|
29075
30108
|
function modelKey4(model) {
|
|
29076
30109
|
return `${model.providerID}/${model.modelID}`;
|
|
@@ -29316,7 +30349,7 @@ function createAvailabilityCache(options) {
|
|
|
29316
30349
|
|
|
29317
30350
|
// src/plugin/capture.ts
|
|
29318
30351
|
function nonNeg(value) {
|
|
29319
|
-
return typeof value === "number" && value >= 0 ? Math.trunc(value) : 0;
|
|
30352
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.trunc(value) : 0;
|
|
29320
30353
|
}
|
|
29321
30354
|
function messageEventFrom(info, now) {
|
|
29322
30355
|
if (info.role !== "assistant") {
|
|
@@ -29330,6 +30363,17 @@ function messageEventFrom(info, now) {
|
|
|
29330
30363
|
}
|
|
29331
30364
|
const created = info.time.created ?? info.time.completed;
|
|
29332
30365
|
const durationMs = Math.max(0, Math.trunc(info.time.completed - created));
|
|
30366
|
+
const counters = [info.tokens?.input, info.tokens?.output];
|
|
30367
|
+
const hasUsage = counters.every((value) => typeof value === "number" && Number.isFinite(value) && value >= 0);
|
|
30368
|
+
const zeroUsage = [
|
|
30369
|
+
info.tokens?.input,
|
|
30370
|
+
info.tokens?.output,
|
|
30371
|
+
info.tokens?.reasoning,
|
|
30372
|
+
info.tokens?.cache?.read,
|
|
30373
|
+
info.tokens?.cache?.write
|
|
30374
|
+
].every((value) => value === undefined || value === 0);
|
|
30375
|
+
const usageStatus = !hasUsage ? "missing" : zeroUsage && info.hasGeneratedOutput !== false ? "zero-unverified" : "reported";
|
|
30376
|
+
const hasCost = typeof info.cost === "number" && Number.isFinite(info.cost) && info.cost >= 0;
|
|
29333
30377
|
const event = {
|
|
29334
30378
|
v: EVENT_SCHEMA_VERSION,
|
|
29335
30379
|
type: "message",
|
|
@@ -29337,7 +30381,11 @@ function messageEventFrom(info, now) {
|
|
|
29337
30381
|
sessionID: info.sessionID,
|
|
29338
30382
|
providerID: info.providerID,
|
|
29339
30383
|
modelID: info.modelID,
|
|
29340
|
-
costUSD:
|
|
30384
|
+
costUSD: hasCost ? info.cost ?? 0 : 0,
|
|
30385
|
+
usageStatus,
|
|
30386
|
+
costStatus: hasCost && (info.cost !== 0 || usageStatus === "reported") ? "reported" : "unavailable",
|
|
30387
|
+
...info.finish === undefined ? {} : { finish: finishReason(info.finish) },
|
|
30388
|
+
...info.truncatedToolCall === true ? { truncatedToolCall: true } : {},
|
|
29341
30389
|
tokensIn: nonNeg(info.tokens?.input),
|
|
29342
30390
|
tokensOut: nonNeg(info.tokens?.output),
|
|
29343
30391
|
tokensReasoning: nonNeg(info.tokens?.reasoning),
|
|
@@ -29348,6 +30396,18 @@ function messageEventFrom(info, now) {
|
|
|
29348
30396
|
if (info.mode !== undefined) {
|
|
29349
30397
|
event.mode = info.mode;
|
|
29350
30398
|
}
|
|
30399
|
+
function finishReason(value) {
|
|
30400
|
+
switch (value) {
|
|
30401
|
+
case "stop":
|
|
30402
|
+
case "length":
|
|
30403
|
+
case "tool-calls":
|
|
30404
|
+
case "content-filter":
|
|
30405
|
+
case "error":
|
|
30406
|
+
return value;
|
|
30407
|
+
default:
|
|
30408
|
+
return "unknown";
|
|
30409
|
+
}
|
|
30410
|
+
}
|
|
29351
30411
|
if (info.id !== undefined) {
|
|
29352
30412
|
event.messageID = info.id;
|
|
29353
30413
|
}
|
|
@@ -30077,36 +31137,36 @@ function formatResponse(response) {
|
|
|
30077
31137
|
}
|
|
30078
31138
|
|
|
30079
31139
|
// src/plugin/reportRunSchema.ts
|
|
30080
|
-
import { z as
|
|
31140
|
+
import { z as z33 } from "zod";
|
|
30081
31141
|
|
|
30082
31142
|
// src/plugin/graphShadowIngress.ts
|
|
30083
|
-
import { z as
|
|
31143
|
+
import { z as z32 } from "zod";
|
|
30084
31144
|
var LEGACY_EXECUTION_TRACE_VERSION = 1;
|
|
30085
|
-
var LegacyExecutionStatusSchema =
|
|
31145
|
+
var LegacyExecutionStatusSchema = z32.enum([
|
|
30086
31146
|
"completed",
|
|
30087
31147
|
"failed",
|
|
30088
31148
|
"cancelled"
|
|
30089
31149
|
]);
|
|
30090
|
-
var LegacyReviewOutcomeSchema =
|
|
31150
|
+
var LegacyReviewOutcomeSchema = z32.enum([
|
|
30091
31151
|
"approved",
|
|
30092
31152
|
"rejected",
|
|
30093
31153
|
"inconclusive"
|
|
30094
31154
|
]);
|
|
30095
|
-
var LegacyTraceNodeV1Schema =
|
|
31155
|
+
var LegacyTraceNodeV1Schema = z32.object({
|
|
30096
31156
|
id: NodeIDSchema,
|
|
30097
31157
|
role: NodeRoleSchema,
|
|
30098
|
-
model:
|
|
30099
|
-
sessionRef:
|
|
31158
|
+
model: z32.string().min(1),
|
|
31159
|
+
sessionRef: z32.string().min(1).optional(),
|
|
30100
31160
|
errorClass: ErrorClassSchema.optional()
|
|
30101
31161
|
}).strict();
|
|
30102
|
-
var LegacyExecutionTraceV1Schema =
|
|
30103
|
-
version:
|
|
31162
|
+
var LegacyExecutionTraceV1Schema = z32.object({
|
|
31163
|
+
version: z32.literal(LEGACY_EXECUTION_TRACE_VERSION),
|
|
30104
31164
|
runID: NodeIDSchema,
|
|
30105
31165
|
status: LegacyExecutionStatusSchema,
|
|
30106
31166
|
outcome: LegacyReviewOutcomeSchema,
|
|
30107
|
-
fixes:
|
|
30108
|
-
nodes:
|
|
30109
|
-
parentSessionRef:
|
|
31167
|
+
fixes: z32.number().int().nonnegative(),
|
|
31168
|
+
nodes: z32.array(LegacyTraceNodeV1Schema).min(1),
|
|
31169
|
+
parentSessionRef: z32.string().min(1).optional()
|
|
30110
31170
|
}).strict();
|
|
30111
31171
|
function gateReason2(gate) {
|
|
30112
31172
|
if (gate === undefined || gate.mode === "off") {
|
|
@@ -30177,20 +31237,20 @@ function parseLegacyExecutionTrace(input) {
|
|
|
30177
31237
|
}
|
|
30178
31238
|
|
|
30179
31239
|
// src/plugin/reportRunSchema.ts
|
|
30180
|
-
var ReportRunNodeSchema =
|
|
31240
|
+
var ReportRunNodeSchema = z33.object({
|
|
30181
31241
|
id: NodeIDSchema,
|
|
30182
31242
|
role: NodeRoleSchema,
|
|
30183
|
-
model:
|
|
30184
|
-
ok:
|
|
30185
|
-
sessionRef:
|
|
31243
|
+
model: z33.string().min(1),
|
|
31244
|
+
ok: z33.boolean(),
|
|
31245
|
+
sessionRef: z33.string().min(1).optional(),
|
|
30186
31246
|
errorClass: ErrorClassSchema.optional()
|
|
30187
31247
|
}).strict();
|
|
30188
|
-
var ReportRunPayloadSchema =
|
|
31248
|
+
var ReportRunPayloadSchema = z33.object({
|
|
30189
31249
|
runID: NodeIDSchema,
|
|
30190
31250
|
status: LegacyExecutionStatusSchema,
|
|
30191
|
-
fixes:
|
|
30192
|
-
nodes:
|
|
30193
|
-
parentSessionRef:
|
|
31251
|
+
fixes: z33.number().int().nonnegative(),
|
|
31252
|
+
nodes: z33.array(ReportRunNodeSchema).min(1),
|
|
31253
|
+
parentSessionRef: z33.string().min(1).optional()
|
|
30194
31254
|
}).strict();
|
|
30195
31255
|
|
|
30196
31256
|
// src/orchestrator/graphShadow.ts
|
|
@@ -30692,7 +31752,7 @@ async function handleReportRun(args, observe, tracker) {
|
|
|
30692
31752
|
}
|
|
30693
31753
|
|
|
30694
31754
|
// src/plugin/modelResidency.ts
|
|
30695
|
-
import { z as
|
|
31755
|
+
import { z as z34 } from "zod";
|
|
30696
31756
|
|
|
30697
31757
|
// src/local/lemonadeRequestGuard.ts
|
|
30698
31758
|
var inferencePaths = new Set([
|
|
@@ -31063,7 +32123,7 @@ function createModelResidencyGuard(config, options) {
|
|
|
31063
32123
|
throw failure2("identity", model.providerID);
|
|
31064
32124
|
fetch2 = installed.fetch;
|
|
31065
32125
|
}
|
|
31066
|
-
const configuredHeaders =
|
|
32126
|
+
const configuredHeaders = z34.record(z34.string(), z34.string()).safeParse(provider?.options?.headers ?? {});
|
|
31067
32127
|
if (!configuredHeaders.success)
|
|
31068
32128
|
throw failure2("configuration", model.providerID);
|
|
31069
32129
|
const headers = new Headers(configuredHeaders.data);
|
|
@@ -31291,62 +32351,62 @@ ${lines.join(`
|
|
|
31291
32351
|
}
|
|
31292
32352
|
|
|
31293
32353
|
// src/memory/types.ts
|
|
31294
|
-
import { z as
|
|
32354
|
+
import { z as z35 } from "zod";
|
|
31295
32355
|
var SHARED_OWNER_KEY = "*";
|
|
31296
|
-
var OwnerKeySchema =
|
|
31297
|
-
var MemoryKindSchema =
|
|
31298
|
-
var MemoryBaseSchema =
|
|
31299
|
-
id:
|
|
32356
|
+
var OwnerKeySchema = z35.string().min(1);
|
|
32357
|
+
var MemoryKindSchema = z35.enum(["fact", "preference", "entity"]);
|
|
32358
|
+
var MemoryBaseSchema = z35.object({
|
|
32359
|
+
id: z35.string().min(1),
|
|
31300
32360
|
ownerKey: OwnerKeySchema,
|
|
31301
|
-
confidence:
|
|
31302
|
-
validFrom:
|
|
31303
|
-
validUntil:
|
|
31304
|
-
createdAt:
|
|
31305
|
-
invalidatedAt:
|
|
31306
|
-
sourceHash:
|
|
31307
|
-
supersededBy:
|
|
32361
|
+
confidence: z35.number().min(0).max(1),
|
|
32362
|
+
validFrom: z35.number().finite(),
|
|
32363
|
+
validUntil: z35.number().finite().nullable().default(null),
|
|
32364
|
+
createdAt: z35.number().finite(),
|
|
32365
|
+
invalidatedAt: z35.number().finite().nullable().default(null),
|
|
32366
|
+
sourceHash: z35.string().min(1),
|
|
32367
|
+
supersededBy: z35.string().min(1).nullable().default(null)
|
|
31308
32368
|
}).strict();
|
|
31309
32369
|
var FactSchema = MemoryBaseSchema.extend({
|
|
31310
|
-
kind:
|
|
31311
|
-
subject:
|
|
31312
|
-
predicate:
|
|
31313
|
-
object:
|
|
31314
|
-
category:
|
|
32370
|
+
kind: z35.literal("fact"),
|
|
32371
|
+
subject: z35.string().min(1),
|
|
32372
|
+
predicate: z35.string().min(1),
|
|
32373
|
+
object: z35.string().min(1),
|
|
32374
|
+
category: z35.string().min(1).nullable().default(null)
|
|
31315
32375
|
});
|
|
31316
32376
|
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
31317
|
-
kind:
|
|
31318
|
-
category:
|
|
31319
|
-
preference:
|
|
31320
|
-
context:
|
|
31321
|
-
lastAccessedAt:
|
|
31322
|
-
accessCount:
|
|
32377
|
+
kind: z35.literal("preference"),
|
|
32378
|
+
category: z35.string().min(1),
|
|
32379
|
+
preference: z35.string().min(1),
|
|
32380
|
+
context: z35.string().min(1).nullable().default(null),
|
|
32381
|
+
lastAccessedAt: z35.number().finite().nullable().default(null),
|
|
32382
|
+
accessCount: z35.number().int().min(0).default(0)
|
|
31323
32383
|
});
|
|
31324
32384
|
var EntitySchema = MemoryBaseSchema.extend({
|
|
31325
|
-
kind:
|
|
31326
|
-
canonicalName:
|
|
31327
|
-
type:
|
|
31328
|
-
aliases:
|
|
32385
|
+
kind: z35.literal("entity"),
|
|
32386
|
+
canonicalName: z35.string().min(1),
|
|
32387
|
+
type: z35.string().min(1),
|
|
32388
|
+
aliases: z35.array(z35.string().min(1)).default([])
|
|
31329
32389
|
});
|
|
31330
32390
|
var RelationSchema = MemoryBaseSchema.extend({
|
|
31331
|
-
kind:
|
|
31332
|
-
from:
|
|
31333
|
-
to:
|
|
31334
|
-
predicate:
|
|
31335
|
-
annotation:
|
|
32391
|
+
kind: z35.literal("relation"),
|
|
32392
|
+
from: z35.string().min(1),
|
|
32393
|
+
to: z35.string().min(1),
|
|
32394
|
+
predicate: z35.string().min(1),
|
|
32395
|
+
annotation: z35.string().min(1).nullable().default(null)
|
|
31336
32396
|
});
|
|
31337
|
-
var MemoryRecordSchema =
|
|
32397
|
+
var MemoryRecordSchema = z35.discriminatedUnion("kind", [
|
|
31338
32398
|
FactSchema,
|
|
31339
32399
|
PreferenceSchema,
|
|
31340
32400
|
EntitySchema,
|
|
31341
32401
|
RelationSchema
|
|
31342
32402
|
]);
|
|
31343
|
-
var RecallQuerySchema =
|
|
32403
|
+
var RecallQuerySchema = z35.object({
|
|
31344
32404
|
ownerKey: OwnerKeySchema,
|
|
31345
|
-
kinds:
|
|
31346
|
-
asOf:
|
|
31347
|
-
limit:
|
|
31348
|
-
minSimilarity:
|
|
31349
|
-
includeShared:
|
|
32405
|
+
kinds: z35.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
|
|
32406
|
+
asOf: z35.number().finite().nullable().default(null),
|
|
32407
|
+
limit: z35.number().int().positive().default(8),
|
|
32408
|
+
minSimilarity: z35.number().min(0).max(1).default(0.2),
|
|
32409
|
+
includeShared: z35.boolean().default(true)
|
|
31350
32410
|
}).strict();
|
|
31351
32411
|
|
|
31352
32412
|
// src/memory/rank.ts
|
|
@@ -31917,42 +32977,42 @@ function buildMemoryInjector(deps, policy) {
|
|
|
31917
32977
|
|
|
31918
32978
|
// src/plugin/memoryTool.ts
|
|
31919
32979
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
31920
|
-
import { z as
|
|
32980
|
+
import { z as z37 } from "zod";
|
|
31921
32981
|
|
|
31922
32982
|
// src/memory/extract.ts
|
|
31923
|
-
import { z as
|
|
32983
|
+
import { z as z36 } from "zod";
|
|
31924
32984
|
var REDACTED = "[redacted]";
|
|
31925
|
-
var RawFactSchema =
|
|
31926
|
-
subject:
|
|
31927
|
-
predicate:
|
|
31928
|
-
object:
|
|
31929
|
-
category:
|
|
31930
|
-
confidence:
|
|
32985
|
+
var RawFactSchema = z36.object({
|
|
32986
|
+
subject: z36.string().min(1),
|
|
32987
|
+
predicate: z36.string().min(1),
|
|
32988
|
+
object: z36.string().min(1),
|
|
32989
|
+
category: z36.string().min(1).nullable().optional(),
|
|
32990
|
+
confidence: z36.number().min(0).max(1).optional()
|
|
31931
32991
|
});
|
|
31932
|
-
var RawPreferenceSchema =
|
|
31933
|
-
category:
|
|
31934
|
-
preference:
|
|
31935
|
-
context:
|
|
31936
|
-
confidence:
|
|
32992
|
+
var RawPreferenceSchema = z36.object({
|
|
32993
|
+
category: z36.string().min(1),
|
|
32994
|
+
preference: z36.string().min(1),
|
|
32995
|
+
context: z36.string().min(1).nullable().optional(),
|
|
32996
|
+
confidence: z36.number().min(0).max(1).optional()
|
|
31937
32997
|
});
|
|
31938
|
-
var RawEntitySchema =
|
|
31939
|
-
canonicalName:
|
|
31940
|
-
type:
|
|
31941
|
-
aliases:
|
|
31942
|
-
confidence:
|
|
32998
|
+
var RawEntitySchema = z36.object({
|
|
32999
|
+
canonicalName: z36.string().min(1),
|
|
33000
|
+
type: z36.string().min(1),
|
|
33001
|
+
aliases: z36.array(z36.string().min(1)).optional(),
|
|
33002
|
+
confidence: z36.number().min(0).max(1).optional()
|
|
31943
33003
|
});
|
|
31944
|
-
var RawRelationSchema =
|
|
31945
|
-
from:
|
|
31946
|
-
to:
|
|
31947
|
-
predicate:
|
|
31948
|
-
annotation:
|
|
31949
|
-
confidence:
|
|
33004
|
+
var RawRelationSchema = z36.object({
|
|
33005
|
+
from: z36.string().min(1),
|
|
33006
|
+
to: z36.string().min(1),
|
|
33007
|
+
predicate: z36.string().min(1),
|
|
33008
|
+
annotation: z36.string().min(1).nullable().optional(),
|
|
33009
|
+
confidence: z36.number().min(0).max(1).optional()
|
|
31950
33010
|
}).strict();
|
|
31951
|
-
var RawExtractionSchema =
|
|
31952
|
-
facts:
|
|
31953
|
-
preferences:
|
|
31954
|
-
entities:
|
|
31955
|
-
relations:
|
|
33011
|
+
var RawExtractionSchema = z36.object({
|
|
33012
|
+
facts: z36.array(RawFactSchema).default([]),
|
|
33013
|
+
preferences: z36.array(RawPreferenceSchema).default([]),
|
|
33014
|
+
entities: z36.array(RawEntitySchema).default([]),
|
|
33015
|
+
relations: z36.array(RawRelationSchema).default([])
|
|
31956
33016
|
});
|
|
31957
33017
|
var DEFAULT_CONFIDENCE = 0.6;
|
|
31958
33018
|
var SYSTEM_PROMPT = [
|
|
@@ -32206,13 +33266,13 @@ var memoryToolMessages = {
|
|
|
32206
33266
|
|
|
32207
33267
|
// src/plugin/memoryTool.ts
|
|
32208
33268
|
var SCRIBE_ROLE_ID = "scribe";
|
|
32209
|
-
var MemoryMessageSchema =
|
|
32210
|
-
role:
|
|
32211
|
-
content:
|
|
33269
|
+
var MemoryMessageSchema = z37.object({
|
|
33270
|
+
role: z37.enum(["system", "user", "assistant"]).describe(memoryToolMessages.messageRoleDescription),
|
|
33271
|
+
content: z37.string().min(1).describe(memoryToolMessages.messageContentDescription)
|
|
32212
33272
|
}).strict();
|
|
32213
|
-
var MemoryWritePayloadSchema =
|
|
32214
|
-
messages:
|
|
32215
|
-
roleID:
|
|
33273
|
+
var MemoryWritePayloadSchema = z37.object({
|
|
33274
|
+
messages: z37.array(MemoryMessageSchema).min(1).describe(memoryToolMessages.messagesDescription),
|
|
33275
|
+
roleID: z37.string().min(1).default(SCRIBE_ROLE_ID).describe(memoryToolMessages.roleIDDescription)
|
|
32216
33276
|
}).strict();
|
|
32217
33277
|
function createMemoryTool(deps) {
|
|
32218
33278
|
return tool5({
|
|
@@ -32396,7 +33456,7 @@ import { Session as Session2 } from "@opencode/schema/session";
|
|
|
32396
33456
|
import { Tool as Tool2 } from "@opencode/schema/tool";
|
|
32397
33457
|
import { tool as legacyTool } from "@opencode-ai/plugin/tool";
|
|
32398
33458
|
import { Clock, Effect, Option, Stream } from "effect";
|
|
32399
|
-
import { z as
|
|
33459
|
+
import { z as z39 } from "zod";
|
|
32400
33460
|
|
|
32401
33461
|
// src/plugin/nativeHostContext.ts
|
|
32402
33462
|
import {
|
|
@@ -32458,7 +33518,7 @@ function nativeConfiguredInventory(models, config) {
|
|
|
32458
33518
|
|
|
32459
33519
|
// src/plugin/nativeResidency.ts
|
|
32460
33520
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
32461
|
-
import { z as
|
|
33521
|
+
import { z as z38 } from "zod";
|
|
32462
33522
|
var NATIVE_RESIDENCY_PROVIDER_PACKAGE = "aisdk:@ai-sdk/openai-compatible@2.0.75";
|
|
32463
33523
|
var NATIVE_ADMISSION_HEADER = "x-openteam-local-admission";
|
|
32464
33524
|
var MAX_ADMISSIONS = 2048;
|
|
@@ -32536,7 +33596,7 @@ function createNativeModelResidencyGuard(config, options) {
|
|
|
32536
33596
|
});
|
|
32537
33597
|
}
|
|
32538
33598
|
function target(model, send, baseURL) {
|
|
32539
|
-
const headers = new Headers(
|
|
33599
|
+
const headers = new Headers(z38.record(z38.string(), z38.string()).parse(model.headers ?? {}));
|
|
32540
33600
|
if (typeof model.settings?.apiKey === "string" && !headers.has("authorization"))
|
|
32541
33601
|
headers.set("authorization", `Bearer ${model.settings.apiKey}`);
|
|
32542
33602
|
return {
|
|
@@ -32574,7 +33634,7 @@ function createNativeModelResidencyGuard(config, options) {
|
|
|
32574
33634
|
localTargets.set(key(ref), target(model, guardedFetch(binding, options.fetch), binding.baseURL));
|
|
32575
33635
|
return model;
|
|
32576
33636
|
} catch (error) {
|
|
32577
|
-
if (!(error instanceof ModelResidencyError) && !(error instanceof
|
|
33637
|
+
if (!(error instanceof ModelResidencyError) && !(error instanceof z38.ZodError))
|
|
32578
33638
|
throw error;
|
|
32579
33639
|
(options.warn ?? console.warn)(modelResidencyMessages.providerDisabled(model.providerID, residentRuntimes.find((runtime) => runtime.defaultModel.providerID === model.providerID)?.kind === "llama-swap" ? "llama-swap" : "Lemonade"));
|
|
32580
33640
|
return { ...model, enabled: false };
|
|
@@ -32731,6 +33791,10 @@ function nativeAssistantResponse(sessionID, message2) {
|
|
|
32731
33791
|
...message2.cost === undefined ? {} : { cost: message2.cost },
|
|
32732
33792
|
...message2.tokens === undefined ? {} : { tokens: message2.tokens },
|
|
32733
33793
|
...message2.error === undefined ? {} : { error: message2.error },
|
|
33794
|
+
...message2.finish === undefined ? {} : { finish: message2.finish },
|
|
33795
|
+
...message2.rawFinish === undefined ? {} : { rawFinish: message2.rawFinish },
|
|
33796
|
+
hasGeneratedOutput: message2.content.some((part) => part.type === "tool" || part.text.length > 0),
|
|
33797
|
+
truncatedToolCall: message2.finish === "length" && message2.content.some((part) => part.type === "tool" && part.executed === false && part.state.status === "error" && part.state.error.type === "tool.input-json"),
|
|
32734
33798
|
time: {
|
|
32735
33799
|
created: DateTime.toEpochMillis(message2.time.created),
|
|
32736
33800
|
...message2.time.completed === undefined ? {} : { completed: DateTime.toEpochMillis(message2.time.completed) }
|
|
@@ -32757,7 +33821,8 @@ function createNativeSessionClient(deps) {
|
|
|
32757
33821
|
}
|
|
32758
33822
|
return {
|
|
32759
33823
|
async create(args) {
|
|
32760
|
-
const
|
|
33824
|
+
const parentSignal = deps.signal?.();
|
|
33825
|
+
const signal = parentSignal === undefined ? args.signal : args.signal === undefined ? parentSignal : AbortSignal.any([parentSignal, args.signal]);
|
|
32761
33826
|
signal?.throwIfAborted();
|
|
32762
33827
|
assertDirectory(args.query?.directory);
|
|
32763
33828
|
if (args.body?.parentID === undefined)
|
|
@@ -32767,7 +33832,7 @@ function createNativeSessionClient(deps) {
|
|
|
32767
33832
|
const child = await deps.run(deps.sessions().create({
|
|
32768
33833
|
parentID,
|
|
32769
33834
|
...args.body.title === undefined ? {} : { title: args.body.title }
|
|
32770
|
-
}));
|
|
33835
|
+
}), signal === undefined ? undefined : { signal });
|
|
32771
33836
|
if (!sameNativeWorkspace(child.location, location))
|
|
32772
33837
|
throw new Error(nativeHostMessages.workspaceMismatch);
|
|
32773
33838
|
if (child.parentID !== parentID)
|
|
@@ -32806,6 +33871,11 @@ function createNativeSessionClient(deps) {
|
|
|
32806
33871
|
const assistant = [...messages].reverse().find((message2) => message2.type === "assistant");
|
|
32807
33872
|
if (final.outcome === "interrupted")
|
|
32808
33873
|
throw new Error(nativeHostMessages.executionInterrupted);
|
|
33874
|
+
if (assistant?.time.completed !== undefined) {
|
|
33875
|
+
const response = nativeAssistantResponse(sessionID, assistant);
|
|
33876
|
+
if (response.info.truncatedToolCall)
|
|
33877
|
+
return { data: response, error: undefined };
|
|
33878
|
+
}
|
|
32809
33879
|
if (final.outcome !== "succeeded" || assistant?.error !== undefined)
|
|
32810
33880
|
throw new Error(nativeHostMessages.executionFailed);
|
|
32811
33881
|
if (assistant?.time.completed === undefined)
|
|
@@ -32845,8 +33915,8 @@ function createNativeSessionClient(deps) {
|
|
|
32845
33915
|
}
|
|
32846
33916
|
|
|
32847
33917
|
// src/plugin/nativeHost.ts
|
|
32848
|
-
var executionEvent =
|
|
32849
|
-
type:
|
|
33918
|
+
var executionEvent = z39.preprocess(only(["type", "location", "data"]), z39.object({
|
|
33919
|
+
type: z39.enum([
|
|
32850
33920
|
"session.created",
|
|
32851
33921
|
"session.deleted",
|
|
32852
33922
|
"session.execution.started",
|
|
@@ -32854,15 +33924,30 @@ var executionEvent = z37.preprocess(only(["type", "location", "data"]), z37.obje
|
|
|
32854
33924
|
"session.execution.failed",
|
|
32855
33925
|
"session.execution.interrupted",
|
|
32856
33926
|
"session.step.ended",
|
|
32857
|
-
"session.step.
|
|
33927
|
+
"session.step.started",
|
|
33928
|
+
"session.step.failed",
|
|
33929
|
+
"session.tool.input.started",
|
|
33930
|
+
"session.tool.success",
|
|
33931
|
+
"session.tool.failed"
|
|
32858
33932
|
]),
|
|
32859
|
-
location:
|
|
32860
|
-
directory:
|
|
32861
|
-
workspaceID:
|
|
33933
|
+
location: z39.preprocess(only(["directory", "workspaceID"]), z39.object({
|
|
33934
|
+
directory: z39.string(),
|
|
33935
|
+
workspaceID: z39.string().optional()
|
|
32862
33936
|
}).strict()).optional(),
|
|
32863
|
-
data:
|
|
32864
|
-
sessionID
|
|
32865
|
-
assistantMessageID
|
|
33937
|
+
data: z39.preprocess(only([
|
|
33938
|
+
"sessionID",
|
|
33939
|
+
"assistantMessageID",
|
|
33940
|
+
"id",
|
|
33941
|
+
"name",
|
|
33942
|
+
"executed",
|
|
33943
|
+
"error"
|
|
33944
|
+
]), z39.object({
|
|
33945
|
+
sessionID: z39.string(),
|
|
33946
|
+
assistantMessageID: z39.string().optional(),
|
|
33947
|
+
id: z39.string().optional(),
|
|
33948
|
+
name: z39.string().optional(),
|
|
33949
|
+
executed: z39.boolean().optional(),
|
|
33950
|
+
error: z39.preprocess(only(["type"]), z39.object({ type: z39.string() }).strict()).optional()
|
|
32866
33951
|
}).strict())
|
|
32867
33952
|
}).strict());
|
|
32868
33953
|
var nativeBindings = Effect.fn("openteam.nativeBindings")(function* () {
|
|
@@ -32903,7 +33988,7 @@ function legacyModel(ref) {
|
|
|
32903
33988
|
}
|
|
32904
33989
|
function createNativePluginEffect(factory) {
|
|
32905
33990
|
return Effect.fn("openteam.native")(function* (ctx) {
|
|
32906
|
-
if (ctx.app.version
|
|
33991
|
+
if (!isSupportedNativeOpencodeVersion(ctx.app.version))
|
|
32907
33992
|
return yield* Effect.die(new Error(nativeHostMessages.unsupportedVersion(ctx.app.version)));
|
|
32908
33993
|
const version = ctx.app.version;
|
|
32909
33994
|
const effectContext = yield* Effect.context();
|
|
@@ -32917,6 +34002,15 @@ function createNativePluginEffect(factory) {
|
|
|
32917
34002
|
let config;
|
|
32918
34003
|
let residency;
|
|
32919
34004
|
const systemPrompts = new Map;
|
|
34005
|
+
const toolNames = new Map;
|
|
34006
|
+
const rememberTool = (sessionID, callID, name) => {
|
|
34007
|
+
toolNames.set(`${sessionID}\x00${callID}`, name);
|
|
34008
|
+
if (toolNames.size > 8192) {
|
|
34009
|
+
const oldest = toolNames.keys().next().value;
|
|
34010
|
+
if (oldest !== undefined)
|
|
34011
|
+
toolNames.delete(oldest);
|
|
34012
|
+
}
|
|
34013
|
+
};
|
|
32920
34014
|
const toolSignals = new AsyncLocalStorage;
|
|
32921
34015
|
const remember = (next) => {
|
|
32922
34016
|
bindings = { ...bindings, ...next };
|
|
@@ -32971,6 +34065,12 @@ function createNativePluginEffect(factory) {
|
|
|
32971
34065
|
directory,
|
|
32972
34066
|
worktree: ctx.location.project.directory,
|
|
32973
34067
|
client,
|
|
34068
|
+
toolOutcomesFromEvents: true,
|
|
34069
|
+
parentSession: async (sessionID) => {
|
|
34070
|
+
const info = await run(requiredBindings().sessions.get(Session2.ID.make(sessionID)));
|
|
34071
|
+
assertWorkspace(info.location);
|
|
34072
|
+
return info.parentID;
|
|
34073
|
+
},
|
|
32974
34074
|
exec: nativeExec(directory),
|
|
32975
34075
|
serverUrl: () => {
|
|
32976
34076
|
const url = bindings?.server?.urls().find((value) => {
|
|
@@ -33015,6 +34115,7 @@ function createNativePluginEffect(factory) {
|
|
|
33015
34115
|
yield* Effect.addFinalizer(() => Effect.promise(async () => {
|
|
33016
34116
|
guard.dispose();
|
|
33017
34117
|
systemPrompts.clear();
|
|
34118
|
+
toolNames.clear();
|
|
33018
34119
|
await hooks.dispose?.();
|
|
33019
34120
|
}));
|
|
33020
34121
|
yield* ctx.provider.transform(guard.providers);
|
|
@@ -33147,7 +34248,10 @@ function createNativePluginEffect(factory) {
|
|
|
33147
34248
|
});
|
|
33148
34249
|
}
|
|
33149
34250
|
});
|
|
33150
|
-
yield* ctx.tool.hook("execute.before", (event) => Effect.promise(() =>
|
|
34251
|
+
yield* ctx.tool.hook("execute.before", (event) => Effect.promise(() => {
|
|
34252
|
+
rememberTool(event.sessionID, event.id, event.tool);
|
|
34253
|
+
return hooks["tool.execute.before"]?.({ tool: event.tool, sessionID: event.sessionID, callID: event.id }, { args: event.input }) ?? Promise.resolve();
|
|
34254
|
+
}));
|
|
33151
34255
|
yield* ctx.tool.hook("execute.after", (event) => Effect.promise(() => hooks["tool.execute.after"]?.({
|
|
33152
34256
|
tool: event.tool,
|
|
33153
34257
|
sessionID: event.sessionID,
|
|
@@ -33174,9 +34278,62 @@ function createNativePluginEffect(factory) {
|
|
|
33174
34278
|
if (value.type === "session.deleted") {
|
|
33175
34279
|
guard.finished(sessionID);
|
|
33176
34280
|
systemPrompts.delete(sessionID);
|
|
34281
|
+
for (const key2 of toolNames.keys()) {
|
|
34282
|
+
if (key2.startsWith(`${sessionID}\x00`))
|
|
34283
|
+
toolNames.delete(key2);
|
|
34284
|
+
}
|
|
33177
34285
|
}
|
|
33178
34286
|
let mapped;
|
|
33179
|
-
if (value.type === "session.
|
|
34287
|
+
if (value.type === "session.tool.input.started") {
|
|
34288
|
+
if (value.data.id !== undefined && value.data.name !== undefined)
|
|
34289
|
+
rememberTool(sessionID, value.data.id, value.data.name);
|
|
34290
|
+
await hooks.event?.({
|
|
34291
|
+
event: {
|
|
34292
|
+
type: "openteam.session.phase",
|
|
34293
|
+
properties: { sessionID, phase: "tool-input" }
|
|
34294
|
+
}
|
|
34295
|
+
});
|
|
34296
|
+
return;
|
|
34297
|
+
} else if (value.type === "session.step.started") {
|
|
34298
|
+
mapped = {
|
|
34299
|
+
type: "openteam.session.phase",
|
|
34300
|
+
properties: { sessionID, phase: "model-request" }
|
|
34301
|
+
};
|
|
34302
|
+
} else if (value.type === "session.tool.success" || value.type === "session.tool.failed") {
|
|
34303
|
+
if (value.data.id === undefined)
|
|
34304
|
+
return;
|
|
34305
|
+
const key2 = `${sessionID}\x00${value.data.id}`;
|
|
34306
|
+
let name = toolNames.get(key2);
|
|
34307
|
+
if (name === undefined && bindings !== undefined) {
|
|
34308
|
+
const messages = await run(bindings.sessions.messages({
|
|
34309
|
+
sessionID: Session2.ID.make(sessionID),
|
|
34310
|
+
limit: 100
|
|
34311
|
+
}));
|
|
34312
|
+
const message2 = messages.find((candidate) => candidate.id === value.data.assistantMessageID);
|
|
34313
|
+
if (message2?.type === "assistant") {
|
|
34314
|
+
const part = message2.content.find((candidate) => candidate.type === "tool" && candidate.id === value.data.id);
|
|
34315
|
+
if (part?.type === "tool")
|
|
34316
|
+
name = part.name;
|
|
34317
|
+
}
|
|
34318
|
+
}
|
|
34319
|
+
const ok2 = value.type === "session.tool.success";
|
|
34320
|
+
const inputFailure = value.data.error?.type === "tool.input-json" || value.data.error?.type === "tool.input-schema";
|
|
34321
|
+
const executionReached = ok2 || value.data.error?.type === "tool.execution";
|
|
34322
|
+
mapped = {
|
|
34323
|
+
type: "openteam.tool.completed",
|
|
34324
|
+
properties: {
|
|
34325
|
+
sessionID,
|
|
34326
|
+
callID: value.data.id,
|
|
34327
|
+
tool: name ?? "unknown",
|
|
34328
|
+
ok: ok2,
|
|
34329
|
+
...inputFailure ? { executed: false } : executionReached ? { executed: true } : {},
|
|
34330
|
+
...value.data.executed === undefined ? {} : { providerExecuted: value.data.executed },
|
|
34331
|
+
...!ok2 ? {
|
|
34332
|
+
failureKind: inputFailure ? "input-invalid" : executionReached ? "execution" : "unknown"
|
|
34333
|
+
} : {}
|
|
34334
|
+
}
|
|
34335
|
+
};
|
|
34336
|
+
} else if (value.type === "session.created" || value.type === "session.deleted") {
|
|
33180
34337
|
mapped = {
|
|
33181
34338
|
type: value.type,
|
|
33182
34339
|
properties: { info: { id: sessionID } }
|
|
@@ -33217,12 +34374,13 @@ function createNativePluginEffect(factory) {
|
|
|
33217
34374
|
}
|
|
33218
34375
|
|
|
33219
34376
|
// src/plugin/orchestrateTool.ts
|
|
34377
|
+
import { resolve as resolve16 } from "node:path";
|
|
33220
34378
|
import { tool as tool6 } from "@opencode-ai/plugin";
|
|
33221
|
-
import { z as
|
|
34379
|
+
import { z as z40 } from "zod";
|
|
33222
34380
|
var _pluginWarnedRoles = new Set;
|
|
33223
34381
|
var EMPTY_ROLE_ID_SET = new Set;
|
|
33224
34382
|
var SAFE_ROLE_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
33225
|
-
var RoleIDSchema =
|
|
34383
|
+
var RoleIDSchema = z40.string().min(1).superRefine((roleID, ctx) => {
|
|
33226
34384
|
if (!SAFE_ROLE_ID.test(roleID)) {
|
|
33227
34385
|
ctx.addIssue({
|
|
33228
34386
|
code: "custom",
|
|
@@ -33230,16 +34388,16 @@ var RoleIDSchema = z38.string().min(1).superRefine((roleID, ctx) => {
|
|
|
33230
34388
|
});
|
|
33231
34389
|
}
|
|
33232
34390
|
});
|
|
33233
|
-
var RoleAssignmentSchema =
|
|
34391
|
+
var RoleAssignmentSchema = z40.object({
|
|
33234
34392
|
roleID: RoleIDSchema.describe("Role identifier from the roster"),
|
|
33235
|
-
prompt:
|
|
33236
|
-
title:
|
|
33237
|
-
dependsOn:
|
|
34393
|
+
prompt: z40.string().min(1).describe("Work prompt for this role"),
|
|
34394
|
+
title: z40.string().min(1).optional().describe("Human-readable title"),
|
|
34395
|
+
dependsOn: z40.array(RoleIDSchema).optional().describe("Role IDs this assignment depends on (DAG edges)")
|
|
33238
34396
|
}).strict();
|
|
33239
|
-
var OrchestratePayloadSchema =
|
|
33240
|
-
assignments:
|
|
33241
|
-
parentSessionID:
|
|
33242
|
-
directory:
|
|
34397
|
+
var OrchestratePayloadSchema = z40.object({
|
|
34398
|
+
assignments: z40.array(RoleAssignmentSchema).min(1).describe("Role assignments to distribute"),
|
|
34399
|
+
parentSessionID: z40.string().min(1).optional().describe(PARENT_SESSION_DESCRIPTION),
|
|
34400
|
+
directory: z40.string().min(1).optional().describe("Working directory override")
|
|
33243
34401
|
}).strict();
|
|
33244
34402
|
function validateAssignmentDependencies(assignments) {
|
|
33245
34403
|
const ids = new Set;
|
|
@@ -33424,8 +34582,15 @@ function adaptSdkClient(sdk, orchestratedModelOwnership) {
|
|
|
33424
34582
|
if (result.error !== undefined) {
|
|
33425
34583
|
out.error = normalizeSdkSessionFailure(result.error, "prompt");
|
|
33426
34584
|
} else {
|
|
34585
|
+
const info = isRecord8(result.data) ? nestedRecord2(result.data, "info") : undefined;
|
|
33427
34586
|
const nestedFailure = nestedAssistantFailure(result.data);
|
|
33428
|
-
if (
|
|
34587
|
+
if (info?.finish === "length" && info.truncatedToolCall === true) {
|
|
34588
|
+
out.error = {
|
|
34589
|
+
kind: "normalized-session-failure",
|
|
34590
|
+
failureClass: "prompt-output-truncated",
|
|
34591
|
+
retryable: true
|
|
34592
|
+
};
|
|
34593
|
+
} else if (nestedFailure !== undefined) {
|
|
33429
34594
|
out.error = normalizeSdkSessionFailure(nestedFailure, "prompt");
|
|
33430
34595
|
} else if (result.data !== undefined) {
|
|
33431
34596
|
out.data = result.data;
|
|
@@ -33585,7 +34750,10 @@ function mapTelemetryFailureClassToErrorClass(cls) {
|
|
|
33585
34750
|
case "prompt-rate-limited":
|
|
33586
34751
|
case "prompt-connection":
|
|
33587
34752
|
case "prompt-server":
|
|
34753
|
+
case "prompt-output-truncated":
|
|
33588
34754
|
return "transient";
|
|
34755
|
+
case "budget-exhausted":
|
|
34756
|
+
return "permanent";
|
|
33589
34757
|
case "create-rejected":
|
|
33590
34758
|
case "create-no-id":
|
|
33591
34759
|
case "prompt-rejected":
|
|
@@ -33868,8 +35036,16 @@ function createOrchestrateTool(deps) {
|
|
|
33868
35036
|
}
|
|
33869
35037
|
const parentOverrideIgnored = parsed.data.parentSessionID !== undefined && parsed.data.parentSessionID !== context.sessionID;
|
|
33870
35038
|
parsed.data.parentSessionID = context.sessionID;
|
|
33871
|
-
if (
|
|
33872
|
-
|
|
35039
|
+
if (deps.workspaceDirectory !== undefined) {
|
|
35040
|
+
const workspace = resolve16(deps.workspaceDirectory);
|
|
35041
|
+
if (resolve16(workspace, parsed.data.directory ?? ".") !== workspace)
|
|
35042
|
+
return reportDeliveryMessages.workspaceMismatch;
|
|
35043
|
+
parsed.data.directory = workspace;
|
|
35044
|
+
} else if (parsed.data.directory === undefined) {
|
|
35045
|
+
const directory = context.directory;
|
|
35046
|
+
if (directory !== undefined)
|
|
35047
|
+
parsed.data.directory = directory;
|
|
35048
|
+
}
|
|
33873
35049
|
const depError = validateAssignmentDependencies(parsed.data.assignments);
|
|
33874
35050
|
if (depError !== undefined) {
|
|
33875
35051
|
return dependencyValidationError(depError.code, depError.detail);
|
|
@@ -33892,6 +35068,14 @@ function createOrchestrateTool(deps) {
|
|
|
33892
35068
|
return missingAgentDefinition(agentName, input.roleID);
|
|
33893
35069
|
}
|
|
33894
35070
|
}
|
|
35071
|
+
const taskRef = await deps.taskEffort?.forSession(context.sessionID);
|
|
35072
|
+
if (taskRef !== undefined && deps.taskEffort !== undefined) {
|
|
35073
|
+
const effort2 = deps.taskEffort.batch(taskRef);
|
|
35074
|
+
if (!effort2.ok)
|
|
35075
|
+
return taskEffortMessages.exhausted(effort2.reason);
|
|
35076
|
+
for (const input of inputs)
|
|
35077
|
+
input.taskID = taskRef.taskID;
|
|
35078
|
+
}
|
|
33895
35079
|
const batchID = deps.newDecisionID();
|
|
33896
35080
|
if (deps.lifecycleRecorder !== undefined) {
|
|
33897
35081
|
const rootOperationID = operationID(batchID, "openteam");
|
|
@@ -33901,7 +35085,7 @@ function createOrchestrateTool(deps) {
|
|
|
33901
35085
|
executionAuthority: "coordinator",
|
|
33902
35086
|
root: {
|
|
33903
35087
|
operationID: rootOperationID,
|
|
33904
|
-
taskID: batchID,
|
|
35088
|
+
taskID: taskRef?.taskID ?? batchID,
|
|
33905
35089
|
kind: "coordinator",
|
|
33906
35090
|
roleID: "openteam",
|
|
33907
35091
|
agentID: context.agent,
|
|
@@ -33926,6 +35110,12 @@ function createOrchestrateTool(deps) {
|
|
|
33926
35110
|
reportedModelSlots: deps.reportedModelSlots,
|
|
33927
35111
|
readReportArtifact: deps.readReportArtifact,
|
|
33928
35112
|
reportArtifactExists: deps.reportArtifactExists,
|
|
35113
|
+
...deps.reportDelivery === undefined ? {} : { reportDelivery: deps.reportDelivery },
|
|
35114
|
+
...deps.sessionPhase === undefined ? {} : { sessionPhase: deps.sessionPhase },
|
|
35115
|
+
signal: context.abort,
|
|
35116
|
+
...deps.taskEffort === undefined || taskRef === undefined ? {} : {
|
|
35117
|
+
taskEffort: { ledger: deps.taskEffort, ref: taskRef }
|
|
35118
|
+
},
|
|
33929
35119
|
abortGraceMs: deps.abortGraceMs,
|
|
33930
35120
|
statusPollMs: deps.statusPollMs,
|
|
33931
35121
|
delay: deps.delay,
|
|
@@ -33943,10 +35133,15 @@ function createOrchestrateTool(deps) {
|
|
|
33943
35133
|
lifecycleStatus = activeLifecycleRecorder?.status() ?? lifecycleStatus;
|
|
33944
35134
|
const projected = projectResults(batch.results, batch.cancelled);
|
|
33945
35135
|
const shadowResult = await runShadowProducer(deps, parsed.data, batch);
|
|
35136
|
+
const effort = taskRef === undefined ? undefined : deps.taskEffort?.check(taskRef);
|
|
35137
|
+
const effortSummary = effort === undefined ? "" : `
|
|
35138
|
+
|
|
35139
|
+
${effort.ok ? taskEffortMessages.summary(effort.batches, effort.attempts, effort.remainingMs, effort.remainingBatches, effort.remainingAttempts) : taskEffortMessages.exhausted(effort.reason)}`;
|
|
33946
35140
|
const base = formatResult(projected) + (parentOverrideIgnored ? `
|
|
33947
35141
|
|
|
33948
|
-
${PARENT_OVERRIDE_IGNORED}` : "");
|
|
33949
|
-
const
|
|
35142
|
+
${PARENT_OVERRIDE_IGNORED}` : "") + effortSummary;
|
|
35143
|
+
const exhausted = effort?.ok === false || effort?.ok === true && (effort.remainingBatches === 0 || effort.remainingAttempts === 0);
|
|
35144
|
+
const advisory = exhausted ? undefined : singleAssignmentAdvisory(parsed.data.assignments.length, assignableRoleIDs(deps.config).length);
|
|
33950
35145
|
const withAdvisory = advisory === undefined ? base : `${base}
|
|
33951
35146
|
|
|
33952
35147
|
${advisory}`;
|
|
@@ -33977,7 +35172,7 @@ ${advisory}`;
|
|
|
33977
35172
|
|
|
33978
35173
|
// src/plugin/registerCastTool.ts
|
|
33979
35174
|
import { tool as tool7 } from "@opencode-ai/plugin";
|
|
33980
|
-
import { z as
|
|
35175
|
+
import { z as z41 } from "zod";
|
|
33981
35176
|
|
|
33982
35177
|
// src/messages/rosterSummary.ts
|
|
33983
35178
|
var ROSTER_SUMMARY_HEADING = "Registered team model policies";
|
|
@@ -34093,12 +35288,12 @@ function createTeamPreparation(deps) {
|
|
|
34093
35288
|
OpenTeamConfigSchema.parse(migrateConfig(baseRaw));
|
|
34094
35289
|
const overlay = overlayBefore === undefined ? undefined : parseConfigFileJson(DEFAULT_LOCAL_OVERLAY_PATH, overlayBefore);
|
|
34095
35290
|
const options = configOptionsFromPluginOptions(deps.options);
|
|
34096
|
-
const
|
|
35291
|
+
const resolve17 = (raw) => {
|
|
34097
35292
|
const config = validateConfigInput(TEAM_PREPARATION_CONFIG, mergeConfigInputs(mergeConfigInputs(raw, options), overlay));
|
|
34098
35293
|
assertEffectiveConfigModelDomains(config);
|
|
34099
35294
|
return config;
|
|
34100
35295
|
};
|
|
34101
|
-
const current =
|
|
35296
|
+
const current = resolve17(baseRaw);
|
|
34102
35297
|
const live = liveConfig ?? current;
|
|
34103
35298
|
if (resolveExecutionMode({
|
|
34104
35299
|
routerMode: current.router.executionMode,
|
|
@@ -34120,7 +35315,7 @@ function createTeamPreparation(deps) {
|
|
|
34120
35315
|
]))
|
|
34121
35316
|
}
|
|
34122
35317
|
});
|
|
34123
|
-
const effective =
|
|
35318
|
+
const effective = resolve17(candidate);
|
|
34124
35319
|
const requestedProfiles = new Set(roster.entries.filter((entry) => !isKnownNonWorkerRole(entry.roleID) && getRoleProfile(entry.roleID, live.orchestrator?.roles) === undefined).map((entry) => getRoleProfile(entry.roleID, effective.orchestrator?.roles)));
|
|
34125
35320
|
const additions = Object.fromEntries(Object.entries(effective.orchestrator?.roles ?? {}).filter(([key2, profile]) => requestedProfiles.has(profile) && !Object.hasOwn(live.orchestrator?.roles ?? {}, key2)));
|
|
34126
35321
|
const hasAdditions = Object.keys(additions).length > 0;
|
|
@@ -34206,13 +35401,13 @@ async function persistPreparedTeam(storage, files) {
|
|
|
34206
35401
|
}
|
|
34207
35402
|
|
|
34208
35403
|
// src/plugin/registerCastTool.ts
|
|
34209
|
-
var CastEntrySchema =
|
|
34210
|
-
roleID:
|
|
34211
|
-
agentName:
|
|
35404
|
+
var CastEntrySchema = z41.object({
|
|
35405
|
+
roleID: z41.string().min(1).describe("Stable role identifier, e.g. scribe or guardian"),
|
|
35406
|
+
agentName: z41.string().min(1).describe("Themed character name assigned to the role")
|
|
34212
35407
|
}).strict();
|
|
34213
|
-
var RegisterCastPayloadSchema =
|
|
34214
|
-
universe:
|
|
34215
|
-
entries:
|
|
35408
|
+
var RegisterCastPayloadSchema = z41.object({
|
|
35409
|
+
universe: z41.string().min(1).describe("Casting universe for this roster"),
|
|
35410
|
+
entries: z41.array(CastEntrySchema).min(1).describe("Role-to-name mappings")
|
|
34216
35411
|
}).strict();
|
|
34217
35412
|
function offendingFields(error) {
|
|
34218
35413
|
const fields = error.issues.flatMap((issue) => {
|
|
@@ -34332,7 +35527,7 @@ function createRegisterCastTool(deps) {
|
|
|
34332
35527
|
}
|
|
34333
35528
|
|
|
34334
35529
|
// src/plugin/reloadTool.ts
|
|
34335
|
-
import { resolve as
|
|
35530
|
+
import { resolve as resolve17 } from "node:path";
|
|
34336
35531
|
import { tool as tool8 } from "@opencode-ai/plugin/tool";
|
|
34337
35532
|
var WAIT_MS = 30000;
|
|
34338
35533
|
var SDK_TIMEOUT_MS = 5000;
|
|
@@ -34366,7 +35561,7 @@ function createReloadController(deps) {
|
|
|
34366
35561
|
return () => clearTimeout(timer);
|
|
34367
35562
|
}
|
|
34368
35563
|
};
|
|
34369
|
-
const directory =
|
|
35564
|
+
const directory = resolve17(deps.directory);
|
|
34370
35565
|
let pending;
|
|
34371
35566
|
let authorizing;
|
|
34372
35567
|
let closed = false;
|
|
@@ -34514,7 +35709,7 @@ function createReloadController(deps) {
|
|
|
34514
35709
|
const parsed = schema.safeParse(args);
|
|
34515
35710
|
if (!parsed.success)
|
|
34516
35711
|
return reloadMessages.invalid;
|
|
34517
|
-
if (context.agent !== "openteam" ||
|
|
35712
|
+
if (context.agent !== "openteam" || resolve17(context.directory) !== directory || context.sessionID.trim().length === 0)
|
|
34518
35713
|
return reloadMessages.denied;
|
|
34519
35714
|
if (parsed.data.action === "cancel") {
|
|
34520
35715
|
if ((pending?.sessionID ?? authorizing?.sessionID) !== context.sessionID)
|
|
@@ -34632,6 +35827,31 @@ function createReloadController(deps) {
|
|
|
34632
35827
|
};
|
|
34633
35828
|
}
|
|
34634
35829
|
|
|
35830
|
+
// src/plugin/reportTool.ts
|
|
35831
|
+
import { tool as tool9 } from "@opencode-ai/plugin";
|
|
35832
|
+
function createReportTool(delivery) {
|
|
35833
|
+
return tool9({
|
|
35834
|
+
description: reportDeliveryMessages.description,
|
|
35835
|
+
args: {
|
|
35836
|
+
status: tool9.schema.enum(["done", "continue"]).describe(reportDeliveryMessages.status),
|
|
35837
|
+
findings: tool9.schema.string().min(1).max(32768).describe(reportDeliveryMessages.findings)
|
|
35838
|
+
},
|
|
35839
|
+
async execute(args, context) {
|
|
35840
|
+
context.abort.throwIfAborted();
|
|
35841
|
+
const path4 = delivery.path(context.sessionID);
|
|
35842
|
+
await context.ask({
|
|
35843
|
+
permission: "openteam-submit-report",
|
|
35844
|
+
patterns: [path4],
|
|
35845
|
+
always: [],
|
|
35846
|
+
metadata: { reportPath: path4 }
|
|
35847
|
+
});
|
|
35848
|
+
context.abort.throwIfAborted();
|
|
35849
|
+
await delivery.submit(context.sessionID, args);
|
|
35850
|
+
return reportDeliveryMessages.submitted(path4);
|
|
35851
|
+
}
|
|
35852
|
+
});
|
|
35853
|
+
}
|
|
35854
|
+
|
|
34635
35855
|
// src/plugin/sessionTracker.ts
|
|
34636
35856
|
function createSessionTracker() {
|
|
34637
35857
|
const knownSessions = new Set;
|
|
@@ -34660,22 +35880,40 @@ function createSessionTracker() {
|
|
|
34660
35880
|
}
|
|
34661
35881
|
|
|
34662
35882
|
// src/plugin/toolcalls.ts
|
|
35883
|
+
var MAX_TRACKED_CALLS = 8192;
|
|
34663
35884
|
function key2(sessionID, callID) {
|
|
34664
35885
|
return `${sessionID}\x00${callID}`;
|
|
34665
35886
|
}
|
|
34666
35887
|
function createToolcallTracker(deps) {
|
|
34667
35888
|
const now = deps.now ?? Date.now;
|
|
34668
35889
|
const started = new Map;
|
|
35890
|
+
const completed = new Set;
|
|
34669
35891
|
return {
|
|
34670
35892
|
before(input) {
|
|
34671
|
-
|
|
35893
|
+
const mapKey = key2(input.sessionID, input.callID);
|
|
35894
|
+
if (completed.has(mapKey) || started.has(mapKey))
|
|
35895
|
+
return;
|
|
35896
|
+
started.set(mapKey, now());
|
|
35897
|
+
if (started.size > MAX_TRACKED_CALLS) {
|
|
35898
|
+
const oldest = started.keys().next().value;
|
|
35899
|
+
if (oldest !== undefined)
|
|
35900
|
+
started.delete(oldest);
|
|
35901
|
+
}
|
|
34672
35902
|
},
|
|
34673
35903
|
after(input) {
|
|
34674
35904
|
const mapKey = key2(input.sessionID, input.callID);
|
|
35905
|
+
if (completed.has(mapKey))
|
|
35906
|
+
return;
|
|
35907
|
+
completed.add(mapKey);
|
|
35908
|
+
if (completed.size > MAX_TRACKED_CALLS) {
|
|
35909
|
+
const oldest = completed.values().next().value;
|
|
35910
|
+
if (oldest !== undefined)
|
|
35911
|
+
completed.delete(oldest);
|
|
35912
|
+
}
|
|
34675
35913
|
const start = started.get(mapKey);
|
|
34676
35914
|
started.delete(mapKey);
|
|
34677
35915
|
const end = now();
|
|
34678
|
-
const durationMs = start === undefined ?
|
|
35916
|
+
const durationMs = input.durationMs !== undefined ? input.durationMs : start === undefined ? null : Math.max(0, Math.trunc(end - start));
|
|
34679
35917
|
const event = {
|
|
34680
35918
|
v: EVENT_SCHEMA_VERSION,
|
|
34681
35919
|
type: "toolcall",
|
|
@@ -34684,9 +35922,23 @@ function createToolcallTracker(deps) {
|
|
|
34684
35922
|
tool: input.tool,
|
|
34685
35923
|
callID: input.callID,
|
|
34686
35924
|
durationMs,
|
|
34687
|
-
ok: true
|
|
35925
|
+
ok: input.ok ?? true,
|
|
35926
|
+
...input.executed === undefined ? {} : { executed: input.executed },
|
|
35927
|
+
...input.providerExecuted === undefined ? {} : { providerExecuted: input.providerExecuted },
|
|
35928
|
+
...input.failureKind === undefined ? {} : { failureKind: input.failureKind }
|
|
34688
35929
|
};
|
|
34689
35930
|
return deps.sink.emit(event);
|
|
35931
|
+
},
|
|
35932
|
+
forgetSession(sessionID) {
|
|
35933
|
+
const prefix = `${sessionID}\x00`;
|
|
35934
|
+
for (const mapKey of started.keys()) {
|
|
35935
|
+
if (mapKey.startsWith(prefix))
|
|
35936
|
+
started.delete(mapKey);
|
|
35937
|
+
}
|
|
35938
|
+
for (const mapKey of completed) {
|
|
35939
|
+
if (mapKey.startsWith(prefix))
|
|
35940
|
+
completed.delete(mapKey);
|
|
35941
|
+
}
|
|
34690
35942
|
}
|
|
34691
35943
|
};
|
|
34692
35944
|
}
|
|
@@ -34874,6 +36126,61 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
34874
36126
|
}
|
|
34875
36127
|
}
|
|
34876
36128
|
|
|
36129
|
+
// src/storage/scopedArtifacts.ts
|
|
36130
|
+
import { lstatSync as lstatSync4, mkdirSync as mkdirSync4, realpathSync as realpathSync3 } from "node:fs";
|
|
36131
|
+
import { dirname as dirname10, join as join22 } from "node:path";
|
|
36132
|
+
function createScopedArtifactStore(directory, root) {
|
|
36133
|
+
function pathFor(name) {
|
|
36134
|
+
const workspace = realpathSync3(directory);
|
|
36135
|
+
const segments = [...splitVirtualPath(root), ...splitVirtualPath(name)];
|
|
36136
|
+
const filename = segments.pop();
|
|
36137
|
+
if (!filename)
|
|
36138
|
+
throw new Error(reportDeliveryMessages.unsafePath);
|
|
36139
|
+
let path4 = workspace;
|
|
36140
|
+
for (const segment of segments) {
|
|
36141
|
+
path4 = join22(path4, segment);
|
|
36142
|
+
try {
|
|
36143
|
+
mkdirSync4(path4, { mode: 448 });
|
|
36144
|
+
} catch (error) {
|
|
36145
|
+
if (!(typeof error === "object" && error !== null && ("code" in error) && error.code === "EEXIST"))
|
|
36146
|
+
throw error;
|
|
36147
|
+
}
|
|
36148
|
+
const stat4 = lstatSync4(path4);
|
|
36149
|
+
if (!stat4.isDirectory() || stat4.isSymbolicLink())
|
|
36150
|
+
throw new Error(reportDeliveryMessages.unsafePath);
|
|
36151
|
+
}
|
|
36152
|
+
const target = join22(path4, filename);
|
|
36153
|
+
try {
|
|
36154
|
+
const stat4 = lstatSync4(target);
|
|
36155
|
+
if (!stat4.isFile() || stat4.isSymbolicLink() || stat4.size > 1048576)
|
|
36156
|
+
throw new Error(reportDeliveryMessages.unsafePath);
|
|
36157
|
+
} catch (error) {
|
|
36158
|
+
if (!isMissingFsError(error))
|
|
36159
|
+
throw error;
|
|
36160
|
+
}
|
|
36161
|
+
return target;
|
|
36162
|
+
}
|
|
36163
|
+
return {
|
|
36164
|
+
read(name) {
|
|
36165
|
+
return readUtf8(pathFor(name));
|
|
36166
|
+
},
|
|
36167
|
+
write(name, content) {
|
|
36168
|
+
if (Buffer.byteLength(content, "utf8") > 1048576)
|
|
36169
|
+
throw new Error(reportDeliveryMessages.unsafePath);
|
|
36170
|
+
writeDurableAtomically(pathFor(name), content);
|
|
36171
|
+
},
|
|
36172
|
+
update(name, change) {
|
|
36173
|
+
const path4 = pathFor(name);
|
|
36174
|
+
withRunMutationLock(dirname10(path4), () => {
|
|
36175
|
+
const content = change(readUtf8(path4));
|
|
36176
|
+
if (Buffer.byteLength(content, "utf8") > 1048576)
|
|
36177
|
+
throw new Error(reportDeliveryMessages.unsafePath);
|
|
36178
|
+
writeDurableAtomically(path4, content);
|
|
36179
|
+
});
|
|
36180
|
+
}
|
|
36181
|
+
};
|
|
36182
|
+
}
|
|
36183
|
+
|
|
34877
36184
|
// src/telemetry/otelExporter.ts
|
|
34878
36185
|
var DEFAULT_SERVICE_NAME = "openteam";
|
|
34879
36186
|
function tracesUrl(ingestionEndpoint) {
|
|
@@ -35018,7 +36325,7 @@ var RELEASE_CERT_PATH = "artifacts/graph-release-certificate.json";
|
|
|
35018
36325
|
var SOAK_CERT_PATH = "artifacts/graph-soak-certificate.json";
|
|
35019
36326
|
async function readPackagedCertificate(path4) {
|
|
35020
36327
|
try {
|
|
35021
|
-
const hostDirectory = basename4(
|
|
36328
|
+
const hostDirectory = basename4(dirname11(path4)) === NATIVE_CERTIFICATE_DIRECTORY ? `${NATIVE_CERTIFICATE_DIRECTORY}/` : "";
|
|
35022
36329
|
return await readFile5(new URL(`./certificates/${hostDirectory}${basename4(path4)}`, import.meta.url), "utf8");
|
|
35023
36330
|
} catch {
|
|
35024
36331
|
return;
|
|
@@ -35143,8 +36450,8 @@ async function tryReadOpencodeVersion(serverUrl, fetchFn, client) {
|
|
|
35143
36450
|
}
|
|
35144
36451
|
var DEFAULT_OPENCODE_VERSION_BACKOFF_MS = [50, 250];
|
|
35145
36452
|
function defaultSleep(ms2) {
|
|
35146
|
-
return new Promise((
|
|
35147
|
-
setTimeout(
|
|
36453
|
+
return new Promise((resolve19) => {
|
|
36454
|
+
setTimeout(resolve19, ms2);
|
|
35148
36455
|
});
|
|
35149
36456
|
}
|
|
35150
36457
|
function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
@@ -35187,7 +36494,7 @@ function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
|
35187
36494
|
};
|
|
35188
36495
|
}
|
|
35189
36496
|
async function buildGateInput(config, storage, opencodeVersion, warn, packagedRead = readPackagedCertificate) {
|
|
35190
|
-
const hostPath = (path4) => opencodeVersion
|
|
36497
|
+
const hostPath = (path4) => isSupportedNativeOpencodeVersion(opencodeVersion) ? `${dirname11(path4)}/${NATIVE_CERTIFICATE_DIRECTORY}/${basename4(path4)}` : path4;
|
|
35191
36498
|
const shadow = await readAndParseCertificate(storage, hostPath(SHADOW_CERT_PATH), (raw) => parseShadowCertificate(raw, opencodeVersion), (cert) => shadowCertificateBindingDigest(cert.evidence), packagedRead);
|
|
35192
36499
|
const shadowDigest = shadow.status === "valid" ? shadow.digest : "0".repeat(64);
|
|
35193
36500
|
const release = await readAndParseCertificate(storage, hostPath(RELEASE_CERT_PATH), (raw) => parseReleaseCertificate(raw, opencodeVersion, shadowDigest), (cert) => cert.digest, packagedRead);
|
|
@@ -35396,7 +36703,7 @@ function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SE
|
|
|
35396
36703
|
telemetryPath,
|
|
35397
36704
|
opencodeConfigPaths: OPENCODE_CONFIG_CANDIDATES,
|
|
35398
36705
|
orchestratorAgentPath: ORCHESTRATOR_AGENT_PATH,
|
|
35399
|
-
agentDir:
|
|
36706
|
+
agentDir: dirname11(ORCHESTRATOR_AGENT_PATH),
|
|
35400
36707
|
cachePort: realCacheAdapter,
|
|
35401
36708
|
purge: createPluginPurgeRuntime(sessionsDir),
|
|
35402
36709
|
loadRosterForDoctor: () => readStoredRosterForDoctor(storage),
|
|
@@ -35547,6 +36854,24 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
35547
36854
|
return version === "unknown" ? undefined : version;
|
|
35548
36855
|
}, workspaceRoot);
|
|
35549
36856
|
const toolcalls = createToolcallTracker({ sink });
|
|
36857
|
+
const sessionPhase = async (sessionID, phase) => {
|
|
36858
|
+
try {
|
|
36859
|
+
await sink.emit({
|
|
36860
|
+
v: 1,
|
|
36861
|
+
type: "activity",
|
|
36862
|
+
ts: now(),
|
|
36863
|
+
sessionID,
|
|
36864
|
+
kind: "agent",
|
|
36865
|
+
summary: executionPhaseMessages[phase],
|
|
36866
|
+
phase
|
|
36867
|
+
});
|
|
36868
|
+
} catch (error) {
|
|
36869
|
+
logTelemetryError(error, diagnostics.warn("telemetry-write-failed", {
|
|
36870
|
+
persist: false,
|
|
36871
|
+
toast: false
|
|
36872
|
+
}));
|
|
36873
|
+
}
|
|
36874
|
+
};
|
|
35550
36875
|
const announcedSessions = new Set;
|
|
35551
36876
|
const announceEndpoint = (sessionID) => {
|
|
35552
36877
|
if (sessionID === undefined || announcedSessions.has(sessionID)) {
|
|
@@ -35667,6 +36992,18 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
35667
36992
|
},
|
|
35668
36993
|
now
|
|
35669
36994
|
});
|
|
36995
|
+
const reportStore = createScopedArtifactStore(ctx.directory, ROLE_REPORTS_ROOT);
|
|
36996
|
+
const taskEffort = createTaskEffort({
|
|
36997
|
+
store: createScopedArtifactStore(ctx.directory, ".opencode/openteam-local/effort"),
|
|
36998
|
+
now,
|
|
36999
|
+
...config.orchestrator?.taskBudget === undefined ? {} : { limits: config.orchestrator.taskBudget },
|
|
37000
|
+
...ctx.parentSession === undefined ? {} : { parentSession: ctx.parentSession }
|
|
37001
|
+
});
|
|
37002
|
+
const reportDelivery = createReportDelivery({
|
|
37003
|
+
write: async (path4, content) => {
|
|
37004
|
+
reportStore.write(path4.slice(ROLE_REPORTS_ROOT.length + 1), content);
|
|
37005
|
+
}
|
|
37006
|
+
});
|
|
35670
37007
|
const orchestrateTool = createOrchestrateTool({
|
|
35671
37008
|
client: orchestrateClient,
|
|
35672
37009
|
sink,
|
|
@@ -35687,11 +37024,15 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
35687
37024
|
capabilityProfiles,
|
|
35688
37025
|
reportArtifactExists,
|
|
35689
37026
|
readReportArtifact,
|
|
37027
|
+
reportDelivery,
|
|
37028
|
+
taskEffort,
|
|
37029
|
+
sessionPhase,
|
|
37030
|
+
workspaceDirectory: ctx.directory,
|
|
35690
37031
|
lifecycleRecorder,
|
|
35691
37032
|
abortGraceMs: DEFAULT_ABORT_GRACE_MS,
|
|
35692
37033
|
statusPollMs: DEFAULT_STATUS_POLL_MS,
|
|
35693
|
-
delay: (ms2) => new Promise((
|
|
35694
|
-
setTimeout(
|
|
37034
|
+
delay: (ms2) => new Promise((resolve19) => {
|
|
37035
|
+
setTimeout(resolve19, ms2);
|
|
35695
37036
|
}),
|
|
35696
37037
|
warn: diagnostics.warn("unknown-role")
|
|
35697
37038
|
});
|
|
@@ -35757,7 +37098,9 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
35757
37098
|
...hooks,
|
|
35758
37099
|
"chat.message": async (input, output) => {
|
|
35759
37100
|
reload.userTurn(input.sessionID);
|
|
37101
|
+
await taskEffort.userTurn(input.sessionID, input.messageID ?? output.message.id);
|
|
35760
37102
|
await hooks["chat.message"]?.(input, output);
|
|
37103
|
+
await sessionPhase(input.sessionID, "model-request");
|
|
35761
37104
|
announceEndpoint(input.sessionID);
|
|
35762
37105
|
},
|
|
35763
37106
|
dispose: async () => {
|
|
@@ -35771,18 +37114,44 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
35771
37114
|
"openteam-orchestrate": orchestrateTool,
|
|
35772
37115
|
"openteam-memory": memoryTool,
|
|
35773
37116
|
"openteam-register-cast": registerCastTool,
|
|
35774
|
-
"openteam-reload": reload.tool
|
|
37117
|
+
"openteam-reload": reload.tool,
|
|
37118
|
+
"openteam-submit-report": createReportTool(reportDelivery)
|
|
35775
37119
|
},
|
|
35776
37120
|
"tool.execute.before": async (input) => {
|
|
35777
37121
|
toolcalls.before(input);
|
|
37122
|
+
await sessionPhase(input.sessionID, "tool-execution");
|
|
35778
37123
|
},
|
|
35779
37124
|
"tool.execute.after": async (input) => {
|
|
35780
|
-
|
|
37125
|
+
if (ctx.toolOutcomesFromEvents !== true)
|
|
37126
|
+
await toolcalls.after(input);
|
|
35781
37127
|
if (input.tool === "openteam-reload")
|
|
35782
37128
|
reload.toolCompleted(input.sessionID);
|
|
35783
37129
|
},
|
|
35784
37130
|
event: async ({ event }) => {
|
|
35785
37131
|
reload.event(event);
|
|
37132
|
+
if (event.type === "openteam.tool.completed") {
|
|
37133
|
+
await toolcalls.after(event.properties);
|
|
37134
|
+
await sessionPhase(event.properties.sessionID, "unknown");
|
|
37135
|
+
} else if (event.type === "openteam.session.phase") {
|
|
37136
|
+
await sessionPhase(event.properties.sessionID, event.properties.phase);
|
|
37137
|
+
} else if (event.type === "session.idle") {
|
|
37138
|
+
if (typeof event.properties?.sessionID === "string")
|
|
37139
|
+
await sessionPhase(event.properties.sessionID, "idle");
|
|
37140
|
+
} else if (event.type === "message.part.updated") {
|
|
37141
|
+
const part = event.properties.part;
|
|
37142
|
+
if (part.type === "tool" && (part.state.status === "completed" || part.state.status === "error")) {
|
|
37143
|
+
await toolcalls.after({
|
|
37144
|
+
tool: part.tool,
|
|
37145
|
+
sessionID: part.sessionID,
|
|
37146
|
+
callID: part.callID,
|
|
37147
|
+
ok: part.state.status === "completed",
|
|
37148
|
+
durationMs: Math.max(0, Math.trunc(part.state.time.end - part.state.time.start)),
|
|
37149
|
+
...part.state.status === "error" ? { failureKind: "execution" } : {}
|
|
37150
|
+
});
|
|
37151
|
+
}
|
|
37152
|
+
} else if (event.type === "session.deleted") {
|
|
37153
|
+
toolcalls.forgetSession(event.properties.info.id);
|
|
37154
|
+
}
|
|
35786
37155
|
if (event.type === "session.created" || event.type === "session.idle") {
|
|
35787
37156
|
cache.refresh();
|
|
35788
37157
|
}
|
|
@@ -35799,6 +37168,7 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
35799
37168
|
announceEndpoint(message2.sessionID);
|
|
35800
37169
|
sessionTracker.trackSession(message2.sessionID);
|
|
35801
37170
|
sink.emit(message2);
|
|
37171
|
+
await sessionPhase(message2.sessionID, "unknown");
|
|
35802
37172
|
}
|
|
35803
37173
|
}
|
|
35804
37174
|
}
|
|
@@ -35808,6 +37178,19 @@ var server = (ctx, rawOptions) => createPluginRuntime({
|
|
|
35808
37178
|
directory: ctx.directory,
|
|
35809
37179
|
worktree: ctx.worktree,
|
|
35810
37180
|
client: ctx.client,
|
|
37181
|
+
...typeof ctx.client.session?.get !== "function" ? {} : {
|
|
37182
|
+
parentSession: async (sessionID) => {
|
|
37183
|
+
const response = await ctx.client.session.get({
|
|
37184
|
+
path: { id: sessionID },
|
|
37185
|
+
query: { directory: ctx.directory }
|
|
37186
|
+
});
|
|
37187
|
+
if (response.error !== undefined || response.data === undefined)
|
|
37188
|
+
throw new Error(nativeHostMessages.missingBindings);
|
|
37189
|
+
if (resolve18(response.data.directory) !== resolve18(ctx.directory))
|
|
37190
|
+
throw new Error(nativeHostMessages.workspaceMismatch);
|
|
37191
|
+
return response.data.parentID;
|
|
37192
|
+
}
|
|
37193
|
+
},
|
|
35811
37194
|
exec: createShellExec(ctx.$),
|
|
35812
37195
|
serverUrl: () => ctx.serverUrl,
|
|
35813
37196
|
...ctx.client.config?.providers === undefined ? {} : {
|
|
@@ -36434,7 +37817,7 @@ function createGitLastCommit(exec) {
|
|
|
36434
37817
|
// src/cli.ts
|
|
36435
37818
|
var execFileAsync3 = promisify3(execFile4);
|
|
36436
37819
|
var execAsync = promisify3(exec);
|
|
36437
|
-
var AGENT_DIR =
|
|
37820
|
+
var AGENT_DIR = dirname12(ORCHESTRATOR_AGENT_PATH);
|
|
36438
37821
|
var storage = createFsStorageProvider(process.cwd());
|
|
36439
37822
|
var CLI_LIFECYCLE_WRITER_IDENTITY = {
|
|
36440
37823
|
processID: process.pid,
|
|
@@ -36521,7 +37904,7 @@ async function readConfigFile(path4, resolution) {
|
|
|
36521
37904
|
return storage.read(path4);
|
|
36522
37905
|
}
|
|
36523
37906
|
try {
|
|
36524
|
-
return await readFile6(
|
|
37907
|
+
return await readFile6(resolve19(path4), "utf8");
|
|
36525
37908
|
} catch (error) {
|
|
36526
37909
|
throw new Error(`[openteam] config file named by --config could not be read: ${path4} (${describeFileReadError(error)})`);
|
|
36527
37910
|
}
|
|
@@ -36544,8 +37927,8 @@ async function saveConfig(config, path4, resolution = { explicit: false }) {
|
|
|
36544
37927
|
return;
|
|
36545
37928
|
}
|
|
36546
37929
|
const contents = serializeOpenTeamConfig(config);
|
|
36547
|
-
const diskPath =
|
|
36548
|
-
await mkdir5(
|
|
37930
|
+
const diskPath = resolve19(path4);
|
|
37931
|
+
await mkdir5(dirname12(diskPath), { recursive: true });
|
|
36549
37932
|
await writeFile2(diskPath, contents, "utf8");
|
|
36550
37933
|
}
|
|
36551
37934
|
function parseConfigSelection(argv) {
|
|
@@ -36590,8 +37973,8 @@ async function openBrowser(url) {
|
|
|
36590
37973
|
}
|
|
36591
37974
|
}
|
|
36592
37975
|
function waitForSignal() {
|
|
36593
|
-
return new Promise((
|
|
36594
|
-
const done = () =>
|
|
37976
|
+
return new Promise((resolve20) => {
|
|
37977
|
+
const done = () => resolve20();
|
|
36595
37978
|
process.once("SIGINT", done);
|
|
36596
37979
|
process.once("SIGTERM", done);
|
|
36597
37980
|
});
|
|
@@ -36792,7 +38175,7 @@ async function main() {
|
|
|
36792
38175
|
workspaceRoot,
|
|
36793
38176
|
configuredRoot: initialConsoleConfig.lifecycle?.root ?? DEFAULT_LIFECYCLE_ROOT
|
|
36794
38177
|
});
|
|
36795
|
-
const legacyGraphRoot =
|
|
38178
|
+
const legacyGraphRoot = resolve19(workspaceRoot, initialConsoleConfig.graph?.journalRoot ?? DEFAULT_GRAPH_JOURNAL_ROOT);
|
|
36796
38179
|
const lifecycleAvailability = initialConsoleConfig.console.graphView?.enabled === true ? "enabled" : "history-disabled";
|
|
36797
38180
|
const lifecycleHistoryReader = createLifecycleHistoryProvider({
|
|
36798
38181
|
lifecycleRoot,
|