@jmanuelcorral/openteam 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.opencode/openteam.example.json +7 -1
- package/README.es.md +22 -4
- package/README.md +28 -4
- package/dist/certificates/graph-release-certificate.json +2 -2
- package/dist/certificates/graph-shadow-certificate.json +2 -2
- package/dist/certificates/opencode-2.0.5/graph-release-certificate.json +2 -2
- package/dist/certificates/opencode-2.0.5/graph-shadow-certificate.json +2 -2
- package/dist/cli/opencodeVersion.d.ts.map +1 -1
- package/dist/cli.js +1641 -258
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/config/errors.d.ts.map +1 -1
- package/dist/config/graphFeatureGate.d.ts +3 -3
- package/dist/config/schema.d.ts +18 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/console/agentView.d.ts +13 -0
- package/dist/console/agentView.d.ts.map +1 -0
- package/dist/console/assets.d.ts.map +1 -1
- package/dist/console/inspector.d.ts.map +1 -1
- package/dist/console/refresh.d.ts +1 -1
- package/dist/console/refresh.d.ts.map +1 -1
- package/dist/console/render.d.ts +1 -0
- package/dist/console/render.d.ts.map +1 -1
- package/dist/contract/opencode.d.ts +13 -12
- package/dist/contract/opencode.d.ts.map +1 -1
- package/dist/graph/certificate.d.ts.map +1 -1
- package/dist/graph/schema.d.ts +6 -0
- package/dist/graph/schema.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1260 -434
- package/dist/lifecycle/contracts.d.ts +2 -2
- package/dist/lifecycle/contracts.d.ts.map +1 -1
- package/dist/lifecycle/schema.d.ts +6 -0
- package/dist/lifecycle/schema.d.ts.map +1 -1
- package/dist/local/concurrency.d.ts +1 -1
- package/dist/local/concurrency.d.ts.map +1 -1
- package/dist/messages/agentView.d.ts +77 -0
- package/dist/messages/agentView.d.ts.map +1 -0
- package/dist/messages/consoleDetail.d.ts +9 -0
- package/dist/messages/consoleDetail.d.ts.map +1 -1
- package/dist/messages/nativeHost.d.ts +1 -0
- package/dist/messages/nativeHost.d.ts.map +1 -1
- package/dist/messages/orchestration.d.ts +26 -0
- package/dist/messages/orchestration.d.ts.map +1 -1
- package/dist/opencodeArtifacts/orchestratorAgent.d.ts.map +1 -1
- package/dist/orchestrator/coordinator.d.ts +13 -1
- package/dist/orchestrator/coordinator.d.ts.map +1 -1
- package/dist/orchestrator/outputContract.d.ts +3 -0
- package/dist/orchestrator/outputContract.d.ts.map +1 -1
- package/dist/orchestrator/reportDelivery.d.ts +13 -0
- package/dist/orchestrator/reportDelivery.d.ts.map +1 -0
- package/dist/orchestrator/subsessions.d.ts +5 -0
- package/dist/orchestrator/subsessions.d.ts.map +1 -1
- package/dist/orchestrator/taskEffort.d.ts +39 -0
- package/dist/orchestrator/taskEffort.d.ts.map +1 -0
- package/dist/plugin/capture.d.ts +3 -0
- package/dist/plugin/capture.d.ts.map +1 -1
- package/dist/plugin/nativeHost.d.ts.map +1 -1
- package/dist/plugin/nativeHostContext.d.ts +1 -1
- package/dist/plugin/nativeHostContext.d.ts.map +1 -1
- package/dist/plugin/nativeSessions.d.ts +9 -0
- package/dist/plugin/nativeSessions.d.ts.map +1 -1
- package/dist/plugin/orchestrateTool.d.ts +6 -0
- package/dist/plugin/orchestrateTool.d.ts.map +1 -1
- package/dist/plugin/reportTool.d.ts +4 -0
- package/dist/plugin/reportTool.d.ts.map +1 -0
- package/dist/plugin/runtimeContext.d.ts +14 -0
- package/dist/plugin/runtimeContext.d.ts.map +1 -1
- package/dist/plugin/toolcalls.d.ts +9 -1
- package/dist/plugin/toolcalls.d.ts.map +1 -1
- package/dist/storage/scopedArtifacts.d.ts +7 -0
- package/dist/storage/scopedArtifacts.d.ts.map +1 -0
- package/dist/telemetry/aggregate.d.ts +7 -0
- package/dist/telemetry/aggregate.d.ts.map +1 -1
- package/dist/telemetry/events.d.ts +68 -2
- package/dist/telemetry/events.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/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",
|
|
@@ -7925,10 +7979,31 @@ function parseSemver(version) {
|
|
|
7925
7979
|
patch: Number(match[3])
|
|
7926
7980
|
};
|
|
7927
7981
|
}
|
|
7982
|
+
function compareSemver2(a, b) {
|
|
7983
|
+
if (a.major !== b.major) {
|
|
7984
|
+
return a.major < b.major ? -1 : 1;
|
|
7985
|
+
}
|
|
7986
|
+
if (a.minor !== b.minor) {
|
|
7987
|
+
return a.minor < b.minor ? -1 : 1;
|
|
7988
|
+
}
|
|
7989
|
+
if (a.patch !== b.patch) {
|
|
7990
|
+
return a.patch < b.patch ? -1 : 1;
|
|
7991
|
+
}
|
|
7992
|
+
return 0;
|
|
7993
|
+
}
|
|
7994
|
+
function isSupportedNativeOpencodeVersion(version) {
|
|
7995
|
+
if (version === undefined || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.test(version))
|
|
7996
|
+
return false;
|
|
7997
|
+
const live = parseSemver(version);
|
|
7998
|
+
const minimum = parseSemver(NATIVE_OPENCODE_VERSION);
|
|
7999
|
+
return Object.values(live).every(Number.isSafeInteger) && live.major === minimum.major && compareSemver2(live, minimum) >= 0;
|
|
8000
|
+
}
|
|
7928
8001
|
function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
7929
8002
|
if (certifiedVersion === liveVersion) {
|
|
7930
8003
|
return true;
|
|
7931
8004
|
}
|
|
8005
|
+
if (isSupportedNativeOpencodeVersion(certifiedVersion) && isSupportedNativeOpencodeVersion(liveVersion))
|
|
8006
|
+
return compareSemver2(parseSemver(liveVersion), parseSemver(certifiedVersion)) >= 0;
|
|
7932
8007
|
let certified;
|
|
7933
8008
|
let live;
|
|
7934
8009
|
try {
|
|
@@ -7946,6 +8021,29 @@ function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
|
7946
8021
|
// src/graph/certificate.ts
|
|
7947
8022
|
import { z as z17 } from "zod";
|
|
7948
8023
|
|
|
8024
|
+
// src/messages/nativeHost.ts
|
|
8025
|
+
var nativeHostMessages = {
|
|
8026
|
+
invalidNativeConfig: "The existing native opencode plugins/providers configuration cannot be safely merged. Correct its object and plugin declaration shapes before running setup.",
|
|
8027
|
+
setupPolicyQuestion: (paths, providers) => `Remove exact project-local provider.use deny rules for ${providers.join(", ")} from ${paths.join(", ")}? Older setup added these rules, but they may also be operator limits. Confirm only if you intend to enable the guarded native transport.`,
|
|
8028
|
+
setupPolicyPreserved: "Setup stopped. Provider-denial rules were preserved and no files were written.",
|
|
8029
|
+
setupPolicyNotice: "Only the explicitly reviewed project rules were removed. Wildcard, scoped, unrelated and global provider denials remain authoritative.",
|
|
8030
|
+
unsupportedVersion: (version) => `openteam does not support native opencode ${version}. The supported stable native range is >=2.0.5 <3.0.0.`,
|
|
8031
|
+
certificateVersionMismatch: (certified, live) => `certified for "${certified}", running "${live}" — evidence is outside the supported host compatibility range`,
|
|
8032
|
+
missingBindings: "The native opencode execution context is unavailable. No child session or privileged operation was started.",
|
|
8033
|
+
missingVersion: "The opencode host did not provide an authoritative version or server endpoint.",
|
|
8034
|
+
workspaceMismatch: "The native opencode session does not belong to this workspace.",
|
|
8035
|
+
noCompletedResponse: "The native opencode session stopped without a completed assistant response.",
|
|
8036
|
+
executionFailed: "The native opencode session failed.",
|
|
8037
|
+
executionInterrupted: "The native opencode session was interrupted.",
|
|
8038
|
+
unknownAgent: "The native opencode session has no available agent.",
|
|
8039
|
+
noAvailableModel: "The native opencode host has no model available in the configured execution domain.",
|
|
8040
|
+
executionDomainBlocked: "The native opencode request is outside the configured execution domain.",
|
|
8041
|
+
transportUnavailable: "This local runtime requires the guarded @ai-sdk/openai-compatible transport. Native and WebSocket transports are not admitted.",
|
|
8042
|
+
missingAdmission: "The native local request has no matching model authorization. No inference was sent.",
|
|
8043
|
+
toolFailed: "The openteam tool failed in the native opencode host.",
|
|
8044
|
+
eventCaptureFailed: "Native opencode event capture failed. The console may be missing activity; reload the plugin after resolving the host error."
|
|
8045
|
+
};
|
|
8046
|
+
|
|
7949
8047
|
// src/graph/soakLedger.ts
|
|
7950
8048
|
import { z as z16 } from "zod";
|
|
7951
8049
|
var Sha256Schema2 = z16.string().regex(/^[0-9a-f]{64}$/);
|
|
@@ -8204,7 +8302,7 @@ function parseShadowCertificate(value, opencodeVersion) {
|
|
|
8204
8302
|
throw new ShadowCertificateError("digest-mismatch", "certificate digest does not cover the presented evidence");
|
|
8205
8303
|
}
|
|
8206
8304
|
if (!isCertificateVersionCompatible(certificate.opencodeVersion, opencodeVersion)) {
|
|
8207
|
-
throw new ShadowCertificateError("opencode-mismatch",
|
|
8305
|
+
throw new ShadowCertificateError("opencode-mismatch", nativeHostMessages.certificateVersionMismatch(certificate.opencodeVersion, opencodeVersion));
|
|
8208
8306
|
}
|
|
8209
8307
|
return certificate;
|
|
8210
8308
|
}
|
|
@@ -8389,7 +8487,7 @@ function parseReleaseCertificate(value, opencodeVersion, expectedShadowDigest) {
|
|
|
8389
8487
|
throw new ReleaseCertificateError("digest-mismatch", "certificate digest does not cover the presented evidence");
|
|
8390
8488
|
}
|
|
8391
8489
|
if (!isCertificateVersionCompatible(certificate.opencodeVersion, opencodeVersion)) {
|
|
8392
|
-
throw new ReleaseCertificateError("opencode-mismatch",
|
|
8490
|
+
throw new ReleaseCertificateError("opencode-mismatch", nativeHostMessages.certificateVersionMismatch(certificate.opencodeVersion, opencodeVersion));
|
|
8393
8491
|
}
|
|
8394
8492
|
return certificate;
|
|
8395
8493
|
}
|
|
@@ -8635,6 +8733,7 @@ var lifecycleFailureSchema = z18.object({
|
|
|
8635
8733
|
"prompt-auth",
|
|
8636
8734
|
"prompt-content-filter",
|
|
8637
8735
|
"prompt-context-length",
|
|
8736
|
+
"prompt-output-truncated",
|
|
8638
8737
|
"prompt-validation",
|
|
8639
8738
|
"prompt-connection",
|
|
8640
8739
|
"prompt-server",
|
|
@@ -9686,17 +9785,31 @@ function createRuntimeConcurrencyLimiter(options) {
|
|
|
9686
9785
|
}
|
|
9687
9786
|
return {
|
|
9688
9787
|
tryAcquire,
|
|
9689
|
-
acquire(runtimeId, priority = "worker") {
|
|
9788
|
+
async acquire(runtimeId, priority = "worker", signal) {
|
|
9789
|
+
signal?.throwIfAborted();
|
|
9690
9790
|
const immediate = tryAcquire(runtimeId, priority);
|
|
9691
9791
|
if (immediate !== undefined) {
|
|
9692
9792
|
return Promise.resolve({ release: immediate, waitedMs: 0 });
|
|
9693
9793
|
}
|
|
9694
9794
|
const state = stateFor(runtimeId);
|
|
9695
9795
|
const queuedAt = options.now();
|
|
9696
|
-
return new Promise((resolve5) => {
|
|
9697
|
-
|
|
9796
|
+
return new Promise((resolve5, reject) => {
|
|
9797
|
+
const waiter = (release) => {
|
|
9798
|
+
signal?.removeEventListener("abort", cancel);
|
|
9698
9799
|
resolve5({ release, waitedMs: options.now() - queuedAt });
|
|
9699
|
-
}
|
|
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();
|
|
9700
9813
|
});
|
|
9701
9814
|
},
|
|
9702
9815
|
activeCount(runtimeId) {
|
|
@@ -11033,29 +11146,33 @@ function withReportedModelSlots(runtime, reported, aliases) {
|
|
|
11033
11146
|
};
|
|
11034
11147
|
}
|
|
11035
11148
|
|
|
11036
|
-
// src/messages/nativeHost.ts
|
|
11037
|
-
var nativeHostMessages = {
|
|
11038
|
-
invalidNativeConfig: "The existing native opencode plugins/providers configuration cannot be safely merged. Correct its object and plugin declaration shapes before running setup.",
|
|
11039
|
-
setupPolicyQuestion: (paths, providers) => `Remove exact project-local provider.use deny rules for ${providers.join(", ")} from ${paths.join(", ")}? Older setup added these rules, but they may also be operator limits. Confirm only if you intend to enable the guarded native transport.`,
|
|
11040
|
-
setupPolicyPreserved: "Setup stopped. Provider-denial rules were preserved and no files were written.",
|
|
11041
|
-
setupPolicyNotice: "Only the explicitly reviewed project rules were removed. Wildcard, scoped, unrelated and global provider denials remain authoritative.",
|
|
11042
|
-
unsupportedVersion: (version) => `openteam has not verified the native plugin contract for opencode ${version}. The supported native host is 2.0.5.`,
|
|
11043
|
-
missingBindings: "The native opencode execution context is unavailable. No child session or privileged operation was started.",
|
|
11044
|
-
missingVersion: "The opencode host did not provide an authoritative version or server endpoint.",
|
|
11045
|
-
workspaceMismatch: "The native opencode session does not belong to this workspace.",
|
|
11046
|
-
noCompletedResponse: "The native opencode session stopped without a completed assistant response.",
|
|
11047
|
-
executionFailed: "The native opencode session failed.",
|
|
11048
|
-
executionInterrupted: "The native opencode session was interrupted.",
|
|
11049
|
-
unknownAgent: "The native opencode session has no available agent.",
|
|
11050
|
-
noAvailableModel: "The native opencode host has no model available in the configured execution domain.",
|
|
11051
|
-
executionDomainBlocked: "The native opencode request is outside the configured execution domain.",
|
|
11052
|
-
transportUnavailable: "This local runtime requires the guarded @ai-sdk/openai-compatible transport. Native and WebSocket transports are not admitted.",
|
|
11053
|
-
missingAdmission: "The native local request has no matching model authorization. No inference was sent.",
|
|
11054
|
-
toolFailed: "The openteam tool failed in the native opencode host.",
|
|
11055
|
-
eventCaptureFailed: "Native opencode event capture failed. The console may be missing activity; reload the plugin after resolving the host error."
|
|
11056
|
-
};
|
|
11057
|
-
|
|
11058
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
|
+
};
|
|
11059
11176
|
var HOST_SESSION_REQUIRED = "Orchestration requires a nonempty host ToolContext sessionID.";
|
|
11060
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.";
|
|
11061
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.";
|
|
@@ -11126,6 +11243,183 @@ function incapableFixedModel(roleID, providerID, modelID) {
|
|
|
11126
11243
|
return `openteam coordinator: request for role "${roleID}" blocked — ` + `execution-policy-model-incapable. Configured model "${providerID}/${modelID}" ` + `does not satisfy the role capability requirements.`;
|
|
11127
11244
|
}
|
|
11128
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
|
+
|
|
11129
11423
|
// src/orchestrator/reportArtifactProbe.ts
|
|
11130
11424
|
import { stat as stat2 } from "node:fs/promises";
|
|
11131
11425
|
var reportArtifactExists = async (reportPath) => {
|
|
@@ -11147,15 +11441,76 @@ var readReportArtifact = async (reportPath) => {
|
|
|
11147
11441
|
}
|
|
11148
11442
|
};
|
|
11149
11443
|
|
|
11150
|
-
// src/orchestrator/
|
|
11444
|
+
// src/orchestrator/reportDelivery.ts
|
|
11151
11445
|
import { z as z20 } from "zod";
|
|
11152
|
-
var
|
|
11153
|
-
|
|
11154
|
-
|
|
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)
|
|
11155
11510
|
}).strict();
|
|
11156
|
-
var RosterSchema =
|
|
11157
|
-
universe:
|
|
11158
|
-
entries:
|
|
11511
|
+
var RosterSchema = z21.object({
|
|
11512
|
+
universe: z21.string().min(1),
|
|
11513
|
+
entries: z21.array(RosterEntrySchema)
|
|
11159
11514
|
}).strict();
|
|
11160
11515
|
var ROSTER_JSON_FENCE = /```json\s*([\s\S]*?)```/;
|
|
11161
11516
|
|
|
@@ -11563,15 +11918,21 @@ function promptArgs(sessionID, req, signal) {
|
|
|
11563
11918
|
}
|
|
11564
11919
|
return args;
|
|
11565
11920
|
}
|
|
11566
|
-
async function withTimeout(promise, timeoutMs) {
|
|
11567
|
-
if (timeoutMs === undefined) {
|
|
11921
|
+
async function withTimeout(promise, timeoutMs, signal) {
|
|
11922
|
+
if (timeoutMs === undefined && signal === undefined) {
|
|
11568
11923
|
return { kind: "settled", value: await promise };
|
|
11569
11924
|
}
|
|
11570
11925
|
let timeoutID;
|
|
11926
|
+
let abortListener;
|
|
11571
11927
|
const timeout = new Promise((resolve5) => {
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
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();
|
|
11575
11936
|
});
|
|
11576
11937
|
try {
|
|
11577
11938
|
return await Promise.race([
|
|
@@ -11580,6 +11941,8 @@ async function withTimeout(promise, timeoutMs) {
|
|
|
11580
11941
|
]);
|
|
11581
11942
|
} finally {
|
|
11582
11943
|
clearTimeout(timeoutID);
|
|
11944
|
+
if (abortListener !== undefined)
|
|
11945
|
+
signal?.removeEventListener("abort", abortListener);
|
|
11583
11946
|
}
|
|
11584
11947
|
}
|
|
11585
11948
|
async function beforeDeadline(request, deadline, deps) {
|
|
@@ -11701,7 +12064,35 @@ async function confirmPromptRequestSettled(isSettled, deps, deadline) {
|
|
|
11701
12064
|
async function runSubsession(client, req, deps) {
|
|
11702
12065
|
let sessionID;
|
|
11703
12066
|
try {
|
|
11704
|
-
|
|
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;
|
|
11705
12096
|
if (created.error !== undefined) {
|
|
11706
12097
|
const normalizedFailure = isNormalizedSessionFailure(created.error) ? created.error : undefined;
|
|
11707
12098
|
return {
|
|
@@ -11728,19 +12119,32 @@ async function runSubsession(client, req, deps) {
|
|
|
11728
12119
|
try {
|
|
11729
12120
|
await deps.onSessionCreated?.(sessionID);
|
|
11730
12121
|
} catch {}
|
|
11731
|
-
|
|
11732
|
-
|
|
11733
|
-
|
|
11734
|
-
|
|
11735
|
-
|
|
11736
|
-
|
|
11737
|
-
|
|
11738
|
-
|
|
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
|
+
};
|
|
12134
|
+
} catch (error) {
|
|
12135
|
+
return {
|
|
12136
|
+
success: false,
|
|
12137
|
+
roleID: req.roleID,
|
|
12138
|
+
model: req.model,
|
|
12139
|
+
failureStage: "create",
|
|
12140
|
+
failureReason: deps.signal?.aborted ? taskEffortMessages.cancelled : errorReason(error),
|
|
12141
|
+
retrySafe: deps.signal?.aborted !== true
|
|
11739
12142
|
};
|
|
11740
12143
|
}
|
|
11741
12144
|
const promptController = new AbortController;
|
|
12145
|
+
const promptSignal = deps.signal === undefined ? promptController.signal : AbortSignal.any([deps.signal, promptController.signal]);
|
|
11742
12146
|
let promptSettled = false;
|
|
11743
|
-
const promptPromise = client.session.prompt(promptArgs(sessionID, req,
|
|
12147
|
+
const promptPromise = client.session.prompt(promptArgs(sessionID, req, promptSignal)).then((value) => {
|
|
11744
12148
|
promptSettled = true;
|
|
11745
12149
|
return value;
|
|
11746
12150
|
}, (error) => {
|
|
@@ -11748,8 +12152,9 @@ async function runSubsession(client, req, deps) {
|
|
|
11748
12152
|
throw error;
|
|
11749
12153
|
});
|
|
11750
12154
|
try {
|
|
11751
|
-
const
|
|
11752
|
-
|
|
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") {
|
|
11753
12158
|
promptController.abort();
|
|
11754
12159
|
const stopDeadline = deps.now() + Math.max(0, deps.abortGraceMs);
|
|
11755
12160
|
const stopped = await confirmSessionStopped(client, sessionID, req.directory, deps, stopDeadline);
|
|
@@ -11760,8 +12165,8 @@ async function runSubsession(client, req, deps) {
|
|
|
11760
12165
|
roleID: req.roleID,
|
|
11761
12166
|
model: req.model,
|
|
11762
12167
|
failureStage: "prompt",
|
|
11763
|
-
failureReason: !stopped.confirmed ? promptStopUnconfirmed(stopped.cause) : requestSettled ? promptTimedOut(deps.timeoutMs ?? 0) : promptStopUnconfirmed("request-unsettled"),
|
|
11764
|
-
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)
|
|
11765
12170
|
};
|
|
11766
12171
|
}
|
|
11767
12172
|
const prompted = outcome.value;
|
|
@@ -11794,12 +12199,137 @@ async function runSubsession(client, req, deps) {
|
|
|
11794
12199
|
roleID: req.roleID,
|
|
11795
12200
|
model: req.model,
|
|
11796
12201
|
failureStage: "prompt",
|
|
11797
|
-
failureReason: stopped.confirmed ? errorReason(error) : promptStopUnconfirmed(stopped.cause),
|
|
11798
|
-
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
|
|
11799
12204
|
};
|
|
11800
12205
|
}
|
|
11801
12206
|
}
|
|
11802
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
|
+
|
|
11803
12333
|
// src/local/modelResidency.ts
|
|
11804
12334
|
function runtimeRequiresModelResidency(kind) {
|
|
11805
12335
|
return kind === "lemonade" || kind === "llama-swap";
|
|
@@ -12053,7 +12583,7 @@ function createAvailabilityCache(options) {
|
|
|
12053
12583
|
|
|
12054
12584
|
// src/plugin/capture.ts
|
|
12055
12585
|
function nonNeg(value) {
|
|
12056
|
-
return typeof value === "number" && value >= 0 ? Math.trunc(value) : 0;
|
|
12586
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.trunc(value) : 0;
|
|
12057
12587
|
}
|
|
12058
12588
|
function messageEventFrom(info, now) {
|
|
12059
12589
|
if (info.role !== "assistant") {
|
|
@@ -12067,6 +12597,17 @@ function messageEventFrom(info, now) {
|
|
|
12067
12597
|
}
|
|
12068
12598
|
const created = info.time.created ?? info.time.completed;
|
|
12069
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;
|
|
12070
12611
|
const event = {
|
|
12071
12612
|
v: EVENT_SCHEMA_VERSION,
|
|
12072
12613
|
type: "message",
|
|
@@ -12074,7 +12615,11 @@ function messageEventFrom(info, now) {
|
|
|
12074
12615
|
sessionID: info.sessionID,
|
|
12075
12616
|
providerID: info.providerID,
|
|
12076
12617
|
modelID: info.modelID,
|
|
12077
|
-
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 } : {},
|
|
12078
12623
|
tokensIn: nonNeg(info.tokens?.input),
|
|
12079
12624
|
tokensOut: nonNeg(info.tokens?.output),
|
|
12080
12625
|
tokensReasoning: nonNeg(info.tokens?.reasoning),
|
|
@@ -12085,6 +12630,18 @@ function messageEventFrom(info, now) {
|
|
|
12085
12630
|
if (info.mode !== undefined) {
|
|
12086
12631
|
event.mode = info.mode;
|
|
12087
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
|
+
}
|
|
12088
12645
|
if (info.id !== undefined) {
|
|
12089
12646
|
event.messageID = info.id;
|
|
12090
12647
|
}
|
|
@@ -12213,7 +12770,7 @@ function planWorktreeReconciliation(input) {
|
|
|
12213
12770
|
}
|
|
12214
12771
|
|
|
12215
12772
|
// src/telemetry/otelConfig.ts
|
|
12216
|
-
import { z as
|
|
12773
|
+
import { z as z23 } from "zod";
|
|
12217
12774
|
|
|
12218
12775
|
// src/telemetry/fanout.ts
|
|
12219
12776
|
function createFanOutSink(deps) {
|
|
@@ -12291,10 +12848,10 @@ function createOtelSink(deps) {
|
|
|
12291
12848
|
}
|
|
12292
12849
|
|
|
12293
12850
|
// src/telemetry/otelConfig.ts
|
|
12294
|
-
var OtelBackendConfigSchema =
|
|
12295
|
-
backend:
|
|
12296
|
-
connectionEnv:
|
|
12297
|
-
serviceName:
|
|
12851
|
+
var OtelBackendConfigSchema = z23.object({
|
|
12852
|
+
backend: z23.literal("opentelemetry"),
|
|
12853
|
+
connectionEnv: z23.string().min(1),
|
|
12854
|
+
serviceName: z23.string().min(1).optional()
|
|
12298
12855
|
}).strict();
|
|
12299
12856
|
function parseConnectionString(raw) {
|
|
12300
12857
|
const pairs = new Map;
|
|
@@ -15691,29 +16248,29 @@ import {
|
|
|
15691
16248
|
unlink
|
|
15692
16249
|
} from "node:fs/promises";
|
|
15693
16250
|
import { dirname as dirname5, join as join12, resolve as resolve7 } from "node:path";
|
|
15694
|
-
import { z as
|
|
16251
|
+
import { z as z24 } from "zod";
|
|
15695
16252
|
var CONSOLE_RUNTIME_SCHEMA_VERSION = 1;
|
|
15696
16253
|
var CONSOLE_RUNTIME_DIRECTORY = ".opencode/openteam-local/console";
|
|
15697
16254
|
var CONSOLE_RUNTIME_FILE = "runtime.json";
|
|
15698
16255
|
var CONSOLE_LAUNCH_LOCK_FILE = "launch.lock";
|
|
15699
16256
|
var CONSOLE_LOG_FILE = "console.log";
|
|
15700
|
-
var ConsoleRuntimeStateSchema =
|
|
15701
|
-
schemaVersion:
|
|
15702
|
-
pid:
|
|
15703
|
-
workspaceRoot:
|
|
15704
|
-
host:
|
|
15705
|
-
port:
|
|
15706
|
-
url:
|
|
15707
|
-
startedAt:
|
|
15708
|
-
launchId:
|
|
15709
|
-
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)
|
|
15710
16267
|
}).strict();
|
|
15711
|
-
var ConsoleLaunchLockSchema =
|
|
15712
|
-
schemaVersion:
|
|
15713
|
-
workspaceRoot:
|
|
15714
|
-
launchId:
|
|
15715
|
-
ownerPid:
|
|
15716
|
-
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 })
|
|
15717
16274
|
}).strict();
|
|
15718
16275
|
|
|
15719
16276
|
class ConsoleRuntimeStateFileError extends Error {
|
|
@@ -16418,36 +16975,36 @@ function formatResponse(response) {
|
|
|
16418
16975
|
}
|
|
16419
16976
|
|
|
16420
16977
|
// src/plugin/reportRunSchema.ts
|
|
16421
|
-
import { z as
|
|
16978
|
+
import { z as z26 } from "zod";
|
|
16422
16979
|
|
|
16423
16980
|
// src/plugin/graphShadowIngress.ts
|
|
16424
|
-
import { z as
|
|
16981
|
+
import { z as z25 } from "zod";
|
|
16425
16982
|
var LEGACY_EXECUTION_TRACE_VERSION = 1;
|
|
16426
|
-
var LegacyExecutionStatusSchema =
|
|
16983
|
+
var LegacyExecutionStatusSchema = z25.enum([
|
|
16427
16984
|
"completed",
|
|
16428
16985
|
"failed",
|
|
16429
16986
|
"cancelled"
|
|
16430
16987
|
]);
|
|
16431
|
-
var LegacyReviewOutcomeSchema =
|
|
16988
|
+
var LegacyReviewOutcomeSchema = z25.enum([
|
|
16432
16989
|
"approved",
|
|
16433
16990
|
"rejected",
|
|
16434
16991
|
"inconclusive"
|
|
16435
16992
|
]);
|
|
16436
|
-
var LegacyTraceNodeV1Schema =
|
|
16993
|
+
var LegacyTraceNodeV1Schema = z25.object({
|
|
16437
16994
|
id: NodeIDSchema,
|
|
16438
16995
|
role: NodeRoleSchema,
|
|
16439
|
-
model:
|
|
16440
|
-
sessionRef:
|
|
16996
|
+
model: z25.string().min(1),
|
|
16997
|
+
sessionRef: z25.string().min(1).optional(),
|
|
16441
16998
|
errorClass: ErrorClassSchema.optional()
|
|
16442
16999
|
}).strict();
|
|
16443
|
-
var LegacyExecutionTraceV1Schema =
|
|
16444
|
-
version:
|
|
17000
|
+
var LegacyExecutionTraceV1Schema = z25.object({
|
|
17001
|
+
version: z25.literal(LEGACY_EXECUTION_TRACE_VERSION),
|
|
16445
17002
|
runID: NodeIDSchema,
|
|
16446
17003
|
status: LegacyExecutionStatusSchema,
|
|
16447
17004
|
outcome: LegacyReviewOutcomeSchema,
|
|
16448
|
-
fixes:
|
|
16449
|
-
nodes:
|
|
16450
|
-
parentSessionRef:
|
|
17005
|
+
fixes: z25.number().int().nonnegative(),
|
|
17006
|
+
nodes: z25.array(LegacyTraceNodeV1Schema).min(1),
|
|
17007
|
+
parentSessionRef: z25.string().min(1).optional()
|
|
16451
17008
|
}).strict();
|
|
16452
17009
|
function gateReason2(gate) {
|
|
16453
17010
|
if (gate === undefined || gate.mode === "off") {
|
|
@@ -16518,20 +17075,20 @@ function parseLegacyExecutionTrace(input) {
|
|
|
16518
17075
|
}
|
|
16519
17076
|
|
|
16520
17077
|
// src/plugin/reportRunSchema.ts
|
|
16521
|
-
var ReportRunNodeSchema =
|
|
17078
|
+
var ReportRunNodeSchema = z26.object({
|
|
16522
17079
|
id: NodeIDSchema,
|
|
16523
17080
|
role: NodeRoleSchema,
|
|
16524
|
-
model:
|
|
16525
|
-
ok:
|
|
16526
|
-
sessionRef:
|
|
17081
|
+
model: z26.string().min(1),
|
|
17082
|
+
ok: z26.boolean(),
|
|
17083
|
+
sessionRef: z26.string().min(1).optional(),
|
|
16527
17084
|
errorClass: ErrorClassSchema.optional()
|
|
16528
17085
|
}).strict();
|
|
16529
|
-
var ReportRunPayloadSchema =
|
|
17086
|
+
var ReportRunPayloadSchema = z26.object({
|
|
16530
17087
|
runID: NodeIDSchema,
|
|
16531
17088
|
status: LegacyExecutionStatusSchema,
|
|
16532
|
-
fixes:
|
|
16533
|
-
nodes:
|
|
16534
|
-
parentSessionRef:
|
|
17089
|
+
fixes: z26.number().int().nonnegative(),
|
|
17090
|
+
nodes: z26.array(ReportRunNodeSchema).min(1),
|
|
17091
|
+
parentSessionRef: z26.string().min(1).optional()
|
|
16535
17092
|
}).strict();
|
|
16536
17093
|
|
|
16537
17094
|
// src/orchestrator/graphShadow.ts
|
|
@@ -17636,7 +18193,7 @@ function hashPrompt(prompt) {
|
|
|
17636
18193
|
}
|
|
17637
18194
|
|
|
17638
18195
|
// src/plugin/modelResidency.ts
|
|
17639
|
-
import { z as
|
|
18196
|
+
import { z as z27 } from "zod";
|
|
17640
18197
|
|
|
17641
18198
|
// src/local/lemonadeRequestGuard.ts
|
|
17642
18199
|
var inferencePaths = new Set([
|
|
@@ -18007,7 +18564,7 @@ function createModelResidencyGuard(config, options) {
|
|
|
18007
18564
|
throw failure("identity", model.providerID);
|
|
18008
18565
|
fetch = installed.fetch;
|
|
18009
18566
|
}
|
|
18010
|
-
const configuredHeaders =
|
|
18567
|
+
const configuredHeaders = z27.record(z27.string(), z27.string()).safeParse(provider?.options?.headers ?? {});
|
|
18011
18568
|
if (!configuredHeaders.success)
|
|
18012
18569
|
throw failure("configuration", model.providerID);
|
|
18013
18570
|
const headers = new Headers(configuredHeaders.data);
|
|
@@ -18235,62 +18792,62 @@ ${lines.join(`
|
|
|
18235
18792
|
}
|
|
18236
18793
|
|
|
18237
18794
|
// src/memory/types.ts
|
|
18238
|
-
import { z as
|
|
18795
|
+
import { z as z28 } from "zod";
|
|
18239
18796
|
var SHARED_OWNER_KEY = "*";
|
|
18240
|
-
var OwnerKeySchema =
|
|
18241
|
-
var MemoryKindSchema =
|
|
18242
|
-
var MemoryBaseSchema =
|
|
18243
|
-
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),
|
|
18244
18801
|
ownerKey: OwnerKeySchema,
|
|
18245
|
-
confidence:
|
|
18246
|
-
validFrom:
|
|
18247
|
-
validUntil:
|
|
18248
|
-
createdAt:
|
|
18249
|
-
invalidatedAt:
|
|
18250
|
-
sourceHash:
|
|
18251
|
-
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)
|
|
18252
18809
|
}).strict();
|
|
18253
18810
|
var FactSchema = MemoryBaseSchema.extend({
|
|
18254
|
-
kind:
|
|
18255
|
-
subject:
|
|
18256
|
-
predicate:
|
|
18257
|
-
object:
|
|
18258
|
-
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)
|
|
18259
18816
|
});
|
|
18260
18817
|
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
18261
|
-
kind:
|
|
18262
|
-
category:
|
|
18263
|
-
preference:
|
|
18264
|
-
context:
|
|
18265
|
-
lastAccessedAt:
|
|
18266
|
-
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)
|
|
18267
18824
|
});
|
|
18268
18825
|
var EntitySchema = MemoryBaseSchema.extend({
|
|
18269
|
-
kind:
|
|
18270
|
-
canonicalName:
|
|
18271
|
-
type:
|
|
18272
|
-
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([])
|
|
18273
18830
|
});
|
|
18274
18831
|
var RelationSchema = MemoryBaseSchema.extend({
|
|
18275
|
-
kind:
|
|
18276
|
-
from:
|
|
18277
|
-
to:
|
|
18278
|
-
predicate:
|
|
18279
|
-
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)
|
|
18280
18837
|
});
|
|
18281
|
-
var MemoryRecordSchema =
|
|
18838
|
+
var MemoryRecordSchema = z28.discriminatedUnion("kind", [
|
|
18282
18839
|
FactSchema,
|
|
18283
18840
|
PreferenceSchema,
|
|
18284
18841
|
EntitySchema,
|
|
18285
18842
|
RelationSchema
|
|
18286
18843
|
]);
|
|
18287
|
-
var RecallQuerySchema =
|
|
18844
|
+
var RecallQuerySchema = z28.object({
|
|
18288
18845
|
ownerKey: OwnerKeySchema,
|
|
18289
|
-
kinds:
|
|
18290
|
-
asOf:
|
|
18291
|
-
limit:
|
|
18292
|
-
minSimilarity:
|
|
18293
|
-
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)
|
|
18294
18851
|
}).strict();
|
|
18295
18852
|
|
|
18296
18853
|
// src/memory/rank.ts
|
|
@@ -18861,42 +19418,42 @@ function buildMemoryInjector(deps, policy) {
|
|
|
18861
19418
|
|
|
18862
19419
|
// src/plugin/memoryTool.ts
|
|
18863
19420
|
import { tool as tool4 } from "@opencode-ai/plugin";
|
|
18864
|
-
import { z as
|
|
19421
|
+
import { z as z30 } from "zod";
|
|
18865
19422
|
|
|
18866
19423
|
// src/memory/extract.ts
|
|
18867
|
-
import { z as
|
|
19424
|
+
import { z as z29 } from "zod";
|
|
18868
19425
|
var REDACTED = "[redacted]";
|
|
18869
|
-
var RawFactSchema =
|
|
18870
|
-
subject:
|
|
18871
|
-
predicate:
|
|
18872
|
-
object:
|
|
18873
|
-
category:
|
|
18874
|
-
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()
|
|
18875
19432
|
});
|
|
18876
|
-
var RawPreferenceSchema =
|
|
18877
|
-
category:
|
|
18878
|
-
preference:
|
|
18879
|
-
context:
|
|
18880
|
-
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()
|
|
18881
19438
|
});
|
|
18882
|
-
var RawEntitySchema =
|
|
18883
|
-
canonicalName:
|
|
18884
|
-
type:
|
|
18885
|
-
aliases:
|
|
18886
|
-
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()
|
|
18887
19444
|
});
|
|
18888
|
-
var RawRelationSchema =
|
|
18889
|
-
from:
|
|
18890
|
-
to:
|
|
18891
|
-
predicate:
|
|
18892
|
-
annotation:
|
|
18893
|
-
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()
|
|
18894
19451
|
}).strict();
|
|
18895
|
-
var RawExtractionSchema =
|
|
18896
|
-
facts:
|
|
18897
|
-
preferences:
|
|
18898
|
-
entities:
|
|
18899
|
-
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([])
|
|
18900
19457
|
});
|
|
18901
19458
|
var DEFAULT_CONFIDENCE = 0.6;
|
|
18902
19459
|
var SYSTEM_PROMPT = [
|
|
@@ -19150,13 +19707,13 @@ var memoryToolMessages = {
|
|
|
19150
19707
|
|
|
19151
19708
|
// src/plugin/memoryTool.ts
|
|
19152
19709
|
var SCRIBE_ROLE_ID = "scribe";
|
|
19153
|
-
var MemoryMessageSchema =
|
|
19154
|
-
role:
|
|
19155
|
-
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)
|
|
19156
19713
|
}).strict();
|
|
19157
|
-
var MemoryWritePayloadSchema =
|
|
19158
|
-
messages:
|
|
19159
|
-
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)
|
|
19160
19717
|
}).strict();
|
|
19161
19718
|
function createMemoryTool(deps) {
|
|
19162
19719
|
return tool4({
|
|
@@ -19340,7 +19897,7 @@ import { Session as Session2 } from "@opencode/schema/session";
|
|
|
19340
19897
|
import { Tool } from "@opencode/schema/tool";
|
|
19341
19898
|
import { tool as legacyTool } from "@opencode-ai/plugin/tool";
|
|
19342
19899
|
import { Clock, Effect, Option, Stream } from "effect";
|
|
19343
|
-
import { z as
|
|
19900
|
+
import { z as z32 } from "zod";
|
|
19344
19901
|
|
|
19345
19902
|
// src/plugin/nativeHostContext.ts
|
|
19346
19903
|
import {
|
|
@@ -19402,7 +19959,7 @@ function nativeConfiguredInventory(models, config) {
|
|
|
19402
19959
|
|
|
19403
19960
|
// src/plugin/nativeResidency.ts
|
|
19404
19961
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
19405
|
-
import { z as
|
|
19962
|
+
import { z as z31 } from "zod";
|
|
19406
19963
|
var NATIVE_RESIDENCY_PROVIDER_PACKAGE = "aisdk:@ai-sdk/openai-compatible@2.0.75";
|
|
19407
19964
|
var NATIVE_ADMISSION_HEADER = "x-openteam-local-admission";
|
|
19408
19965
|
var MAX_ADMISSIONS = 2048;
|
|
@@ -19480,7 +20037,7 @@ function createNativeModelResidencyGuard(config, options) {
|
|
|
19480
20037
|
});
|
|
19481
20038
|
}
|
|
19482
20039
|
function target(model, send, baseURL) {
|
|
19483
|
-
const headers = new Headers(
|
|
20040
|
+
const headers = new Headers(z31.record(z31.string(), z31.string()).parse(model.headers ?? {}));
|
|
19484
20041
|
if (typeof model.settings?.apiKey === "string" && !headers.has("authorization"))
|
|
19485
20042
|
headers.set("authorization", `Bearer ${model.settings.apiKey}`);
|
|
19486
20043
|
return {
|
|
@@ -19518,7 +20075,7 @@ function createNativeModelResidencyGuard(config, options) {
|
|
|
19518
20075
|
localTargets.set(key(ref), target(model, guardedFetch(binding, options.fetch), binding.baseURL));
|
|
19519
20076
|
return model;
|
|
19520
20077
|
} catch (error) {
|
|
19521
|
-
if (!(error instanceof ModelResidencyError) && !(error instanceof
|
|
20078
|
+
if (!(error instanceof ModelResidencyError) && !(error instanceof z31.ZodError))
|
|
19522
20079
|
throw error;
|
|
19523
20080
|
(options.warn ?? console.warn)(modelResidencyMessages.providerDisabled(model.providerID, residentRuntimes.find((runtime) => runtime.defaultModel.providerID === model.providerID)?.kind === "llama-swap" ? "llama-swap" : "Lemonade"));
|
|
19524
20081
|
return { ...model, enabled: false };
|
|
@@ -19675,6 +20232,10 @@ function nativeAssistantResponse(sessionID, message) {
|
|
|
19675
20232
|
...message.cost === undefined ? {} : { cost: message.cost },
|
|
19676
20233
|
...message.tokens === undefined ? {} : { tokens: message.tokens },
|
|
19677
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"),
|
|
19678
20239
|
time: {
|
|
19679
20240
|
created: DateTime.toEpochMillis(message.time.created),
|
|
19680
20241
|
...message.time.completed === undefined ? {} : { completed: DateTime.toEpochMillis(message.time.completed) }
|
|
@@ -19701,7 +20262,8 @@ function createNativeSessionClient(deps) {
|
|
|
19701
20262
|
}
|
|
19702
20263
|
return {
|
|
19703
20264
|
async create(args) {
|
|
19704
|
-
const
|
|
20265
|
+
const parentSignal = deps.signal?.();
|
|
20266
|
+
const signal = parentSignal === undefined ? args.signal : args.signal === undefined ? parentSignal : AbortSignal.any([parentSignal, args.signal]);
|
|
19705
20267
|
signal?.throwIfAborted();
|
|
19706
20268
|
assertDirectory(args.query?.directory);
|
|
19707
20269
|
if (args.body?.parentID === undefined)
|
|
@@ -19711,7 +20273,7 @@ function createNativeSessionClient(deps) {
|
|
|
19711
20273
|
const child = await deps.run(deps.sessions().create({
|
|
19712
20274
|
parentID,
|
|
19713
20275
|
...args.body.title === undefined ? {} : { title: args.body.title }
|
|
19714
|
-
}));
|
|
20276
|
+
}), signal === undefined ? undefined : { signal });
|
|
19715
20277
|
if (!sameNativeWorkspace(child.location, location))
|
|
19716
20278
|
throw new Error(nativeHostMessages.workspaceMismatch);
|
|
19717
20279
|
if (child.parentID !== parentID)
|
|
@@ -19750,6 +20312,11 @@ function createNativeSessionClient(deps) {
|
|
|
19750
20312
|
const assistant = [...messages].reverse().find((message) => message.type === "assistant");
|
|
19751
20313
|
if (final.outcome === "interrupted")
|
|
19752
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
|
+
}
|
|
19753
20320
|
if (final.outcome !== "succeeded" || assistant?.error !== undefined)
|
|
19754
20321
|
throw new Error(nativeHostMessages.executionFailed);
|
|
19755
20322
|
if (assistant?.time.completed === undefined)
|
|
@@ -19789,8 +20356,8 @@ function createNativeSessionClient(deps) {
|
|
|
19789
20356
|
}
|
|
19790
20357
|
|
|
19791
20358
|
// src/plugin/nativeHost.ts
|
|
19792
|
-
var executionEvent =
|
|
19793
|
-
type:
|
|
20359
|
+
var executionEvent = z32.preprocess(only(["type", "location", "data"]), z32.object({
|
|
20360
|
+
type: z32.enum([
|
|
19794
20361
|
"session.created",
|
|
19795
20362
|
"session.deleted",
|
|
19796
20363
|
"session.execution.started",
|
|
@@ -19798,15 +20365,30 @@ var executionEvent = z30.preprocess(only(["type", "location", "data"]), z30.obje
|
|
|
19798
20365
|
"session.execution.failed",
|
|
19799
20366
|
"session.execution.interrupted",
|
|
19800
20367
|
"session.step.ended",
|
|
19801
|
-
"session.step.
|
|
20368
|
+
"session.step.started",
|
|
20369
|
+
"session.step.failed",
|
|
20370
|
+
"session.tool.input.started",
|
|
20371
|
+
"session.tool.success",
|
|
20372
|
+
"session.tool.failed"
|
|
19802
20373
|
]),
|
|
19803
|
-
location:
|
|
19804
|
-
directory:
|
|
19805
|
-
workspaceID:
|
|
20374
|
+
location: z32.preprocess(only(["directory", "workspaceID"]), z32.object({
|
|
20375
|
+
directory: z32.string(),
|
|
20376
|
+
workspaceID: z32.string().optional()
|
|
19806
20377
|
}).strict()).optional(),
|
|
19807
|
-
data:
|
|
19808
|
-
sessionID
|
|
19809
|
-
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()
|
|
19810
20392
|
}).strict())
|
|
19811
20393
|
}).strict());
|
|
19812
20394
|
var nativeBindings = Effect.fn("openteam.nativeBindings")(function* () {
|
|
@@ -19847,7 +20429,7 @@ function legacyModel(ref) {
|
|
|
19847
20429
|
}
|
|
19848
20430
|
function createNativePluginEffect(factory) {
|
|
19849
20431
|
return Effect.fn("openteam.native")(function* (ctx) {
|
|
19850
|
-
if (ctx.app.version
|
|
20432
|
+
if (!isSupportedNativeOpencodeVersion(ctx.app.version))
|
|
19851
20433
|
return yield* Effect.die(new Error(nativeHostMessages.unsupportedVersion(ctx.app.version)));
|
|
19852
20434
|
const version = ctx.app.version;
|
|
19853
20435
|
const effectContext = yield* Effect.context();
|
|
@@ -19861,6 +20443,15 @@ function createNativePluginEffect(factory) {
|
|
|
19861
20443
|
let config;
|
|
19862
20444
|
let residency;
|
|
19863
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
|
+
};
|
|
19864
20455
|
const toolSignals = new AsyncLocalStorage;
|
|
19865
20456
|
const remember = (next) => {
|
|
19866
20457
|
bindings = { ...bindings, ...next };
|
|
@@ -19915,6 +20506,12 @@ function createNativePluginEffect(factory) {
|
|
|
19915
20506
|
directory,
|
|
19916
20507
|
worktree: ctx.location.project.directory,
|
|
19917
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
|
+
},
|
|
19918
20515
|
exec: nativeExec(directory),
|
|
19919
20516
|
serverUrl: () => {
|
|
19920
20517
|
const url = bindings?.server?.urls().find((value) => {
|
|
@@ -19959,6 +20556,7 @@ function createNativePluginEffect(factory) {
|
|
|
19959
20556
|
yield* Effect.addFinalizer(() => Effect.promise(async () => {
|
|
19960
20557
|
guard.dispose();
|
|
19961
20558
|
systemPrompts.clear();
|
|
20559
|
+
toolNames.clear();
|
|
19962
20560
|
await hooks.dispose?.();
|
|
19963
20561
|
}));
|
|
19964
20562
|
yield* ctx.provider.transform(guard.providers);
|
|
@@ -20091,7 +20689,10 @@ function createNativePluginEffect(factory) {
|
|
|
20091
20689
|
});
|
|
20092
20690
|
}
|
|
20093
20691
|
});
|
|
20094
|
-
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
|
+
}));
|
|
20095
20696
|
yield* ctx.tool.hook("execute.after", (event) => Effect.promise(() => hooks["tool.execute.after"]?.({
|
|
20096
20697
|
tool: event.tool,
|
|
20097
20698
|
sessionID: event.sessionID,
|
|
@@ -20118,9 +20719,62 @@ function createNativePluginEffect(factory) {
|
|
|
20118
20719
|
if (value.type === "session.deleted") {
|
|
20119
20720
|
guard.finished(sessionID);
|
|
20120
20721
|
systemPrompts.delete(sessionID);
|
|
20722
|
+
for (const key2 of toolNames.keys()) {
|
|
20723
|
+
if (key2.startsWith(`${sessionID}\x00`))
|
|
20724
|
+
toolNames.delete(key2);
|
|
20725
|
+
}
|
|
20121
20726
|
}
|
|
20122
20727
|
let mapped;
|
|
20123
|
-
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") {
|
|
20124
20778
|
mapped = {
|
|
20125
20779
|
type: value.type,
|
|
20126
20780
|
properties: { info: { id: sessionID } }
|
|
@@ -20161,11 +20815,12 @@ function createNativePluginEffect(factory) {
|
|
|
20161
20815
|
}
|
|
20162
20816
|
|
|
20163
20817
|
// src/plugin/orchestrateTool.ts
|
|
20818
|
+
import { resolve as resolve11 } from "node:path";
|
|
20164
20819
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
20165
|
-
import { z as
|
|
20820
|
+
import { z as z34 } from "zod";
|
|
20166
20821
|
|
|
20167
20822
|
// src/orchestrator/coordinator.ts
|
|
20168
|
-
import { z as
|
|
20823
|
+
import { z as z33 } from "zod";
|
|
20169
20824
|
|
|
20170
20825
|
// src/orchestrator/nodeIteration.ts
|
|
20171
20826
|
var DEFAULT_MAX_RETRIES = 2;
|
|
@@ -20173,153 +20828,6 @@ function nodePassBudget(maxRetries) {
|
|
|
20173
20828
|
return 1 + (maxRetries ?? DEFAULT_MAX_RETRIES);
|
|
20174
20829
|
}
|
|
20175
20830
|
|
|
20176
|
-
// src/orchestrator/outputContract.ts
|
|
20177
|
-
import { createHash as createHash3 } from "node:crypto";
|
|
20178
|
-
var ROLE_REPORTS_ROOT = ".opencode/openteam-local/reports";
|
|
20179
|
-
var REPORT_STATUS_MARKER = "openteam-status";
|
|
20180
|
-
var REPORT_STATUS_LINE_PATTERN = /^[ ]{0,3}openteam-status:[ \t]*(.*?)[ \t]*$/i;
|
|
20181
|
-
var FENCE_DELIMITER_PATTERN = /^ {0,3}(`{3,}|~{3,})(.*)$/;
|
|
20182
|
-
function fenceDelimiter(line) {
|
|
20183
|
-
const match = FENCE_DELIMITER_PATTERN.exec(line);
|
|
20184
|
-
const run = match?.[1];
|
|
20185
|
-
if (run === undefined)
|
|
20186
|
-
return;
|
|
20187
|
-
const marker = run.startsWith("`") ? "`" : "~";
|
|
20188
|
-
return {
|
|
20189
|
-
marker,
|
|
20190
|
-
length: run.length,
|
|
20191
|
-
remainder: match?.[2] ?? ""
|
|
20192
|
-
};
|
|
20193
|
-
}
|
|
20194
|
-
function declaredStatus(value) {
|
|
20195
|
-
const normalized = value.toLowerCase();
|
|
20196
|
-
if (normalized === "done")
|
|
20197
|
-
return "done";
|
|
20198
|
-
if (normalized === "continue")
|
|
20199
|
-
return "continue";
|
|
20200
|
-
return "unknown";
|
|
20201
|
-
}
|
|
20202
|
-
function analyzeReport(text) {
|
|
20203
|
-
let status = "unknown";
|
|
20204
|
-
let fence;
|
|
20205
|
-
const bodyLines = [];
|
|
20206
|
-
for (const line of text.split(/\r?\n/)) {
|
|
20207
|
-
const delimiter = fenceDelimiter(line);
|
|
20208
|
-
if (fence !== undefined) {
|
|
20209
|
-
bodyLines.push(line);
|
|
20210
|
-
if (delimiter?.marker === fence.marker && delimiter.length >= fence.length && delimiter.remainder.trim().length === 0) {
|
|
20211
|
-
fence = undefined;
|
|
20212
|
-
}
|
|
20213
|
-
continue;
|
|
20214
|
-
}
|
|
20215
|
-
if (delimiter !== undefined) {
|
|
20216
|
-
fence = delimiter;
|
|
20217
|
-
bodyLines.push(line);
|
|
20218
|
-
continue;
|
|
20219
|
-
}
|
|
20220
|
-
const declaration = REPORT_STATUS_LINE_PATTERN.exec(line);
|
|
20221
|
-
if (declaration !== null) {
|
|
20222
|
-
status = declaredStatus(declaration[1] ?? "");
|
|
20223
|
-
continue;
|
|
20224
|
-
}
|
|
20225
|
-
bodyLines.push(line);
|
|
20226
|
-
}
|
|
20227
|
-
return {
|
|
20228
|
-
status,
|
|
20229
|
-
body: bodyLines.join(`
|
|
20230
|
-
`).trim()
|
|
20231
|
-
};
|
|
20232
|
-
}
|
|
20233
|
-
function parseReportStatus(text) {
|
|
20234
|
-
if (text === undefined || text.length === 0)
|
|
20235
|
-
return "unknown";
|
|
20236
|
-
return analyzeReport(text).status;
|
|
20237
|
-
}
|
|
20238
|
-
var MIN_REPORT_BODY_CHARS = 40;
|
|
20239
|
-
var MAX_REPORT_SEGMENT_CHARS = 64;
|
|
20240
|
-
var REPORT_SEGMENT_HASH_CHARS = 24;
|
|
20241
|
-
var SAFE_REPORT_SEGMENT = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62}[A-Za-z0-9_-])?$/;
|
|
20242
|
-
var WINDOWS_DEVICE_NAME = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i;
|
|
20243
|
-
function reportSegmentHash(value) {
|
|
20244
|
-
return createHash3("sha256").update(value, "utf8").digest("hex").slice(0, REPORT_SEGMENT_HASH_CHARS);
|
|
20245
|
-
}
|
|
20246
|
-
function reportPathSegment(value) {
|
|
20247
|
-
if (value.length <= MAX_REPORT_SEGMENT_CHARS && SAFE_REPORT_SEGMENT.test(value) && value === value.toLowerCase() && !WINDOWS_DEVICE_NAME.test(value)) {
|
|
20248
|
-
return value;
|
|
20249
|
-
}
|
|
20250
|
-
const suffix = `~${reportSegmentHash(value)}`;
|
|
20251
|
-
const maxPrefixChars = MAX_REPORT_SEGMENT_CHARS - suffix.length;
|
|
20252
|
-
let prefix = value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[^A-Za-z0-9]+/, "").slice(0, maxPrefixChars).replace(/[.]+$/, "");
|
|
20253
|
-
if (prefix.length === 0) {
|
|
20254
|
-
prefix = "segment";
|
|
20255
|
-
}
|
|
20256
|
-
if (WINDOWS_DEVICE_NAME.test(prefix)) {
|
|
20257
|
-
prefix = `safe-${prefix}`.slice(0, maxPrefixChars).replace(/[.]+$/, "");
|
|
20258
|
-
}
|
|
20259
|
-
return `${prefix}${suffix}`;
|
|
20260
|
-
}
|
|
20261
|
-
function reportHasSubstance(text) {
|
|
20262
|
-
if (text === undefined)
|
|
20263
|
-
return false;
|
|
20264
|
-
return analyzeReport(text).body.length >= MIN_REPORT_BODY_CHARS;
|
|
20265
|
-
}
|
|
20266
|
-
function roleReportPath(batchID, roleID) {
|
|
20267
|
-
return `${ROLE_REPORTS_ROOT}/${reportPathSegment(batchID)}/${reportPathSegment(roleID)}.md`;
|
|
20268
|
-
}
|
|
20269
|
-
function outputContractInstruction(reportPath) {
|
|
20270
|
-
return [
|
|
20271
|
-
"## Output contract (openteam)",
|
|
20272
|
-
"",
|
|
20273
|
-
"Write your complete findings to the report file below using the `write`",
|
|
20274
|
-
"tool (create parent directories as needed), and keep it updated with",
|
|
20275
|
-
"`edit` as you progress. This file is the ONLY channel your work reaches",
|
|
20276
|
-
"the coordinator: anything you do not write there is discarded and lost,",
|
|
20277
|
-
"and the coordinator will have no record of it.",
|
|
20278
|
-
"",
|
|
20279
|
-
`Report file: ${reportPath}`,
|
|
20280
|
-
"",
|
|
20281
|
-
"Requirements:",
|
|
20282
|
-
"- Write the ACTUAL results — what you found, what you changed, concrete",
|
|
20283
|
-
" conclusions, and any risks or follow-ups — never a promise to do the",
|
|
20284
|
-
" work later.",
|
|
20285
|
-
"- Make it self-contained: the coordinator reads only this file, not your",
|
|
20286
|
-
" session transcript.",
|
|
20287
|
-
"- If you could not complete the task, write what you attempted and why it",
|
|
20288
|
-
" is blocked, so the coordinator can report the truth.",
|
|
20289
|
-
"- If the report file already exists from a previous pass, read it first and",
|
|
20290
|
-
" continue from where it left off rather than starting over.",
|
|
20291
|
-
"",
|
|
20292
|
-
"Completion status (REQUIRED — this is how the coordinator knows to stop):",
|
|
20293
|
-
"On its own line in the report, declare your status EXACTLY as one of:",
|
|
20294
|
-
`${REPORT_STATUS_MARKER}: done`,
|
|
20295
|
-
" The task is fully complete; no further passes are needed.",
|
|
20296
|
-
`${REPORT_STATUS_MARKER}: continue`,
|
|
20297
|
-
" You have more work to do and will be run again.",
|
|
20298
|
-
"The marker line must contain nothing else.",
|
|
20299
|
-
"If you omit this line or write anything else, the coordinator treats the",
|
|
20300
|
-
"task as NOT complete and runs you again, up to the configured retry bound."
|
|
20301
|
-
].join(`
|
|
20302
|
-
`);
|
|
20303
|
-
}
|
|
20304
|
-
function composeSubsessionPrompt(input) {
|
|
20305
|
-
const reportPath = roleReportPath(input.batchID, input.roleID);
|
|
20306
|
-
const handoff = input.handoff ? [
|
|
20307
|
-
"",
|
|
20308
|
-
"## Model handoff",
|
|
20309
|
-
"",
|
|
20310
|
-
"Continue the SAME node and original goal. Read the existing report first,",
|
|
20311
|
-
"preserve useful prior findings, and complete the remaining work instead of",
|
|
20312
|
-
"starting a new batch or replacing the objective."
|
|
20313
|
-
].join(`
|
|
20314
|
-
`) : "";
|
|
20315
|
-
return {
|
|
20316
|
-
prompt: `${input.prompt}${handoff}
|
|
20317
|
-
|
|
20318
|
-
${outputContractInstruction(reportPath)}`,
|
|
20319
|
-
reportPath
|
|
20320
|
-
};
|
|
20321
|
-
}
|
|
20322
|
-
|
|
20323
20831
|
// src/orchestrator/permissions.ts
|
|
20324
20832
|
var ROLE_PERMISSIONS = {
|
|
20325
20833
|
architect: [
|
|
@@ -20639,7 +21147,7 @@ function buildRecord(input, decision2, subsession, deps, decisionID, batchID) {
|
|
|
20639
21147
|
}
|
|
20640
21148
|
return record;
|
|
20641
21149
|
}
|
|
20642
|
-
var TelemetryFailureClassSchema =
|
|
21150
|
+
var TelemetryFailureClassSchema = z33.enum([
|
|
20643
21151
|
"create-rejected",
|
|
20644
21152
|
"create-no-id",
|
|
20645
21153
|
"prompt-rejected",
|
|
@@ -20648,12 +21156,15 @@ var TelemetryFailureClassSchema = z31.enum([
|
|
|
20648
21156
|
"prompt-auth",
|
|
20649
21157
|
"prompt-content-filter",
|
|
20650
21158
|
"prompt-context-length",
|
|
21159
|
+
"prompt-output-truncated",
|
|
21160
|
+
"budget-exhausted",
|
|
20651
21161
|
"prompt-validation",
|
|
20652
21162
|
"prompt-connection",
|
|
20653
21163
|
"prompt-server",
|
|
20654
21164
|
"unknown"
|
|
20655
21165
|
]);
|
|
20656
21166
|
var FAILURE_CAUSE_RULES = [
|
|
21167
|
+
[["prompt-output-truncated"], "prompt-output-truncated"],
|
|
20657
21168
|
[
|
|
20658
21169
|
[
|
|
20659
21170
|
"rate limit",
|
|
@@ -20756,6 +21267,8 @@ function matchFailureCause(lowerReason) {
|
|
|
20756
21267
|
}
|
|
20757
21268
|
function classifyFailureForTelemetry(failureReason, failureStage) {
|
|
20758
21269
|
const lower = failureReason.toLowerCase();
|
|
21270
|
+
if (lower.startsWith("task-budget-exhausted:"))
|
|
21271
|
+
return "budget-exhausted";
|
|
20759
21272
|
if (TIMEOUT_NEEDLES.some((needle) => lower.includes(needle))) {
|
|
20760
21273
|
return "prompt-timeout";
|
|
20761
21274
|
}
|
|
@@ -20824,6 +21337,8 @@ async function recordLifecycle(lifecycle, event) {
|
|
|
20824
21337
|
await lifecycle.recorder.append(event);
|
|
20825
21338
|
}
|
|
20826
21339
|
function lifecycleFailureFor(subsession) {
|
|
21340
|
+
if (subsession.failureReason?.startsWith("task-budget-exhausted:"))
|
|
21341
|
+
return { class: "budget-exhausted", retryable: false };
|
|
20827
21342
|
const normalized = subsession.normalizedFailure;
|
|
20828
21343
|
if (normalized !== undefined) {
|
|
20829
21344
|
return {
|
|
@@ -20893,7 +21408,7 @@ function buildNodeBudgetExhaustedEvent(roleID, passCount, sessionID, ts) {
|
|
|
20893
21408
|
passCount
|
|
20894
21409
|
};
|
|
20895
21410
|
}
|
|
20896
|
-
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) {
|
|
20897
21412
|
const role = roleFor(input);
|
|
20898
21413
|
if (routed.routeKind === "blocked") {
|
|
20899
21414
|
throw new Error(coordinatorRoutingBlocked(input.roleID, routed.blockReason));
|
|
@@ -20904,13 +21419,18 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
20904
21419
|
prompt: input.prompt,
|
|
20905
21420
|
roleID: input.roleID,
|
|
20906
21421
|
batchID: reportBatchID,
|
|
20907
|
-
handoff
|
|
21422
|
+
handoff,
|
|
21423
|
+
structuredReport: deps.reportDelivery !== undefined,
|
|
21424
|
+
...repair === undefined ? {} : { repair },
|
|
21425
|
+
...truncated === true ? { truncated: true } : {}
|
|
20908
21426
|
});
|
|
20909
21427
|
const request = {
|
|
20910
21428
|
roleID: input.roleID,
|
|
20911
21429
|
model: decision2.selected,
|
|
20912
21430
|
prompt: composed.prompt
|
|
20913
21431
|
};
|
|
21432
|
+
if (existingSessionID !== undefined)
|
|
21433
|
+
request.existingSessionID = existingSessionID;
|
|
20914
21434
|
if (input.parentSessionID !== undefined) {
|
|
20915
21435
|
request.parentSessionID = input.parentSessionID;
|
|
20916
21436
|
}
|
|
@@ -20928,11 +21448,17 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
20928
21448
|
if (input.directory !== undefined) {
|
|
20929
21449
|
request.directory = input.directory;
|
|
20930
21450
|
}
|
|
21451
|
+
let reportLease;
|
|
20931
21452
|
const subsessionDeps = {
|
|
20932
21453
|
abortGraceMs: deps.abortGraceMs,
|
|
20933
21454
|
statusPollMs: deps.statusPollMs,
|
|
20934
21455
|
now: deps.now,
|
|
20935
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
|
+
},
|
|
20936
21462
|
...deps.timeoutMs === undefined ? {} : { timeoutMs: deps.timeoutMs },
|
|
20937
21463
|
...attemptLifecycle === undefined ? {} : {
|
|
20938
21464
|
onSessionCreated: (sessionID) => recordLifecycle(attemptLifecycle.lifecycle, {
|
|
@@ -20977,27 +21503,66 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
20977
21503
|
}
|
|
20978
21504
|
let release;
|
|
20979
21505
|
let queueObservation;
|
|
20980
|
-
|
|
20981
|
-
|
|
20982
|
-
const
|
|
20983
|
-
|
|
20984
|
-
|
|
20985
|
-
|
|
20986
|
-
|
|
20987
|
-
|
|
20988
|
-
|
|
20989
|
-
const acquisition = await limiter.acquire(poolKey, priority);
|
|
20990
|
-
release = acquisition.release;
|
|
20991
|
-
waitedMs = acquisition.waitedMs;
|
|
20992
|
-
}
|
|
20993
|
-
queueObservation = {
|
|
20994
|
-
runtimeId,
|
|
20995
|
-
waitedMs,
|
|
20996
|
-
activeCount: limiter.activeCount(poolKey),
|
|
20997
|
-
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
|
|
20998
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 };
|
|
20999
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;
|
|
21000
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;
|
|
21001
21566
|
if (attemptLifecycle !== undefined) {
|
|
21002
21567
|
await recordLifecycle(attemptLifecycle.lifecycle, {
|
|
21003
21568
|
type: "attempt.started",
|
|
@@ -21025,8 +21590,17 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
21025
21590
|
await safeEmit(deps.sink, buildQueueEvent(queueObservation, sessionID, deps.now(), queueCorrelation));
|
|
21026
21591
|
}
|
|
21027
21592
|
}
|
|
21028
|
-
|
|
21593
|
+
const reportSubmitted = await reportLease?.close();
|
|
21594
|
+
return {
|
|
21595
|
+
decision: decision2,
|
|
21596
|
+
subsession,
|
|
21597
|
+
record,
|
|
21598
|
+
reportPath: composed.reportPath,
|
|
21599
|
+
...reportSubmitted === undefined ? {} : { reportSubmitted }
|
|
21600
|
+
};
|
|
21029
21601
|
} finally {
|
|
21602
|
+
clearTimeout(queueDeadline);
|
|
21603
|
+
await reportLease?.close();
|
|
21030
21604
|
release?.();
|
|
21031
21605
|
}
|
|
21032
21606
|
}
|
|
@@ -21138,15 +21712,19 @@ async function assessCurrentAttemptReport(input, before, result, deps) {
|
|
|
21138
21712
|
done: false
|
|
21139
21713
|
};
|
|
21140
21714
|
}
|
|
21141
|
-
if (after === before) {
|
|
21715
|
+
if (after === before && result.reportSubmitted !== true) {
|
|
21142
21716
|
return {
|
|
21143
21717
|
result: withFailure(gated, REPORT_STALE_REASON, "report"),
|
|
21144
21718
|
done: false
|
|
21145
21719
|
};
|
|
21146
21720
|
}
|
|
21721
|
+
const done = parseReportStatus(after) === "done" && reportHasSubstance(after);
|
|
21147
21722
|
return {
|
|
21148
21723
|
result: gated,
|
|
21149
|
-
done
|
|
21724
|
+
done,
|
|
21725
|
+
...!done ? {
|
|
21726
|
+
repairReason: !reportHasSubstance(after) ? "report-without-substance" : parseReportStatus(after) === "continue" ? "report-continue" : "report-status-missing"
|
|
21727
|
+
} : {}
|
|
21150
21728
|
};
|
|
21151
21729
|
}
|
|
21152
21730
|
function failedPassDisposition(subsession) {
|
|
@@ -21157,6 +21735,8 @@ function failedPassDisposition(subsession) {
|
|
|
21157
21735
|
if (subsession.failureStage === "report")
|
|
21158
21736
|
return "retry-incomplete";
|
|
21159
21737
|
if (subsession.normalizedFailure !== undefined) {
|
|
21738
|
+
if (subsession.normalizedFailure.failureClass === "prompt-output-truncated")
|
|
21739
|
+
return "retry-incomplete";
|
|
21160
21740
|
return subsession.normalizedFailure.retryable ? "retry-transport" : "terminal";
|
|
21161
21741
|
}
|
|
21162
21742
|
const failureReason = subsession.failureReason ?? "";
|
|
@@ -21256,6 +21836,7 @@ async function runNodeWithIteration(input, deps, correlation, batch, lifecycle)
|
|
|
21256
21836
|
let totalPasses = 0;
|
|
21257
21837
|
let spend = { usd: 0, frontierTokens: 0 };
|
|
21258
21838
|
let lastResult;
|
|
21839
|
+
let reportRepairReason;
|
|
21259
21840
|
let escalationReason;
|
|
21260
21841
|
const reportBatchID = correlation.batchID ?? correlation.decisionID;
|
|
21261
21842
|
modelLoop:
|
|
@@ -21328,14 +21909,19 @@ async function runNodeWithIteration(input, deps, correlation, batch, lifecycle)
|
|
|
21328
21909
|
retryIndex: pass - 1,
|
|
21329
21910
|
selectionCause: lifecycleSelectionCause(totalPasses, modelIndex, retryReason, escalationReason)
|
|
21330
21911
|
};
|
|
21331
|
-
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);
|
|
21332
21913
|
totalPasses += 1;
|
|
21333
21914
|
spend = {
|
|
21334
21915
|
usd: attemptDecision.estimatedCostUSD === null ? spend.usd : spend.usd + attemptDecision.estimatedCostUSD,
|
|
21335
21916
|
frontierTokens: spend.frontierTokens + (attemptDecision.routeKind === "frontier" ? (input.task.estimatedInputTokens ?? 0) + (input.task.estimatedOutputTokens ?? 0) : 0)
|
|
21336
21917
|
};
|
|
21918
|
+
if (result.subsession.sessionID !== undefined)
|
|
21919
|
+
await deps.sessionPhase?.(result.subsession.sessionID, "report-validation");
|
|
21337
21920
|
const assessment = await assessCurrentAttemptReport(input, before, result, deps);
|
|
21921
|
+
if (result.subsession.sessionID !== undefined)
|
|
21922
|
+
await deps.sessionPhase?.(result.subsession.sessionID, "idle");
|
|
21338
21923
|
result = assessment.result;
|
|
21924
|
+
reportRepairReason = assessment.repairReason ?? (result.subsession.failureStage === "report" ? result.subsession.failureReason : undefined);
|
|
21339
21925
|
lastResult = result;
|
|
21340
21926
|
if (assessment.done) {
|
|
21341
21927
|
await recordAttemptTerminal(attemptLifecycle, result, "none", true);
|
|
@@ -21421,13 +22007,28 @@ async function runRoleTasks(inputs, deps, options = {}) {
|
|
|
21421
22007
|
});
|
|
21422
22008
|
}
|
|
21423
22009
|
}
|
|
21424
|
-
const
|
|
21425
|
-
|
|
21426
|
-
|
|
21427
|
-
|
|
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;
|
|
21428
22025
|
}
|
|
21429
|
-
|
|
21430
|
-
|
|
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
|
+
});
|
|
21431
22032
|
for (const result of waveResults) {
|
|
21432
22033
|
allResults.push(result);
|
|
21433
22034
|
if (result.subsession.success) {
|
|
@@ -21456,7 +22057,7 @@ async function runRoleTasks(inputs, deps, options = {}) {
|
|
|
21456
22057
|
var _pluginWarnedRoles = new Set;
|
|
21457
22058
|
var EMPTY_ROLE_ID_SET = new Set;
|
|
21458
22059
|
var SAFE_ROLE_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
21459
|
-
var RoleIDSchema =
|
|
22060
|
+
var RoleIDSchema = z34.string().min(1).superRefine((roleID, ctx) => {
|
|
21460
22061
|
if (!SAFE_ROLE_ID.test(roleID)) {
|
|
21461
22062
|
ctx.addIssue({
|
|
21462
22063
|
code: "custom",
|
|
@@ -21464,16 +22065,16 @@ var RoleIDSchema = z32.string().min(1).superRefine((roleID, ctx) => {
|
|
|
21464
22065
|
});
|
|
21465
22066
|
}
|
|
21466
22067
|
});
|
|
21467
|
-
var RoleAssignmentSchema =
|
|
22068
|
+
var RoleAssignmentSchema = z34.object({
|
|
21468
22069
|
roleID: RoleIDSchema.describe("Role identifier from the roster"),
|
|
21469
|
-
prompt:
|
|
21470
|
-
title:
|
|
21471
|
-
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)")
|
|
21472
22073
|
}).strict();
|
|
21473
|
-
var OrchestratePayloadSchema =
|
|
21474
|
-
assignments:
|
|
21475
|
-
parentSessionID:
|
|
21476
|
-
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")
|
|
21477
22078
|
}).strict();
|
|
21478
22079
|
function validateAssignmentDependencies(assignments) {
|
|
21479
22080
|
const ids = new Set;
|
|
@@ -21658,8 +22259,15 @@ function adaptSdkClient(sdk, orchestratedModelOwnership) {
|
|
|
21658
22259
|
if (result.error !== undefined) {
|
|
21659
22260
|
out.error = normalizeSdkSessionFailure(result.error, "prompt");
|
|
21660
22261
|
} else {
|
|
22262
|
+
const info = isRecord7(result.data) ? nestedRecord2(result.data, "info") : undefined;
|
|
21661
22263
|
const nestedFailure = nestedAssistantFailure(result.data);
|
|
21662
|
-
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) {
|
|
21663
22271
|
out.error = normalizeSdkSessionFailure(nestedFailure, "prompt");
|
|
21664
22272
|
} else if (result.data !== undefined) {
|
|
21665
22273
|
out.data = result.data;
|
|
@@ -21819,7 +22427,10 @@ function mapTelemetryFailureClassToErrorClass(cls) {
|
|
|
21819
22427
|
case "prompt-rate-limited":
|
|
21820
22428
|
case "prompt-connection":
|
|
21821
22429
|
case "prompt-server":
|
|
22430
|
+
case "prompt-output-truncated":
|
|
21822
22431
|
return "transient";
|
|
22432
|
+
case "budget-exhausted":
|
|
22433
|
+
return "permanent";
|
|
21823
22434
|
case "create-rejected":
|
|
21824
22435
|
case "create-no-id":
|
|
21825
22436
|
case "prompt-rejected":
|
|
@@ -22102,8 +22713,16 @@ function createOrchestrateTool(deps) {
|
|
|
22102
22713
|
}
|
|
22103
22714
|
const parentOverrideIgnored = parsed.data.parentSessionID !== undefined && parsed.data.parentSessionID !== context.sessionID;
|
|
22104
22715
|
parsed.data.parentSessionID = context.sessionID;
|
|
22105
|
-
if (
|
|
22106
|
-
|
|
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
|
+
}
|
|
22107
22726
|
const depError = validateAssignmentDependencies(parsed.data.assignments);
|
|
22108
22727
|
if (depError !== undefined) {
|
|
22109
22728
|
return dependencyValidationError(depError.code, depError.detail);
|
|
@@ -22126,6 +22745,14 @@ function createOrchestrateTool(deps) {
|
|
|
22126
22745
|
return missingAgentDefinition(agentName, input.roleID);
|
|
22127
22746
|
}
|
|
22128
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
|
+
}
|
|
22129
22756
|
const batchID = deps.newDecisionID();
|
|
22130
22757
|
if (deps.lifecycleRecorder !== undefined) {
|
|
22131
22758
|
const rootOperationID = operationID(batchID, "openteam");
|
|
@@ -22135,7 +22762,7 @@ function createOrchestrateTool(deps) {
|
|
|
22135
22762
|
executionAuthority: "coordinator",
|
|
22136
22763
|
root: {
|
|
22137
22764
|
operationID: rootOperationID,
|
|
22138
|
-
taskID: batchID,
|
|
22765
|
+
taskID: taskRef?.taskID ?? batchID,
|
|
22139
22766
|
kind: "coordinator",
|
|
22140
22767
|
roleID: "openteam",
|
|
22141
22768
|
agentID: context.agent,
|
|
@@ -22160,6 +22787,12 @@ function createOrchestrateTool(deps) {
|
|
|
22160
22787
|
reportedModelSlots: deps.reportedModelSlots,
|
|
22161
22788
|
readReportArtifact: deps.readReportArtifact,
|
|
22162
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
|
+
},
|
|
22163
22796
|
abortGraceMs: deps.abortGraceMs,
|
|
22164
22797
|
statusPollMs: deps.statusPollMs,
|
|
22165
22798
|
delay: deps.delay,
|
|
@@ -22177,10 +22810,15 @@ function createOrchestrateTool(deps) {
|
|
|
22177
22810
|
lifecycleStatus = activeLifecycleRecorder?.status() ?? lifecycleStatus;
|
|
22178
22811
|
const projected = projectResults(batch.results, batch.cancelled);
|
|
22179
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)}`;
|
|
22180
22817
|
const base = formatResult(projected) + (parentOverrideIgnored ? `
|
|
22181
22818
|
|
|
22182
|
-
${PARENT_OVERRIDE_IGNORED}` : "");
|
|
22183
|
-
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);
|
|
22184
22822
|
const withAdvisory = advisory === undefined ? base : `${base}
|
|
22185
22823
|
|
|
22186
22824
|
${advisory}`;
|
|
@@ -22211,7 +22849,7 @@ ${advisory}`;
|
|
|
22211
22849
|
|
|
22212
22850
|
// src/plugin/registerCastTool.ts
|
|
22213
22851
|
import { tool as tool6 } from "@opencode-ai/plugin";
|
|
22214
|
-
import { z as
|
|
22852
|
+
import { z as z35 } from "zod";
|
|
22215
22853
|
|
|
22216
22854
|
// src/messages/rosterSummary.ts
|
|
22217
22855
|
var ROSTER_SUMMARY_HEADING = "Registered team model policies";
|
|
@@ -22327,12 +22965,12 @@ function createTeamPreparation(deps) {
|
|
|
22327
22965
|
OpenTeamConfigSchema.parse(migrateConfig(baseRaw));
|
|
22328
22966
|
const overlay = overlayBefore === undefined ? undefined : parseConfigFileJson(DEFAULT_LOCAL_OVERLAY_PATH, overlayBefore);
|
|
22329
22967
|
const options = configOptionsFromPluginOptions(deps.options);
|
|
22330
|
-
const
|
|
22968
|
+
const resolve12 = (raw) => {
|
|
22331
22969
|
const config = validateConfigInput(TEAM_PREPARATION_CONFIG, mergeConfigInputs(mergeConfigInputs(raw, options), overlay));
|
|
22332
22970
|
assertEffectiveConfigModelDomains(config);
|
|
22333
22971
|
return config;
|
|
22334
22972
|
};
|
|
22335
|
-
const current =
|
|
22973
|
+
const current = resolve12(baseRaw);
|
|
22336
22974
|
const live = liveConfig ?? current;
|
|
22337
22975
|
if (resolveExecutionMode({
|
|
22338
22976
|
routerMode: current.router.executionMode,
|
|
@@ -22354,7 +22992,7 @@ function createTeamPreparation(deps) {
|
|
|
22354
22992
|
]))
|
|
22355
22993
|
}
|
|
22356
22994
|
});
|
|
22357
|
-
const effective =
|
|
22995
|
+
const effective = resolve12(candidate);
|
|
22358
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)));
|
|
22359
22997
|
const additions = Object.fromEntries(Object.entries(effective.orchestrator?.roles ?? {}).filter(([key2, profile]) => requestedProfiles.has(profile) && !Object.hasOwn(live.orchestrator?.roles ?? {}, key2)));
|
|
22360
22998
|
const hasAdditions = Object.keys(additions).length > 0;
|
|
@@ -22440,13 +23078,13 @@ async function persistPreparedTeam(storage, files) {
|
|
|
22440
23078
|
}
|
|
22441
23079
|
|
|
22442
23080
|
// src/plugin/registerCastTool.ts
|
|
22443
|
-
var CastEntrySchema =
|
|
22444
|
-
roleID:
|
|
22445
|
-
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")
|
|
22446
23084
|
}).strict();
|
|
22447
|
-
var RegisterCastPayloadSchema =
|
|
22448
|
-
universe:
|
|
22449
|
-
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")
|
|
22450
23088
|
}).strict();
|
|
22451
23089
|
function offendingFields(error) {
|
|
22452
23090
|
const fields = error.issues.flatMap((issue) => {
|
|
@@ -22566,7 +23204,7 @@ function createRegisterCastTool(deps) {
|
|
|
22566
23204
|
}
|
|
22567
23205
|
|
|
22568
23206
|
// src/plugin/reloadTool.ts
|
|
22569
|
-
import { resolve as
|
|
23207
|
+
import { resolve as resolve12 } from "node:path";
|
|
22570
23208
|
import { tool as tool7 } from "@opencode-ai/plugin/tool";
|
|
22571
23209
|
var WAIT_MS = 30000;
|
|
22572
23210
|
var SDK_TIMEOUT_MS = 5000;
|
|
@@ -22600,7 +23238,7 @@ function createReloadController(deps) {
|
|
|
22600
23238
|
return () => clearTimeout(timer);
|
|
22601
23239
|
}
|
|
22602
23240
|
};
|
|
22603
|
-
const directory =
|
|
23241
|
+
const directory = resolve12(deps.directory);
|
|
22604
23242
|
let pending;
|
|
22605
23243
|
let authorizing;
|
|
22606
23244
|
let closed = false;
|
|
@@ -22748,7 +23386,7 @@ function createReloadController(deps) {
|
|
|
22748
23386
|
const parsed = schema.safeParse(args);
|
|
22749
23387
|
if (!parsed.success)
|
|
22750
23388
|
return reloadMessages.invalid;
|
|
22751
|
-
if (context.agent !== "openteam" ||
|
|
23389
|
+
if (context.agent !== "openteam" || resolve12(context.directory) !== directory || context.sessionID.trim().length === 0)
|
|
22752
23390
|
return reloadMessages.denied;
|
|
22753
23391
|
if (parsed.data.action === "cancel") {
|
|
22754
23392
|
if ((pending?.sessionID ?? authorizing?.sessionID) !== context.sessionID)
|
|
@@ -22866,6 +23504,31 @@ function createReloadController(deps) {
|
|
|
22866
23504
|
};
|
|
22867
23505
|
}
|
|
22868
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
|
+
|
|
22869
23532
|
// src/plugin/sessionTracker.ts
|
|
22870
23533
|
function createSessionTracker() {
|
|
22871
23534
|
const knownSessions = new Set;
|
|
@@ -22894,22 +23557,40 @@ function createSessionTracker() {
|
|
|
22894
23557
|
}
|
|
22895
23558
|
|
|
22896
23559
|
// src/plugin/toolcalls.ts
|
|
23560
|
+
var MAX_TRACKED_CALLS = 8192;
|
|
22897
23561
|
function key2(sessionID, callID) {
|
|
22898
23562
|
return `${sessionID}\x00${callID}`;
|
|
22899
23563
|
}
|
|
22900
23564
|
function createToolcallTracker(deps) {
|
|
22901
23565
|
const now = deps.now ?? Date.now;
|
|
22902
23566
|
const started = new Map;
|
|
23567
|
+
const completed = new Set;
|
|
22903
23568
|
return {
|
|
22904
23569
|
before(input) {
|
|
22905
|
-
|
|
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
|
+
}
|
|
22906
23579
|
},
|
|
22907
23580
|
after(input) {
|
|
22908
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
|
+
}
|
|
22909
23590
|
const start = started.get(mapKey);
|
|
22910
23591
|
started.delete(mapKey);
|
|
22911
23592
|
const end = now();
|
|
22912
|
-
const durationMs = start === undefined ?
|
|
23593
|
+
const durationMs = input.durationMs !== undefined ? input.durationMs : start === undefined ? null : Math.max(0, Math.trunc(end - start));
|
|
22913
23594
|
const event = {
|
|
22914
23595
|
v: EVENT_SCHEMA_VERSION,
|
|
22915
23596
|
type: "toolcall",
|
|
@@ -22918,9 +23599,23 @@ function createToolcallTracker(deps) {
|
|
|
22918
23599
|
tool: input.tool,
|
|
22919
23600
|
callID: input.callID,
|
|
22920
23601
|
durationMs,
|
|
22921
|
-
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 }
|
|
22922
23606
|
};
|
|
22923
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
|
+
}
|
|
22924
23619
|
}
|
|
22925
23620
|
};
|
|
22926
23621
|
}
|
|
@@ -23125,22 +23820,22 @@ import {
|
|
|
23125
23820
|
statSync,
|
|
23126
23821
|
unlinkSync as unlinkSync2
|
|
23127
23822
|
} from "node:fs";
|
|
23128
|
-
import { join as join15, resolve as
|
|
23823
|
+
import { join as join15, resolve as resolve14 } from "node:path";
|
|
23129
23824
|
import { ZodError } from "zod";
|
|
23130
23825
|
|
|
23131
23826
|
// src/storage/lifecycle/codec.ts
|
|
23132
|
-
import { z as
|
|
23827
|
+
import { z as z36 } from "zod";
|
|
23133
23828
|
var LIFECYCLE_CODEC_VERSION = 1;
|
|
23134
23829
|
var LIFECYCLE_GENESIS_DIGEST = sha256Hex("openteam/lifecycle-journal/genesis/v1");
|
|
23135
23830
|
var NUL5 = "\x00";
|
|
23136
23831
|
var NEWLINE2 = `
|
|
23137
23832
|
`;
|
|
23138
|
-
var frameSchema =
|
|
23139
|
-
v:
|
|
23140
|
-
seq:
|
|
23141
|
-
prev:
|
|
23142
|
-
sum:
|
|
23143
|
-
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()
|
|
23144
23839
|
}).strict();
|
|
23145
23840
|
function canonical2(value) {
|
|
23146
23841
|
if (Array.isArray(value)) {
|
|
@@ -23244,7 +23939,7 @@ import {
|
|
|
23244
23939
|
unlinkSync,
|
|
23245
23940
|
writeSync as writeSync2
|
|
23246
23941
|
} from "node:fs";
|
|
23247
|
-
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";
|
|
23248
23943
|
var SAFE_RUN_ID = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,126}[A-Za-z0-9])?$/u;
|
|
23249
23944
|
|
|
23250
23945
|
class LifecycleFsError extends Error {
|
|
@@ -23268,7 +23963,7 @@ function validateRunID(runID) {
|
|
|
23268
23963
|
}
|
|
23269
23964
|
function resolvedLifecycleRoot(root) {
|
|
23270
23965
|
try {
|
|
23271
|
-
const absolute =
|
|
23966
|
+
const absolute = resolve13(root);
|
|
23272
23967
|
mkdirSync2(absolute, { recursive: true });
|
|
23273
23968
|
const rootStat = lstatSync2(absolute);
|
|
23274
23969
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
|
|
@@ -23311,7 +24006,7 @@ function assertExistingSafeRun(root, runID) {
|
|
|
23311
24006
|
throw new LifecycleFsError("unavailable");
|
|
23312
24007
|
}
|
|
23313
24008
|
const child = relative3(root, real);
|
|
23314
|
-
if (child === "" || child.startsWith("..") ||
|
|
24009
|
+
if (child === "" || child.startsWith("..") || resolve13(root, child) !== real || dirname7(real) !== root) {
|
|
23315
24010
|
throw new LifecycleFsError("corrupt");
|
|
23316
24011
|
}
|
|
23317
24012
|
return real;
|
|
@@ -23551,7 +24246,7 @@ function canDeleteTerminalRun(runDir, runID, now) {
|
|
|
23551
24246
|
return now >= lease.expiresAt;
|
|
23552
24247
|
}
|
|
23553
24248
|
var createFsLifecycleJournal = (options) => {
|
|
23554
|
-
const configuredRoot =
|
|
24249
|
+
const configuredRoot = resolve14(options.root);
|
|
23555
24250
|
const now = options.now ?? Date.now;
|
|
23556
24251
|
const mutateRun = options.withMutationLock ?? withRunMutationLock;
|
|
23557
24252
|
return {
|
|
@@ -23907,6 +24602,61 @@ var createFsLifecycleWriterLivenessProbe = (options) => ({
|
|
|
23907
24602
|
}
|
|
23908
24603
|
});
|
|
23909
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
|
+
|
|
23910
24660
|
// src/telemetry/otelExporter.ts
|
|
23911
24661
|
var DEFAULT_SERVICE_NAME = "openteam";
|
|
23912
24662
|
function tracesUrl(ingestionEndpoint) {
|
|
@@ -24051,7 +24801,7 @@ var RELEASE_CERT_PATH = "artifacts/graph-release-certificate.json";
|
|
|
24051
24801
|
var SOAK_CERT_PATH = "artifacts/graph-soak-certificate.json";
|
|
24052
24802
|
async function readPackagedCertificate(path4) {
|
|
24053
24803
|
try {
|
|
24054
|
-
const hostDirectory = basename4(
|
|
24804
|
+
const hostDirectory = basename4(dirname9(path4)) === NATIVE_CERTIFICATE_DIRECTORY ? `${NATIVE_CERTIFICATE_DIRECTORY}/` : "";
|
|
24055
24805
|
return await readFile5(new URL(`./certificates/${hostDirectory}${basename4(path4)}`, import.meta.url), "utf8");
|
|
24056
24806
|
} catch {
|
|
24057
24807
|
return;
|
|
@@ -24184,8 +24934,8 @@ async function readOpencodeVersion(serverUrl, options = {}) {
|
|
|
24184
24934
|
}
|
|
24185
24935
|
var DEFAULT_OPENCODE_VERSION_BACKOFF_MS = [50, 250];
|
|
24186
24936
|
function defaultSleep(ms) {
|
|
24187
|
-
return new Promise((
|
|
24188
|
-
setTimeout(
|
|
24937
|
+
return new Promise((resolve16) => {
|
|
24938
|
+
setTimeout(resolve16, ms);
|
|
24189
24939
|
});
|
|
24190
24940
|
}
|
|
24191
24941
|
function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
@@ -24228,7 +24978,7 @@ function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
|
24228
24978
|
};
|
|
24229
24979
|
}
|
|
24230
24980
|
async function buildGateInput(config, storage, opencodeVersion, warn, packagedRead = readPackagedCertificate) {
|
|
24231
|
-
const hostPath = (path4) => opencodeVersion
|
|
24981
|
+
const hostPath = (path4) => isSupportedNativeOpencodeVersion(opencodeVersion) ? `${dirname9(path4)}/${NATIVE_CERTIFICATE_DIRECTORY}/${basename4(path4)}` : path4;
|
|
24232
24982
|
const shadow = await readAndParseCertificate(storage, hostPath(SHADOW_CERT_PATH), (raw) => parseShadowCertificate(raw, opencodeVersion), (cert) => shadowCertificateBindingDigest(cert.evidence), packagedRead);
|
|
24233
24983
|
const shadowDigest = shadow.status === "valid" ? shadow.digest : "0".repeat(64);
|
|
24234
24984
|
const release = await readAndParseCertificate(storage, hostPath(RELEASE_CERT_PATH), (raw) => parseReleaseCertificate(raw, opencodeVersion, shadowDigest), (cert) => cert.digest, packagedRead);
|
|
@@ -24437,7 +25187,7 @@ function createCliDeps(config, registry, telemetryPath, sessionsDir = DEFAULT_SE
|
|
|
24437
25187
|
telemetryPath,
|
|
24438
25188
|
opencodeConfigPaths: OPENCODE_CONFIG_CANDIDATES,
|
|
24439
25189
|
orchestratorAgentPath: ORCHESTRATOR_AGENT_PATH,
|
|
24440
|
-
agentDir:
|
|
25190
|
+
agentDir: dirname9(ORCHESTRATOR_AGENT_PATH),
|
|
24441
25191
|
cachePort: realCacheAdapter,
|
|
24442
25192
|
purge: createPluginPurgeRuntime(sessionsDir),
|
|
24443
25193
|
loadRosterForDoctor: () => readStoredRosterForDoctor(storage),
|
|
@@ -24588,6 +25338,24 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24588
25338
|
return version === "unknown" ? undefined : version;
|
|
24589
25339
|
}, workspaceRoot);
|
|
24590
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
|
+
};
|
|
24591
25359
|
const announcedSessions = new Set;
|
|
24592
25360
|
const announceEndpoint = (sessionID) => {
|
|
24593
25361
|
if (sessionID === undefined || announcedSessions.has(sessionID)) {
|
|
@@ -24708,6 +25476,18 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24708
25476
|
},
|
|
24709
25477
|
now
|
|
24710
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
|
+
});
|
|
24711
25491
|
const orchestrateTool = createOrchestrateTool({
|
|
24712
25492
|
client: orchestrateClient,
|
|
24713
25493
|
sink,
|
|
@@ -24728,11 +25508,15 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24728
25508
|
capabilityProfiles,
|
|
24729
25509
|
reportArtifactExists,
|
|
24730
25510
|
readReportArtifact,
|
|
25511
|
+
reportDelivery,
|
|
25512
|
+
taskEffort,
|
|
25513
|
+
sessionPhase,
|
|
25514
|
+
workspaceDirectory: ctx.directory,
|
|
24731
25515
|
lifecycleRecorder,
|
|
24732
25516
|
abortGraceMs: DEFAULT_ABORT_GRACE_MS,
|
|
24733
25517
|
statusPollMs: DEFAULT_STATUS_POLL_MS,
|
|
24734
|
-
delay: (ms) => new Promise((
|
|
24735
|
-
setTimeout(
|
|
25518
|
+
delay: (ms) => new Promise((resolve16) => {
|
|
25519
|
+
setTimeout(resolve16, ms);
|
|
24736
25520
|
}),
|
|
24737
25521
|
warn: diagnostics.warn("unknown-role")
|
|
24738
25522
|
});
|
|
@@ -24798,7 +25582,9 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24798
25582
|
...hooks,
|
|
24799
25583
|
"chat.message": async (input, output) => {
|
|
24800
25584
|
reload.userTurn(input.sessionID);
|
|
25585
|
+
await taskEffort.userTurn(input.sessionID, input.messageID ?? output.message.id);
|
|
24801
25586
|
await hooks["chat.message"]?.(input, output);
|
|
25587
|
+
await sessionPhase(input.sessionID, "model-request");
|
|
24802
25588
|
announceEndpoint(input.sessionID);
|
|
24803
25589
|
},
|
|
24804
25590
|
dispose: async () => {
|
|
@@ -24812,18 +25598,44 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24812
25598
|
"openteam-orchestrate": orchestrateTool,
|
|
24813
25599
|
"openteam-memory": memoryTool,
|
|
24814
25600
|
"openteam-register-cast": registerCastTool,
|
|
24815
|
-
"openteam-reload": reload.tool
|
|
25601
|
+
"openteam-reload": reload.tool,
|
|
25602
|
+
"openteam-submit-report": createReportTool(reportDelivery)
|
|
24816
25603
|
},
|
|
24817
25604
|
"tool.execute.before": async (input) => {
|
|
24818
25605
|
toolcalls.before(input);
|
|
25606
|
+
await sessionPhase(input.sessionID, "tool-execution");
|
|
24819
25607
|
},
|
|
24820
25608
|
"tool.execute.after": async (input) => {
|
|
24821
|
-
|
|
25609
|
+
if (ctx.toolOutcomesFromEvents !== true)
|
|
25610
|
+
await toolcalls.after(input);
|
|
24822
25611
|
if (input.tool === "openteam-reload")
|
|
24823
25612
|
reload.toolCompleted(input.sessionID);
|
|
24824
25613
|
},
|
|
24825
25614
|
event: async ({ event }) => {
|
|
24826
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
|
+
}
|
|
24827
25639
|
if (event.type === "session.created" || event.type === "session.idle") {
|
|
24828
25640
|
cache.refresh();
|
|
24829
25641
|
}
|
|
@@ -24840,6 +25652,7 @@ async function createPluginRuntime(ctx, rawOptions) {
|
|
|
24840
25652
|
announceEndpoint(message.sessionID);
|
|
24841
25653
|
sessionTracker.trackSession(message.sessionID);
|
|
24842
25654
|
sink.emit(message);
|
|
25655
|
+
await sessionPhase(message.sessionID, "unknown");
|
|
24843
25656
|
}
|
|
24844
25657
|
}
|
|
24845
25658
|
}
|
|
@@ -24849,6 +25662,19 @@ var server = (ctx, rawOptions) => createPluginRuntime({
|
|
|
24849
25662
|
directory: ctx.directory,
|
|
24850
25663
|
worktree: ctx.worktree,
|
|
24851
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
|
+
},
|
|
24852
25678
|
exec: createShellExec(ctx.$),
|
|
24853
25679
|
serverUrl: () => ctx.serverUrl,
|
|
24854
25680
|
...ctx.client.config?.providers === undefined ? {} : {
|