@jmanuelcorral/openteam 0.27.1 → 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 +19 -1
- package/README.md +25 -1
- 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.js +1609 -248
- package/dist/config/errors.d.ts.map +1 -1
- 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/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 +1207 -403
- 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/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/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
5
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
6
|
-
import { basename as basename4, dirname as
|
|
6
|
+
import { basename as basename4, dirname as dirname9, resolve as resolve15 } from "node:path";
|
|
7
7
|
|
|
8
8
|
// src/capabilities/curated.ts
|
|
9
9
|
var CURATED_FRONTIER_PROFILES = [
|
|
@@ -786,6 +786,15 @@ function migrateConfig(raw) {
|
|
|
786
786
|
var consoleDetailMessages = {
|
|
787
787
|
runtimeStateCleanupFailed: "The Console runtime state could not be published and its staging file could not be removed.",
|
|
788
788
|
requestFailed: "The local opencode request failed.",
|
|
789
|
+
usageUnavailable: "Unavailable / partial",
|
|
790
|
+
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.",
|
|
791
|
+
timingUnknown: "Unknown",
|
|
792
|
+
estimatedCost: "Estimated cost",
|
|
793
|
+
estimatedBaseline: "Estimated baseline",
|
|
794
|
+
estimatedSavings: "Estimated savings",
|
|
795
|
+
estimatedInput: "Estimated tokens in",
|
|
796
|
+
estimatedOutput: "Estimated tokens out",
|
|
797
|
+
estimatesNotUsage: "Routing estimates are separate from host-reported usage; they are not measured spend or proven savings.",
|
|
789
798
|
nativeToolFailed: "The native tool execution failed.",
|
|
790
799
|
follow: "Follow new activity",
|
|
791
800
|
metadataOnly: "Lifecycle and telemetry stay metadata-only.",
|
|
@@ -1041,7 +1050,13 @@ var OrchestratorConfigSchema = z3.object({
|
|
|
1041
1050
|
roles: OrchestratorRolesSchema,
|
|
1042
1051
|
primary: AgentExecutionPolicySchema.optional(),
|
|
1043
1052
|
maxRetries: z3.number().int().min(0).optional(),
|
|
1044
|
-
maxModelsPerNode: z3.number().int().positive().optional()
|
|
1053
|
+
maxModelsPerNode: z3.number().int().positive().optional(),
|
|
1054
|
+
taskBudget: z3.object({
|
|
1055
|
+
maxBatches: z3.number().int().min(1).max(1000).optional(),
|
|
1056
|
+
maxAttempts: z3.number().int().min(1).max(1e4).optional(),
|
|
1057
|
+
maxDurationMs: z3.number().int().min(1000).max(86400000).optional(),
|
|
1058
|
+
maxDepth: z3.number().int().min(0).max(32).optional()
|
|
1059
|
+
}).strict().optional()
|
|
1045
1060
|
}).strict();
|
|
1046
1061
|
var defaultFrontierModel = {
|
|
1047
1062
|
providerID: "google",
|
|
@@ -1566,6 +1581,8 @@ var NodeFailureClassSchema = z6.enum([
|
|
|
1566
1581
|
"prompt-auth",
|
|
1567
1582
|
"prompt-content-filter",
|
|
1568
1583
|
"prompt-context-length",
|
|
1584
|
+
"prompt-output-truncated",
|
|
1585
|
+
"budget-exhausted",
|
|
1569
1586
|
"prompt-validation",
|
|
1570
1587
|
"prompt-connection",
|
|
1571
1588
|
"prompt-server",
|
|
@@ -3975,8 +3992,15 @@ var KNOWN_CONFIG_KEYS_BY_PATH = new Map([
|
|
|
3975
3992
|
["graph.worktrees", ["enabled"]],
|
|
3976
3993
|
["lifecycle", ["root", "retention"]],
|
|
3977
3994
|
["lifecycle.retention", ["maxTerminalRuns", "maxAgeDays", "maxBytes"]],
|
|
3978
|
-
[
|
|
3995
|
+
[
|
|
3996
|
+
"orchestrator",
|
|
3997
|
+
["roles", "primary", "maxRetries", "maxModelsPerNode", "taskBudget"]
|
|
3998
|
+
],
|
|
3979
3999
|
["orchestrator.primary", ["executionMode", "model", "fallbacks"]],
|
|
4000
|
+
[
|
|
4001
|
+
"orchestrator.taskBudget",
|
|
4002
|
+
["maxBatches", "maxAttempts", "maxDurationMs", "maxDepth"]
|
|
4003
|
+
],
|
|
3980
4004
|
["orchestrator.primary.fallbacks[]", MODEL_REF_KEYS]
|
|
3981
4005
|
]);
|
|
3982
4006
|
function isUnrecognizedKeysIssue(issue) {
|
|
@@ -4251,15 +4275,29 @@ var MessageEventSchema = EventBaseSchema.extend({
|
|
|
4251
4275
|
tokensReasoning: z11.number().int().min(0),
|
|
4252
4276
|
tokensCacheRead: z11.number().int().min(0),
|
|
4253
4277
|
tokensCacheWrite: z11.number().int().min(0),
|
|
4254
|
-
durationMs: z11.number().int().min(0)
|
|
4278
|
+
durationMs: z11.number().int().min(0),
|
|
4279
|
+
usageStatus: z11.enum(["reported", "missing", "zero-unverified"]).optional(),
|
|
4280
|
+
costStatus: z11.enum(["reported", "unavailable"]).optional(),
|
|
4281
|
+
finish: z11.enum([
|
|
4282
|
+
"stop",
|
|
4283
|
+
"length",
|
|
4284
|
+
"tool-calls",
|
|
4285
|
+
"content-filter",
|
|
4286
|
+
"error",
|
|
4287
|
+
"unknown"
|
|
4288
|
+
]).optional(),
|
|
4289
|
+
truncatedToolCall: z11.boolean().optional()
|
|
4255
4290
|
});
|
|
4256
4291
|
var ToolcallEventSchema = EventBaseSchema.extend({
|
|
4257
4292
|
type: z11.literal("toolcall"),
|
|
4258
4293
|
tool: z11.string().min(1),
|
|
4259
4294
|
callID: z11.string().min(1),
|
|
4260
4295
|
agent: z11.string().min(1).optional(),
|
|
4261
|
-
durationMs: z11.number().int().min(0),
|
|
4296
|
+
durationMs: z11.number().int().min(0).nullable(),
|
|
4262
4297
|
ok: z11.boolean(),
|
|
4298
|
+
executed: z11.boolean().optional(),
|
|
4299
|
+
providerExecuted: z11.boolean().optional(),
|
|
4300
|
+
failureKind: z11.enum(["input-invalid", "execution", "unknown"]).optional(),
|
|
4263
4301
|
title: z11.string().optional()
|
|
4264
4302
|
});
|
|
4265
4303
|
var MeetingEventSchema = EventBaseSchema.extend({
|
|
@@ -4289,7 +4327,15 @@ var ActivityEventSchema = EventBaseSchema.extend({
|
|
|
4289
4327
|
type: z11.literal("activity"),
|
|
4290
4328
|
kind: z11.enum(["route", "agent", "decision", "commit"]),
|
|
4291
4329
|
agent: z11.string().min(1).optional(),
|
|
4292
|
-
summary: z11.string().min(1)
|
|
4330
|
+
summary: z11.string().min(1),
|
|
4331
|
+
phase: z11.enum([
|
|
4332
|
+
"model-request",
|
|
4333
|
+
"tool-input",
|
|
4334
|
+
"tool-execution",
|
|
4335
|
+
"report-validation",
|
|
4336
|
+
"idle",
|
|
4337
|
+
"unknown"
|
|
4338
|
+
]).optional()
|
|
4293
4339
|
});
|
|
4294
4340
|
var SessionEndpointEventSchema = EventBaseSchema.extend({
|
|
4295
4341
|
type: z11.literal("session-endpoint"),
|
|
@@ -5298,7 +5344,15 @@ function buildOrchestratorAgent(model, options = {}) {
|
|
|
5298
5344
|
" `title` is optional and only for readability.",
|
|
5299
5345
|
"- `parentSessionID` (optional): the current session, so that the subsessions",
|
|
5300
5346
|
" link as children.",
|
|
5301
|
-
"- `directory` (optional):
|
|
5347
|
+
"- `directory` (optional): omit it to use the trusted host workspace. A different",
|
|
5348
|
+
" directory is rejected; this argument cannot authorize another workspace.",
|
|
5349
|
+
"",
|
|
5350
|
+
"Related and nested batches share a cumulative task budget, not a fresh allowance",
|
|
5351
|
+
"per call. On `task-budget-exhausted`, stop delegation and summarize preserved",
|
|
5352
|
+
"work and remaining tasks. Never create another batch/session or edit effort",
|
|
5353
|
+
"state to reset that allowance. Only a genuinely new root user turn starts a new task.",
|
|
5354
|
+
"Workers should use `openteam-submit-report` for their assigned report, retaining",
|
|
5355
|
+
"operator permission checks. Do not broaden file or shell permissions to deliver it.",
|
|
5302
5356
|
"",
|
|
5303
5357
|
"The tool returns a per-role summary: selected model, success or",
|
|
5304
5358
|
"failure, the created session, and — for each role — a `report` file path",
|
|
@@ -5760,7 +5814,7 @@ import { z as z15 } from "zod";
|
|
|
5760
5814
|
// package.json
|
|
5761
5815
|
var package_default = {
|
|
5762
5816
|
name: "@jmanuelcorral/openteam",
|
|
5763
|
-
version: "0.
|
|
5817
|
+
version: "0.28.0",
|
|
5764
5818
|
packageManager: "bun@1.3.14",
|
|
5765
5819
|
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
5766
5820
|
license: "MIT",
|
|
@@ -8679,6 +8733,7 @@ var lifecycleFailureSchema = z18.object({
|
|
|
8679
8733
|
"prompt-auth",
|
|
8680
8734
|
"prompt-content-filter",
|
|
8681
8735
|
"prompt-context-length",
|
|
8736
|
+
"prompt-output-truncated",
|
|
8682
8737
|
"prompt-validation",
|
|
8683
8738
|
"prompt-connection",
|
|
8684
8739
|
"prompt-server",
|
|
@@ -9730,17 +9785,31 @@ function createRuntimeConcurrencyLimiter(options) {
|
|
|
9730
9785
|
}
|
|
9731
9786
|
return {
|
|
9732
9787
|
tryAcquire,
|
|
9733
|
-
acquire(runtimeId, priority = "worker") {
|
|
9788
|
+
async acquire(runtimeId, priority = "worker", signal) {
|
|
9789
|
+
signal?.throwIfAborted();
|
|
9734
9790
|
const immediate = tryAcquire(runtimeId, priority);
|
|
9735
9791
|
if (immediate !== undefined) {
|
|
9736
9792
|
return Promise.resolve({ release: immediate, waitedMs: 0 });
|
|
9737
9793
|
}
|
|
9738
9794
|
const state = stateFor(runtimeId);
|
|
9739
9795
|
const queuedAt = options.now();
|
|
9740
|
-
return new Promise((resolve5) => {
|
|
9741
|
-
|
|
9796
|
+
return new Promise((resolve5, reject) => {
|
|
9797
|
+
const waiter = (release) => {
|
|
9798
|
+
signal?.removeEventListener("abort", cancel);
|
|
9742
9799
|
resolve5({ release, waitedMs: options.now() - queuedAt });
|
|
9743
|
-
}
|
|
9800
|
+
};
|
|
9801
|
+
function cancel() {
|
|
9802
|
+
const index = state.queues[priority].indexOf(waiter);
|
|
9803
|
+
if (index < 0)
|
|
9804
|
+
return;
|
|
9805
|
+
state.queues[priority].splice(index, 1);
|
|
9806
|
+
signal?.removeEventListener("abort", cancel);
|
|
9807
|
+
reject(signal?.reason);
|
|
9808
|
+
}
|
|
9809
|
+
state.queues[priority].push(waiter);
|
|
9810
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
9811
|
+
if (signal?.aborted)
|
|
9812
|
+
cancel();
|
|
9744
9813
|
});
|
|
9745
9814
|
},
|
|
9746
9815
|
activeCount(runtimeId) {
|
|
@@ -11078,6 +11147,32 @@ function withReportedModelSlots(runtime, reported, aliases) {
|
|
|
11078
11147
|
}
|
|
11079
11148
|
|
|
11080
11149
|
// src/messages/orchestration.ts
|
|
11150
|
+
var reportDeliveryMessages = {
|
|
11151
|
+
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.",
|
|
11152
|
+
status: "Whether the assigned work is done or needs another bounded pass.",
|
|
11153
|
+
findings: "Concrete findings, changes, evidence and remaining work; at most 32768 characters.",
|
|
11154
|
+
assignmentConflict: "A report assignment is already active for this session.",
|
|
11155
|
+
noAssignment: "No active coordinator-owned report assignment exists for this session.",
|
|
11156
|
+
invalidReport: "Report delivery requires substantive findings and a valid done/continue status within 32768 characters.",
|
|
11157
|
+
unsafePath: "The private artifact path is unavailable, linked or outside the allowed boundary.",
|
|
11158
|
+
workspaceMismatch: "Orchestration directory must match the trusted host workspace; a model-authored directory cannot change report or session scope.",
|
|
11159
|
+
submitted: (path2) => `Report persisted at ${path2}. The coordinator will independently validate current, substantive completion.`
|
|
11160
|
+
};
|
|
11161
|
+
var taskEffortMessages = {
|
|
11162
|
+
cancelled: "Task execution was cancelled; no replacement attempt was dispatched.",
|
|
11163
|
+
createDeadline: "task-budget-exhausted: duration. Session creation did not settle before the deadline; no prompt was dispatched and retry is disabled.",
|
|
11164
|
+
ledgerInvalid: "The cumulative task-effort ledger is invalid or unavailable; orchestration is stopped rather than resetting its allowance.",
|
|
11165
|
+
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.`,
|
|
11166
|
+
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.`
|
|
11167
|
+
};
|
|
11168
|
+
var executionPhaseMessages = {
|
|
11169
|
+
"model-request": "Model request",
|
|
11170
|
+
"tool-input": "Preparing tool input",
|
|
11171
|
+
"tool-execution": "Executing a tool",
|
|
11172
|
+
"report-validation": "Validating durable report",
|
|
11173
|
+
idle: "Session idle",
|
|
11174
|
+
unknown: "Session phase unavailable"
|
|
11175
|
+
};
|
|
11081
11176
|
var HOST_SESSION_REQUIRED = "Orchestration requires a nonempty host ToolContext sessionID.";
|
|
11082
11177
|
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.";
|
|
11083
11178
|
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.";
|
|
@@ -11148,6 +11243,183 @@ function incapableFixedModel(roleID, providerID, modelID) {
|
|
|
11148
11243
|
return `openteam coordinator: request for role "${roleID}" blocked — ` + `execution-policy-model-incapable. Configured model "${providerID}/${modelID}" ` + `does not satisfy the role capability requirements.`;
|
|
11149
11244
|
}
|
|
11150
11245
|
|
|
11246
|
+
// src/orchestrator/outputContract.ts
|
|
11247
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
11248
|
+
var ROLE_REPORTS_ROOT = ".opencode/openteam-local/reports";
|
|
11249
|
+
var REPORT_STATUS_MARKER = "openteam-status";
|
|
11250
|
+
var REPORT_STATUS_LINE_PATTERN = /^[ ]{0,3}openteam-status:[ \t]*(.*?)[ \t]*$/i;
|
|
11251
|
+
var FENCE_DELIMITER_PATTERN = /^ {0,3}(`{3,}|~{3,})(.*)$/;
|
|
11252
|
+
function fenceDelimiter(line) {
|
|
11253
|
+
const match = FENCE_DELIMITER_PATTERN.exec(line);
|
|
11254
|
+
const run = match?.[1];
|
|
11255
|
+
if (run === undefined)
|
|
11256
|
+
return;
|
|
11257
|
+
const marker = run.startsWith("`") ? "`" : "~";
|
|
11258
|
+
return {
|
|
11259
|
+
marker,
|
|
11260
|
+
length: run.length,
|
|
11261
|
+
remainder: match?.[2] ?? ""
|
|
11262
|
+
};
|
|
11263
|
+
}
|
|
11264
|
+
function declaredStatus(value) {
|
|
11265
|
+
const normalized = value.toLowerCase();
|
|
11266
|
+
if (normalized === "done")
|
|
11267
|
+
return "done";
|
|
11268
|
+
if (normalized === "continue")
|
|
11269
|
+
return "continue";
|
|
11270
|
+
return "unknown";
|
|
11271
|
+
}
|
|
11272
|
+
function analyzeReport(text) {
|
|
11273
|
+
let status = "unknown";
|
|
11274
|
+
let fence;
|
|
11275
|
+
const bodyLines = [];
|
|
11276
|
+
for (const line of text.split(/\r?\n/)) {
|
|
11277
|
+
const delimiter = fenceDelimiter(line);
|
|
11278
|
+
if (fence !== undefined) {
|
|
11279
|
+
bodyLines.push(line);
|
|
11280
|
+
if (delimiter?.marker === fence.marker && delimiter.length >= fence.length && delimiter.remainder.trim().length === 0) {
|
|
11281
|
+
fence = undefined;
|
|
11282
|
+
}
|
|
11283
|
+
continue;
|
|
11284
|
+
}
|
|
11285
|
+
if (delimiter !== undefined) {
|
|
11286
|
+
fence = delimiter;
|
|
11287
|
+
bodyLines.push(line);
|
|
11288
|
+
continue;
|
|
11289
|
+
}
|
|
11290
|
+
const declaration = REPORT_STATUS_LINE_PATTERN.exec(line);
|
|
11291
|
+
if (declaration !== null) {
|
|
11292
|
+
status = declaredStatus(declaration[1] ?? "");
|
|
11293
|
+
continue;
|
|
11294
|
+
}
|
|
11295
|
+
bodyLines.push(line);
|
|
11296
|
+
}
|
|
11297
|
+
return {
|
|
11298
|
+
status,
|
|
11299
|
+
body: bodyLines.join(`
|
|
11300
|
+
`).trim()
|
|
11301
|
+
};
|
|
11302
|
+
}
|
|
11303
|
+
function parseReportStatus(text) {
|
|
11304
|
+
if (text === undefined || text.length === 0)
|
|
11305
|
+
return "unknown";
|
|
11306
|
+
return analyzeReport(text).status;
|
|
11307
|
+
}
|
|
11308
|
+
var MIN_REPORT_BODY_CHARS = 40;
|
|
11309
|
+
var MAX_REPORT_SEGMENT_CHARS = 64;
|
|
11310
|
+
var REPORT_SEGMENT_HASH_CHARS = 24;
|
|
11311
|
+
var SAFE_REPORT_SEGMENT = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62}[A-Za-z0-9_-])?$/;
|
|
11312
|
+
var WINDOWS_DEVICE_NAME = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i;
|
|
11313
|
+
function reportSegmentHash(value) {
|
|
11314
|
+
return createHash3("sha256").update(value, "utf8").digest("hex").slice(0, REPORT_SEGMENT_HASH_CHARS);
|
|
11315
|
+
}
|
|
11316
|
+
function reportPathSegment(value) {
|
|
11317
|
+
if (value.length <= MAX_REPORT_SEGMENT_CHARS && SAFE_REPORT_SEGMENT.test(value) && value === value.toLowerCase() && !WINDOWS_DEVICE_NAME.test(value)) {
|
|
11318
|
+
return value;
|
|
11319
|
+
}
|
|
11320
|
+
const suffix = `~${reportSegmentHash(value)}`;
|
|
11321
|
+
const maxPrefixChars = MAX_REPORT_SEGMENT_CHARS - suffix.length;
|
|
11322
|
+
let prefix = value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[^A-Za-z0-9]+/, "").slice(0, maxPrefixChars).replace(/[.]+$/, "");
|
|
11323
|
+
if (prefix.length === 0) {
|
|
11324
|
+
prefix = "segment";
|
|
11325
|
+
}
|
|
11326
|
+
if (WINDOWS_DEVICE_NAME.test(prefix)) {
|
|
11327
|
+
prefix = `safe-${prefix}`.slice(0, maxPrefixChars).replace(/[.]+$/, "");
|
|
11328
|
+
}
|
|
11329
|
+
return `${prefix}${suffix}`;
|
|
11330
|
+
}
|
|
11331
|
+
function reportHasSubstance(text) {
|
|
11332
|
+
if (text === undefined)
|
|
11333
|
+
return false;
|
|
11334
|
+
return analyzeReport(text).body.length >= MIN_REPORT_BODY_CHARS;
|
|
11335
|
+
}
|
|
11336
|
+
function roleReportPath(batchID, roleID) {
|
|
11337
|
+
return `${ROLE_REPORTS_ROOT}/${reportPathSegment(batchID)}/${reportPathSegment(roleID)}.md`;
|
|
11338
|
+
}
|
|
11339
|
+
function outputContractInstruction(reportPath, structuredReport) {
|
|
11340
|
+
return [
|
|
11341
|
+
"## Output contract (openteam)",
|
|
11342
|
+
"",
|
|
11343
|
+
...structuredReport ? [
|
|
11344
|
+
"Prefer `openteam-submit-report` with substantive `findings` and `status`",
|
|
11345
|
+
"(`done` or `continue`): openteam persists only your assigned report and",
|
|
11346
|
+
"confirms the write. Keep submissions concise; split large work into small",
|
|
11347
|
+
"tool calls. If that tool is unavailable, write your complete findings"
|
|
11348
|
+
] : ["Write your complete findings"],
|
|
11349
|
+
"to the report file below using the `write`",
|
|
11350
|
+
"tool (create parent directories as needed), and keep it updated with",
|
|
11351
|
+
"`edit` as you progress. This file is the ONLY channel your work reaches",
|
|
11352
|
+
"the coordinator: anything you do not write there is discarded and lost,",
|
|
11353
|
+
"and the coordinator will have no record of it.",
|
|
11354
|
+
"",
|
|
11355
|
+
`Report file: ${reportPath}`,
|
|
11356
|
+
"",
|
|
11357
|
+
"Requirements:",
|
|
11358
|
+
"- Write the ACTUAL results — what you found, what you changed, concrete",
|
|
11359
|
+
" conclusions, and any risks or follow-ups — never a promise to do the",
|
|
11360
|
+
" work later.",
|
|
11361
|
+
"- Make it self-contained: the coordinator reads only this file, not your",
|
|
11362
|
+
" session transcript.",
|
|
11363
|
+
"- If you could not complete the task, write what you attempted and why it",
|
|
11364
|
+
" is blocked, so the coordinator can report the truth.",
|
|
11365
|
+
"- If the report file already exists from a previous pass, read it first and",
|
|
11366
|
+
" continue from where it left off rather than starting over.",
|
|
11367
|
+
"",
|
|
11368
|
+
"Completion status (REQUIRED — this is how the coordinator knows to stop):",
|
|
11369
|
+
"On its own line in the report, declare your status EXACTLY as one of:",
|
|
11370
|
+
`${REPORT_STATUS_MARKER}: done`,
|
|
11371
|
+
" The task is fully complete; no further passes are needed.",
|
|
11372
|
+
`${REPORT_STATUS_MARKER}: continue`,
|
|
11373
|
+
" You have more work to do and will be run again.",
|
|
11374
|
+
"The marker line must contain nothing else.",
|
|
11375
|
+
"If you omit this line or write anything else, the coordinator treats the",
|
|
11376
|
+
"task as NOT complete and runs you again, up to the configured retry bound."
|
|
11377
|
+
].join(`
|
|
11378
|
+
`);
|
|
11379
|
+
}
|
|
11380
|
+
function composeSubsessionPrompt(input) {
|
|
11381
|
+
const reportPath = roleReportPath(input.batchID, input.roleID);
|
|
11382
|
+
const handoff = input.handoff ? [
|
|
11383
|
+
"",
|
|
11384
|
+
"## Model handoff",
|
|
11385
|
+
"",
|
|
11386
|
+
"Continue the SAME node and original goal. Read the existing report first,",
|
|
11387
|
+
"preserve useful prior findings, and complete the remaining work instead of",
|
|
11388
|
+
"starting a new batch or replacing the objective."
|
|
11389
|
+
].join(`
|
|
11390
|
+
`) : "";
|
|
11391
|
+
return {
|
|
11392
|
+
prompt: `${input.prompt}${handoff}${input.truncated !== true ? "" : [
|
|
11393
|
+
"",
|
|
11394
|
+
"",
|
|
11395
|
+
"## Truncated tool-call recovery",
|
|
11396
|
+
"",
|
|
11397
|
+
"The previous response ended at the output limit and a tool call was invalid",
|
|
11398
|
+
"before execution. Use smaller, bounded tool calls and concise findings.",
|
|
11399
|
+
"Inspect the existing workspace and assigned report before continuing.",
|
|
11400
|
+
"Never repair and execute the malformed JSON. Produce a fresh, complete",
|
|
11401
|
+
"call only for work that is still necessary. Do not increase model limits",
|
|
11402
|
+
"or change the execution domain. This continuation uses the same pass budget."
|
|
11403
|
+
].join(`
|
|
11404
|
+
`)}${input.repair === undefined ? "" : [
|
|
11405
|
+
"",
|
|
11406
|
+
"",
|
|
11407
|
+
"## Report delivery repair",
|
|
11408
|
+
"",
|
|
11409
|
+
`Previous pass did not prove completion: ${input.repair}.`,
|
|
11410
|
+
"Continue the SAME goal and existing workspace, not a new orchestration.",
|
|
11411
|
+
"Read the assigned report and inspect the existing work first. Do not redo",
|
|
11412
|
+
"completed implementation merely because its delivery failed. Persist the",
|
|
11413
|
+
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.",
|
|
11414
|
+
"This repair consumes the existing node pass allowance."
|
|
11415
|
+
].join(`
|
|
11416
|
+
`)}
|
|
11417
|
+
|
|
11418
|
+
${outputContractInstruction(reportPath, input.structuredReport !== false)}`,
|
|
11419
|
+
reportPath
|
|
11420
|
+
};
|
|
11421
|
+
}
|
|
11422
|
+
|
|
11151
11423
|
// src/orchestrator/reportArtifactProbe.ts
|
|
11152
11424
|
import { stat as stat2 } from "node:fs/promises";
|
|
11153
11425
|
var reportArtifactExists = async (reportPath) => {
|
|
@@ -11169,15 +11441,76 @@ var readReportArtifact = async (reportPath) => {
|
|
|
11169
11441
|
}
|
|
11170
11442
|
};
|
|
11171
11443
|
|
|
11172
|
-
// src/orchestrator/
|
|
11444
|
+
// src/orchestrator/reportDelivery.ts
|
|
11173
11445
|
import { z as z20 } from "zod";
|
|
11174
|
-
var
|
|
11175
|
-
|
|
11176
|
-
|
|
11446
|
+
var Submission = z20.object({
|
|
11447
|
+
status: z20.enum(["done", "continue"]),
|
|
11448
|
+
findings: z20.string().min(1).max(32768)
|
|
11449
|
+
}).strict();
|
|
11450
|
+
function createReportDelivery(deps) {
|
|
11451
|
+
const active = new Map;
|
|
11452
|
+
return {
|
|
11453
|
+
open(sessionID, batchID, roleID) {
|
|
11454
|
+
if (active.has(sessionID))
|
|
11455
|
+
throw new Error(reportDeliveryMessages.assignmentConflict);
|
|
11456
|
+
const lease = {
|
|
11457
|
+
path: roleReportPath(batchID, roleID),
|
|
11458
|
+
open: true,
|
|
11459
|
+
submitted: false,
|
|
11460
|
+
pending: Promise.resolve()
|
|
11461
|
+
};
|
|
11462
|
+
active.set(sessionID, lease);
|
|
11463
|
+
return {
|
|
11464
|
+
async close() {
|
|
11465
|
+
lease.open = false;
|
|
11466
|
+
await lease.pending;
|
|
11467
|
+
if (active.get(sessionID) === lease)
|
|
11468
|
+
active.delete(sessionID);
|
|
11469
|
+
return lease.submitted;
|
|
11470
|
+
}
|
|
11471
|
+
};
|
|
11472
|
+
},
|
|
11473
|
+
path(sessionID) {
|
|
11474
|
+
const lease = active.get(sessionID);
|
|
11475
|
+
if (lease?.open !== true)
|
|
11476
|
+
throw new Error(reportDeliveryMessages.noAssignment);
|
|
11477
|
+
return lease.path;
|
|
11478
|
+
},
|
|
11479
|
+
async submit(sessionID, input) {
|
|
11480
|
+
const payload = Submission.safeParse(input);
|
|
11481
|
+
if (!payload.success || !reportHasSubstance(payload.data.findings))
|
|
11482
|
+
throw new Error(reportDeliveryMessages.invalidReport);
|
|
11483
|
+
const lease = active.get(sessionID);
|
|
11484
|
+
if (lease?.open !== true)
|
|
11485
|
+
throw new Error(reportDeliveryMessages.noAssignment);
|
|
11486
|
+
const content = `${payload.data.findings.trim()}
|
|
11487
|
+
|
|
11488
|
+
openteam-status: ${payload.data.status}
|
|
11489
|
+
`;
|
|
11490
|
+
if (parseReportStatus(content) !== payload.data.status)
|
|
11491
|
+
throw new Error(reportDeliveryMessages.invalidReport);
|
|
11492
|
+
const write = lease.pending.then(async () => {
|
|
11493
|
+
if (!lease.open)
|
|
11494
|
+
throw new Error(reportDeliveryMessages.noAssignment);
|
|
11495
|
+
await deps.write(lease.path, content);
|
|
11496
|
+
lease.submitted = true;
|
|
11497
|
+
});
|
|
11498
|
+
lease.pending = write.then(() => {}, () => {});
|
|
11499
|
+
await write;
|
|
11500
|
+
return lease.path;
|
|
11501
|
+
}
|
|
11502
|
+
};
|
|
11503
|
+
}
|
|
11504
|
+
|
|
11505
|
+
// src/orchestrator/roster.ts
|
|
11506
|
+
import { z as z21 } from "zod";
|
|
11507
|
+
var RosterEntrySchema = z21.object({
|
|
11508
|
+
roleID: z21.string().min(1),
|
|
11509
|
+
agentName: z21.string().min(1)
|
|
11177
11510
|
}).strict();
|
|
11178
|
-
var RosterSchema =
|
|
11179
|
-
universe:
|
|
11180
|
-
entries:
|
|
11511
|
+
var RosterSchema = z21.object({
|
|
11512
|
+
universe: z21.string().min(1),
|
|
11513
|
+
entries: z21.array(RosterEntrySchema)
|
|
11181
11514
|
}).strict();
|
|
11182
11515
|
var ROSTER_JSON_FENCE = /```json\s*([\s\S]*?)```/;
|
|
11183
11516
|
|
|
@@ -11585,15 +11918,21 @@ function promptArgs(sessionID, req, signal) {
|
|
|
11585
11918
|
}
|
|
11586
11919
|
return args;
|
|
11587
11920
|
}
|
|
11588
|
-
async function withTimeout(promise, timeoutMs) {
|
|
11589
|
-
if (timeoutMs === undefined) {
|
|
11921
|
+
async function withTimeout(promise, timeoutMs, signal) {
|
|
11922
|
+
if (timeoutMs === undefined && signal === undefined) {
|
|
11590
11923
|
return { kind: "settled", value: await promise };
|
|
11591
11924
|
}
|
|
11592
11925
|
let timeoutID;
|
|
11926
|
+
let abortListener;
|
|
11593
11927
|
const timeout = new Promise((resolve5) => {
|
|
11594
|
-
|
|
11595
|
-
|
|
11596
|
-
|
|
11928
|
+
if (timeoutMs !== undefined)
|
|
11929
|
+
timeoutID = setTimeout(() => {
|
|
11930
|
+
resolve5({ kind: "timeout" });
|
|
11931
|
+
}, timeoutMs);
|
|
11932
|
+
abortListener = () => resolve5({ kind: "aborted" });
|
|
11933
|
+
signal?.addEventListener("abort", abortListener, { once: true });
|
|
11934
|
+
if (signal?.aborted)
|
|
11935
|
+
abortListener();
|
|
11597
11936
|
});
|
|
11598
11937
|
try {
|
|
11599
11938
|
return await Promise.race([
|
|
@@ -11602,6 +11941,8 @@ async function withTimeout(promise, timeoutMs) {
|
|
|
11602
11941
|
]);
|
|
11603
11942
|
} finally {
|
|
11604
11943
|
clearTimeout(timeoutID);
|
|
11944
|
+
if (abortListener !== undefined)
|
|
11945
|
+
signal?.removeEventListener("abort", abortListener);
|
|
11605
11946
|
}
|
|
11606
11947
|
}
|
|
11607
11948
|
async function beforeDeadline(request, deadline, deps) {
|
|
@@ -11723,7 +12064,35 @@ async function confirmPromptRequestSettled(isSettled, deps, deadline) {
|
|
|
11723
12064
|
async function runSubsession(client, req, deps) {
|
|
11724
12065
|
let sessionID;
|
|
11725
12066
|
try {
|
|
11726
|
-
|
|
12067
|
+
deps.signal?.throwIfAborted();
|
|
12068
|
+
const createController = new AbortController;
|
|
12069
|
+
const createSignal = deps.signal === undefined ? createController.signal : AbortSignal.any([deps.signal, createController.signal]);
|
|
12070
|
+
const remaining = deps.deadlineAt === undefined ? undefined : Math.max(0, deps.deadlineAt - deps.now());
|
|
12071
|
+
if (remaining === 0)
|
|
12072
|
+
return {
|
|
12073
|
+
success: false,
|
|
12074
|
+
roleID: req.roleID,
|
|
12075
|
+
model: req.model,
|
|
12076
|
+
failureStage: "create",
|
|
12077
|
+
failureReason: taskEffortMessages.createDeadline,
|
|
12078
|
+
retrySafe: false
|
|
12079
|
+
};
|
|
12080
|
+
const createOutcome = await withTimeout(req.existingSessionID === undefined ? client.session.create(remaining === undefined && deps.signal === undefined ? createArgs(req) : { ...createArgs(req), signal: createSignal }) : Promise.resolve({
|
|
12081
|
+
data: { id: req.existingSessionID },
|
|
12082
|
+
error: undefined
|
|
12083
|
+
}), remaining, deps.signal);
|
|
12084
|
+
if (createOutcome.kind !== "settled") {
|
|
12085
|
+
createController.abort();
|
|
12086
|
+
return {
|
|
12087
|
+
success: false,
|
|
12088
|
+
roleID: req.roleID,
|
|
12089
|
+
model: req.model,
|
|
12090
|
+
failureStage: "create",
|
|
12091
|
+
failureReason: createOutcome.kind === "timeout" ? taskEffortMessages.createDeadline : taskEffortMessages.cancelled,
|
|
12092
|
+
retrySafe: false
|
|
12093
|
+
};
|
|
12094
|
+
}
|
|
12095
|
+
const created = createOutcome.value;
|
|
11727
12096
|
if (created.error !== undefined) {
|
|
11728
12097
|
const normalizedFailure = isNormalizedSessionFailure(created.error) ? created.error : undefined;
|
|
11729
12098
|
return {
|
|
@@ -11750,19 +12119,32 @@ async function runSubsession(client, req, deps) {
|
|
|
11750
12119
|
try {
|
|
11751
12120
|
await deps.onSessionCreated?.(sessionID);
|
|
11752
12121
|
} catch {}
|
|
12122
|
+
await deps.prepareSession?.(sessionID);
|
|
12123
|
+
deps.signal?.throwIfAborted();
|
|
12124
|
+
if (deps.deadlineAt !== undefined && deps.now() >= deps.deadlineAt)
|
|
12125
|
+
return {
|
|
12126
|
+
success: false,
|
|
12127
|
+
sessionID,
|
|
12128
|
+
roleID: req.roleID,
|
|
12129
|
+
model: req.model,
|
|
12130
|
+
failureStage: "create",
|
|
12131
|
+
failureReason: taskEffortMessages.createDeadline,
|
|
12132
|
+
retrySafe: false
|
|
12133
|
+
};
|
|
11753
12134
|
} catch (error) {
|
|
11754
12135
|
return {
|
|
11755
12136
|
success: false,
|
|
11756
12137
|
roleID: req.roleID,
|
|
11757
12138
|
model: req.model,
|
|
11758
12139
|
failureStage: "create",
|
|
11759
|
-
failureReason: errorReason(error),
|
|
11760
|
-
retrySafe: true
|
|
12140
|
+
failureReason: deps.signal?.aborted ? taskEffortMessages.cancelled : errorReason(error),
|
|
12141
|
+
retrySafe: deps.signal?.aborted !== true
|
|
11761
12142
|
};
|
|
11762
12143
|
}
|
|
11763
12144
|
const promptController = new AbortController;
|
|
12145
|
+
const promptSignal = deps.signal === undefined ? promptController.signal : AbortSignal.any([deps.signal, promptController.signal]);
|
|
11764
12146
|
let promptSettled = false;
|
|
11765
|
-
const promptPromise = client.session.prompt(promptArgs(sessionID, req,
|
|
12147
|
+
const promptPromise = client.session.prompt(promptArgs(sessionID, req, promptSignal)).then((value) => {
|
|
11766
12148
|
promptSettled = true;
|
|
11767
12149
|
return value;
|
|
11768
12150
|
}, (error) => {
|
|
@@ -11770,8 +12152,9 @@ async function runSubsession(client, req, deps) {
|
|
|
11770
12152
|
throw error;
|
|
11771
12153
|
});
|
|
11772
12154
|
try {
|
|
11773
|
-
const
|
|
11774
|
-
|
|
12155
|
+
const timeoutMs = deps.deadlineAt === undefined ? deps.timeoutMs : Math.min(deps.timeoutMs ?? Infinity, Math.max(0, deps.deadlineAt - deps.now()));
|
|
12156
|
+
const outcome = await withTimeout(promptPromise, timeoutMs, deps.signal);
|
|
12157
|
+
if (outcome.kind !== "settled") {
|
|
11775
12158
|
promptController.abort();
|
|
11776
12159
|
const stopDeadline = deps.now() + Math.max(0, deps.abortGraceMs);
|
|
11777
12160
|
const stopped = await confirmSessionStopped(client, sessionID, req.directory, deps, stopDeadline);
|
|
@@ -11782,8 +12165,8 @@ async function runSubsession(client, req, deps) {
|
|
|
11782
12165
|
roleID: req.roleID,
|
|
11783
12166
|
model: req.model,
|
|
11784
12167
|
failureStage: "prompt",
|
|
11785
|
-
failureReason: !stopped.confirmed ? promptStopUnconfirmed(stopped.cause) : requestSettled ? promptTimedOut(deps.timeoutMs ?? 0) : promptStopUnconfirmed("request-unsettled"),
|
|
11786
|
-
retrySafe: stopped.confirmed && requestSettled
|
|
12168
|
+
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"),
|
|
12169
|
+
retrySafe: stopped.confirmed && requestSettled && outcome.kind !== "aborted" && (deps.deadlineAt === undefined || deps.now() < deps.deadlineAt)
|
|
11787
12170
|
};
|
|
11788
12171
|
}
|
|
11789
12172
|
const prompted = outcome.value;
|
|
@@ -11816,12 +12199,137 @@ async function runSubsession(client, req, deps) {
|
|
|
11816
12199
|
roleID: req.roleID,
|
|
11817
12200
|
model: req.model,
|
|
11818
12201
|
failureStage: "prompt",
|
|
11819
|
-
failureReason: stopped.confirmed ? errorReason(error) : promptStopUnconfirmed(stopped.cause),
|
|
11820
|
-
retrySafe: stopped.confirmed
|
|
12202
|
+
failureReason: stopped.confirmed ? deps.signal?.aborted ? taskEffortMessages.cancelled : errorReason(error) : promptStopUnconfirmed(stopped.cause),
|
|
12203
|
+
retrySafe: stopped.confirmed && deps.signal?.aborted !== true
|
|
11821
12204
|
};
|
|
11822
12205
|
}
|
|
11823
12206
|
}
|
|
11824
12207
|
|
|
12208
|
+
// src/orchestrator/taskEffort.ts
|
|
12209
|
+
import { z as z22 } from "zod";
|
|
12210
|
+
var Binding = z22.object({
|
|
12211
|
+
taskID: z22.string().regex(/^[a-f0-9]{64}$/),
|
|
12212
|
+
depth: z22.number().int().min(0).max(128),
|
|
12213
|
+
worker: z22.boolean()
|
|
12214
|
+
}).strict();
|
|
12215
|
+
var Record = z22.object({
|
|
12216
|
+
v: z22.literal(1),
|
|
12217
|
+
startedAt: z22.number().finite(),
|
|
12218
|
+
batches: z22.number().int().min(0),
|
|
12219
|
+
attempts: z22.number().int().min(0),
|
|
12220
|
+
maxBatches: z22.number().int().positive(),
|
|
12221
|
+
maxAttempts: z22.number().int().positive(),
|
|
12222
|
+
maxDurationMs: z22.number().int().positive(),
|
|
12223
|
+
maxDepth: z22.number().int().min(0)
|
|
12224
|
+
}).strict();
|
|
12225
|
+
function decode(schema, raw) {
|
|
12226
|
+
let value;
|
|
12227
|
+
try {
|
|
12228
|
+
value = JSON.parse(raw ?? "null");
|
|
12229
|
+
} catch {
|
|
12230
|
+
throw new Error(taskEffortMessages.ledgerInvalid);
|
|
12231
|
+
}
|
|
12232
|
+
const parsed = schema.safeParse(value);
|
|
12233
|
+
if (!parsed.success)
|
|
12234
|
+
throw new Error(taskEffortMessages.ledgerInvalid);
|
|
12235
|
+
return parsed.data;
|
|
12236
|
+
}
|
|
12237
|
+
function createTaskEffort(deps) {
|
|
12238
|
+
const limits = {
|
|
12239
|
+
maxBatches: deps.limits?.maxBatches ?? 8,
|
|
12240
|
+
maxAttempts: deps.limits?.maxAttempts ?? 32,
|
|
12241
|
+
maxDurationMs: deps.limits?.maxDurationMs ?? 7200000,
|
|
12242
|
+
maxDepth: deps.limits?.maxDepth ?? 3
|
|
12243
|
+
};
|
|
12244
|
+
const bindingPath = (sessionID) => `sessions/${sha256Hex(sessionID)}.json`;
|
|
12245
|
+
const taskPath = (taskID) => `tasks/${taskID}.json`;
|
|
12246
|
+
function initialize(sessionID, messageID) {
|
|
12247
|
+
const taskID = sha256Hex(`${sessionID}\x00${messageID}`);
|
|
12248
|
+
deps.store.update(taskPath(taskID), (previous) => {
|
|
12249
|
+
if (previous !== undefined) {
|
|
12250
|
+
decode(Record, previous);
|
|
12251
|
+
return previous;
|
|
12252
|
+
}
|
|
12253
|
+
return JSON.stringify({
|
|
12254
|
+
v: 1,
|
|
12255
|
+
startedAt: deps.now(),
|
|
12256
|
+
batches: 0,
|
|
12257
|
+
attempts: 0,
|
|
12258
|
+
...limits
|
|
12259
|
+
});
|
|
12260
|
+
});
|
|
12261
|
+
const binding = { taskID, depth: 0, worker: false };
|
|
12262
|
+
deps.store.write(bindingPath(sessionID), JSON.stringify(binding));
|
|
12263
|
+
return binding;
|
|
12264
|
+
}
|
|
12265
|
+
function bindChild(parent, sessionID) {
|
|
12266
|
+
if (parent.depth >= 128)
|
|
12267
|
+
throw new Error(taskEffortMessages.ledgerInvalid);
|
|
12268
|
+
deps.store.write(bindingPath(sessionID), JSON.stringify({
|
|
12269
|
+
taskID: parent.taskID,
|
|
12270
|
+
depth: parent.depth + 1,
|
|
12271
|
+
worker: true
|
|
12272
|
+
}));
|
|
12273
|
+
}
|
|
12274
|
+
async function forSession(sessionID, ancestors = new Set) {
|
|
12275
|
+
if (ancestors.has(sessionID) || ancestors.size >= 128)
|
|
12276
|
+
throw new Error(taskEffortMessages.ledgerInvalid);
|
|
12277
|
+
const stored = deps.store.read(bindingPath(sessionID));
|
|
12278
|
+
if (stored !== undefined)
|
|
12279
|
+
return decode(Binding, stored);
|
|
12280
|
+
ancestors.add(sessionID);
|
|
12281
|
+
const parentID = await deps.parentSession?.(sessionID);
|
|
12282
|
+
if (parentID !== undefined) {
|
|
12283
|
+
const parent = await forSession(parentID, ancestors);
|
|
12284
|
+
bindChild(parent, sessionID);
|
|
12285
|
+
return { taskID: parent.taskID, depth: parent.depth + 1 };
|
|
12286
|
+
}
|
|
12287
|
+
return initialize(sessionID, "restored-session");
|
|
12288
|
+
}
|
|
12289
|
+
function consume(ref, kind) {
|
|
12290
|
+
let result = { ok: false, reason: "duration" };
|
|
12291
|
+
deps.store.update(taskPath(ref.taskID), (raw) => {
|
|
12292
|
+
const record = decode(Record, raw);
|
|
12293
|
+
const remainingMs = Math.min(record.maxDurationMs, limits.maxDurationMs) - Math.max(0, deps.now() - record.startedAt);
|
|
12294
|
+
const reason = ref.depth > Math.min(record.maxDepth, limits.maxDepth) ? "depth" : remainingMs <= 0 ? "duration" : kind === "batches" && record.batches >= Math.min(record.maxBatches, limits.maxBatches) ? "batches" : kind === "attempts" && record.attempts >= Math.min(record.maxAttempts, limits.maxAttempts) ? "attempts" : undefined;
|
|
12295
|
+
if (reason !== undefined)
|
|
12296
|
+
result = { ok: false, reason };
|
|
12297
|
+
else {
|
|
12298
|
+
if (kind !== "check")
|
|
12299
|
+
record[kind] += 1;
|
|
12300
|
+
result = {
|
|
12301
|
+
ok: true,
|
|
12302
|
+
remainingMs,
|
|
12303
|
+
batches: record.batches,
|
|
12304
|
+
attempts: record.attempts,
|
|
12305
|
+
remainingBatches: Math.max(0, Math.min(record.maxBatches, limits.maxBatches) - record.batches),
|
|
12306
|
+
remainingAttempts: Math.max(0, Math.min(record.maxAttempts, limits.maxAttempts) - record.attempts)
|
|
12307
|
+
};
|
|
12308
|
+
}
|
|
12309
|
+
return JSON.stringify(record);
|
|
12310
|
+
});
|
|
12311
|
+
return result;
|
|
12312
|
+
}
|
|
12313
|
+
return {
|
|
12314
|
+
async userTurn(sessionID, messageID) {
|
|
12315
|
+
const stored = deps.store.read(bindingPath(sessionID));
|
|
12316
|
+
if (stored !== undefined && decode(Binding, stored).worker)
|
|
12317
|
+
return;
|
|
12318
|
+
const parentID = await deps.parentSession?.(sessionID);
|
|
12319
|
+
if (parentID !== undefined) {
|
|
12320
|
+
bindChild(await forSession(parentID), sessionID);
|
|
12321
|
+
return;
|
|
12322
|
+
}
|
|
12323
|
+
initialize(sessionID, messageID);
|
|
12324
|
+
},
|
|
12325
|
+
forSession,
|
|
12326
|
+
bindChild,
|
|
12327
|
+
batch: (ref) => consume(ref, "batches"),
|
|
12328
|
+
attempt: (ref) => consume(ref, "attempts"),
|
|
12329
|
+
check: (ref) => consume(ref, "check")
|
|
12330
|
+
};
|
|
12331
|
+
}
|
|
12332
|
+
|
|
11825
12333
|
// src/local/modelResidency.ts
|
|
11826
12334
|
function runtimeRequiresModelResidency(kind) {
|
|
11827
12335
|
return kind === "lemonade" || kind === "llama-swap";
|
|
@@ -12075,7 +12583,7 @@ function createAvailabilityCache(options) {
|
|
|
12075
12583
|
|
|
12076
12584
|
// src/plugin/capture.ts
|
|
12077
12585
|
function nonNeg(value) {
|
|
12078
|
-
return typeof value === "number" && value >= 0 ? Math.trunc(value) : 0;
|
|
12586
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.trunc(value) : 0;
|
|
12079
12587
|
}
|
|
12080
12588
|
function messageEventFrom(info, now) {
|
|
12081
12589
|
if (info.role !== "assistant") {
|
|
@@ -12089,6 +12597,17 @@ function messageEventFrom(info, now) {
|
|
|
12089
12597
|
}
|
|
12090
12598
|
const created = info.time.created ?? info.time.completed;
|
|
12091
12599
|
const durationMs = Math.max(0, Math.trunc(info.time.completed - created));
|
|
12600
|
+
const counters = [info.tokens?.input, info.tokens?.output];
|
|
12601
|
+
const hasUsage = counters.every((value) => typeof value === "number" && Number.isFinite(value) && value >= 0);
|
|
12602
|
+
const zeroUsage = [
|
|
12603
|
+
info.tokens?.input,
|
|
12604
|
+
info.tokens?.output,
|
|
12605
|
+
info.tokens?.reasoning,
|
|
12606
|
+
info.tokens?.cache?.read,
|
|
12607
|
+
info.tokens?.cache?.write
|
|
12608
|
+
].every((value) => value === undefined || value === 0);
|
|
12609
|
+
const usageStatus = !hasUsage ? "missing" : zeroUsage && info.hasGeneratedOutput !== false ? "zero-unverified" : "reported";
|
|
12610
|
+
const hasCost = typeof info.cost === "number" && Number.isFinite(info.cost) && info.cost >= 0;
|
|
12092
12611
|
const event = {
|
|
12093
12612
|
v: EVENT_SCHEMA_VERSION,
|
|
12094
12613
|
type: "message",
|
|
@@ -12096,7 +12615,11 @@ function messageEventFrom(info, now) {
|
|
|
12096
12615
|
sessionID: info.sessionID,
|
|
12097
12616
|
providerID: info.providerID,
|
|
12098
12617
|
modelID: info.modelID,
|
|
12099
|
-
costUSD:
|
|
12618
|
+
costUSD: hasCost ? info.cost ?? 0 : 0,
|
|
12619
|
+
usageStatus,
|
|
12620
|
+
costStatus: hasCost && (info.cost !== 0 || usageStatus === "reported") ? "reported" : "unavailable",
|
|
12621
|
+
...info.finish === undefined ? {} : { finish: finishReason(info.finish) },
|
|
12622
|
+
...info.truncatedToolCall === true ? { truncatedToolCall: true } : {},
|
|
12100
12623
|
tokensIn: nonNeg(info.tokens?.input),
|
|
12101
12624
|
tokensOut: nonNeg(info.tokens?.output),
|
|
12102
12625
|
tokensReasoning: nonNeg(info.tokens?.reasoning),
|
|
@@ -12107,6 +12630,18 @@ function messageEventFrom(info, now) {
|
|
|
12107
12630
|
if (info.mode !== undefined) {
|
|
12108
12631
|
event.mode = info.mode;
|
|
12109
12632
|
}
|
|
12633
|
+
function finishReason(value) {
|
|
12634
|
+
switch (value) {
|
|
12635
|
+
case "stop":
|
|
12636
|
+
case "length":
|
|
12637
|
+
case "tool-calls":
|
|
12638
|
+
case "content-filter":
|
|
12639
|
+
case "error":
|
|
12640
|
+
return value;
|
|
12641
|
+
default:
|
|
12642
|
+
return "unknown";
|
|
12643
|
+
}
|
|
12644
|
+
}
|
|
12110
12645
|
if (info.id !== undefined) {
|
|
12111
12646
|
event.messageID = info.id;
|
|
12112
12647
|
}
|
|
@@ -12235,7 +12770,7 @@ function planWorktreeReconciliation(input) {
|
|
|
12235
12770
|
}
|
|
12236
12771
|
|
|
12237
12772
|
// src/telemetry/otelConfig.ts
|
|
12238
|
-
import { z as
|
|
12773
|
+
import { z as z23 } from "zod";
|
|
12239
12774
|
|
|
12240
12775
|
// src/telemetry/fanout.ts
|
|
12241
12776
|
function createFanOutSink(deps) {
|
|
@@ -12313,10 +12848,10 @@ function createOtelSink(deps) {
|
|
|
12313
12848
|
}
|
|
12314
12849
|
|
|
12315
12850
|
// src/telemetry/otelConfig.ts
|
|
12316
|
-
var OtelBackendConfigSchema =
|
|
12317
|
-
backend:
|
|
12318
|
-
connectionEnv:
|
|
12319
|
-
serviceName:
|
|
12851
|
+
var OtelBackendConfigSchema = z23.object({
|
|
12852
|
+
backend: z23.literal("opentelemetry"),
|
|
12853
|
+
connectionEnv: z23.string().min(1),
|
|
12854
|
+
serviceName: z23.string().min(1).optional()
|
|
12320
12855
|
}).strict();
|
|
12321
12856
|
function parseConnectionString(raw) {
|
|
12322
12857
|
const pairs = new Map;
|
|
@@ -15713,29 +16248,29 @@ import {
|
|
|
15713
16248
|
unlink
|
|
15714
16249
|
} from "node:fs/promises";
|
|
15715
16250
|
import { dirname as dirname5, join as join12, resolve as resolve7 } from "node:path";
|
|
15716
|
-
import { z as
|
|
16251
|
+
import { z as z24 } from "zod";
|
|
15717
16252
|
var CONSOLE_RUNTIME_SCHEMA_VERSION = 1;
|
|
15718
16253
|
var CONSOLE_RUNTIME_DIRECTORY = ".opencode/openteam-local/console";
|
|
15719
16254
|
var CONSOLE_RUNTIME_FILE = "runtime.json";
|
|
15720
16255
|
var CONSOLE_LAUNCH_LOCK_FILE = "launch.lock";
|
|
15721
16256
|
var CONSOLE_LOG_FILE = "console.log";
|
|
15722
|
-
var ConsoleRuntimeStateSchema =
|
|
15723
|
-
schemaVersion:
|
|
15724
|
-
pid:
|
|
15725
|
-
workspaceRoot:
|
|
15726
|
-
host:
|
|
15727
|
-
port:
|
|
15728
|
-
url:
|
|
15729
|
-
startedAt:
|
|
15730
|
-
launchId:
|
|
15731
|
-
logPath:
|
|
16257
|
+
var ConsoleRuntimeStateSchema = z24.object({
|
|
16258
|
+
schemaVersion: z24.literal(CONSOLE_RUNTIME_SCHEMA_VERSION),
|
|
16259
|
+
pid: z24.number().int().positive(),
|
|
16260
|
+
workspaceRoot: z24.string().min(1),
|
|
16261
|
+
host: z24.string().min(1),
|
|
16262
|
+
port: z24.number().int().min(1).max(65535),
|
|
16263
|
+
url: z24.url(),
|
|
16264
|
+
startedAt: z24.iso.datetime({ offset: true }),
|
|
16265
|
+
launchId: z24.uuid(),
|
|
16266
|
+
logPath: z24.string().min(1)
|
|
15732
16267
|
}).strict();
|
|
15733
|
-
var ConsoleLaunchLockSchema =
|
|
15734
|
-
schemaVersion:
|
|
15735
|
-
workspaceRoot:
|
|
15736
|
-
launchId:
|
|
15737
|
-
ownerPid:
|
|
15738
|
-
createdAt:
|
|
16268
|
+
var ConsoleLaunchLockSchema = z24.object({
|
|
16269
|
+
schemaVersion: z24.literal(CONSOLE_RUNTIME_SCHEMA_VERSION),
|
|
16270
|
+
workspaceRoot: z24.string().min(1),
|
|
16271
|
+
launchId: z24.uuid(),
|
|
16272
|
+
ownerPid: z24.number().int().positive(),
|
|
16273
|
+
createdAt: z24.iso.datetime({ offset: true })
|
|
15739
16274
|
}).strict();
|
|
15740
16275
|
|
|
15741
16276
|
class ConsoleRuntimeStateFileError extends Error {
|
|
@@ -16440,36 +16975,36 @@ function formatResponse(response) {
|
|
|
16440
16975
|
}
|
|
16441
16976
|
|
|
16442
16977
|
// src/plugin/reportRunSchema.ts
|
|
16443
|
-
import { z as
|
|
16978
|
+
import { z as z26 } from "zod";
|
|
16444
16979
|
|
|
16445
16980
|
// src/plugin/graphShadowIngress.ts
|
|
16446
|
-
import { z as
|
|
16981
|
+
import { z as z25 } from "zod";
|
|
16447
16982
|
var LEGACY_EXECUTION_TRACE_VERSION = 1;
|
|
16448
|
-
var LegacyExecutionStatusSchema =
|
|
16983
|
+
var LegacyExecutionStatusSchema = z25.enum([
|
|
16449
16984
|
"completed",
|
|
16450
16985
|
"failed",
|
|
16451
16986
|
"cancelled"
|
|
16452
16987
|
]);
|
|
16453
|
-
var LegacyReviewOutcomeSchema =
|
|
16988
|
+
var LegacyReviewOutcomeSchema = z25.enum([
|
|
16454
16989
|
"approved",
|
|
16455
16990
|
"rejected",
|
|
16456
16991
|
"inconclusive"
|
|
16457
16992
|
]);
|
|
16458
|
-
var LegacyTraceNodeV1Schema =
|
|
16993
|
+
var LegacyTraceNodeV1Schema = z25.object({
|
|
16459
16994
|
id: NodeIDSchema,
|
|
16460
16995
|
role: NodeRoleSchema,
|
|
16461
|
-
model:
|
|
16462
|
-
sessionRef:
|
|
16996
|
+
model: z25.string().min(1),
|
|
16997
|
+
sessionRef: z25.string().min(1).optional(),
|
|
16463
16998
|
errorClass: ErrorClassSchema.optional()
|
|
16464
16999
|
}).strict();
|
|
16465
|
-
var LegacyExecutionTraceV1Schema =
|
|
16466
|
-
version:
|
|
17000
|
+
var LegacyExecutionTraceV1Schema = z25.object({
|
|
17001
|
+
version: z25.literal(LEGACY_EXECUTION_TRACE_VERSION),
|
|
16467
17002
|
runID: NodeIDSchema,
|
|
16468
17003
|
status: LegacyExecutionStatusSchema,
|
|
16469
17004
|
outcome: LegacyReviewOutcomeSchema,
|
|
16470
|
-
fixes:
|
|
16471
|
-
nodes:
|
|
16472
|
-
parentSessionRef:
|
|
17005
|
+
fixes: z25.number().int().nonnegative(),
|
|
17006
|
+
nodes: z25.array(LegacyTraceNodeV1Schema).min(1),
|
|
17007
|
+
parentSessionRef: z25.string().min(1).optional()
|
|
16473
17008
|
}).strict();
|
|
16474
17009
|
function gateReason2(gate) {
|
|
16475
17010
|
if (gate === undefined || gate.mode === "off") {
|
|
@@ -16540,20 +17075,20 @@ function parseLegacyExecutionTrace(input) {
|
|
|
16540
17075
|
}
|
|
16541
17076
|
|
|
16542
17077
|
// src/plugin/reportRunSchema.ts
|
|
16543
|
-
var ReportRunNodeSchema =
|
|
17078
|
+
var ReportRunNodeSchema = z26.object({
|
|
16544
17079
|
id: NodeIDSchema,
|
|
16545
17080
|
role: NodeRoleSchema,
|
|
16546
|
-
model:
|
|
16547
|
-
ok:
|
|
16548
|
-
sessionRef:
|
|
17081
|
+
model: z26.string().min(1),
|
|
17082
|
+
ok: z26.boolean(),
|
|
17083
|
+
sessionRef: z26.string().min(1).optional(),
|
|
16549
17084
|
errorClass: ErrorClassSchema.optional()
|
|
16550
17085
|
}).strict();
|
|
16551
|
-
var ReportRunPayloadSchema =
|
|
17086
|
+
var ReportRunPayloadSchema = z26.object({
|
|
16552
17087
|
runID: NodeIDSchema,
|
|
16553
17088
|
status: LegacyExecutionStatusSchema,
|
|
16554
|
-
fixes:
|
|
16555
|
-
nodes:
|
|
16556
|
-
parentSessionRef:
|
|
17089
|
+
fixes: z26.number().int().nonnegative(),
|
|
17090
|
+
nodes: z26.array(ReportRunNodeSchema).min(1),
|
|
17091
|
+
parentSessionRef: z26.string().min(1).optional()
|
|
16557
17092
|
}).strict();
|
|
16558
17093
|
|
|
16559
17094
|
// src/orchestrator/graphShadow.ts
|
|
@@ -17658,7 +18193,7 @@ function hashPrompt(prompt) {
|
|
|
17658
18193
|
}
|
|
17659
18194
|
|
|
17660
18195
|
// src/plugin/modelResidency.ts
|
|
17661
|
-
import { z as
|
|
18196
|
+
import { z as z27 } from "zod";
|
|
17662
18197
|
|
|
17663
18198
|
// src/local/lemonadeRequestGuard.ts
|
|
17664
18199
|
var inferencePaths = new Set([
|
|
@@ -18029,7 +18564,7 @@ function createModelResidencyGuard(config, options) {
|
|
|
18029
18564
|
throw failure("identity", model.providerID);
|
|
18030
18565
|
fetch = installed.fetch;
|
|
18031
18566
|
}
|
|
18032
|
-
const configuredHeaders =
|
|
18567
|
+
const configuredHeaders = z27.record(z27.string(), z27.string()).safeParse(provider?.options?.headers ?? {});
|
|
18033
18568
|
if (!configuredHeaders.success)
|
|
18034
18569
|
throw failure("configuration", model.providerID);
|
|
18035
18570
|
const headers = new Headers(configuredHeaders.data);
|
|
@@ -18257,62 +18792,62 @@ ${lines.join(`
|
|
|
18257
18792
|
}
|
|
18258
18793
|
|
|
18259
18794
|
// src/memory/types.ts
|
|
18260
|
-
import { z as
|
|
18795
|
+
import { z as z28 } from "zod";
|
|
18261
18796
|
var SHARED_OWNER_KEY = "*";
|
|
18262
|
-
var OwnerKeySchema =
|
|
18263
|
-
var MemoryKindSchema =
|
|
18264
|
-
var MemoryBaseSchema =
|
|
18265
|
-
id:
|
|
18797
|
+
var OwnerKeySchema = z28.string().min(1);
|
|
18798
|
+
var MemoryKindSchema = z28.enum(["fact", "preference", "entity"]);
|
|
18799
|
+
var MemoryBaseSchema = z28.object({
|
|
18800
|
+
id: z28.string().min(1),
|
|
18266
18801
|
ownerKey: OwnerKeySchema,
|
|
18267
|
-
confidence:
|
|
18268
|
-
validFrom:
|
|
18269
|
-
validUntil:
|
|
18270
|
-
createdAt:
|
|
18271
|
-
invalidatedAt:
|
|
18272
|
-
sourceHash:
|
|
18273
|
-
supersededBy:
|
|
18802
|
+
confidence: z28.number().min(0).max(1),
|
|
18803
|
+
validFrom: z28.number().finite(),
|
|
18804
|
+
validUntil: z28.number().finite().nullable().default(null),
|
|
18805
|
+
createdAt: z28.number().finite(),
|
|
18806
|
+
invalidatedAt: z28.number().finite().nullable().default(null),
|
|
18807
|
+
sourceHash: z28.string().min(1),
|
|
18808
|
+
supersededBy: z28.string().min(1).nullable().default(null)
|
|
18274
18809
|
}).strict();
|
|
18275
18810
|
var FactSchema = MemoryBaseSchema.extend({
|
|
18276
|
-
kind:
|
|
18277
|
-
subject:
|
|
18278
|
-
predicate:
|
|
18279
|
-
object:
|
|
18280
|
-
category:
|
|
18811
|
+
kind: z28.literal("fact"),
|
|
18812
|
+
subject: z28.string().min(1),
|
|
18813
|
+
predicate: z28.string().min(1),
|
|
18814
|
+
object: z28.string().min(1),
|
|
18815
|
+
category: z28.string().min(1).nullable().default(null)
|
|
18281
18816
|
});
|
|
18282
18817
|
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
18283
|
-
kind:
|
|
18284
|
-
category:
|
|
18285
|
-
preference:
|
|
18286
|
-
context:
|
|
18287
|
-
lastAccessedAt:
|
|
18288
|
-
accessCount:
|
|
18818
|
+
kind: z28.literal("preference"),
|
|
18819
|
+
category: z28.string().min(1),
|
|
18820
|
+
preference: z28.string().min(1),
|
|
18821
|
+
context: z28.string().min(1).nullable().default(null),
|
|
18822
|
+
lastAccessedAt: z28.number().finite().nullable().default(null),
|
|
18823
|
+
accessCount: z28.number().int().min(0).default(0)
|
|
18289
18824
|
});
|
|
18290
18825
|
var EntitySchema = MemoryBaseSchema.extend({
|
|
18291
|
-
kind:
|
|
18292
|
-
canonicalName:
|
|
18293
|
-
type:
|
|
18294
|
-
aliases:
|
|
18826
|
+
kind: z28.literal("entity"),
|
|
18827
|
+
canonicalName: z28.string().min(1),
|
|
18828
|
+
type: z28.string().min(1),
|
|
18829
|
+
aliases: z28.array(z28.string().min(1)).default([])
|
|
18295
18830
|
});
|
|
18296
18831
|
var RelationSchema = MemoryBaseSchema.extend({
|
|
18297
|
-
kind:
|
|
18298
|
-
from:
|
|
18299
|
-
to:
|
|
18300
|
-
predicate:
|
|
18301
|
-
annotation:
|
|
18832
|
+
kind: z28.literal("relation"),
|
|
18833
|
+
from: z28.string().min(1),
|
|
18834
|
+
to: z28.string().min(1),
|
|
18835
|
+
predicate: z28.string().min(1),
|
|
18836
|
+
annotation: z28.string().min(1).nullable().default(null)
|
|
18302
18837
|
});
|
|
18303
|
-
var MemoryRecordSchema =
|
|
18838
|
+
var MemoryRecordSchema = z28.discriminatedUnion("kind", [
|
|
18304
18839
|
FactSchema,
|
|
18305
18840
|
PreferenceSchema,
|
|
18306
18841
|
EntitySchema,
|
|
18307
18842
|
RelationSchema
|
|
18308
18843
|
]);
|
|
18309
|
-
var RecallQuerySchema =
|
|
18844
|
+
var RecallQuerySchema = z28.object({
|
|
18310
18845
|
ownerKey: OwnerKeySchema,
|
|
18311
|
-
kinds:
|
|
18312
|
-
asOf:
|
|
18313
|
-
limit:
|
|
18314
|
-
minSimilarity:
|
|
18315
|
-
includeShared:
|
|
18846
|
+
kinds: z28.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
|
|
18847
|
+
asOf: z28.number().finite().nullable().default(null),
|
|
18848
|
+
limit: z28.number().int().positive().default(8),
|
|
18849
|
+
minSimilarity: z28.number().min(0).max(1).default(0.2),
|
|
18850
|
+
includeShared: z28.boolean().default(true)
|
|
18316
18851
|
}).strict();
|
|
18317
18852
|
|
|
18318
18853
|
// src/memory/rank.ts
|
|
@@ -18883,42 +19418,42 @@ function buildMemoryInjector(deps, policy) {
|
|
|
18883
19418
|
|
|
18884
19419
|
// src/plugin/memoryTool.ts
|
|
18885
19420
|
import { tool as tool4 } from "@opencode-ai/plugin";
|
|
18886
|
-
import { z as
|
|
19421
|
+
import { z as z30 } from "zod";
|
|
18887
19422
|
|
|
18888
19423
|
// src/memory/extract.ts
|
|
18889
|
-
import { z as
|
|
19424
|
+
import { z as z29 } from "zod";
|
|
18890
19425
|
var REDACTED = "[redacted]";
|
|
18891
|
-
var RawFactSchema =
|
|
18892
|
-
subject:
|
|
18893
|
-
predicate:
|
|
18894
|
-
object:
|
|
18895
|
-
category:
|
|
18896
|
-
confidence:
|
|
19426
|
+
var RawFactSchema = z29.object({
|
|
19427
|
+
subject: z29.string().min(1),
|
|
19428
|
+
predicate: z29.string().min(1),
|
|
19429
|
+
object: z29.string().min(1),
|
|
19430
|
+
category: z29.string().min(1).nullable().optional(),
|
|
19431
|
+
confidence: z29.number().min(0).max(1).optional()
|
|
18897
19432
|
});
|
|
18898
|
-
var RawPreferenceSchema =
|
|
18899
|
-
category:
|
|
18900
|
-
preference:
|
|
18901
|
-
context:
|
|
18902
|
-
confidence:
|
|
19433
|
+
var RawPreferenceSchema = z29.object({
|
|
19434
|
+
category: z29.string().min(1),
|
|
19435
|
+
preference: z29.string().min(1),
|
|
19436
|
+
context: z29.string().min(1).nullable().optional(),
|
|
19437
|
+
confidence: z29.number().min(0).max(1).optional()
|
|
18903
19438
|
});
|
|
18904
|
-
var RawEntitySchema =
|
|
18905
|
-
canonicalName:
|
|
18906
|
-
type:
|
|
18907
|
-
aliases:
|
|
18908
|
-
confidence:
|
|
19439
|
+
var RawEntitySchema = z29.object({
|
|
19440
|
+
canonicalName: z29.string().min(1),
|
|
19441
|
+
type: z29.string().min(1),
|
|
19442
|
+
aliases: z29.array(z29.string().min(1)).optional(),
|
|
19443
|
+
confidence: z29.number().min(0).max(1).optional()
|
|
18909
19444
|
});
|
|
18910
|
-
var RawRelationSchema =
|
|
18911
|
-
from:
|
|
18912
|
-
to:
|
|
18913
|
-
predicate:
|
|
18914
|
-
annotation:
|
|
18915
|
-
confidence:
|
|
19445
|
+
var RawRelationSchema = z29.object({
|
|
19446
|
+
from: z29.string().min(1),
|
|
19447
|
+
to: z29.string().min(1),
|
|
19448
|
+
predicate: z29.string().min(1),
|
|
19449
|
+
annotation: z29.string().min(1).nullable().optional(),
|
|
19450
|
+
confidence: z29.number().min(0).max(1).optional()
|
|
18916
19451
|
}).strict();
|
|
18917
|
-
var RawExtractionSchema =
|
|
18918
|
-
facts:
|
|
18919
|
-
preferences:
|
|
18920
|
-
entities:
|
|
18921
|
-
relations:
|
|
19452
|
+
var RawExtractionSchema = z29.object({
|
|
19453
|
+
facts: z29.array(RawFactSchema).default([]),
|
|
19454
|
+
preferences: z29.array(RawPreferenceSchema).default([]),
|
|
19455
|
+
entities: z29.array(RawEntitySchema).default([]),
|
|
19456
|
+
relations: z29.array(RawRelationSchema).default([])
|
|
18922
19457
|
});
|
|
18923
19458
|
var DEFAULT_CONFIDENCE = 0.6;
|
|
18924
19459
|
var SYSTEM_PROMPT = [
|
|
@@ -19172,13 +19707,13 @@ var memoryToolMessages = {
|
|
|
19172
19707
|
|
|
19173
19708
|
// src/plugin/memoryTool.ts
|
|
19174
19709
|
var SCRIBE_ROLE_ID = "scribe";
|
|
19175
|
-
var MemoryMessageSchema =
|
|
19176
|
-
role:
|
|
19177
|
-
content:
|
|
19710
|
+
var MemoryMessageSchema = z30.object({
|
|
19711
|
+
role: z30.enum(["system", "user", "assistant"]).describe(memoryToolMessages.messageRoleDescription),
|
|
19712
|
+
content: z30.string().min(1).describe(memoryToolMessages.messageContentDescription)
|
|
19178
19713
|
}).strict();
|
|
19179
|
-
var MemoryWritePayloadSchema =
|
|
19180
|
-
messages:
|
|
19181
|
-
roleID:
|
|
19714
|
+
var MemoryWritePayloadSchema = z30.object({
|
|
19715
|
+
messages: z30.array(MemoryMessageSchema).min(1).describe(memoryToolMessages.messagesDescription),
|
|
19716
|
+
roleID: z30.string().min(1).default(SCRIBE_ROLE_ID).describe(memoryToolMessages.roleIDDescription)
|
|
19182
19717
|
}).strict();
|
|
19183
19718
|
function createMemoryTool(deps) {
|
|
19184
19719
|
return tool4({
|
|
@@ -19362,7 +19897,7 @@ import { Session as Session2 } from "@opencode/schema/session";
|
|
|
19362
19897
|
import { Tool } from "@opencode/schema/tool";
|
|
19363
19898
|
import { tool as legacyTool } from "@opencode-ai/plugin/tool";
|
|
19364
19899
|
import { Clock, Effect, Option, Stream } from "effect";
|
|
19365
|
-
import { z as
|
|
19900
|
+
import { z as z32 } from "zod";
|
|
19366
19901
|
|
|
19367
19902
|
// src/plugin/nativeHostContext.ts
|
|
19368
19903
|
import {
|
|
@@ -19424,7 +19959,7 @@ function nativeConfiguredInventory(models, config) {
|
|
|
19424
19959
|
|
|
19425
19960
|
// src/plugin/nativeResidency.ts
|
|
19426
19961
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
19427
|
-
import { z as
|
|
19962
|
+
import { z as z31 } from "zod";
|
|
19428
19963
|
var NATIVE_RESIDENCY_PROVIDER_PACKAGE = "aisdk:@ai-sdk/openai-compatible@2.0.75";
|
|
19429
19964
|
var NATIVE_ADMISSION_HEADER = "x-openteam-local-admission";
|
|
19430
19965
|
var MAX_ADMISSIONS = 2048;
|
|
@@ -19502,7 +20037,7 @@ function createNativeModelResidencyGuard(config, options) {
|
|
|
19502
20037
|
});
|
|
19503
20038
|
}
|
|
19504
20039
|
function target(model, send, baseURL) {
|
|
19505
|
-
const headers = new Headers(
|
|
20040
|
+
const headers = new Headers(z31.record(z31.string(), z31.string()).parse(model.headers ?? {}));
|
|
19506
20041
|
if (typeof model.settings?.apiKey === "string" && !headers.has("authorization"))
|
|
19507
20042
|
headers.set("authorization", `Bearer ${model.settings.apiKey}`);
|
|
19508
20043
|
return {
|
|
@@ -19540,7 +20075,7 @@ function createNativeModelResidencyGuard(config, options) {
|
|
|
19540
20075
|
localTargets.set(key(ref), target(model, guardedFetch(binding, options.fetch), binding.baseURL));
|
|
19541
20076
|
return model;
|
|
19542
20077
|
} catch (error) {
|
|
19543
|
-
if (!(error instanceof ModelResidencyError) && !(error instanceof
|
|
20078
|
+
if (!(error instanceof ModelResidencyError) && !(error instanceof z31.ZodError))
|
|
19544
20079
|
throw error;
|
|
19545
20080
|
(options.warn ?? console.warn)(modelResidencyMessages.providerDisabled(model.providerID, residentRuntimes.find((runtime) => runtime.defaultModel.providerID === model.providerID)?.kind === "llama-swap" ? "llama-swap" : "Lemonade"));
|
|
19546
20081
|
return { ...model, enabled: false };
|
|
@@ -19697,6 +20232,10 @@ function nativeAssistantResponse(sessionID, message) {
|
|
|
19697
20232
|
...message.cost === undefined ? {} : { cost: message.cost },
|
|
19698
20233
|
...message.tokens === undefined ? {} : { tokens: message.tokens },
|
|
19699
20234
|
...message.error === undefined ? {} : { error: message.error },
|
|
20235
|
+
...message.finish === undefined ? {} : { finish: message.finish },
|
|
20236
|
+
...message.rawFinish === undefined ? {} : { rawFinish: message.rawFinish },
|
|
20237
|
+
hasGeneratedOutput: message.content.some((part) => part.type === "tool" || part.text.length > 0),
|
|
20238
|
+
truncatedToolCall: message.finish === "length" && message.content.some((part) => part.type === "tool" && part.executed === false && part.state.status === "error" && part.state.error.type === "tool.input-json"),
|
|
19700
20239
|
time: {
|
|
19701
20240
|
created: DateTime.toEpochMillis(message.time.created),
|
|
19702
20241
|
...message.time.completed === undefined ? {} : { completed: DateTime.toEpochMillis(message.time.completed) }
|
|
@@ -19723,7 +20262,8 @@ function createNativeSessionClient(deps) {
|
|
|
19723
20262
|
}
|
|
19724
20263
|
return {
|
|
19725
20264
|
async create(args) {
|
|
19726
|
-
const
|
|
20265
|
+
const parentSignal = deps.signal?.();
|
|
20266
|
+
const signal = parentSignal === undefined ? args.signal : args.signal === undefined ? parentSignal : AbortSignal.any([parentSignal, args.signal]);
|
|
19727
20267
|
signal?.throwIfAborted();
|
|
19728
20268
|
assertDirectory(args.query?.directory);
|
|
19729
20269
|
if (args.body?.parentID === undefined)
|
|
@@ -19733,7 +20273,7 @@ function createNativeSessionClient(deps) {
|
|
|
19733
20273
|
const child = await deps.run(deps.sessions().create({
|
|
19734
20274
|
parentID,
|
|
19735
20275
|
...args.body.title === undefined ? {} : { title: args.body.title }
|
|
19736
|
-
}));
|
|
20276
|
+
}), signal === undefined ? undefined : { signal });
|
|
19737
20277
|
if (!sameNativeWorkspace(child.location, location))
|
|
19738
20278
|
throw new Error(nativeHostMessages.workspaceMismatch);
|
|
19739
20279
|
if (child.parentID !== parentID)
|
|
@@ -19772,6 +20312,11 @@ function createNativeSessionClient(deps) {
|
|
|
19772
20312
|
const assistant = [...messages].reverse().find((message) => message.type === "assistant");
|
|
19773
20313
|
if (final.outcome === "interrupted")
|
|
19774
20314
|
throw new Error(nativeHostMessages.executionInterrupted);
|
|
20315
|
+
if (assistant?.time.completed !== undefined) {
|
|
20316
|
+
const response = nativeAssistantResponse(sessionID, assistant);
|
|
20317
|
+
if (response.info.truncatedToolCall)
|
|
20318
|
+
return { data: response, error: undefined };
|
|
20319
|
+
}
|
|
19775
20320
|
if (final.outcome !== "succeeded" || assistant?.error !== undefined)
|
|
19776
20321
|
throw new Error(nativeHostMessages.executionFailed);
|
|
19777
20322
|
if (assistant?.time.completed === undefined)
|
|
@@ -19811,8 +20356,8 @@ function createNativeSessionClient(deps) {
|
|
|
19811
20356
|
}
|
|
19812
20357
|
|
|
19813
20358
|
// src/plugin/nativeHost.ts
|
|
19814
|
-
var executionEvent =
|
|
19815
|
-
type:
|
|
20359
|
+
var executionEvent = z32.preprocess(only(["type", "location", "data"]), z32.object({
|
|
20360
|
+
type: z32.enum([
|
|
19816
20361
|
"session.created",
|
|
19817
20362
|
"session.deleted",
|
|
19818
20363
|
"session.execution.started",
|
|
@@ -19820,15 +20365,30 @@ var executionEvent = z30.preprocess(only(["type", "location", "data"]), z30.obje
|
|
|
19820
20365
|
"session.execution.failed",
|
|
19821
20366
|
"session.execution.interrupted",
|
|
19822
20367
|
"session.step.ended",
|
|
19823
|
-
"session.step.
|
|
20368
|
+
"session.step.started",
|
|
20369
|
+
"session.step.failed",
|
|
20370
|
+
"session.tool.input.started",
|
|
20371
|
+
"session.tool.success",
|
|
20372
|
+
"session.tool.failed"
|
|
19824
20373
|
]),
|
|
19825
|
-
location:
|
|
19826
|
-
directory:
|
|
19827
|
-
workspaceID:
|
|
20374
|
+
location: z32.preprocess(only(["directory", "workspaceID"]), z32.object({
|
|
20375
|
+
directory: z32.string(),
|
|
20376
|
+
workspaceID: z32.string().optional()
|
|
19828
20377
|
}).strict()).optional(),
|
|
19829
|
-
data:
|
|
19830
|
-
sessionID
|
|
19831
|
-
assistantMessageID
|
|
20378
|
+
data: z32.preprocess(only([
|
|
20379
|
+
"sessionID",
|
|
20380
|
+
"assistantMessageID",
|
|
20381
|
+
"id",
|
|
20382
|
+
"name",
|
|
20383
|
+
"executed",
|
|
20384
|
+
"error"
|
|
20385
|
+
]), z32.object({
|
|
20386
|
+
sessionID: z32.string(),
|
|
20387
|
+
assistantMessageID: z32.string().optional(),
|
|
20388
|
+
id: z32.string().optional(),
|
|
20389
|
+
name: z32.string().optional(),
|
|
20390
|
+
executed: z32.boolean().optional(),
|
|
20391
|
+
error: z32.preprocess(only(["type"]), z32.object({ type: z32.string() }).strict()).optional()
|
|
19832
20392
|
}).strict())
|
|
19833
20393
|
}).strict());
|
|
19834
20394
|
var nativeBindings = Effect.fn("openteam.nativeBindings")(function* () {
|
|
@@ -19883,6 +20443,15 @@ function createNativePluginEffect(factory) {
|
|
|
19883
20443
|
let config;
|
|
19884
20444
|
let residency;
|
|
19885
20445
|
const systemPrompts = new Map;
|
|
20446
|
+
const toolNames = new Map;
|
|
20447
|
+
const rememberTool = (sessionID, callID, name) => {
|
|
20448
|
+
toolNames.set(`${sessionID}\x00${callID}`, name);
|
|
20449
|
+
if (toolNames.size > 8192) {
|
|
20450
|
+
const oldest = toolNames.keys().next().value;
|
|
20451
|
+
if (oldest !== undefined)
|
|
20452
|
+
toolNames.delete(oldest);
|
|
20453
|
+
}
|
|
20454
|
+
};
|
|
19886
20455
|
const toolSignals = new AsyncLocalStorage;
|
|
19887
20456
|
const remember = (next) => {
|
|
19888
20457
|
bindings = { ...bindings, ...next };
|
|
@@ -19937,6 +20506,12 @@ function createNativePluginEffect(factory) {
|
|
|
19937
20506
|
directory,
|
|
19938
20507
|
worktree: ctx.location.project.directory,
|
|
19939
20508
|
client,
|
|
20509
|
+
toolOutcomesFromEvents: true,
|
|
20510
|
+
parentSession: async (sessionID) => {
|
|
20511
|
+
const info = await run(requiredBindings().sessions.get(Session2.ID.make(sessionID)));
|
|
20512
|
+
assertWorkspace(info.location);
|
|
20513
|
+
return info.parentID;
|
|
20514
|
+
},
|
|
19940
20515
|
exec: nativeExec(directory),
|
|
19941
20516
|
serverUrl: () => {
|
|
19942
20517
|
const url = bindings?.server?.urls().find((value) => {
|
|
@@ -19981,6 +20556,7 @@ function createNativePluginEffect(factory) {
|
|
|
19981
20556
|
yield* Effect.addFinalizer(() => Effect.promise(async () => {
|
|
19982
20557
|
guard.dispose();
|
|
19983
20558
|
systemPrompts.clear();
|
|
20559
|
+
toolNames.clear();
|
|
19984
20560
|
await hooks.dispose?.();
|
|
19985
20561
|
}));
|
|
19986
20562
|
yield* ctx.provider.transform(guard.providers);
|
|
@@ -20113,7 +20689,10 @@ function createNativePluginEffect(factory) {
|
|
|
20113
20689
|
});
|
|
20114
20690
|
}
|
|
20115
20691
|
});
|
|
20116
|
-
yield* ctx.tool.hook("execute.before", (event) => Effect.promise(() =>
|
|
20692
|
+
yield* ctx.tool.hook("execute.before", (event) => Effect.promise(() => {
|
|
20693
|
+
rememberTool(event.sessionID, event.id, event.tool);
|
|
20694
|
+
return hooks["tool.execute.before"]?.({ tool: event.tool, sessionID: event.sessionID, callID: event.id }, { args: event.input }) ?? Promise.resolve();
|
|
20695
|
+
}));
|
|
20117
20696
|
yield* ctx.tool.hook("execute.after", (event) => Effect.promise(() => hooks["tool.execute.after"]?.({
|
|
20118
20697
|
tool: event.tool,
|
|
20119
20698
|
sessionID: event.sessionID,
|
|
@@ -20140,9 +20719,62 @@ function createNativePluginEffect(factory) {
|
|
|
20140
20719
|
if (value.type === "session.deleted") {
|
|
20141
20720
|
guard.finished(sessionID);
|
|
20142
20721
|
systemPrompts.delete(sessionID);
|
|
20722
|
+
for (const key2 of toolNames.keys()) {
|
|
20723
|
+
if (key2.startsWith(`${sessionID}\x00`))
|
|
20724
|
+
toolNames.delete(key2);
|
|
20725
|
+
}
|
|
20143
20726
|
}
|
|
20144
20727
|
let mapped;
|
|
20145
|
-
if (value.type === "session.
|
|
20728
|
+
if (value.type === "session.tool.input.started") {
|
|
20729
|
+
if (value.data.id !== undefined && value.data.name !== undefined)
|
|
20730
|
+
rememberTool(sessionID, value.data.id, value.data.name);
|
|
20731
|
+
await hooks.event?.({
|
|
20732
|
+
event: {
|
|
20733
|
+
type: "openteam.session.phase",
|
|
20734
|
+
properties: { sessionID, phase: "tool-input" }
|
|
20735
|
+
}
|
|
20736
|
+
});
|
|
20737
|
+
return;
|
|
20738
|
+
} else if (value.type === "session.step.started") {
|
|
20739
|
+
mapped = {
|
|
20740
|
+
type: "openteam.session.phase",
|
|
20741
|
+
properties: { sessionID, phase: "model-request" }
|
|
20742
|
+
};
|
|
20743
|
+
} else if (value.type === "session.tool.success" || value.type === "session.tool.failed") {
|
|
20744
|
+
if (value.data.id === undefined)
|
|
20745
|
+
return;
|
|
20746
|
+
const key2 = `${sessionID}\x00${value.data.id}`;
|
|
20747
|
+
let name = toolNames.get(key2);
|
|
20748
|
+
if (name === undefined && bindings !== undefined) {
|
|
20749
|
+
const messages = await run(bindings.sessions.messages({
|
|
20750
|
+
sessionID: Session2.ID.make(sessionID),
|
|
20751
|
+
limit: 100
|
|
20752
|
+
}));
|
|
20753
|
+
const message = messages.find((candidate) => candidate.id === value.data.assistantMessageID);
|
|
20754
|
+
if (message?.type === "assistant") {
|
|
20755
|
+
const part = message.content.find((candidate) => candidate.type === "tool" && candidate.id === value.data.id);
|
|
20756
|
+
if (part?.type === "tool")
|
|
20757
|
+
name = part.name;
|
|
20758
|
+
}
|
|
20759
|
+
}
|
|
20760
|
+
const ok = value.type === "session.tool.success";
|
|
20761
|
+
const inputFailure = value.data.error?.type === "tool.input-json" || value.data.error?.type === "tool.input-schema";
|
|
20762
|
+
const executionReached = ok || value.data.error?.type === "tool.execution";
|
|
20763
|
+
mapped = {
|
|
20764
|
+
type: "openteam.tool.completed",
|
|
20765
|
+
properties: {
|
|
20766
|
+
sessionID,
|
|
20767
|
+
callID: value.data.id,
|
|
20768
|
+
tool: name ?? "unknown",
|
|
20769
|
+
ok,
|
|
20770
|
+
...inputFailure ? { executed: false } : executionReached ? { executed: true } : {},
|
|
20771
|
+
...value.data.executed === undefined ? {} : { providerExecuted: value.data.executed },
|
|
20772
|
+
...!ok ? {
|
|
20773
|
+
failureKind: inputFailure ? "input-invalid" : executionReached ? "execution" : "unknown"
|
|
20774
|
+
} : {}
|
|
20775
|
+
}
|
|
20776
|
+
};
|
|
20777
|
+
} else if (value.type === "session.created" || value.type === "session.deleted") {
|
|
20146
20778
|
mapped = {
|
|
20147
20779
|
type: value.type,
|
|
20148
20780
|
properties: { info: { id: sessionID } }
|
|
@@ -20183,11 +20815,12 @@ function createNativePluginEffect(factory) {
|
|
|
20183
20815
|
}
|
|
20184
20816
|
|
|
20185
20817
|
// src/plugin/orchestrateTool.ts
|
|
20818
|
+
import { resolve as resolve11 } from "node:path";
|
|
20186
20819
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
20187
|
-
import { z as
|
|
20820
|
+
import { z as z34 } from "zod";
|
|
20188
20821
|
|
|
20189
20822
|
// src/orchestrator/coordinator.ts
|
|
20190
|
-
import { z as
|
|
20823
|
+
import { z as z33 } from "zod";
|
|
20191
20824
|
|
|
20192
20825
|
// src/orchestrator/nodeIteration.ts
|
|
20193
20826
|
var DEFAULT_MAX_RETRIES = 2;
|
|
@@ -20195,153 +20828,6 @@ function nodePassBudget(maxRetries) {
|
|
|
20195
20828
|
return 1 + (maxRetries ?? DEFAULT_MAX_RETRIES);
|
|
20196
20829
|
}
|
|
20197
20830
|
|
|
20198
|
-
// src/orchestrator/outputContract.ts
|
|
20199
|
-
import { createHash as createHash3 } from "node:crypto";
|
|
20200
|
-
var ROLE_REPORTS_ROOT = ".opencode/openteam-local/reports";
|
|
20201
|
-
var REPORT_STATUS_MARKER = "openteam-status";
|
|
20202
|
-
var REPORT_STATUS_LINE_PATTERN = /^[ ]{0,3}openteam-status:[ \t]*(.*?)[ \t]*$/i;
|
|
20203
|
-
var FENCE_DELIMITER_PATTERN = /^ {0,3}(`{3,}|~{3,})(.*)$/;
|
|
20204
|
-
function fenceDelimiter(line) {
|
|
20205
|
-
const match = FENCE_DELIMITER_PATTERN.exec(line);
|
|
20206
|
-
const run = match?.[1];
|
|
20207
|
-
if (run === undefined)
|
|
20208
|
-
return;
|
|
20209
|
-
const marker = run.startsWith("`") ? "`" : "~";
|
|
20210
|
-
return {
|
|
20211
|
-
marker,
|
|
20212
|
-
length: run.length,
|
|
20213
|
-
remainder: match?.[2] ?? ""
|
|
20214
|
-
};
|
|
20215
|
-
}
|
|
20216
|
-
function declaredStatus(value) {
|
|
20217
|
-
const normalized = value.toLowerCase();
|
|
20218
|
-
if (normalized === "done")
|
|
20219
|
-
return "done";
|
|
20220
|
-
if (normalized === "continue")
|
|
20221
|
-
return "continue";
|
|
20222
|
-
return "unknown";
|
|
20223
|
-
}
|
|
20224
|
-
function analyzeReport(text) {
|
|
20225
|
-
let status = "unknown";
|
|
20226
|
-
let fence;
|
|
20227
|
-
const bodyLines = [];
|
|
20228
|
-
for (const line of text.split(/\r?\n/)) {
|
|
20229
|
-
const delimiter = fenceDelimiter(line);
|
|
20230
|
-
if (fence !== undefined) {
|
|
20231
|
-
bodyLines.push(line);
|
|
20232
|
-
if (delimiter?.marker === fence.marker && delimiter.length >= fence.length && delimiter.remainder.trim().length === 0) {
|
|
20233
|
-
fence = undefined;
|
|
20234
|
-
}
|
|
20235
|
-
continue;
|
|
20236
|
-
}
|
|
20237
|
-
if (delimiter !== undefined) {
|
|
20238
|
-
fence = delimiter;
|
|
20239
|
-
bodyLines.push(line);
|
|
20240
|
-
continue;
|
|
20241
|
-
}
|
|
20242
|
-
const declaration = REPORT_STATUS_LINE_PATTERN.exec(line);
|
|
20243
|
-
if (declaration !== null) {
|
|
20244
|
-
status = declaredStatus(declaration[1] ?? "");
|
|
20245
|
-
continue;
|
|
20246
|
-
}
|
|
20247
|
-
bodyLines.push(line);
|
|
20248
|
-
}
|
|
20249
|
-
return {
|
|
20250
|
-
status,
|
|
20251
|
-
body: bodyLines.join(`
|
|
20252
|
-
`).trim()
|
|
20253
|
-
};
|
|
20254
|
-
}
|
|
20255
|
-
function parseReportStatus(text) {
|
|
20256
|
-
if (text === undefined || text.length === 0)
|
|
20257
|
-
return "unknown";
|
|
20258
|
-
return analyzeReport(text).status;
|
|
20259
|
-
}
|
|
20260
|
-
var MIN_REPORT_BODY_CHARS = 40;
|
|
20261
|
-
var MAX_REPORT_SEGMENT_CHARS = 64;
|
|
20262
|
-
var REPORT_SEGMENT_HASH_CHARS = 24;
|
|
20263
|
-
var SAFE_REPORT_SEGMENT = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62}[A-Za-z0-9_-])?$/;
|
|
20264
|
-
var WINDOWS_DEVICE_NAME = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i;
|
|
20265
|
-
function reportSegmentHash(value) {
|
|
20266
|
-
return createHash3("sha256").update(value, "utf8").digest("hex").slice(0, REPORT_SEGMENT_HASH_CHARS);
|
|
20267
|
-
}
|
|
20268
|
-
function reportPathSegment(value) {
|
|
20269
|
-
if (value.length <= MAX_REPORT_SEGMENT_CHARS && SAFE_REPORT_SEGMENT.test(value) && value === value.toLowerCase() && !WINDOWS_DEVICE_NAME.test(value)) {
|
|
20270
|
-
return value;
|
|
20271
|
-
}
|
|
20272
|
-
const suffix = `~${reportSegmentHash(value)}`;
|
|
20273
|
-
const maxPrefixChars = MAX_REPORT_SEGMENT_CHARS - suffix.length;
|
|
20274
|
-
let prefix = value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[^A-Za-z0-9]+/, "").slice(0, maxPrefixChars).replace(/[.]+$/, "");
|
|
20275
|
-
if (prefix.length === 0) {
|
|
20276
|
-
prefix = "segment";
|
|
20277
|
-
}
|
|
20278
|
-
if (WINDOWS_DEVICE_NAME.test(prefix)) {
|
|
20279
|
-
prefix = `safe-${prefix}`.slice(0, maxPrefixChars).replace(/[.]+$/, "");
|
|
20280
|
-
}
|
|
20281
|
-
return `${prefix}${suffix}`;
|
|
20282
|
-
}
|
|
20283
|
-
function reportHasSubstance(text) {
|
|
20284
|
-
if (text === undefined)
|
|
20285
|
-
return false;
|
|
20286
|
-
return analyzeReport(text).body.length >= MIN_REPORT_BODY_CHARS;
|
|
20287
|
-
}
|
|
20288
|
-
function roleReportPath(batchID, roleID) {
|
|
20289
|
-
return `${ROLE_REPORTS_ROOT}/${reportPathSegment(batchID)}/${reportPathSegment(roleID)}.md`;
|
|
20290
|
-
}
|
|
20291
|
-
function outputContractInstruction(reportPath) {
|
|
20292
|
-
return [
|
|
20293
|
-
"## Output contract (openteam)",
|
|
20294
|
-
"",
|
|
20295
|
-
"Write your complete findings to the report file below using the `write`",
|
|
20296
|
-
"tool (create parent directories as needed), and keep it updated with",
|
|
20297
|
-
"`edit` as you progress. This file is the ONLY channel your work reaches",
|
|
20298
|
-
"the coordinator: anything you do not write there is discarded and lost,",
|
|
20299
|
-
"and the coordinator will have no record of it.",
|
|
20300
|
-
"",
|
|
20301
|
-
`Report file: ${reportPath}`,
|
|
20302
|
-
"",
|
|
20303
|
-
"Requirements:",
|
|
20304
|
-
"- Write the ACTUAL results — what you found, what you changed, concrete",
|
|
20305
|
-
" conclusions, and any risks or follow-ups — never a promise to do the",
|
|
20306
|
-
" work later.",
|
|
20307
|
-
"- Make it self-contained: the coordinator reads only this file, not your",
|
|
20308
|
-
" session transcript.",
|
|
20309
|
-
"- If you could not complete the task, write what you attempted and why it",
|
|
20310
|
-
" is blocked, so the coordinator can report the truth.",
|
|
20311
|
-
"- If the report file already exists from a previous pass, read it first and",
|
|
20312
|
-
" continue from where it left off rather than starting over.",
|
|
20313
|
-
"",
|
|
20314
|
-
"Completion status (REQUIRED — this is how the coordinator knows to stop):",
|
|
20315
|
-
"On its own line in the report, declare your status EXACTLY as one of:",
|
|
20316
|
-
`${REPORT_STATUS_MARKER}: done`,
|
|
20317
|
-
" The task is fully complete; no further passes are needed.",
|
|
20318
|
-
`${REPORT_STATUS_MARKER}: continue`,
|
|
20319
|
-
" You have more work to do and will be run again.",
|
|
20320
|
-
"The marker line must contain nothing else.",
|
|
20321
|
-
"If you omit this line or write anything else, the coordinator treats the",
|
|
20322
|
-
"task as NOT complete and runs you again, up to the configured retry bound."
|
|
20323
|
-
].join(`
|
|
20324
|
-
`);
|
|
20325
|
-
}
|
|
20326
|
-
function composeSubsessionPrompt(input) {
|
|
20327
|
-
const reportPath = roleReportPath(input.batchID, input.roleID);
|
|
20328
|
-
const handoff = input.handoff ? [
|
|
20329
|
-
"",
|
|
20330
|
-
"## Model handoff",
|
|
20331
|
-
"",
|
|
20332
|
-
"Continue the SAME node and original goal. Read the existing report first,",
|
|
20333
|
-
"preserve useful prior findings, and complete the remaining work instead of",
|
|
20334
|
-
"starting a new batch or replacing the objective."
|
|
20335
|
-
].join(`
|
|
20336
|
-
`) : "";
|
|
20337
|
-
return {
|
|
20338
|
-
prompt: `${input.prompt}${handoff}
|
|
20339
|
-
|
|
20340
|
-
${outputContractInstruction(reportPath)}`,
|
|
20341
|
-
reportPath
|
|
20342
|
-
};
|
|
20343
|
-
}
|
|
20344
|
-
|
|
20345
20831
|
// src/orchestrator/permissions.ts
|
|
20346
20832
|
var ROLE_PERMISSIONS = {
|
|
20347
20833
|
architect: [
|
|
@@ -20661,7 +21147,7 @@ function buildRecord(input, decision2, subsession, deps, decisionID, batchID) {
|
|
|
20661
21147
|
}
|
|
20662
21148
|
return record;
|
|
20663
21149
|
}
|
|
20664
|
-
var TelemetryFailureClassSchema =
|
|
21150
|
+
var TelemetryFailureClassSchema = z33.enum([
|
|
20665
21151
|
"create-rejected",
|
|
20666
21152
|
"create-no-id",
|
|
20667
21153
|
"prompt-rejected",
|
|
@@ -20670,12 +21156,15 @@ var TelemetryFailureClassSchema = z31.enum([
|
|
|
20670
21156
|
"prompt-auth",
|
|
20671
21157
|
"prompt-content-filter",
|
|
20672
21158
|
"prompt-context-length",
|
|
21159
|
+
"prompt-output-truncated",
|
|
21160
|
+
"budget-exhausted",
|
|
20673
21161
|
"prompt-validation",
|
|
20674
21162
|
"prompt-connection",
|
|
20675
21163
|
"prompt-server",
|
|
20676
21164
|
"unknown"
|
|
20677
21165
|
]);
|
|
20678
21166
|
var FAILURE_CAUSE_RULES = [
|
|
21167
|
+
[["prompt-output-truncated"], "prompt-output-truncated"],
|
|
20679
21168
|
[
|
|
20680
21169
|
[
|
|
20681
21170
|
"rate limit",
|
|
@@ -20778,6 +21267,8 @@ function matchFailureCause(lowerReason) {
|
|
|
20778
21267
|
}
|
|
20779
21268
|
function classifyFailureForTelemetry(failureReason, failureStage) {
|
|
20780
21269
|
const lower = failureReason.toLowerCase();
|
|
21270
|
+
if (lower.startsWith("task-budget-exhausted:"))
|
|
21271
|
+
return "budget-exhausted";
|
|
20781
21272
|
if (TIMEOUT_NEEDLES.some((needle) => lower.includes(needle))) {
|
|
20782
21273
|
return "prompt-timeout";
|
|
20783
21274
|
}
|
|
@@ -20846,6 +21337,8 @@ async function recordLifecycle(lifecycle, event) {
|
|
|
20846
21337
|
await lifecycle.recorder.append(event);
|
|
20847
21338
|
}
|
|
20848
21339
|
function lifecycleFailureFor(subsession) {
|
|
21340
|
+
if (subsession.failureReason?.startsWith("task-budget-exhausted:"))
|
|
21341
|
+
return { class: "budget-exhausted", retryable: false };
|
|
20849
21342
|
const normalized = subsession.normalizedFailure;
|
|
20850
21343
|
if (normalized !== undefined) {
|
|
20851
21344
|
return {
|
|
@@ -20915,7 +21408,7 @@ function buildNodeBudgetExhaustedEvent(roleID, passCount, sessionID, ts) {
|
|
|
20915
21408
|
passCount
|
|
20916
21409
|
};
|
|
20917
21410
|
}
|
|
20918
|
-
async function runRoleTaskWithCorrelation(input, deps, correlation, batch, routed, handoff, reportBatchID, attemptLifecycle) {
|
|
21411
|
+
async function runRoleTaskWithCorrelation(input, deps, correlation, batch, routed, handoff, reportBatchID, attemptLifecycle, repair, truncated, existingSessionID) {
|
|
20919
21412
|
const role = roleFor(input);
|
|
20920
21413
|
if (routed.routeKind === "blocked") {
|
|
20921
21414
|
throw new Error(coordinatorRoutingBlocked(input.roleID, routed.blockReason));
|
|
@@ -20926,13 +21419,18 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
20926
21419
|
prompt: input.prompt,
|
|
20927
21420
|
roleID: input.roleID,
|
|
20928
21421
|
batchID: reportBatchID,
|
|
20929
|
-
handoff
|
|
21422
|
+
handoff,
|
|
21423
|
+
structuredReport: deps.reportDelivery !== undefined,
|
|
21424
|
+
...repair === undefined ? {} : { repair },
|
|
21425
|
+
...truncated === true ? { truncated: true } : {}
|
|
20930
21426
|
});
|
|
20931
21427
|
const request = {
|
|
20932
21428
|
roleID: input.roleID,
|
|
20933
21429
|
model: decision2.selected,
|
|
20934
21430
|
prompt: composed.prompt
|
|
20935
21431
|
};
|
|
21432
|
+
if (existingSessionID !== undefined)
|
|
21433
|
+
request.existingSessionID = existingSessionID;
|
|
20936
21434
|
if (input.parentSessionID !== undefined) {
|
|
20937
21435
|
request.parentSessionID = input.parentSessionID;
|
|
20938
21436
|
}
|
|
@@ -20950,11 +21448,17 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
20950
21448
|
if (input.directory !== undefined) {
|
|
20951
21449
|
request.directory = input.directory;
|
|
20952
21450
|
}
|
|
21451
|
+
let reportLease;
|
|
20953
21452
|
const subsessionDeps = {
|
|
20954
21453
|
abortGraceMs: deps.abortGraceMs,
|
|
20955
21454
|
statusPollMs: deps.statusPollMs,
|
|
20956
21455
|
now: deps.now,
|
|
20957
21456
|
delay: deps.delay,
|
|
21457
|
+
prepareSession: async (sessionID) => {
|
|
21458
|
+
if (deps.taskEffort !== undefined)
|
|
21459
|
+
deps.taskEffort.ledger.bindChild(deps.taskEffort.ref, sessionID);
|
|
21460
|
+
reportLease = deps.reportDelivery?.open(sessionID, reportBatchID, input.roleID);
|
|
21461
|
+
},
|
|
20958
21462
|
...deps.timeoutMs === undefined ? {} : { timeoutMs: deps.timeoutMs },
|
|
20959
21463
|
...attemptLifecycle === undefined ? {} : {
|
|
20960
21464
|
onSessionCreated: (sessionID) => recordLifecycle(attemptLifecycle.lifecycle, {
|
|
@@ -20999,27 +21503,66 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
20999
21503
|
}
|
|
21000
21504
|
let release;
|
|
21001
21505
|
let queueObservation;
|
|
21002
|
-
|
|
21003
|
-
|
|
21004
|
-
const
|
|
21005
|
-
|
|
21006
|
-
|
|
21007
|
-
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
const acquisition = await limiter.acquire(poolKey, priority);
|
|
21012
|
-
release = acquisition.release;
|
|
21013
|
-
waitedMs = acquisition.waitedMs;
|
|
21014
|
-
}
|
|
21015
|
-
queueObservation = {
|
|
21016
|
-
runtimeId,
|
|
21017
|
-
waitedMs,
|
|
21018
|
-
activeCount: limiter.activeCount(poolKey),
|
|
21019
|
-
queuedCount: limiter.queuedCount(poolKey)
|
|
21506
|
+
const admission = deps.taskEffort?.ledger.check(deps.taskEffort.ref);
|
|
21507
|
+
async function denied(reason) {
|
|
21508
|
+
const subsession = {
|
|
21509
|
+
roleID: input.roleID,
|
|
21510
|
+
model: decision2.selected,
|
|
21511
|
+
success: false,
|
|
21512
|
+
failureStage: "create",
|
|
21513
|
+
retrySafe: false,
|
|
21514
|
+
failureReason: reason
|
|
21020
21515
|
};
|
|
21516
|
+
const record = buildRecord(input, decision2, subsession, deps, correlation.decisionID, correlation.batchID);
|
|
21517
|
+
await safeEmit(deps.sink, correlatedCostRecordToRouteEvent(record));
|
|
21518
|
+
return { decision: decision2, subsession, record, reportPath: composed.reportPath };
|
|
21021
21519
|
}
|
|
21520
|
+
if (admission?.ok === false)
|
|
21521
|
+
return denied(taskEffortMessages.exhausted(admission.reason));
|
|
21522
|
+
if (deps.signal?.aborted)
|
|
21523
|
+
return denied(taskEffortMessages.cancelled);
|
|
21524
|
+
const queueController = new AbortController;
|
|
21525
|
+
const queueSignal = deps.signal === undefined ? queueController.signal : AbortSignal.any([deps.signal, queueController.signal]);
|
|
21526
|
+
const queueDeadline = admission?.ok === true ? setTimeout(() => queueController.abort(), admission.remainingMs) : undefined;
|
|
21022
21527
|
try {
|
|
21528
|
+
if (runtimeId !== undefined && deps.runtimeLimiter !== undefined) {
|
|
21529
|
+
const limiter = deps.runtimeLimiter;
|
|
21530
|
+
const priority = priorityForRole(role);
|
|
21531
|
+
const dispatchRuntime = configuredRuntime2(runtimeId, input.config) ?? { id: runtimeId };
|
|
21532
|
+
const aliases = localModelAliases(decision2.selected.providerID, input.availableModels);
|
|
21533
|
+
const poolKey = slotPoolKey(withReportedModelSlots(dispatchRuntime, deps.reportedModelSlots?.(runtimeId), aliases), aliases.get(decision2.selected.modelID) ?? decision2.selected.modelID);
|
|
21534
|
+
release = limiter.tryAcquire(poolKey, priority);
|
|
21535
|
+
let waitedMs = 0;
|
|
21536
|
+
if (release === undefined) {
|
|
21537
|
+
let acquisition;
|
|
21538
|
+
try {
|
|
21539
|
+
acquisition = await limiter.acquire(poolKey, priority, queueSignal);
|
|
21540
|
+
} catch (error) {
|
|
21541
|
+
if (!queueSignal.aborted)
|
|
21542
|
+
throw error;
|
|
21543
|
+
return denied(queueController.signal.aborted ? taskEffortMessages.exhausted("duration") : taskEffortMessages.cancelled);
|
|
21544
|
+
}
|
|
21545
|
+
release = acquisition.release;
|
|
21546
|
+
waitedMs = acquisition.waitedMs;
|
|
21547
|
+
}
|
|
21548
|
+
queueObservation = {
|
|
21549
|
+
runtimeId,
|
|
21550
|
+
waitedMs,
|
|
21551
|
+
activeCount: limiter.activeCount(poolKey),
|
|
21552
|
+
queuedCount: limiter.queuedCount(poolKey)
|
|
21553
|
+
};
|
|
21554
|
+
}
|
|
21555
|
+
clearTimeout(queueDeadline);
|
|
21556
|
+
const effort = deps.taskEffort?.ledger.attempt(deps.taskEffort.ref);
|
|
21557
|
+
if (effort?.ok === false) {
|
|
21558
|
+
return denied(taskEffortMessages.exhausted(effort.reason));
|
|
21559
|
+
}
|
|
21560
|
+
if (effort?.ok === true) {
|
|
21561
|
+
subsessionDeps.timeoutMs = Math.min(subsessionDeps.timeoutMs ?? Infinity, effort.remainingMs);
|
|
21562
|
+
subsessionDeps.deadlineAt = deps.now() + effort.remainingMs;
|
|
21563
|
+
}
|
|
21564
|
+
if (deps.signal !== undefined)
|
|
21565
|
+
subsessionDeps.signal = deps.signal;
|
|
21023
21566
|
if (attemptLifecycle !== undefined) {
|
|
21024
21567
|
await recordLifecycle(attemptLifecycle.lifecycle, {
|
|
21025
21568
|
type: "attempt.started",
|
|
@@ -21047,8 +21590,17 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
21047
21590
|
await safeEmit(deps.sink, buildQueueEvent(queueObservation, sessionID, deps.now(), queueCorrelation));
|
|
21048
21591
|
}
|
|
21049
21592
|
}
|
|
21050
|
-
|
|
21593
|
+
const reportSubmitted = await reportLease?.close();
|
|
21594
|
+
return {
|
|
21595
|
+
decision: decision2,
|
|
21596
|
+
subsession,
|
|
21597
|
+
record,
|
|
21598
|
+
reportPath: composed.reportPath,
|
|
21599
|
+
...reportSubmitted === undefined ? {} : { reportSubmitted }
|
|
21600
|
+
};
|
|
21051
21601
|
} finally {
|
|
21602
|
+
clearTimeout(queueDeadline);
|
|
21603
|
+
await reportLease?.close();
|
|
21052
21604
|
release?.();
|
|
21053
21605
|
}
|
|
21054
21606
|
}
|
|
@@ -21160,15 +21712,19 @@ async function assessCurrentAttemptReport(input, before, result, deps) {
|
|
|
21160
21712
|
done: false
|
|
21161
21713
|
};
|
|
21162
21714
|
}
|
|
21163
|
-
if (after === before) {
|
|
21715
|
+
if (after === before && result.reportSubmitted !== true) {
|
|
21164
21716
|
return {
|
|
21165
21717
|
result: withFailure(gated, REPORT_STALE_REASON, "report"),
|
|
21166
21718
|
done: false
|
|
21167
21719
|
};
|
|
21168
21720
|
}
|
|
21721
|
+
const done = parseReportStatus(after) === "done" && reportHasSubstance(after);
|
|
21169
21722
|
return {
|
|
21170
21723
|
result: gated,
|
|
21171
|
-
done
|
|
21724
|
+
done,
|
|
21725
|
+
...!done ? {
|
|
21726
|
+
repairReason: !reportHasSubstance(after) ? "report-without-substance" : parseReportStatus(after) === "continue" ? "report-continue" : "report-status-missing"
|
|
21727
|
+
} : {}
|
|
21172
21728
|
};
|
|
21173
21729
|
}
|
|
21174
21730
|
function failedPassDisposition(subsession) {
|
|
@@ -21179,6 +21735,8 @@ function failedPassDisposition(subsession) {
|
|
|
21179
21735
|
if (subsession.failureStage === "report")
|
|
21180
21736
|
return "retry-incomplete";
|
|
21181
21737
|
if (subsession.normalizedFailure !== undefined) {
|
|
21738
|
+
if (subsession.normalizedFailure.failureClass === "prompt-output-truncated")
|
|
21739
|
+
return "retry-incomplete";
|
|
21182
21740
|
return subsession.normalizedFailure.retryable ? "retry-transport" : "terminal";
|
|
21183
21741
|
}
|
|
21184
21742
|
const failureReason = subsession.failureReason ?? "";
|
|
@@ -21278,6 +21836,7 @@ async function runNodeWithIteration(input, deps, correlation, batch, lifecycle)
|
|
|
21278
21836
|
let totalPasses = 0;
|
|
21279
21837
|
let spend = { usd: 0, frontierTokens: 0 };
|
|
21280
21838
|
let lastResult;
|
|
21839
|
+
let reportRepairReason;
|
|
21281
21840
|
let escalationReason;
|
|
21282
21841
|
const reportBatchID = correlation.batchID ?? correlation.decisionID;
|
|
21283
21842
|
modelLoop:
|
|
@@ -21350,14 +21909,19 @@ async function runNodeWithIteration(input, deps, correlation, batch, lifecycle)
|
|
|
21350
21909
|
retryIndex: pass - 1,
|
|
21351
21910
|
selectionCause: lifecycleSelectionCause(totalPasses, modelIndex, retryReason, escalationReason)
|
|
21352
21911
|
};
|
|
21353
|
-
let result = await runRoleTaskWithCorrelation(input, deps, attemptCorrelation, batch, attemptDecision, modelIndex > 0, reportBatchID, attemptLifecycle);
|
|
21912
|
+
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);
|
|
21354
21913
|
totalPasses += 1;
|
|
21355
21914
|
spend = {
|
|
21356
21915
|
usd: attemptDecision.estimatedCostUSD === null ? spend.usd : spend.usd + attemptDecision.estimatedCostUSD,
|
|
21357
21916
|
frontierTokens: spend.frontierTokens + (attemptDecision.routeKind === "frontier" ? (input.task.estimatedInputTokens ?? 0) + (input.task.estimatedOutputTokens ?? 0) : 0)
|
|
21358
21917
|
};
|
|
21918
|
+
if (result.subsession.sessionID !== undefined)
|
|
21919
|
+
await deps.sessionPhase?.(result.subsession.sessionID, "report-validation");
|
|
21359
21920
|
const assessment = await assessCurrentAttemptReport(input, before, result, deps);
|
|
21921
|
+
if (result.subsession.sessionID !== undefined)
|
|
21922
|
+
await deps.sessionPhase?.(result.subsession.sessionID, "idle");
|
|
21360
21923
|
result = assessment.result;
|
|
21924
|
+
reportRepairReason = assessment.repairReason ?? (result.subsession.failureStage === "report" ? result.subsession.failureReason : undefined);
|
|
21361
21925
|
lastResult = result;
|
|
21362
21926
|
if (assessment.done) {
|
|
21363
21927
|
await recordAttemptTerminal(attemptLifecycle, result, "none", true);
|
|
@@ -21443,13 +22007,28 @@ async function runRoleTasks(inputs, deps, options = {}) {
|
|
|
21443
22007
|
});
|
|
21444
22008
|
}
|
|
21445
22009
|
}
|
|
21446
|
-
const
|
|
21447
|
-
|
|
21448
|
-
|
|
21449
|
-
|
|
22010
|
+
const waveController = deps.taskEffort === undefined ? undefined : new AbortController;
|
|
22011
|
+
const waveDeps = waveController === undefined ? deps : {
|
|
22012
|
+
...deps,
|
|
22013
|
+
signal: deps.signal === undefined ? waveController.signal : AbortSignal.any([deps.signal, waveController.signal])
|
|
22014
|
+
};
|
|
22015
|
+
const waveTasks = runnable.map(async (input) => {
|
|
22016
|
+
try {
|
|
22017
|
+
const correlation = correlationByRole.get(input.roleID);
|
|
22018
|
+
if (correlation === undefined) {
|
|
22019
|
+
throw new Error(`missing correlation for ${input.roleID}`);
|
|
22020
|
+
}
|
|
22021
|
+
return await runNodeWithIteration(input, waveDeps, correlation, batch, lifecycle);
|
|
22022
|
+
} catch (error) {
|
|
22023
|
+
waveController?.abort();
|
|
22024
|
+
throw error;
|
|
21450
22025
|
}
|
|
21451
|
-
|
|
21452
|
-
|
|
22026
|
+
});
|
|
22027
|
+
const waveResults = waveController === undefined ? await Promise.all(waveTasks) : (await Promise.allSettled(waveTasks)).map((outcome) => {
|
|
22028
|
+
if (outcome.status === "rejected")
|
|
22029
|
+
throw outcome.reason;
|
|
22030
|
+
return outcome.value;
|
|
22031
|
+
});
|
|
21453
22032
|
for (const result of waveResults) {
|
|
21454
22033
|
allResults.push(result);
|
|
21455
22034
|
if (result.subsession.success) {
|
|
@@ -21478,7 +22057,7 @@ async function runRoleTasks(inputs, deps, options = {}) {
|
|
|
21478
22057
|
var _pluginWarnedRoles = new Set;
|
|
21479
22058
|
var EMPTY_ROLE_ID_SET = new Set;
|
|
21480
22059
|
var SAFE_ROLE_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
21481
|
-
var RoleIDSchema =
|
|
22060
|
+
var RoleIDSchema = z34.string().min(1).superRefine((roleID, ctx) => {
|
|
21482
22061
|
if (!SAFE_ROLE_ID.test(roleID)) {
|
|
21483
22062
|
ctx.addIssue({
|
|
21484
22063
|
code: "custom",
|
|
@@ -21486,16 +22065,16 @@ var RoleIDSchema = z32.string().min(1).superRefine((roleID, ctx) => {
|
|
|
21486
22065
|
});
|
|
21487
22066
|
}
|
|
21488
22067
|
});
|
|
21489
|
-
var RoleAssignmentSchema =
|
|
22068
|
+
var RoleAssignmentSchema = z34.object({
|
|
21490
22069
|
roleID: RoleIDSchema.describe("Role identifier from the roster"),
|
|
21491
|
-
prompt:
|
|
21492
|
-
title:
|
|
21493
|
-
dependsOn:
|
|
22070
|
+
prompt: z34.string().min(1).describe("Work prompt for this role"),
|
|
22071
|
+
title: z34.string().min(1).optional().describe("Human-readable title"),
|
|
22072
|
+
dependsOn: z34.array(RoleIDSchema).optional().describe("Role IDs this assignment depends on (DAG edges)")
|
|
21494
22073
|
}).strict();
|
|
21495
|
-
var OrchestratePayloadSchema =
|
|
21496
|
-
assignments:
|
|
21497
|
-
parentSessionID:
|
|
21498
|
-
directory:
|
|
22074
|
+
var OrchestratePayloadSchema = z34.object({
|
|
22075
|
+
assignments: z34.array(RoleAssignmentSchema).min(1).describe("Role assignments to distribute"),
|
|
22076
|
+
parentSessionID: z34.string().min(1).optional().describe(PARENT_SESSION_DESCRIPTION),
|
|
22077
|
+
directory: z34.string().min(1).optional().describe("Working directory override")
|
|
21499
22078
|
}).strict();
|
|
21500
22079
|
function validateAssignmentDependencies(assignments) {
|
|
21501
22080
|
const ids = new Set;
|
|
@@ -21680,8 +22259,15 @@ function adaptSdkClient(sdk, orchestratedModelOwnership) {
|
|
|
21680
22259
|
if (result.error !== undefined) {
|
|
21681
22260
|
out.error = normalizeSdkSessionFailure(result.error, "prompt");
|
|
21682
22261
|
} else {
|
|
22262
|
+
const info = isRecord7(result.data) ? nestedRecord2(result.data, "info") : undefined;
|
|
21683
22263
|
const nestedFailure = nestedAssistantFailure(result.data);
|
|
21684
|
-
if (
|
|
22264
|
+
if (info?.finish === "length" && info.truncatedToolCall === true) {
|
|
22265
|
+
out.error = {
|
|
22266
|
+
kind: "normalized-session-failure",
|
|
22267
|
+
failureClass: "prompt-output-truncated",
|
|
22268
|
+
retryable: true
|
|
22269
|
+
};
|
|
22270
|
+
} else if (nestedFailure !== undefined) {
|
|
21685
22271
|
out.error = normalizeSdkSessionFailure(nestedFailure, "prompt");
|
|
21686
22272
|
} else if (result.data !== undefined) {
|
|
21687
22273
|
out.data = result.data;
|
|
@@ -21841,7 +22427,10 @@ function mapTelemetryFailureClassToErrorClass(cls) {
|
|
|
21841
22427
|
case "prompt-rate-limited":
|
|
21842
22428
|
case "prompt-connection":
|
|
21843
22429
|
case "prompt-server":
|
|
22430
|
+
case "prompt-output-truncated":
|
|
21844
22431
|
return "transient";
|
|
22432
|
+
case "budget-exhausted":
|
|
22433
|
+
return "permanent";
|
|
21845
22434
|
case "create-rejected":
|
|
21846
22435
|
case "create-no-id":
|
|
21847
22436
|
case "prompt-rejected":
|
|
@@ -22124,8 +22713,16 @@ function createOrchestrateTool(deps) {
|
|
|
22124
22713
|
}
|
|
22125
22714
|
const parentOverrideIgnored = parsed.data.parentSessionID !== undefined && parsed.data.parentSessionID !== context.sessionID;
|
|
22126
22715
|
parsed.data.parentSessionID = context.sessionID;
|
|
22127
|
-
if (
|
|
22128
|
-
|
|
22716
|
+
if (deps.workspaceDirectory !== undefined) {
|
|
22717
|
+
const workspace = resolve11(deps.workspaceDirectory);
|
|
22718
|
+
if (resolve11(workspace, parsed.data.directory ?? ".") !== workspace)
|
|
22719
|
+
return reportDeliveryMessages.workspaceMismatch;
|
|
22720
|
+
parsed.data.directory = workspace;
|
|
22721
|
+
} else if (parsed.data.directory === undefined) {
|
|
22722
|
+
const directory = context.directory;
|
|
22723
|
+
if (directory !== undefined)
|
|
22724
|
+
parsed.data.directory = directory;
|
|
22725
|
+
}
|
|
22129
22726
|
const depError = validateAssignmentDependencies(parsed.data.assignments);
|
|
22130
22727
|
if (depError !== undefined) {
|
|
22131
22728
|
return dependencyValidationError(depError.code, depError.detail);
|
|
@@ -22148,6 +22745,14 @@ function createOrchestrateTool(deps) {
|
|
|
22148
22745
|
return missingAgentDefinition(agentName, input.roleID);
|
|
22149
22746
|
}
|
|
22150
22747
|
}
|
|
22748
|
+
const taskRef = await deps.taskEffort?.forSession(context.sessionID);
|
|
22749
|
+
if (taskRef !== undefined && deps.taskEffort !== undefined) {
|
|
22750
|
+
const effort2 = deps.taskEffort.batch(taskRef);
|
|
22751
|
+
if (!effort2.ok)
|
|
22752
|
+
return taskEffortMessages.exhausted(effort2.reason);
|
|
22753
|
+
for (const input of inputs)
|
|
22754
|
+
input.taskID = taskRef.taskID;
|
|
22755
|
+
}
|
|
22151
22756
|
const batchID = deps.newDecisionID();
|
|
22152
22757
|
if (deps.lifecycleRecorder !== undefined) {
|
|
22153
22758
|
const rootOperationID = operationID(batchID, "openteam");
|
|
@@ -22157,7 +22762,7 @@ function createOrchestrateTool(deps) {
|
|
|
22157
22762
|
executionAuthority: "coordinator",
|
|
22158
22763
|
root: {
|
|
22159
22764
|
operationID: rootOperationID,
|
|
22160
|
-
taskID: batchID,
|
|
22765
|
+
taskID: taskRef?.taskID ?? batchID,
|
|
22161
22766
|
kind: "coordinator",
|
|
22162
22767
|
roleID: "openteam",
|
|
22163
22768
|
agentID: context.agent,
|
|
@@ -22182,6 +22787,12 @@ function createOrchestrateTool(deps) {
|
|
|
22182
22787
|
reportedModelSlots: deps.reportedModelSlots,
|
|
22183
22788
|
readReportArtifact: deps.readReportArtifact,
|
|
22184
22789
|
reportArtifactExists: deps.reportArtifactExists,
|
|
22790
|
+
...deps.reportDelivery === undefined ? {} : { reportDelivery: deps.reportDelivery },
|
|
22791
|
+
...deps.sessionPhase === undefined ? {} : { sessionPhase: deps.sessionPhase },
|
|
22792
|
+
signal: context.abort,
|
|
22793
|
+
...deps.taskEffort === undefined || taskRef === undefined ? {} : {
|
|
22794
|
+
taskEffort: { ledger: deps.taskEffort, ref: taskRef }
|
|
22795
|
+
},
|
|
22185
22796
|
abortGraceMs: deps.abortGraceMs,
|
|
22186
22797
|
statusPollMs: deps.statusPollMs,
|
|
22187
22798
|
delay: deps.delay,
|
|
@@ -22199,10 +22810,15 @@ function createOrchestrateTool(deps) {
|
|
|
22199
22810
|
lifecycleStatus = activeLifecycleRecorder?.status() ?? lifecycleStatus;
|
|
22200
22811
|
const projected = projectResults(batch.results, batch.cancelled);
|
|
22201
22812
|
const shadowResult = await runShadowProducer(deps, parsed.data, batch);
|
|
22813
|
+
const effort = taskRef === undefined ? undefined : deps.taskEffort?.check(taskRef);
|
|
22814
|
+
const effortSummary = effort === undefined ? "" : `
|
|
22815
|
+
|
|
22816
|
+
${effort.ok ? taskEffortMessages.summary(effort.batches, effort.attempts, effort.remainingMs, effort.remainingBatches, effort.remainingAttempts) : taskEffortMessages.exhausted(effort.reason)}`;
|
|
22202
22817
|
const base = formatResult(projected) + (parentOverrideIgnored ? `
|
|
22203
22818
|
|
|
22204
|
-
${PARENT_OVERRIDE_IGNORED}` : "");
|
|
22205
|
-
const
|
|
22819
|
+
${PARENT_OVERRIDE_IGNORED}` : "") + effortSummary;
|
|
22820
|
+
const exhausted = effort?.ok === false || effort?.ok === true && (effort.remainingBatches === 0 || effort.remainingAttempts === 0);
|
|
22821
|
+
const advisory = exhausted ? undefined : singleAssignmentAdvisory(parsed.data.assignments.length, assignableRoleIDs(deps.config).length);
|
|
22206
22822
|
const withAdvisory = advisory === undefined ? base : `${base}
|
|
22207
22823
|
|
|
22208
22824
|
${advisory}`;
|
|
@@ -22233,7 +22849,7 @@ ${advisory}`;
|
|
|
22233
22849
|
|
|
22234
22850
|
// src/plugin/registerCastTool.ts
|
|
22235
22851
|
import { tool as tool6 } from "@opencode-ai/plugin";
|
|
22236
|
-
import { z as
|
|
22852
|
+
import { z as z35 } from "zod";
|
|
22237
22853
|
|
|
22238
22854
|
// src/messages/rosterSummary.ts
|
|
22239
22855
|
var ROSTER_SUMMARY_HEADING = "Registered team model policies";
|
|
@@ -22349,12 +22965,12 @@ function createTeamPreparation(deps) {
|
|
|
22349
22965
|
OpenTeamConfigSchema.parse(migrateConfig(baseRaw));
|
|
22350
22966
|
const overlay = overlayBefore === undefined ? undefined : parseConfigFileJson(DEFAULT_LOCAL_OVERLAY_PATH, overlayBefore);
|
|
22351
22967
|
const options = configOptionsFromPluginOptions(deps.options);
|
|
22352
|
-
const
|
|
22968
|
+
const resolve12 = (raw) => {
|
|
22353
22969
|
const config = validateConfigInput(TEAM_PREPARATION_CONFIG, mergeConfigInputs(mergeConfigInputs(raw, options), overlay));
|
|
22354
22970
|
assertEffectiveConfigModelDomains(config);
|
|
22355
22971
|
return config;
|
|
22356
22972
|
};
|
|
22357
|
-
const current =
|
|
22973
|
+
const current = resolve12(baseRaw);
|
|
22358
22974
|
const live = liveConfig ?? current;
|
|
22359
22975
|
if (resolveExecutionMode({
|
|
22360
22976
|
routerMode: current.router.executionMode,
|
|
@@ -22376,7 +22992,7 @@ function createTeamPreparation(deps) {
|
|
|
22376
22992
|
]))
|
|
22377
22993
|
}
|
|
22378
22994
|
});
|
|
22379
|
-
const effective =
|
|
22995
|
+
const effective = resolve12(candidate);
|
|
22380
22996
|
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)));
|
|
22381
22997
|
const additions = Object.fromEntries(Object.entries(effective.orchestrator?.roles ?? {}).filter(([key2, profile]) => requestedProfiles.has(profile) && !Object.hasOwn(live.orchestrator?.roles ?? {}, key2)));
|
|
22382
22998
|
const hasAdditions = Object.keys(additions).length > 0;
|
|
@@ -22462,13 +23078,13 @@ async function persistPreparedTeam(storage, files) {
|
|
|
22462
23078
|
}
|
|
22463
23079
|
|
|
22464
23080
|
// src/plugin/registerCastTool.ts
|
|
22465
|
-
var CastEntrySchema =
|
|
22466
|
-
roleID:
|
|
22467
|
-
agentName:
|
|
23081
|
+
var CastEntrySchema = z35.object({
|
|
23082
|
+
roleID: z35.string().min(1).describe("Stable role identifier, e.g. scribe or guardian"),
|
|
23083
|
+
agentName: z35.string().min(1).describe("Themed character name assigned to the role")
|
|
22468
23084
|
}).strict();
|
|
22469
|
-
var RegisterCastPayloadSchema =
|
|
22470
|
-
universe:
|
|
22471
|
-
entries:
|
|
23085
|
+
var RegisterCastPayloadSchema = z35.object({
|
|
23086
|
+
universe: z35.string().min(1).describe("Casting universe for this roster"),
|
|
23087
|
+
entries: z35.array(CastEntrySchema).min(1).describe("Role-to-name mappings")
|
|
22472
23088
|
}).strict();
|
|
22473
23089
|
function offendingFields(error) {
|
|
22474
23090
|
const fields = error.issues.flatMap((issue) => {
|
|
@@ -22588,7 +23204,7 @@ function createRegisterCastTool(deps) {
|
|
|
22588
23204
|
}
|
|
22589
23205
|
|
|
22590
23206
|
// src/plugin/reloadTool.ts
|
|
22591
|
-
import { resolve as
|
|
23207
|
+
import { resolve as resolve12 } from "node:path";
|
|
22592
23208
|
import { tool as tool7 } from "@opencode-ai/plugin/tool";
|
|
22593
23209
|
var WAIT_MS = 30000;
|
|
22594
23210
|
var SDK_TIMEOUT_MS = 5000;
|
|
@@ -22622,7 +23238,7 @@ function createReloadController(deps) {
|
|
|
22622
23238
|
return () => clearTimeout(timer);
|
|
22623
23239
|
}
|
|
22624
23240
|
};
|
|
22625
|
-
const directory =
|
|
23241
|
+
const directory = resolve12(deps.directory);
|
|
22626
23242
|
let pending;
|
|
22627
23243
|
let authorizing;
|
|
22628
23244
|
let closed = false;
|
|
@@ -22770,7 +23386,7 @@ function createReloadController(deps) {
|
|
|
22770
23386
|
const parsed = schema.safeParse(args);
|
|
22771
23387
|
if (!parsed.success)
|
|
22772
23388
|
return reloadMessages.invalid;
|
|
22773
|
-
if (context.agent !== "openteam" ||
|
|
23389
|
+
if (context.agent !== "openteam" || resolve12(context.directory) !== directory || context.sessionID.trim().length === 0)
|
|
22774
23390
|
return reloadMessages.denied;
|
|
22775
23391
|
if (parsed.data.action === "cancel") {
|
|
22776
23392
|
if ((pending?.sessionID ?? authorizing?.sessionID) !== context.sessionID)
|
|
@@ -22888,6 +23504,31 @@ function createReloadController(deps) {
|
|
|
22888
23504
|
};
|
|
22889
23505
|
}
|
|
22890
23506
|
|
|
23507
|
+
// src/plugin/reportTool.ts
|
|
23508
|
+
import { tool as tool8 } from "@opencode-ai/plugin";
|
|
23509
|
+
function createReportTool(delivery) {
|
|
23510
|
+
return tool8({
|
|
23511
|
+
description: reportDeliveryMessages.description,
|
|
23512
|
+
args: {
|
|
23513
|
+
status: tool8.schema.enum(["done", "continue"]).describe(reportDeliveryMessages.status),
|
|
23514
|
+
findings: tool8.schema.string().min(1).max(32768).describe(reportDeliveryMessages.findings)
|
|
23515
|
+
},
|
|
23516
|
+
async execute(args, context) {
|
|
23517
|
+
context.abort.throwIfAborted();
|
|
23518
|
+
const path4 = delivery.path(context.sessionID);
|
|
23519
|
+
await context.ask({
|
|
23520
|
+
permission: "openteam-submit-report",
|
|
23521
|
+
patterns: [path4],
|
|
23522
|
+
always: [],
|
|
23523
|
+
metadata: { reportPath: path4 }
|
|
23524
|
+
});
|
|
23525
|
+
context.abort.throwIfAborted();
|
|
23526
|
+
await delivery.submit(context.sessionID, args);
|
|
23527
|
+
return reportDeliveryMessages.submitted(path4);
|
|
23528
|
+
}
|
|
23529
|
+
});
|
|
23530
|
+
}
|
|
23531
|
+
|
|
22891
23532
|
// src/plugin/sessionTracker.ts
|
|
22892
23533
|
function createSessionTracker() {
|
|
22893
23534
|
const knownSessions = new Set;
|
|
@@ -22916,22 +23557,40 @@ function createSessionTracker() {
|
|
|
22916
23557
|
}
|
|
22917
23558
|
|
|
22918
23559
|
// src/plugin/toolcalls.ts
|
|
23560
|
+
var MAX_TRACKED_CALLS = 8192;
|
|
22919
23561
|
function key2(sessionID, callID) {
|
|
22920
23562
|
return `${sessionID}\x00${callID}`;
|
|
22921
23563
|
}
|
|
22922
23564
|
function createToolcallTracker(deps) {
|
|
22923
23565
|
const now = deps.now ?? Date.now;
|
|
22924
23566
|
const started = new Map;
|
|
23567
|
+
const completed = new Set;
|
|
22925
23568
|
return {
|
|
22926
23569
|
before(input) {
|
|
22927
|
-
|
|
23570
|
+
const mapKey = key2(input.sessionID, input.callID);
|
|
23571
|
+
if (completed.has(mapKey) || started.has(mapKey))
|
|
23572
|
+
return;
|
|
23573
|
+
started.set(mapKey, now());
|
|
23574
|
+
if (started.size > MAX_TRACKED_CALLS) {
|
|
23575
|
+
const oldest = started.keys().next().value;
|
|
23576
|
+
if (oldest !== undefined)
|
|
23577
|
+
started.delete(oldest);
|
|
23578
|
+
}
|
|
22928
23579
|
},
|
|
22929
23580
|
after(input) {
|
|
22930
23581
|
const mapKey = key2(input.sessionID, input.callID);
|
|
23582
|
+
if (completed.has(mapKey))
|
|
23583
|
+
return;
|
|
23584
|
+
completed.add(mapKey);
|
|
23585
|
+
if (completed.size > MAX_TRACKED_CALLS) {
|
|
23586
|
+
const oldest = completed.values().next().value;
|
|
23587
|
+
if (oldest !== undefined)
|
|
23588
|
+
completed.delete(oldest);
|
|
23589
|
+
}
|
|
22931
23590
|
const start = started.get(mapKey);
|
|
22932
23591
|
started.delete(mapKey);
|
|
22933
23592
|
const end = now();
|
|
22934
|
-
const durationMs = start === undefined ?
|
|
23593
|
+
const durationMs = input.durationMs !== undefined ? input.durationMs : start === undefined ? null : Math.max(0, Math.trunc(end - start));
|
|
22935
23594
|
const event = {
|
|
22936
23595
|
v: EVENT_SCHEMA_VERSION,
|
|
22937
23596
|
type: "toolcall",
|
|
@@ -22940,9 +23599,23 @@ function createToolcallTracker(deps) {
|
|
|
22940
23599
|
tool: input.tool,
|
|
22941
23600
|
callID: input.callID,
|
|
22942
23601
|
durationMs,
|
|
22943
|
-
ok: true
|
|
23602
|
+
ok: input.ok ?? true,
|
|
23603
|
+
...input.executed === undefined ? {} : { executed: input.executed },
|
|
23604
|
+
...input.providerExecuted === undefined ? {} : { providerExecuted: input.providerExecuted },
|
|
23605
|
+
...input.failureKind === undefined ? {} : { failureKind: input.failureKind }
|
|
22944
23606
|
};
|
|
22945
23607
|
return deps.sink.emit(event);
|
|
23608
|
+
},
|
|
23609
|
+
forgetSession(sessionID) {
|
|
23610
|
+
const prefix = `${sessionID}\x00`;
|
|
23611
|
+
for (const mapKey of started.keys()) {
|
|
23612
|
+
if (mapKey.startsWith(prefix))
|
|
23613
|
+
started.delete(mapKey);
|
|
23614
|
+
}
|
|
23615
|
+
for (const mapKey of completed) {
|
|
23616
|
+
if (mapKey.startsWith(prefix))
|
|
23617
|
+
completed.delete(mapKey);
|
|
23618
|
+
}
|
|
22946
23619
|
}
|
|
22947
23620
|
};
|
|
22948
23621
|
}
|
|
@@ -23147,22 +23820,22 @@ import {
|
|
|
23147
23820
|
statSync,
|
|
23148
23821
|
unlinkSync as unlinkSync2
|
|
23149
23822
|
} from "node:fs";
|
|
23150
|
-
import { join as join15, resolve as
|
|
23823
|
+
import { join as join15, resolve as resolve14 } from "node:path";
|
|
23151
23824
|
import { ZodError } from "zod";
|
|
23152
23825
|
|
|
23153
23826
|
// src/storage/lifecycle/codec.ts
|
|
23154
|
-
import { z as
|
|
23827
|
+
import { z as z36 } from "zod";
|
|
23155
23828
|
var LIFECYCLE_CODEC_VERSION = 1;
|
|
23156
23829
|
var LIFECYCLE_GENESIS_DIGEST = sha256Hex("openteam/lifecycle-journal/genesis/v1");
|
|
23157
23830
|
var NUL5 = "\x00";
|
|
23158
23831
|
var NEWLINE2 = `
|
|
23159
23832
|
`;
|
|
23160
|
-
var frameSchema =
|
|
23161
|
-
v:
|
|
23162
|
-
seq:
|
|
23163
|
-
prev:
|
|
23164
|
-
sum:
|
|
23165
|
-
event:
|
|
23833
|
+
var frameSchema = z36.object({
|
|
23834
|
+
v: z36.literal(LIFECYCLE_CODEC_VERSION),
|
|
23835
|
+
seq: z36.number().int().nonnegative(),
|
|
23836
|
+
prev: z36.string().min(1),
|
|
23837
|
+
sum: z36.string().min(1),
|
|
23838
|
+
event: z36.unknown()
|
|
23166
23839
|
}).strict();
|
|
23167
23840
|
function canonical2(value) {
|
|
23168
23841
|
if (Array.isArray(value)) {
|
|
@@ -23266,7 +23939,7 @@ import {
|
|
|
23266
23939
|
unlinkSync,
|
|
23267
23940
|
writeSync as writeSync2
|
|
23268
23941
|
} from "node:fs";
|
|
23269
|
-
import { basename as basename3, dirname as dirname7, join as join14, relative as relative3, resolve as
|
|
23942
|
+
import { basename as basename3, dirname as dirname7, join as join14, relative as relative3, resolve as resolve13 } from "node:path";
|
|
23270
23943
|
var SAFE_RUN_ID = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,126}[A-Za-z0-9])?$/u;
|
|
23271
23944
|
|
|
23272
23945
|
class LifecycleFsError extends Error {
|
|
@@ -23290,7 +23963,7 @@ function validateRunID(runID) {
|
|
|
23290
23963
|
}
|
|
23291
23964
|
function resolvedLifecycleRoot(root) {
|
|
23292
23965
|
try {
|
|
23293
|
-
const absolute =
|
|
23966
|
+
const absolute = resolve13(root);
|
|
23294
23967
|
mkdirSync2(absolute, { recursive: true });
|
|
23295
23968
|
const rootStat = lstatSync2(absolute);
|
|
23296
23969
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
|
|
@@ -23333,7 +24006,7 @@ function assertExistingSafeRun(root, runID) {
|
|
|
23333
24006
|
throw new LifecycleFsError("unavailable");
|
|
23334
24007
|
}
|
|
23335
24008
|
const child = relative3(root, real);
|
|
23336
|
-
if (child === "" || child.startsWith("..") ||
|
|
24009
|
+
if (child === "" || child.startsWith("..") || resolve13(root, child) !== real || dirname7(real) !== root) {
|
|
23337
24010
|
throw new LifecycleFsError("corrupt");
|
|
23338
24011
|
}
|
|
23339
24012
|
return real;
|
|
@@ -23573,7 +24246,7 @@ function canDeleteTerminalRun(runDir, runID, now) {
|
|
|
23573
24246
|
return now >= lease.expiresAt;
|
|
23574
24247
|
}
|
|
23575
24248
|
var createFsLifecycleJournal = (options) => {
|
|
23576
|
-
const configuredRoot =
|
|
24249
|
+
const configuredRoot = resolve14(options.root);
|
|
23577
24250
|
const now = options.now ?? Date.now;
|
|
23578
24251
|
const mutateRun = options.withMutationLock ?? withRunMutationLock;
|
|
23579
24252
|
return {
|
|
@@ -23929,6 +24602,61 @@ var createFsLifecycleWriterLivenessProbe = (options) => ({
|
|
|
23929
24602
|
}
|
|
23930
24603
|
});
|
|
23931
24604
|
|
|
24605
|
+
// src/storage/scopedArtifacts.ts
|
|
24606
|
+
import { lstatSync as lstatSync4, mkdirSync as mkdirSync4, realpathSync as realpathSync3 } from "node:fs";
|
|
24607
|
+
import { dirname as dirname8, join as join17 } from "node:path";
|
|
24608
|
+
function createScopedArtifactStore(directory, root) {
|
|
24609
|
+
function pathFor(name) {
|
|
24610
|
+
const workspace = realpathSync3(directory);
|
|
24611
|
+
const segments = [...splitVirtualPath(root), ...splitVirtualPath(name)];
|
|
24612
|
+
const filename = segments.pop();
|
|
24613
|
+
if (!filename)
|
|
24614
|
+
throw new Error(reportDeliveryMessages.unsafePath);
|
|
24615
|
+
let path4 = workspace;
|
|
24616
|
+
for (const segment of segments) {
|
|
24617
|
+
path4 = join17(path4, segment);
|
|
24618
|
+
try {
|
|
24619
|
+
mkdirSync4(path4, { mode: 448 });
|
|
24620
|
+
} catch (error) {
|
|
24621
|
+
if (!(typeof error === "object" && error !== null && ("code" in error) && error.code === "EEXIST"))
|
|
24622
|
+
throw error;
|
|
24623
|
+
}
|
|
24624
|
+
const stat4 = lstatSync4(path4);
|
|
24625
|
+
if (!stat4.isDirectory() || stat4.isSymbolicLink())
|
|
24626
|
+
throw new Error(reportDeliveryMessages.unsafePath);
|
|
24627
|
+
}
|
|
24628
|
+
const target = join17(path4, filename);
|
|
24629
|
+
try {
|
|
24630
|
+
const stat4 = lstatSync4(target);
|
|
24631
|
+
if (!stat4.isFile() || stat4.isSymbolicLink() || stat4.size > 1048576)
|
|
24632
|
+
throw new Error(reportDeliveryMessages.unsafePath);
|
|
24633
|
+
} catch (error) {
|
|
24634
|
+
if (!isMissingFsError(error))
|
|
24635
|
+
throw error;
|
|
24636
|
+
}
|
|
24637
|
+
return target;
|
|
24638
|
+
}
|
|
24639
|
+
return {
|
|
24640
|
+
read(name) {
|
|
24641
|
+
return readUtf8(pathFor(name));
|
|
24642
|
+
},
|
|
24643
|
+
write(name, content) {
|
|
24644
|
+
if (Buffer.byteLength(content, "utf8") > 1048576)
|
|
24645
|
+
throw new Error(reportDeliveryMessages.unsafePath);
|
|
24646
|
+
writeDurableAtomically(pathFor(name), content);
|
|
24647
|
+
},
|
|
24648
|
+
update(name, change) {
|
|
24649
|
+
const path4 = pathFor(name);
|
|
24650
|
+
withRunMutationLock(dirname8(path4), () => {
|
|
24651
|
+
const content = change(readUtf8(path4));
|
|
24652
|
+
if (Buffer.byteLength(content, "utf8") > 1048576)
|
|
24653
|
+
throw new Error(reportDeliveryMessages.unsafePath);
|
|
24654
|
+
writeDurableAtomically(path4, content);
|
|
24655
|
+
});
|
|
24656
|
+
}
|
|
24657
|
+
};
|
|
24658
|
+
}
|
|
24659
|
+
|
|
23932
24660
|
// src/telemetry/otelExporter.ts
|
|
23933
24661
|
var DEFAULT_SERVICE_NAME = "openteam";
|
|
23934
24662
|
function tracesUrl(ingestionEndpoint) {
|
|
@@ -24073,7 +24801,7 @@ var RELEASE_CERT_PATH = "artifacts/graph-release-certificate.json";
|
|
|
24073
24801
|
var SOAK_CERT_PATH = "artifacts/graph-soak-certificate.json";
|
|
24074
24802
|
async function readPackagedCertificate(path4) {
|
|
24075
24803
|
try {
|
|
24076
|
-
const hostDirectory = basename4(
|
|
24804
|
+
const hostDirectory = basename4(dirname9(path4)) === NATIVE_CERTIFICATE_DIRECTORY ? `${NATIVE_CERTIFICATE_DIRECTORY}/` : "";
|
|
24077
24805
|
return await readFile5(new URL(`./certificates/${hostDirectory}${basename4(path4)}`, import.meta.url), "utf8");
|
|
24078
24806
|
} catch {
|
|
24079
24807
|
return;
|
|
@@ -24206,8 +24934,8 @@ async function readOpencodeVersion(serverUrl, options = {}) {
|
|
|
24206
24934
|
}
|
|
24207
24935
|
var DEFAULT_OPENCODE_VERSION_BACKOFF_MS = [50, 250];
|
|
24208
24936
|
function defaultSleep(ms) {
|
|
24209
|
-
return new Promise((
|
|
24210
|
-
setTimeout(
|
|
24937
|
+
return new Promise((resolve16) => {
|
|
24938
|
+
setTimeout(resolve16, ms);
|
|
24211
24939
|
});
|
|
24212
24940
|
}
|
|
24213
24941
|
function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
@@ -24250,7 +24978,7 @@ function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
|
24250
24978
|
};
|
|
24251
24979
|
}
|
|
24252
24980
|
async function buildGateInput(config, storage, opencodeVersion, warn, packagedRead = readPackagedCertificate) {
|
|
24253
|
-
const hostPath = (path4) => isSupportedNativeOpencodeVersion(opencodeVersion) ? `${
|
|
24981
|
+
const hostPath = (path4) => isSupportedNativeOpencodeVersion(opencodeVersion) ? `${dirname9(path4)}/${NATIVE_CERTIFICATE_DIRECTORY}/${basename4(path4)}` : path4;
|
|
24254
24982
|
const shadow = await readAndParseCertificate(storage, hostPath(SHADOW_CERT_PATH), (raw) => parseShadowCertificate(raw, opencodeVersion), (cert) => shadowCertificateBindingDigest(cert.evidence), packagedRead);
|
|
24255
24983
|
const shadowDigest = shadow.status === "valid" ? shadow.digest : "0".repeat(64);
|
|
24256
24984
|
const release = await readAndParseCertificate(storage, hostPath(RELEASE_CERT_PATH), (raw) => parseReleaseCertificate(raw, opencodeVersion, shadowDigest), (cert) => cert.digest, packagedRead);
|
|
@@ -24459,7 +25187,7 @@ function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SE
|
|
|
24459
25187
|
telemetryPath,
|
|
24460
25188
|
opencodeConfigPaths: OPENCODE_CONFIG_CANDIDATES,
|
|
24461
25189
|
orchestratorAgentPath: ORCHESTRATOR_AGENT_PATH,
|
|
24462
|
-
agentDir:
|
|
25190
|
+
agentDir: dirname9(ORCHESTRATOR_AGENT_PATH),
|
|
24463
25191
|
cachePort: realCacheAdapter,
|
|
24464
25192
|
purge: createPluginPurgeRuntime(sessionsDir),
|
|
24465
25193
|
loadRosterForDoctor: () => readStoredRosterForDoctor(storage),
|
|
@@ -24610,6 +25338,24 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24610
25338
|
return version === "unknown" ? undefined : version;
|
|
24611
25339
|
}, workspaceRoot);
|
|
24612
25340
|
const toolcalls = createToolcallTracker({ sink });
|
|
25341
|
+
const sessionPhase = async (sessionID, phase) => {
|
|
25342
|
+
try {
|
|
25343
|
+
await sink.emit({
|
|
25344
|
+
v: 1,
|
|
25345
|
+
type: "activity",
|
|
25346
|
+
ts: now(),
|
|
25347
|
+
sessionID,
|
|
25348
|
+
kind: "agent",
|
|
25349
|
+
summary: executionPhaseMessages[phase],
|
|
25350
|
+
phase
|
|
25351
|
+
});
|
|
25352
|
+
} catch (error) {
|
|
25353
|
+
logTelemetryError(error, diagnostics.warn("telemetry-write-failed", {
|
|
25354
|
+
persist: false,
|
|
25355
|
+
toast: false
|
|
25356
|
+
}));
|
|
25357
|
+
}
|
|
25358
|
+
};
|
|
24613
25359
|
const announcedSessions = new Set;
|
|
24614
25360
|
const announceEndpoint = (sessionID) => {
|
|
24615
25361
|
if (sessionID === undefined || announcedSessions.has(sessionID)) {
|
|
@@ -24730,6 +25476,18 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24730
25476
|
},
|
|
24731
25477
|
now
|
|
24732
25478
|
});
|
|
25479
|
+
const reportStore = createScopedArtifactStore(ctx.directory, ROLE_REPORTS_ROOT);
|
|
25480
|
+
const taskEffort = createTaskEffort({
|
|
25481
|
+
store: createScopedArtifactStore(ctx.directory, ".opencode/openteam-local/effort"),
|
|
25482
|
+
now,
|
|
25483
|
+
...config.orchestrator?.taskBudget === undefined ? {} : { limits: config.orchestrator.taskBudget },
|
|
25484
|
+
...ctx.parentSession === undefined ? {} : { parentSession: ctx.parentSession }
|
|
25485
|
+
});
|
|
25486
|
+
const reportDelivery = createReportDelivery({
|
|
25487
|
+
write: async (path4, content) => {
|
|
25488
|
+
reportStore.write(path4.slice(ROLE_REPORTS_ROOT.length + 1), content);
|
|
25489
|
+
}
|
|
25490
|
+
});
|
|
24733
25491
|
const orchestrateTool = createOrchestrateTool({
|
|
24734
25492
|
client: orchestrateClient,
|
|
24735
25493
|
sink,
|
|
@@ -24750,11 +25508,15 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24750
25508
|
capabilityProfiles,
|
|
24751
25509
|
reportArtifactExists,
|
|
24752
25510
|
readReportArtifact,
|
|
25511
|
+
reportDelivery,
|
|
25512
|
+
taskEffort,
|
|
25513
|
+
sessionPhase,
|
|
25514
|
+
workspaceDirectory: ctx.directory,
|
|
24753
25515
|
lifecycleRecorder,
|
|
24754
25516
|
abortGraceMs: DEFAULT_ABORT_GRACE_MS,
|
|
24755
25517
|
statusPollMs: DEFAULT_STATUS_POLL_MS,
|
|
24756
|
-
delay: (ms) => new Promise((
|
|
24757
|
-
setTimeout(
|
|
25518
|
+
delay: (ms) => new Promise((resolve16) => {
|
|
25519
|
+
setTimeout(resolve16, ms);
|
|
24758
25520
|
}),
|
|
24759
25521
|
warn: diagnostics.warn("unknown-role")
|
|
24760
25522
|
});
|
|
@@ -24820,7 +25582,9 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24820
25582
|
...hooks,
|
|
24821
25583
|
"chat.message": async (input, output) => {
|
|
24822
25584
|
reload.userTurn(input.sessionID);
|
|
25585
|
+
await taskEffort.userTurn(input.sessionID, input.messageID ?? output.message.id);
|
|
24823
25586
|
await hooks["chat.message"]?.(input, output);
|
|
25587
|
+
await sessionPhase(input.sessionID, "model-request");
|
|
24824
25588
|
announceEndpoint(input.sessionID);
|
|
24825
25589
|
},
|
|
24826
25590
|
dispose: async () => {
|
|
@@ -24834,18 +25598,44 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24834
25598
|
"openteam-orchestrate": orchestrateTool,
|
|
24835
25599
|
"openteam-memory": memoryTool,
|
|
24836
25600
|
"openteam-register-cast": registerCastTool,
|
|
24837
|
-
"openteam-reload": reload.tool
|
|
25601
|
+
"openteam-reload": reload.tool,
|
|
25602
|
+
"openteam-submit-report": createReportTool(reportDelivery)
|
|
24838
25603
|
},
|
|
24839
25604
|
"tool.execute.before": async (input) => {
|
|
24840
25605
|
toolcalls.before(input);
|
|
25606
|
+
await sessionPhase(input.sessionID, "tool-execution");
|
|
24841
25607
|
},
|
|
24842
25608
|
"tool.execute.after": async (input) => {
|
|
24843
|
-
|
|
25609
|
+
if (ctx.toolOutcomesFromEvents !== true)
|
|
25610
|
+
await toolcalls.after(input);
|
|
24844
25611
|
if (input.tool === "openteam-reload")
|
|
24845
25612
|
reload.toolCompleted(input.sessionID);
|
|
24846
25613
|
},
|
|
24847
25614
|
event: async ({ event }) => {
|
|
24848
25615
|
reload.event(event);
|
|
25616
|
+
if (event.type === "openteam.tool.completed") {
|
|
25617
|
+
await toolcalls.after(event.properties);
|
|
25618
|
+
await sessionPhase(event.properties.sessionID, "unknown");
|
|
25619
|
+
} else if (event.type === "openteam.session.phase") {
|
|
25620
|
+
await sessionPhase(event.properties.sessionID, event.properties.phase);
|
|
25621
|
+
} else if (event.type === "session.idle") {
|
|
25622
|
+
if (typeof event.properties?.sessionID === "string")
|
|
25623
|
+
await sessionPhase(event.properties.sessionID, "idle");
|
|
25624
|
+
} else if (event.type === "message.part.updated") {
|
|
25625
|
+
const part = event.properties.part;
|
|
25626
|
+
if (part.type === "tool" && (part.state.status === "completed" || part.state.status === "error")) {
|
|
25627
|
+
await toolcalls.after({
|
|
25628
|
+
tool: part.tool,
|
|
25629
|
+
sessionID: part.sessionID,
|
|
25630
|
+
callID: part.callID,
|
|
25631
|
+
ok: part.state.status === "completed",
|
|
25632
|
+
durationMs: Math.max(0, Math.trunc(part.state.time.end - part.state.time.start)),
|
|
25633
|
+
...part.state.status === "error" ? { failureKind: "execution" } : {}
|
|
25634
|
+
});
|
|
25635
|
+
}
|
|
25636
|
+
} else if (event.type === "session.deleted") {
|
|
25637
|
+
toolcalls.forgetSession(event.properties.info.id);
|
|
25638
|
+
}
|
|
24849
25639
|
if (event.type === "session.created" || event.type === "session.idle") {
|
|
24850
25640
|
cache.refresh();
|
|
24851
25641
|
}
|
|
@@ -24862,6 +25652,7 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24862
25652
|
announceEndpoint(message.sessionID);
|
|
24863
25653
|
sessionTracker.trackSession(message.sessionID);
|
|
24864
25654
|
sink.emit(message);
|
|
25655
|
+
await sessionPhase(message.sessionID, "unknown");
|
|
24865
25656
|
}
|
|
24866
25657
|
}
|
|
24867
25658
|
}
|
|
@@ -24871,6 +25662,19 @@ var server = (ctx, rawOptions) => createPluginRuntime({
|
|
|
24871
25662
|
directory: ctx.directory,
|
|
24872
25663
|
worktree: ctx.worktree,
|
|
24873
25664
|
client: ctx.client,
|
|
25665
|
+
...typeof ctx.client.session?.get !== "function" ? {} : {
|
|
25666
|
+
parentSession: async (sessionID) => {
|
|
25667
|
+
const response = await ctx.client.session.get({
|
|
25668
|
+
path: { id: sessionID },
|
|
25669
|
+
query: { directory: ctx.directory }
|
|
25670
|
+
});
|
|
25671
|
+
if (response.error !== undefined || response.data === undefined)
|
|
25672
|
+
throw new Error(nativeHostMessages.missingBindings);
|
|
25673
|
+
if (resolve15(response.data.directory) !== resolve15(ctx.directory))
|
|
25674
|
+
throw new Error(nativeHostMessages.workspaceMismatch);
|
|
25675
|
+
return response.data.parentID;
|
|
25676
|
+
}
|
|
25677
|
+
},
|
|
24874
25678
|
exec: createShellExec(ctx.$),
|
|
24875
25679
|
serverUrl: () => ctx.serverUrl,
|
|
24876
25680
|
...ctx.client.config?.providers === undefined ? {} : {
|