@jmanuelcorral/openteam 0.24.0 → 0.25.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/README.es.md +20 -5
- package/README.md +14 -2
- package/dist/certificates/graph-release-certificate.json +2 -2
- package/dist/certificates/graph-shadow-certificate.json +2 -2
- package/dist/cli/setupAdapters.d.ts +2 -2
- package/dist/cli/setupAdapters.d.ts.map +1 -1
- package/dist/cli.js +1251 -554
- package/dist/commands/agents.d.ts +6 -4
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/dispatch.d.ts +1 -1
- package/dist/commands/dispatch.d.ts.map +1 -1
- package/dist/commands/setup.d.ts +22 -14
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/console/assets.d.ts.map +1 -1
- package/dist/console/conversation.d.ts +5 -1
- package/dist/console/conversation.d.ts.map +1 -1
- package/dist/console/credentials.d.ts +4 -0
- package/dist/console/credentials.d.ts.map +1 -0
- package/dist/console/inspector.d.ts +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.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +999 -287
- package/dist/local/lemonade.d.ts.map +1 -1
- package/dist/local/lemonadeRequestGuard.d.ts +11 -0
- package/dist/local/lemonadeRequestGuard.d.ts.map +1 -0
- package/dist/local/lemonadeResidency.d.ts +22 -0
- package/dist/local/lemonadeResidency.d.ts.map +1 -0
- package/dist/local/modelResidency.d.ts +4 -0
- package/dist/local/modelResidency.d.ts.map +1 -0
- package/dist/local/slotPool.d.ts +13 -7
- package/dist/local/slotPool.d.ts.map +1 -1
- package/dist/messages/consoleDetail.d.ts +8 -5
- package/dist/messages/consoleDetail.d.ts.map +1 -1
- package/dist/messages/executionSetup.d.ts +19 -0
- package/dist/messages/executionSetup.d.ts.map +1 -1
- package/dist/messages/modelResidency.d.ts +19 -0
- package/dist/messages/modelResidency.d.ts.map +1 -0
- package/dist/orchestrator/coordinator.d.ts.map +1 -1
- package/dist/orchestrator/runtimeSelection.d.ts +4 -3
- package/dist/orchestrator/runtimeSelection.d.ts.map +1 -1
- package/dist/plugin/availability.d.ts +4 -1
- package/dist/plugin/availability.d.ts.map +1 -1
- package/dist/plugin/hooks.d.ts +2 -0
- package/dist/plugin/hooks.d.ts.map +1 -1
- package/dist/plugin/memoryTool.d.ts +9 -3
- package/dist/plugin/memoryTool.d.ts.map +1 -1
- package/dist/plugin/modelResidency.d.ts +47 -0
- package/dist/plugin/modelResidency.d.ts.map +1 -0
- package/dist/router/types.d.ts +2 -0
- package/dist/router/types.d.ts.map +1 -1
- package/dist/web/conversationRoute.d.ts +2 -2
- package/dist/web/conversationRoute.d.ts.map +1 -1
- package/dist/web/server.d.ts +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -424,6 +424,9 @@ function migrateConfig(raw) {
|
|
|
424
424
|
var consoleDetailMessages = {
|
|
425
425
|
follow: "Follow new activity",
|
|
426
426
|
metadataOnly: "Lifecycle and telemetry stay metadata-only.",
|
|
427
|
+
logsDescription: "Current recorded conversations load automatically. Lifecycle and telemetry remain metadata-only; credentials are masked.",
|
|
428
|
+
credentialMasked: "[credential masked]",
|
|
429
|
+
offscreen: "Messages load automatically when this conversation is visible.",
|
|
427
430
|
filter: "Filter sessions",
|
|
428
431
|
incoming: "New activity available — show updates",
|
|
429
432
|
refreshError: "Live updates unavailable; retrying.",
|
|
@@ -444,7 +447,7 @@ var consoleDetailMessages = {
|
|
|
444
447
|
partialMetadata: "Some current session titles are unavailable or outside the bounded batch; fallback labels remain.",
|
|
445
448
|
rootCurrent: "Current whole orchestrator session; may contain multiple batches. Not a historical or batch-only transcript.",
|
|
446
449
|
recovered: "Read-only association verified from current opencode history; not an immutable lifecycle event.",
|
|
447
|
-
rootUnlinked: "Orchestrator session not recorded.
|
|
450
|
+
rootUnlinked: "Orchestrator session not recorded. A bounded, read-only relationship search is attempted when visible.",
|
|
448
451
|
rootUnavailable: "Orchestrator session unavailable: no unique, verifiable relationship was found in local history.",
|
|
449
452
|
rootAmbiguous: "Orchestrator session unavailable: conflicting or copied relationships are ambiguous.",
|
|
450
453
|
searchIncomplete: "Orchestrator association search incomplete or exceeded its bounded budget. No session was guessed.",
|
|
@@ -457,9 +460,9 @@ var consoleDetailMessages = {
|
|
|
457
460
|
arguments: "Arguments",
|
|
458
461
|
result: "Result",
|
|
459
462
|
loading: "Loading local conversation…",
|
|
460
|
-
current: "Present-day session, not a timeline reconstruction
|
|
461
|
-
historical: "Historical cursor: conversation content is hidden to avoid showing future mutable text. Return to live
|
|
462
|
-
disabled: "Content is disabled
|
|
463
|
+
current: "Present-day whole session, not a timeline reconstruction or per-attempt transcript. Visible messages update automatically while live.",
|
|
464
|
+
historical: "Historical cursor: conversation content is hidden to avoid showing future mutable text. Return to live to read current messages.",
|
|
465
|
+
disabled: "Content is disabled by console.sessionHistory.contentEnabled: false. Lifecycle and telemetry remain metadata-only.",
|
|
463
466
|
unavailable: "Conversation unavailable. Start an operator-owned local opencode serve against the same workspace and user history, configure console.sessionHistory.endpoint, then retry. No inference was requested.",
|
|
464
467
|
empty: "No readable user messages, assistant output or tool calls remain in this session.",
|
|
465
468
|
invalid: "This attempt has no recorded session in the selected run, or its history is incomplete.",
|
|
@@ -469,7 +472,7 @@ var consoleDetailMessages = {
|
|
|
469
472
|
invalidEndpoint: "Expected a loopback HTTP origin without credentials, path, query or fragment.",
|
|
470
473
|
readFailed: "Local session history could not be read.",
|
|
471
474
|
oversized: "Conversation exceeds the local size limit (4 MiB). No content was loaded.",
|
|
472
|
-
truncated: "Conversation display is truncated by local safety limits
|
|
475
|
+
truncated: "Conversation display is truncated by local safety limits. The newest bounded message window is shown; older messages or oversized fields may be omitted, not empty history.",
|
|
473
476
|
truncatedMarker: `
|
|
474
477
|
[truncated]`,
|
|
475
478
|
terminalGap: "Live collection was interrupted; events during the gap are unavailable. This is not complete session history.",
|
|
@@ -546,7 +549,7 @@ var ConsoleConfigSchema = z2.object({
|
|
|
546
549
|
openBrowser: z2.boolean().default(false),
|
|
547
550
|
remoteStorage: z2.boolean().default(false),
|
|
548
551
|
sessionHistory: z2.object({
|
|
549
|
-
contentEnabled: z2.boolean().default(
|
|
552
|
+
contentEnabled: z2.boolean().default(true),
|
|
550
553
|
endpoint: z2.string().refine(isLocalHistoryEndpoint, consoleDetailMessages.invalidEndpoint).optional()
|
|
551
554
|
}).strict().optional(),
|
|
552
555
|
terminal: z2.object({
|
|
@@ -891,6 +894,27 @@ import { isAbsolute, normalize, parse, resolve, sep } from "node:path";
|
|
|
891
894
|
import { createOpencodeClient } from "@opencode-ai/sdk";
|
|
892
895
|
import { z as z4 } from "zod";
|
|
893
896
|
|
|
897
|
+
// src/console/credentials.ts
|
|
898
|
+
var URL_WITH_AUTHORITY = /https?:\/\/[^\s/?#]+/giu;
|
|
899
|
+
function maskUrlCredentials(value) {
|
|
900
|
+
return value.replace(URL_WITH_AUTHORITY, (candidate) => {
|
|
901
|
+
const schemeEnd = candidate.indexOf("://") + 3;
|
|
902
|
+
const at = candidate.indexOf("@", schemeEnd);
|
|
903
|
+
if (at === -1)
|
|
904
|
+
return candidate;
|
|
905
|
+
const colon = candidate.indexOf(":", schemeEnd);
|
|
906
|
+
if (colon === -1 || colon <= schemeEnd || colon + 1 >= at || colon > at)
|
|
907
|
+
return candidate;
|
|
908
|
+
return `${candidate.slice(0, schemeEnd)}${consoleDetailMessages.credentialMasked}${candidate.slice(at)}`;
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
function maskConversationCredentials(value) {
|
|
912
|
+
return maskUrlCredentials(value.replace(/-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----[\s\S]*?(?:-----END (?:[A-Z]+ )?PRIVATE KEY-----|$)/gu, consoleDetailMessages.credentialMasked).replace(/\b(?:Bearer|Basic)\s+[A-Za-z0-9._~+/=-]+/giu, consoleDetailMessages.credentialMasked).replace(/\b(?:sk-[A-Za-z0-9_-]{16,}|gh[pousr]_[A-Za-z0-9]{16,}|github_pat_[A-Za-z0-9_]{16,}|AKIA[A-Z0-9]{16}|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)\b/gu, consoleDetailMessages.credentialMasked).replace(/(\b(?:password|passwd|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|token|authorization|cookie|set-cookie)\b["']?\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;}\]]+)/giu, (_match, prefix) => prefix + consoleDetailMessages.credentialMasked));
|
|
913
|
+
}
|
|
914
|
+
function isCredentialKey(key) {
|
|
915
|
+
return /^(?:password|passwd|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|token|authorization|cookie|set-cookie|private[_-]?key)$/iu.test(key);
|
|
916
|
+
}
|
|
917
|
+
|
|
894
918
|
// src/console/historyBoundary.ts
|
|
895
919
|
function only(keys) {
|
|
896
920
|
return (value) => {
|
|
@@ -1148,7 +1172,7 @@ class ConversationTooLargeError extends Error {
|
|
|
1148
1172
|
}
|
|
1149
1173
|
}
|
|
1150
1174
|
var Info = z4.preprocess(only(["id", "sessionID", "role", "time"]), z4.object({
|
|
1151
|
-
id: z4.string(),
|
|
1175
|
+
id: z4.string().min(1).max(256),
|
|
1152
1176
|
sessionID: z4.string(),
|
|
1153
1177
|
role: z4.enum(["user", "assistant"]),
|
|
1154
1178
|
time: z4.preprocess(only(["created", "completed"]), z4.object({
|
|
@@ -1168,7 +1192,7 @@ var Text = PartIdentity.extend({
|
|
|
1168
1192
|
});
|
|
1169
1193
|
var Tool = PartIdentity.extend({
|
|
1170
1194
|
type: z4.literal("tool"),
|
|
1171
|
-
callID: z4.string(),
|
|
1195
|
+
callID: z4.string().min(1).max(256),
|
|
1172
1196
|
tool: z4.string(),
|
|
1173
1197
|
state: z4.preprocess(only(["status", "input", "output", "error", "time"]), z4.object({
|
|
1174
1198
|
status: z4.enum(["pending", "running", "completed", "error"]),
|
|
@@ -1191,6 +1215,7 @@ function projectConversation(raw, sessionID) {
|
|
|
1191
1215
|
let remaining = limits.totalChars;
|
|
1192
1216
|
let toolsRemaining = limits.tools;
|
|
1193
1217
|
function text(value) {
|
|
1218
|
+
value = maskConversationCredentials(value);
|
|
1194
1219
|
const length = Math.min(value.length, limits.fieldChars, remaining);
|
|
1195
1220
|
remaining -= length;
|
|
1196
1221
|
if (length === value.length)
|
|
@@ -1222,7 +1247,7 @@ function projectConversation(raw, sessionID) {
|
|
|
1222
1247
|
truncated = true;
|
|
1223
1248
|
break;
|
|
1224
1249
|
}
|
|
1225
|
-
const child = bounded(value[key], depth + 1);
|
|
1250
|
+
const child = isCredentialKey(key) ? consoleDetailMessages.credentialMasked : bounded(value[key], depth + 1);
|
|
1226
1251
|
if (Array.isArray(value))
|
|
1227
1252
|
array.push(child);
|
|
1228
1253
|
else
|
|
@@ -1233,7 +1258,7 @@ function projectConversation(raw, sessionID) {
|
|
|
1233
1258
|
return text(JSON.stringify(bounded(input, 0), null, 2));
|
|
1234
1259
|
}
|
|
1235
1260
|
const messages = [];
|
|
1236
|
-
for (const rawRow of raw.slice(
|
|
1261
|
+
for (const rawRow of raw.slice(-limits.messages).reverse()) {
|
|
1237
1262
|
if (remaining <= 0) {
|
|
1238
1263
|
truncated = true;
|
|
1239
1264
|
break;
|
|
@@ -1242,12 +1267,13 @@ function projectConversation(raw, sessionID) {
|
|
|
1242
1267
|
if (row.info.sessionID !== sessionID)
|
|
1243
1268
|
throw new Error(consoleDetailMessages.readFailed);
|
|
1244
1269
|
const message = {
|
|
1245
|
-
id:
|
|
1270
|
+
id: row.info.id,
|
|
1246
1271
|
role: row.info.role,
|
|
1247
1272
|
createdAt: row.info.time.created,
|
|
1248
1273
|
...row.info.time.completed !== undefined ? { completedAt: row.info.time.completed } : {},
|
|
1249
1274
|
text: [],
|
|
1250
|
-
tools: []
|
|
1275
|
+
tools: [],
|
|
1276
|
+
order: []
|
|
1251
1277
|
};
|
|
1252
1278
|
if (row.parts.length > limits.parts)
|
|
1253
1279
|
truncated = true;
|
|
@@ -1271,16 +1297,19 @@ function projectConversation(raw, sessionID) {
|
|
|
1271
1297
|
if (part.sessionID !== sessionID || part.messageID !== row.info.id)
|
|
1272
1298
|
throw new Error(consoleDetailMessages.readFailed);
|
|
1273
1299
|
if (part.type === "text") {
|
|
1274
|
-
if (!part.ignored)
|
|
1300
|
+
if (!part.ignored) {
|
|
1301
|
+
message.order?.push({ type: "text", index: message.text.length });
|
|
1275
1302
|
message.text.push(text(part.text));
|
|
1303
|
+
}
|
|
1276
1304
|
} else {
|
|
1277
1305
|
if (toolsRemaining-- <= 0) {
|
|
1278
1306
|
truncated = true;
|
|
1279
1307
|
continue;
|
|
1280
1308
|
}
|
|
1281
1309
|
const state = part.state;
|
|
1310
|
+
message.order?.push({ type: "tool", index: message.tools.length });
|
|
1282
1311
|
message.tools.push({
|
|
1283
|
-
id:
|
|
1312
|
+
id: part.callID,
|
|
1284
1313
|
name: text(part.tool),
|
|
1285
1314
|
status: state.status,
|
|
1286
1315
|
arguments: argumentsText(state.input),
|
|
@@ -1385,7 +1414,7 @@ function createConversationReader(deps) {
|
|
|
1385
1414
|
if (workspaceKey(session.directory) !== workspaceKey(directory))
|
|
1386
1415
|
throw new Error(consoleDetailMessages.readFailed);
|
|
1387
1416
|
const time = z4.preprocess(only(["created"]), z4.object({ created: z4.number().finite().min(0).max(8640000000000000) }).strict()).safeParse(session.time);
|
|
1388
|
-
const title = boundedTitle(session.title);
|
|
1417
|
+
const title = boundedTitle(typeof session.title === "string" ? maskConversationCredentials(session.title) : session.title);
|
|
1389
1418
|
return {
|
|
1390
1419
|
id: session.id,
|
|
1391
1420
|
directory: session.directory,
|
|
@@ -1435,10 +1464,13 @@ function createConversationReader(deps) {
|
|
|
1435
1464
|
labels.delete(oldest);
|
|
1436
1465
|
return session;
|
|
1437
1466
|
},
|
|
1438
|
-
messages: async (id) => {
|
|
1467
|
+
messages: async (id, limit) => {
|
|
1439
1468
|
if (!verified.has(id))
|
|
1440
1469
|
throw new Error(consoleDetailMessages.readFailed);
|
|
1441
|
-
const result = await client.session.messages({
|
|
1470
|
+
const result = await client.session.messages({
|
|
1471
|
+
path: { id },
|
|
1472
|
+
...limit === undefined ? {} : { query: { limit } }
|
|
1473
|
+
});
|
|
1442
1474
|
if (!result.response.ok || result.error !== undefined)
|
|
1443
1475
|
throw new Error(consoleDetailMessages.readFailed);
|
|
1444
1476
|
return result.data;
|
|
@@ -1475,14 +1507,37 @@ function createConversationReader(deps) {
|
|
|
1475
1507
|
const read = async (endpoint, sessionID, signal) => withHistory(endpoint, signal, async (port) => {
|
|
1476
1508
|
const session = await port.get(sessionID);
|
|
1477
1509
|
return {
|
|
1478
|
-
...projectConversation(await port.messages(sessionID), sessionID),
|
|
1510
|
+
...projectConversation(await port.messages(sessionID, CONVERSATION_LIMITS.messages + 1), sessionID),
|
|
1479
1511
|
session: session.label
|
|
1480
1512
|
};
|
|
1481
1513
|
});
|
|
1514
|
+
const roots = new Map;
|
|
1482
1515
|
read.root = (endpoint, projection, signal) => withHistory(endpoint, signal, async (port) => {
|
|
1483
|
-
const
|
|
1516
|
+
const key = JSON.stringify([
|
|
1517
|
+
endpoint,
|
|
1518
|
+
projection.runID,
|
|
1519
|
+
projection.rootOperationID,
|
|
1520
|
+
projection.operations.flatMap((operation) => operation.attempts.map((attempt) => [
|
|
1521
|
+
operation.operationID,
|
|
1522
|
+
attempt.attemptID,
|
|
1523
|
+
attempt.sessionID
|
|
1524
|
+
]))
|
|
1525
|
+
]);
|
|
1526
|
+
const cached = roots.get(key);
|
|
1527
|
+
const recovered = cached ? {
|
|
1528
|
+
session: await port.get(cached),
|
|
1529
|
+
association: "sdk-parent"
|
|
1530
|
+
} : await recoverRootSession(port, projection);
|
|
1531
|
+
roots.delete(key);
|
|
1532
|
+
if (recovered.association === "sdk-parent")
|
|
1533
|
+
roots.set(key, recovered.session.id);
|
|
1534
|
+
if (roots.size > 32) {
|
|
1535
|
+
const oldest = roots.keys().next().value;
|
|
1536
|
+
if (oldest !== undefined)
|
|
1537
|
+
roots.delete(oldest);
|
|
1538
|
+
}
|
|
1484
1539
|
return {
|
|
1485
|
-
...projectConversation(await port.messages(recovered.session.id), recovered.session.id),
|
|
1540
|
+
...projectConversation(await port.messages(recovered.session.id, CONVERSATION_LIMITS.messages + 1), recovered.session.id),
|
|
1486
1541
|
session: recovered.session.label,
|
|
1487
1542
|
association: recovered.association
|
|
1488
1543
|
};
|
|
@@ -3356,6 +3411,25 @@ var executionSetupMessages = {
|
|
|
3356
3411
|
`),
|
|
3357
3412
|
localOnlyTitle: "Local execution",
|
|
3358
3413
|
localRequiredError: "local execution requires an enabled local runtime",
|
|
3414
|
+
lemonadeDetectedHint: (loaded, advertised) => `detected - ${loaded} confirmed loaded of ${advertised} advertised text model(s)`,
|
|
3415
|
+
lemonadeNoLoadedModels: "Lemonade has no text models verified as loaded and ready. Keep the intended model active in Lemonade and rerun setup; inactive or unknown models cannot be selected or entered manually.",
|
|
3416
|
+
lemonadeModelNotLoaded: (model) => `Lemonade model "${model}" is not positively verified as loaded and ready. Keep that exact text model active and rerun setup; no substitute was selected and no implicit loading is allowed.`,
|
|
3417
|
+
lemonadeProbeRequired: "Lemonade setup requires a fresh read-only residency probe before writing configuration. Use the CLI with its runtime probe enabled; manual model IDs cannot bypass this requirement.",
|
|
3418
|
+
lemonadeProbeFailed: "Lemonade residency could not be verified at the configured endpoint. Check connectivity and the read-only /models, /health, and /internal/aliases responses, then rerun setup with the intended text models already active.",
|
|
3419
|
+
lemonadeEndpointMismatch: "Lemonade endpoint/provider mapping differs from the selected runtime. Reconcile the configured base URL and provider before rerunning setup; no model was substituted.",
|
|
3420
|
+
lemonadeModelIdentityUnknown: (model) => `Lemonade model "${model}" has no usable registered wire identity in the effective opencode configuration. Fix its model declaration before rerunning setup; setup will not replace or guess an alias.`,
|
|
3421
|
+
lemonadeEffectiveConfigLabel: "effective setup configuration",
|
|
3422
|
+
lemonadeEffectiveConfigAmbiguous: "Cannot establish one effective openteam configuration from the configured plugin loaders. Reconcile their options before rerunning setup; no provider identity was guessed.",
|
|
3423
|
+
lemonadeRetainedProviderUnprotected: (providerID) => `Cannot safely keep retained Lemonade provider "${providerID}": the effective configuration must retain one matching Lemonade runtime, disabled when deselected. Reconcile the plugin options or machine overlay, or explicitly remove the provider registration before rerunning setup; no configuration was written.`,
|
|
3424
|
+
lemonadeV2InvalidProvider: (providerID) => `Lemonade provider ${JSON.stringify(providerID)} cannot be represented as an exact native V2 policy resource. Choose a non-empty provider ID without wildcards, slashes, backslashes, or whitespace; setup will not broaden a deny rule.`,
|
|
3425
|
+
lemonadeV2InvalidPolicies: "Cannot safely preserve experimental.policies: experimental must be an object and policies must be an array of provider.use statements with a string resource and allow/deny effect. Fix the project configuration before rerunning setup.",
|
|
3426
|
+
lemonadeV2Title: "Lemonade transport compatibility",
|
|
3427
|
+
lemonadeV2Restriction: (providers) => `Project policies disable native V2 Lemonade access for: ${providers.join(", ")}. Ordinary guarded V1 configuration remains supported; V2 is not an openteam-hook execution path. Higher-precedence or global policies can override this project restriction; it is not a server-atomic no-autoload guarantee.`,
|
|
3428
|
+
lemonadeInventory: (instanceID, providerID, models) => {
|
|
3429
|
+
const inventory = models.map((model) => `${model.modelID} (${model.loaded === true ? "loaded" : model.loaded === false ? "inactive" : "residency unknown"})`).join(", ");
|
|
3430
|
+
return `Lemonade inventory ${instanceID} (provider ${providerID}): ${inventory || "no advertised text models"}. Only confirmed loaded text models count as ready.`;
|
|
3431
|
+
},
|
|
3432
|
+
lemonadeAgentResidency: (agent, model, state) => `Lemonade readiness: ${agent} (${model}): ${state === "not-loaded" ? "inactive (not ready)" : "residency unknown"}; advertised inventory is not loaded readiness. Keep this exact model active and verify residency before use; requests without verified readiness are blocked.`,
|
|
3359
3433
|
mixedPrimaryQuestion: "Primary coordinator model",
|
|
3360
3434
|
mixedPrimaryLocal: (model) => `Use local thinking model ${model}`,
|
|
3361
3435
|
mixedPrimaryFrontier: "Choose a frontier model",
|
|
@@ -4463,234 +4537,286 @@ async function handleLifecycleHistoryRoute(request, response, url, deps) {
|
|
|
4463
4537
|
// src/console/inspector.ts
|
|
4464
4538
|
var CONVERSATION_CLIENT_JS = `
|
|
4465
4539
|
function wireConversationInspector(){
|
|
4540
|
+
if(document.__conversationsWired){return}document.__conversationsWired=true;
|
|
4541
|
+
var msg=${JSON.stringify(consoleDetailMessages)},limits=${JSON.stringify(CONVERSATION_LIMITS)};
|
|
4542
|
+
var records=new Map(),recoveries=new Map(),stopped=false,timer=null,scheduled=null,active=0,serial=0,retained=null;
|
|
4466
4543
|
var mount=document.getElementById('lifecycle-timeline-mount');
|
|
4467
|
-
if(
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
function
|
|
4477
|
-
if(
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
if(
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
retained=null;
|
|
4544
|
+
function el(tag,text){var node=document.createElement(tag);if(text!==undefined){node.textContent=text}return node}
|
|
4545
|
+
function setText(node,text){if(node.textContent!==text){node.textContent=text}}
|
|
4546
|
+
function visible(node){
|
|
4547
|
+
if(document.hidden||!node.isConnected){return false}
|
|
4548
|
+
var parent=node;
|
|
4549
|
+
while(parent){if(parent.hidden){return false}parent=parent.parentElement}
|
|
4550
|
+
var rect=node.getBoundingClientRect();
|
|
4551
|
+
return rect.bottom>=0&&rect.top<(window.innerHeight||1000);
|
|
4552
|
+
}
|
|
4553
|
+
function cancel(record){
|
|
4554
|
+
if(record.request){record.request.abort();record.request=null}
|
|
4555
|
+
if(record.finish){record.finish();record.finish=null}
|
|
4556
|
+
record.version++;
|
|
4557
|
+
}
|
|
4558
|
+
function discard(record){
|
|
4559
|
+
cancel(record);record.panel.remove();record.body.textContent='';record.source.textContent='';record.rows.clear();records.delete(record.key);
|
|
4560
|
+
}
|
|
4561
|
+
function clear(scope){
|
|
4562
|
+
Array.from(records.values()).forEach(function(record){
|
|
4563
|
+
if(scope==='native'&&record.selection.target==='session'){return}
|
|
4564
|
+
discard(record);
|
|
4565
|
+
});
|
|
4566
|
+
if(scope!=='native'){retained=null}
|
|
4567
|
+
}
|
|
4568
|
+
function recovery(record){
|
|
4569
|
+
var saved=recoveries.get(record.key);
|
|
4570
|
+
if(saved&&saved.until<=Date.now()){recoveries.delete(record.key);return null}
|
|
4571
|
+
return saved||null;
|
|
4572
|
+
}
|
|
4573
|
+
function rootRecovery(record,data){
|
|
4574
|
+
return record.selection.target==='root'&&!record.selection.session&&data.kind==='unavailable'&&
|
|
4575
|
+
[msg.rootUnavailable,msg.rootAmbiguous,msg.searchIncomplete].includes(data.message)?
|
|
4576
|
+
{message:data.message,until:Date.now()+30000}:null;
|
|
4577
|
+
}
|
|
4578
|
+
function rememberRecovery(record,saved){
|
|
4579
|
+
if(!saved){recoveries.delete(record.key);return}
|
|
4580
|
+
recoveries.delete(record.key);recoveries.set(record.key,saved);
|
|
4581
|
+
if(recoveries.size>128){recoveries.delete(recoveries.keys().next().value)}
|
|
4582
|
+
}
|
|
4583
|
+
function desired(){
|
|
4584
|
+
var result=[];
|
|
4585
|
+
if(stopped||document.hidden){return result}
|
|
4586
|
+
var explicitHistorical=!!((mount&&mount.getAttribute('data-conversation-cursor'))||new URLSearchParams(window.location.search).has('cursor'));
|
|
4587
|
+
var transitioning=mount&&mount.getAttribute('data-conversation-transition')==='1';
|
|
4588
|
+
if(mount){
|
|
4589
|
+
var notice=mount.querySelector('[data-conversation-historical]');
|
|
4590
|
+
if(explicitHistorical){
|
|
4591
|
+
if(!notice){notice=el('p',msg.historical);notice.setAttribute('data-conversation-historical','');mount.appendChild(notice)}
|
|
4592
|
+
}else if(notice){notice.remove()}
|
|
4593
|
+
}
|
|
4594
|
+
if(mount&&!explicitHistorical&&!transitioning){
|
|
4595
|
+
mount.querySelectorAll('[data-inspect-root],[data-inspect-attempt]').forEach(function(button){
|
|
4596
|
+
if(button.disabled){return}
|
|
4597
|
+
var root=button.hasAttribute('data-inspect-root');
|
|
4598
|
+
var session=button.closest(root?'[data-root-session-id]':'[data-lifecycle-session-id]');
|
|
4599
|
+
var host=root?button.closest('.lct-operation-card'):button.closest('[data-lifecycle-attempt-id]');
|
|
4600
|
+
if(!session||!host){return}
|
|
4601
|
+
var selection={target:root?'root':'attempt',run:mount.getAttribute('data-lifecycle-run'),
|
|
4602
|
+
operation:button.getAttribute('data-inspect-operation'),attempt:root?null:button.getAttribute('data-inspect-attempt'),
|
|
4603
|
+
session:session.getAttribute(root?'data-root-session-id':'data-lifecycle-session-id')};
|
|
4604
|
+
if(!selection.run||!selection.operation){return}
|
|
4605
|
+
result.push({key:JSON.stringify(selection),selection:selection,host:host,button:button});
|
|
4606
|
+
});
|
|
4531
4607
|
}
|
|
4608
|
+
document.querySelectorAll('[data-session-conversation]').forEach(function(host){
|
|
4609
|
+
var selection={target:'session',session:host.getAttribute('data-session-conversation')};
|
|
4610
|
+
if(explicitHistorical){
|
|
4611
|
+
if(visible(host)){setText(host,msg.historical)}
|
|
4612
|
+
return;
|
|
4613
|
+
}
|
|
4614
|
+
result.push({key:JSON.stringify(selection),selection:selection,host:host});
|
|
4615
|
+
});
|
|
4616
|
+
return result;
|
|
4532
4617
|
}
|
|
4533
|
-
function
|
|
4534
|
-
panel.
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
var
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
var
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
var
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4618
|
+
function create(item){
|
|
4619
|
+
var panel=el('section');panel.className='lc-conversation';panel.id='lc-conversation-'+(++serial);
|
|
4620
|
+
panel.setAttribute('data-conversation-inspector','');
|
|
4621
|
+
panel.setAttribute('data-conversation-target',item.selection.target);
|
|
4622
|
+
panel.setAttribute('data-conversation-session',item.selection.session||'');
|
|
4623
|
+
if(item.selection.run){panel.setAttribute('data-conversation-run',item.selection.run)}
|
|
4624
|
+
if(item.selection.attempt){panel.setAttribute('data-conversation-attempt',item.selection.attempt)}
|
|
4625
|
+
var heading=el('h3',msg.title);panel.appendChild(heading);
|
|
4626
|
+
var status=el('p',msg.loading);status.setAttribute('role','status');panel.appendChild(status);
|
|
4627
|
+
var source=el('p');panel.appendChild(source);
|
|
4628
|
+
var body=el('div');body.setAttribute('data-conversation-messages','');panel.appendChild(body);
|
|
4629
|
+
var refresh=el('button',msg.refresh);refresh.type='button';refresh.setAttribute('data-conversation-refresh','');panel.appendChild(refresh);
|
|
4630
|
+
var record={key:item.key,selection:item.selection,host:item.host,panel:panel,status:status,source:source,body:body,rows:new Map(),
|
|
4631
|
+
request:null,finish:null,version:0,due:0,button:item.button};
|
|
4632
|
+
refresh.addEventListener('click',function(){record.due=0;recoveries.delete(record.key);sync()});
|
|
4633
|
+
item.host.appendChild(panel);records.set(item.key,record);
|
|
4634
|
+
return record;
|
|
4635
|
+
}
|
|
4636
|
+
function matches(record,data){
|
|
4637
|
+
var s=record.selection;
|
|
4638
|
+
return data.sessionID&&(s.session?data.sessionID===s.session:['sdk-parent','tool-result'].includes(data.association))&&
|
|
4639
|
+
(s.target==='session'?data.target==='session'&&!data.runID:
|
|
4640
|
+
data.runID===s.run&&data.operationID===s.operation&&data.target===s.target&&
|
|
4641
|
+
(s.target==='root'?data.attemptID===undefined:data.attemptID===s.attempt));
|
|
4642
|
+
}
|
|
4643
|
+
function render(record,messages){
|
|
4644
|
+
var remaining=limits.totalChars,tools=0,truncated=false,used=new Set();
|
|
4645
|
+
function text(value){
|
|
4646
|
+
value=String(value===undefined?'':value);
|
|
4647
|
+
var length=Math.min(value.length,limits.fieldChars+msg.truncatedMarker.length,remaining);
|
|
4648
|
+
remaining-=length;if(length<value.length){truncated=true}return value.slice(0,length);
|
|
4649
|
+
}
|
|
4650
|
+
if(messages.length>limits.messages){truncated=true}
|
|
4651
|
+
messages.slice(0,limits.messages).forEach(function(message){
|
|
4652
|
+
if(!message||!['user','assistant'].includes(message.role)||typeof message.id!=='string'||used.has(message.id)){return}
|
|
4653
|
+
used.add(message.id);
|
|
4654
|
+
var row=record.rows.get(message.id);
|
|
4655
|
+
if(!row){
|
|
4656
|
+
var article=el('article');article.setAttribute('data-conversation-role',message.role);
|
|
4657
|
+
article.appendChild(el('h4',message.role==='user'?msg.prompt:msg.assistant));
|
|
4658
|
+
var time=el('time');article.appendChild(time);
|
|
4659
|
+
row={node:article,time:time,texts:[],tools:new Map()};record.rows.set(message.id,row);record.body.appendChild(article);
|
|
4660
|
+
}
|
|
4661
|
+
var selection=window.getSelection&&window.getSelection();
|
|
4662
|
+
if(selection&&!selection.isCollapsed&&row.node.contains(selection.anchorNode)){return}
|
|
4663
|
+
setText(row.time,consoleLabels.utcTime(message.createdAt));
|
|
4664
|
+
var parts=(message.text||[]).slice(0,limits.parts);
|
|
4665
|
+
parts.forEach(function(value,index){
|
|
4666
|
+
if(!row.texts[index]){row.texts[index]=el('pre');row.node.insertBefore(row.texts[index],row.node.querySelector('details'))}
|
|
4667
|
+
setText(row.texts[index],text(value));
|
|
4668
|
+
});
|
|
4669
|
+
while(row.texts.length>parts.length){row.texts.pop().remove()}
|
|
4670
|
+
var seenTools=new Set();
|
|
4671
|
+
(message.tools||[]).slice(0,limits.parts).forEach(function(tool){
|
|
4672
|
+
if(tools++>=limits.tools||remaining<=0){truncated=true;return}
|
|
4673
|
+
seenTools.add(tool.id);
|
|
4674
|
+
var call=row.tools.get(tool.id);
|
|
4675
|
+
if(!call){
|
|
4676
|
+
var detail=el('details');detail.setAttribute('data-tool-call',tool.id);detail.open=true;
|
|
4677
|
+
var summary=el('summary');detail.appendChild(summary);
|
|
4678
|
+
detail.appendChild(el('h5',msg.arguments));var args=el('pre');detail.appendChild(args);
|
|
4679
|
+
detail.appendChild(el('h5',msg.result));var result=el('pre');detail.appendChild(result);
|
|
4680
|
+
call={node:detail,summary:summary,args:args,result:result};row.tools.set(tool.id,call);row.node.appendChild(detail);
|
|
4587
4681
|
}
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
if(bringIntoView){panel.querySelector('h3').scrollIntoView({block:'start',inline:'nearest'})}
|
|
4591
|
-
}).catch(function(){
|
|
4592
|
-
if(epoch===current){status.textContent=msg.unavailable;panel.setAttribute('data-conversation-kind','unavailable')}
|
|
4593
|
-
}).finally(function(){
|
|
4594
|
-
clearTimeout(timeout);
|
|
4595
|
-
if(epoch!==current){return}
|
|
4596
|
-
request=null;
|
|
4597
|
-
panel.setAttribute('aria-busy','false');
|
|
4598
|
-
var refresh=element('button',msg.refresh);refresh.type='button';refresh.setAttribute('data-conversation-refresh','');
|
|
4599
|
-
refresh.addEventListener('click',load);panel.appendChild(refresh);
|
|
4682
|
+
setText(call.summary,text(tool.name)+' · '+text(tool.status));
|
|
4683
|
+
setText(call.args,text(tool.arguments));setText(call.result,text(tool.result===undefined?msg.pending:tool.result));
|
|
4600
4684
|
});
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
var calls=element('div');calls.setAttribute('data-conversation-tool-list','');tools.appendChild(calls);
|
|
4609
|
-
panel.appendChild(tools);
|
|
4610
|
-
function text(value){
|
|
4611
|
-
value=String(value);
|
|
4612
|
-
var size=Math.min(value.length,limits.fieldChars+msg.truncatedMarker.length,remaining);
|
|
4613
|
-
remaining-=size;
|
|
4614
|
-
if(size<value.length){truncated=true}
|
|
4615
|
-
return value.slice(0,size);
|
|
4616
|
-
}
|
|
4617
|
-
['user','assistant'].forEach(function(role){
|
|
4618
|
-
var section=element('section');section.setAttribute('data-conversation-role',role);
|
|
4619
|
-
section.appendChild(element('h4',role==='user'?msg.prompt:msg.assistant));
|
|
4620
|
-
var hasText=false;
|
|
4621
|
-
messages.filter(function(m){return m.role===role}).forEach(function(m){
|
|
4622
|
-
var item=element('article');item.appendChild(element('time',consoleLabels.utcTime(m.createdAt)));
|
|
4623
|
-
if((m.text||[]).length>limits.parts){truncated=true}
|
|
4624
|
-
(m.text||[]).slice(0,limits.parts).forEach(function(value){
|
|
4625
|
-
if(!value){return}
|
|
4626
|
-
hasText=true;
|
|
4627
|
-
if(remaining>0){item.appendChild(element('pre',text(value)))}else{truncated=true}
|
|
4685
|
+
row.tools.forEach(function(call,id){if(!seenTools.has(id)){call.node.remove();row.tools.delete(id)}});
|
|
4686
|
+
if(Array.isArray(message.order)){
|
|
4687
|
+
var previous=row.time;
|
|
4688
|
+
message.order.slice(0,limits.parts).forEach(function(part){
|
|
4689
|
+
var node=part.type==='text'?row.texts[part.index]:row.tools.get((message.tools[part.index]||{}).id);
|
|
4690
|
+
node=node&&node.node||node;
|
|
4691
|
+
if(node){if(previous.nextSibling!==node){row.node.insertBefore(node,previous.nextSibling||null)}previous=node}
|
|
4628
4692
|
});
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4693
|
+
}
|
|
4694
|
+
});
|
|
4695
|
+
record.rows.forEach(function(row,id){if(!used.has(id)){row.node.remove();record.rows.delete(id)}});
|
|
4696
|
+
if(truncated){setText(record.status,msg.current+'\\n'+msg.truncated)}
|
|
4697
|
+
}
|
|
4698
|
+
function load(record){
|
|
4699
|
+
var selected=record.selection,controller=new AbortController(),version=++record.version;
|
|
4700
|
+
record.request=controller;active++;record.panel.setAttribute('aria-busy','true');
|
|
4701
|
+
var finished=false;
|
|
4702
|
+
record.finish=function(){if(!finished){finished=true;active--;clearTimeout(timeout)}};
|
|
4703
|
+
var query=new URLSearchParams({token:document.documentElement.getAttribute('data-token')||''});
|
|
4704
|
+
var path='/api/graph/conversation';
|
|
4705
|
+
if(selected.target==='session'){path='/api/console/conversation';query.set('session',selected.session)}
|
|
4706
|
+
else{query.set('run',selected.run);query.set('operation',selected.operation);
|
|
4707
|
+
if(selected.target==='root'){query.set('target','root')}else{query.set('attempt',selected.attempt)}}
|
|
4708
|
+
var timeout=setTimeout(function(){
|
|
4709
|
+
if(record.version!==version){return}
|
|
4710
|
+
cancel(record);record.due=Date.now()+30000;setText(record.status,msg.unavailable);
|
|
4711
|
+
record.panel.setAttribute('aria-busy','false');schedule();
|
|
4712
|
+
},15000);
|
|
4713
|
+
fetch(path+'?'+query,{signal:controller.signal,cache:'no-store'}).then(function(response){return response.json()}).then(function(data){
|
|
4714
|
+
if(record.version!==version||!records.has(record.key)||!visible(record.host)||controller.signal.aborted){return}
|
|
4715
|
+
if((data.kind==='conversation'||data.kind==='empty')&&!matches(record,data)){data={kind:'unavailable',message:msg.unavailable}}
|
|
4716
|
+
var negative=rootRecovery(record,data);
|
|
4717
|
+
record.panel.setAttribute('data-conversation-kind',data.kind||'unavailable');
|
|
4718
|
+
setText(record.status,data.message||((data.kind==='conversation'||data.kind==='empty')?msg.current:msg.unavailable));
|
|
4719
|
+
if(data.kind==='conversation'||data.kind==='empty'){
|
|
4720
|
+
recoveries.delete(record.key);
|
|
4721
|
+
record.panel.setAttribute('data-conversation-session',data.sessionID);
|
|
4722
|
+
setText(record.source,(data.session&&data.session.title||msg.session)+' · '+data.sessionID);
|
|
4723
|
+
var focus=record.panel.contains(document.activeElement)?document.activeElement:null;
|
|
4724
|
+
render(record,data.messages||[]);
|
|
4725
|
+
if(focus&&focus.isConnected&&focus!==document.activeElement&&
|
|
4726
|
+
(!document.activeElement||document.activeElement===document.body)){focus.focus({preventScroll:true})}
|
|
4727
|
+
if(data.session&&data.session.id===data.sessionID){
|
|
4728
|
+
document.dispatchEvent(new CustomEvent('console-session-metadata',{detail:{session:data.session,runID:data.runID,target:selected.target}}));
|
|
4729
|
+
}
|
|
4730
|
+
}else{rememberRecovery(record,negative);record.body.textContent='';record.source.textContent='';record.rows.clear()}
|
|
4731
|
+
record.due=['disabled','unauthorized','historical','invalid','oversized'].includes(data.kind)?Infinity:Date.now()+(data.kind==='unavailable'?30000:2000);
|
|
4732
|
+
}).catch(function(){
|
|
4733
|
+
if(record.version===version&&!controller.signal.aborted){
|
|
4734
|
+
recoveries.delete(record.key);
|
|
4735
|
+
setText(record.status,msg.unavailable);record.panel.setAttribute('data-conversation-kind','unavailable');
|
|
4736
|
+
record.body.textContent='';record.source.textContent='';record.rows.clear();record.due=Date.now()+30000;
|
|
4737
|
+
}
|
|
4738
|
+
}).finally(function(){
|
|
4739
|
+
if(!finished){finished=true;clearTimeout(timeout);active--}
|
|
4740
|
+
if(record.version===version){record.request=null;record.panel.setAttribute('aria-busy','false');if(controller.signal.aborted){record.due=Date.now()+30000;setText(record.status,msg.unavailable)}}
|
|
4741
|
+
schedule();
|
|
4742
|
+
});
|
|
4743
|
+
}
|
|
4744
|
+
function sync(){
|
|
4745
|
+
var items=desired(),byKey=new Map(items.map(function(item){return [item.key,item]}));
|
|
4746
|
+
Array.from(records.values()).forEach(function(record){
|
|
4747
|
+
var item=byKey.get(record.key);
|
|
4748
|
+
if(!item||!visible(item.host)){
|
|
4749
|
+
if(item&&item.host.isConnected){item.host.style.minHeight=item.host.getBoundingClientRect().height+'px'}
|
|
4750
|
+
discard(record);return;
|
|
4751
|
+
}
|
|
4752
|
+
record.host=item.host;
|
|
4753
|
+
if(record.panel.parentElement!==item.host){item.host.appendChild(record.panel)}
|
|
4632
4754
|
});
|
|
4633
|
-
|
|
4634
|
-
if((
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4755
|
+
items.forEach(function(item){
|
|
4756
|
+
if(!visible(item.host)){return}
|
|
4757
|
+
var record=records.get(item.key);
|
|
4758
|
+
if(!record&&records.size<8){
|
|
4759
|
+
if(item.selection.target==='session'){item.host.textContent=''}
|
|
4760
|
+
record=create(item);
|
|
4761
|
+
}
|
|
4762
|
+
if(!record){return}
|
|
4763
|
+
if(item.button){item.button.hidden=true;item.button.setAttribute('aria-controls',record.panel.id)}
|
|
4764
|
+
var saved=recovery(record);
|
|
4765
|
+
if(saved&&!record.rows.size&&!record.request){record.panel.setAttribute('data-conversation-kind','unavailable');setText(record.status,saved.message)}
|
|
4766
|
+
if(!record.request&&active<2&&record.due<=Date.now()&&!saved){load(record)}
|
|
4767
|
+
});
|
|
4768
|
+
}
|
|
4769
|
+
function schedule(){
|
|
4770
|
+
if(stopped||scheduled!==null){return}
|
|
4771
|
+
scheduled=setTimeout(function(){scheduled=null;sync()},50);
|
|
4772
|
+
}
|
|
4773
|
+
document.addEventListener('conversation-selection',function(event){
|
|
4774
|
+
clear(event&&event.detail&&event.detail.scope==='native'?'native':'all');
|
|
4775
|
+
sync();
|
|
4776
|
+
});
|
|
4777
|
+
document.addEventListener('conversation-tree-replacing',function(){
|
|
4778
|
+
var scroll=document.querySelector('.scroll'),tree=mount&&mount.querySelector('[data-lifecycle-tree-mount]');
|
|
4779
|
+
retained={focus:document.activeElement,scroll:scroll,scrollTop:scroll&&scroll.scrollTop,treeTop:tree&&tree.scrollTop,positions:[]};
|
|
4780
|
+
records.forEach(function(record){
|
|
4781
|
+
[record.body].concat(Array.from(record.panel.querySelectorAll('pre'))).forEach(function(node){
|
|
4782
|
+
retained.positions.push([node,node.scrollTop,node.scrollLeft]);
|
|
4643
4783
|
});
|
|
4644
4784
|
});
|
|
4645
|
-
|
|
4646
|
-
if(truncated){panel.appendChild(element('p',msg.truncated))}
|
|
4647
|
-
}
|
|
4648
|
-
mount.addEventListener('click',function(event){
|
|
4649
|
-
var button=event.target.closest('[data-inspect-attempt],[data-inspect-root]');
|
|
4650
|
-
if(!button||button.disabled||mount.getAttribute('data-conversation-transition')==='1'){return}
|
|
4651
|
-
if(button===selectedButton()){close(true);return}
|
|
4652
|
-
close();
|
|
4653
|
-
var root=button.hasAttribute('data-inspect-root');
|
|
4654
|
-
var session=button.closest(root?'[data-root-session-id]':'[data-lifecycle-session-id]');
|
|
4655
|
-
if(!session){return}
|
|
4656
|
-
selection={
|
|
4657
|
-
run:mount.getAttribute('data-lifecycle-run'),
|
|
4658
|
-
operation:button.getAttribute('data-inspect-operation'),
|
|
4659
|
-
attempt:button.getAttribute('data-inspect-attempt'),
|
|
4660
|
-
target:root?'root':'attempt',
|
|
4661
|
-
session:session.getAttribute(root?'data-root-session-id':'data-lifecycle-session-id'),
|
|
4662
|
-
cursor:mount.getAttribute('data-conversation-cursor')||null
|
|
4663
|
-
};
|
|
4664
|
-
if(!selectedButton()){close();return}
|
|
4665
|
-
panel.setAttribute('data-conversation-run',selection.run);
|
|
4666
|
-
panel.setAttribute('data-conversation-operation',selection.operation);
|
|
4667
|
-
if(selection.attempt){panel.setAttribute('data-conversation-attempt',selection.attempt)}
|
|
4668
|
-
panel.setAttribute('data-conversation-target',selection.target);
|
|
4669
|
-
panel.setAttribute('data-conversation-session',selection.session);
|
|
4670
|
-
reanchor();
|
|
4671
|
-
panel.hidden=false;
|
|
4672
|
-
if(selection.cursor!==null){reset();panel.setAttribute('data-conversation-kind','historical');panel.appendChild(element('p',msg.historical));showHeading()}
|
|
4673
|
-
else{load(true)}
|
|
4785
|
+
records.forEach(function(record){if(record.selection.target!=='session'){record.panel.remove()}});
|
|
4674
4786
|
});
|
|
4675
|
-
document.addEventListener('conversation-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4787
|
+
document.addEventListener('conversation-tree-committed',function(){
|
|
4788
|
+
sync();
|
|
4789
|
+
if(retained){
|
|
4790
|
+
retained.positions.forEach(function(item){if(item[0].isConnected){item[0].scrollTop=item[1];item[0].scrollLeft=item[2]}});
|
|
4791
|
+
var tree=mount&&mount.querySelector('[data-lifecycle-tree-mount]');
|
|
4792
|
+
if(tree&&retained.treeTop!==null){tree.scrollTop=retained.treeTop}
|
|
4793
|
+
if(retained.scroll){retained.scroll.scrollTop=retained.scrollTop}
|
|
4794
|
+
if(retained.focus&&retained.focus.isConnected&&retained.focus!==document.activeElement&&
|
|
4795
|
+
(!document.activeElement||document.activeElement===document.body||document.activeElement===document.documentElement)){
|
|
4796
|
+
retained.focus.focus({preventScroll:true});
|
|
4797
|
+
}
|
|
4798
|
+
retained=null;
|
|
4799
|
+
}
|
|
4800
|
+
});
|
|
4801
|
+
document.addEventListener('console-conversation-selection',sync);
|
|
4802
|
+
document.addEventListener('visibilitychange',function(){if(document.hidden){clear()}else{sync()}});
|
|
4803
|
+
document.addEventListener('scroll',schedule,true);
|
|
4804
|
+
window.addEventListener('resize',schedule);
|
|
4805
|
+
window.addEventListener('pagehide',function(){stopped=true;clear();clearInterval(timer);clearTimeout(scheduled);scheduled=null});
|
|
4806
|
+
window.addEventListener('pageshow',function(event){if(event.persisted){stopped=false;timer=setInterval(sync,2000);sync()}});
|
|
4807
|
+
timer=setInterval(sync,2000);sync();
|
|
4679
4808
|
}
|
|
4680
4809
|
`;
|
|
4681
4810
|
var CONVERSATION_STYLE = `
|
|
4682
|
-
.lc-conversation{margin-top:12px;padding:12px;min-width:0;border:1px solid var(--cp-border);border-radius:
|
|
4811
|
+
.lc-conversation{margin-top:12px;padding:12px;min-width:0;border:1px solid var(--cp-border,var(--border));border-radius:12px;background:var(--cp-surface,var(--surface));color:var(--cp-text,var(--fg));overflow-anchor:none}
|
|
4683
4812
|
.lc-conversation[hidden]{display:none}
|
|
4684
|
-
.lc-conversation-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px}
|
|
4685
4813
|
.lc-conversation h3,.lc-conversation h4,.lc-conversation p{margin:8px 0}
|
|
4686
|
-
.lc-conversation
|
|
4687
|
-
.lc-conversation pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:400px;overflow:auto;background:var(--cp-surface-soft);padding:12px;font-family:
|
|
4688
|
-
.lc-conversation
|
|
4689
|
-
.lc-conversation
|
|
4690
|
-
.lc-conversation
|
|
4691
|
-
.lc-conversation
|
|
4692
|
-
.lc-conversation time{font-size:11px;color:var(--cp-text-muted)}
|
|
4693
|
-
.lc-conversation button,[data-inspect-attempt],[data-inspect-root]{padding:6px 10px;margin:6px;border:1px solid var(--cp-border);border-radius:.625rem;background:var(--cp-surface);color:var(--cp-accent)}
|
|
4814
|
+
.lc-conversation [data-conversation-messages]{max-height:520px;overflow:auto;overflow-anchor:none}
|
|
4815
|
+
.lc-conversation pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:400px;overflow:auto;background:var(--cp-surface-soft,var(--bg));padding:12px;font-family:var(--font-mono)}
|
|
4816
|
+
.lc-conversation details{margin:12px 0;padding:8px;border:1px solid var(--cp-border,var(--border));border-radius:8px}
|
|
4817
|
+
.lc-conversation summary{cursor:pointer;color:var(--cp-accent,var(--accent))}
|
|
4818
|
+
.lc-conversation time{font-size:11px;color:var(--cp-text-muted,var(--muted))}
|
|
4819
|
+
.lc-conversation button,[data-inspect-attempt],[data-inspect-root]{padding:6px 10px;margin:6px;border:1px solid var(--cp-border,var(--border));border-radius:8px;background:var(--cp-surface,var(--surface));color:var(--cp-accent,var(--accent))}
|
|
4694
4820
|
.lct-operation-name{display:block;font-size:16px}
|
|
4695
4821
|
.lct-operation-head details,.lct-session details{font-size:11px;color:var(--cp-text-muted)}
|
|
4696
4822
|
.lct-session small,.session-btn small{display:block;color:var(--cp-text-muted)}
|
|
@@ -4724,7 +4850,7 @@ var CONSOLE_REFRESH_JS = `
|
|
|
4724
4850
|
if(old.getAttribute('data-label-fallback')!==next.textContent){old.setAttribute('data-label-fallback',next.textContent)}
|
|
4725
4851
|
return;
|
|
4726
4852
|
}
|
|
4727
|
-
if(old.matches('input,textarea,select,.term,.pty,.graph-drill,[data-config-mount]')){return}
|
|
4853
|
+
if(old.matches('input,textarea,select,.term,.pty,.graph-drill,[data-config-mount],[data-session-conversation]')){return}
|
|
4728
4854
|
Array.from(old.attributes).forEach(function(a){
|
|
4729
4855
|
if(a.name!=='open'&&a.name!=='hidden'&&a.name!=='aria-selected'&&!next.hasAttribute(a.name)){old.removeAttribute(a.name)}
|
|
4730
4856
|
});
|
|
@@ -4938,6 +5064,8 @@ svg.graph{display:block}
|
|
|
4938
5064
|
.graph-drill .drilllog .tl.error{color:#f85149}
|
|
4939
5065
|
`;
|
|
4940
5066
|
var CONSOLE_CLIENT_JS = `
|
|
5067
|
+
${LABELS_CLIENT_JS}
|
|
5068
|
+
${CONVERSATION_CLIENT_JS}
|
|
4941
5069
|
(function(){
|
|
4942
5070
|
var detailMsg=${JSON.stringify(consoleDetailMessages)};
|
|
4943
5071
|
var terminalCollectors=[];
|
|
@@ -4992,6 +5120,7 @@ var CONSOLE_CLIENT_JS = `
|
|
|
4992
5120
|
if(show){matched=true;if(!screen.hidden){connectTerminal(cards[j],id)}}
|
|
4993
5121
|
}
|
|
4994
5122
|
updateTerminalLeases();
|
|
5123
|
+
document.dispatchEvent(new CustomEvent('console-conversation-selection'));
|
|
4995
5124
|
return matched;
|
|
4996
5125
|
}
|
|
4997
5126
|
if(!screen.__logsWired){
|
|
@@ -5052,6 +5181,7 @@ var CONSOLE_CLIENT_JS = `
|
|
|
5052
5181
|
if(name==='config'&&activeScreen){loadConfig(activeScreen)}
|
|
5053
5182
|
if(name==='logs'&&activeScreen){wireLogsScreen(activeScreen)}
|
|
5054
5183
|
updateTerminalLeases();
|
|
5184
|
+
document.dispatchEvent(new CustomEvent('console-conversation-selection'));
|
|
5055
5185
|
try{localStorage.setItem('openteam.screen',name)}catch(e){}
|
|
5056
5186
|
document.body.classList.remove('nav-open');
|
|
5057
5187
|
return true;
|
|
@@ -5453,8 +5583,6 @@ var LIFECYCLE_THEME_BOOT = `
|
|
|
5453
5583
|
})();
|
|
5454
5584
|
`;
|
|
5455
5585
|
var LIFECYCLE_CLIENT_JS = `
|
|
5456
|
-
${LABELS_CLIENT_JS}
|
|
5457
|
-
${CONVERSATION_CLIENT_JS}
|
|
5458
5586
|
function wireLifecycleTimeline(){
|
|
5459
5587
|
var mount=document.getElementById('lifecycle-timeline-mount');
|
|
5460
5588
|
if(!mount){return}
|
|
@@ -5501,7 +5629,7 @@ function wireLifecycleTimeline(){
|
|
|
5501
5629
|
treeMountEl.setAttribute('inert','');
|
|
5502
5630
|
treeMountEl.querySelectorAll('[data-inspect-attempt],[data-inspect-root]').forEach(function(button){button.disabled=true});
|
|
5503
5631
|
}
|
|
5504
|
-
document.dispatchEvent(new CustomEvent('conversation-selection'));
|
|
5632
|
+
document.dispatchEvent(new CustomEvent('conversation-selection',{detail:{scope:'native'}}));
|
|
5505
5633
|
}
|
|
5506
5634
|
function commitConversation(run,cursor){
|
|
5507
5635
|
cursor=cursor===null?null:String(cursor);
|
|
@@ -5963,6 +6091,7 @@ function wireLifecycleTimeline(){
|
|
|
5963
6091
|
inspect.setAttribute('aria-expanded','false');
|
|
5964
6092
|
inspect.setAttribute('aria-controls','lc-attempt-conversation');
|
|
5965
6093
|
inspect.setAttribute('data-inspect-attempt',attempt.attemptID);
|
|
6094
|
+
inspect.hidden=true;
|
|
5966
6095
|
inspect.setAttribute('data-inspect-operation',attempt.operationID);
|
|
5967
6096
|
session.appendChild(inspect);
|
|
5968
6097
|
if(attempt.parentSessionID){
|
|
@@ -6115,7 +6244,7 @@ function wireLifecycleTimeline(){
|
|
|
6115
6244
|
var time=makeElement('small','',${JSON.stringify(consoleDetailMessages.timeUnknown)});time.setAttribute('data-session-time',rootID);rootSession.appendChild(time);
|
|
6116
6245
|
var id=makeElement('code','',rootID);rootSession.appendChild(id);
|
|
6117
6246
|
}else{rootSession.appendChild(makeElement('span','',${JSON.stringify(consoleDetailMessages.rootUnlinked)}))}
|
|
6118
|
-
var inspect=makeElement('button','',message('inspect'));inspect.type='button';inspect.setAttribute('data-inspect-root','');inspect.setAttribute('data-inspect-operation',op.operationID);
|
|
6247
|
+
var inspect=makeElement('button','',message('inspect'));inspect.type='button';inspect.hidden=true;inspect.setAttribute('data-inspect-root','');inspect.setAttribute('data-inspect-operation',op.operationID);rootSession.appendChild(inspect);
|
|
6119
6248
|
card.insertBefore(rootSession,card.querySelector('.lct-attempts'));
|
|
6120
6249
|
}
|
|
6121
6250
|
var children=childrenByParent.get(op.operationID)||[];
|
|
@@ -6727,6 +6856,7 @@ function sessionDetailCard(tab, terminalEnabled, ptyEnabled, visible) {
|
|
|
6727
6856
|
const idSuffix = domIdPart(tab.sessionID);
|
|
6728
6857
|
const body = [
|
|
6729
6858
|
sessionHeaderPanel(tab),
|
|
6859
|
+
`<div data-session-conversation="${escapeHtml(tab.sessionID)}"></div>`,
|
|
6730
6860
|
terminalEnabled ? terminalPanel(tab) : "",
|
|
6731
6861
|
terminalEnabled && ptyEnabled ? ptyPanel(tab) : "",
|
|
6732
6862
|
routesPanel(tab.recentRoutes, idSuffix),
|
|
@@ -7112,7 +7242,7 @@ function lcSessionHtml(attempt, role) {
|
|
|
7112
7242
|
sessionNameHtml(attempt.sessionID, role),
|
|
7113
7243
|
`<small data-session-time="${escapeHtml(attempt.sessionID)}">${escapeHtml(consoleDetailMessages.timeUnknown)}</small>`,
|
|
7114
7244
|
`<details><summary>${escapeHtml(consoleDetailMessages.technicalID)}</summary><code>${escapeHtml(attempt.sessionID)}</code></details>`,
|
|
7115
|
-
`<button type="button"
|
|
7245
|
+
`<button type="button" hidden data-inspect-operation="${escapeHtml(attempt.operationID)}" data-inspect-attempt="${escapeHtml(attempt.attemptID)}">${escapeHtml(consoleDetailMessages.inspectConversation)}</button>`,
|
|
7116
7246
|
attempt.parentSessionID === undefined ? "" : `<span class="lct-parent-session">${escapeHtml(lifecycleMessages.parentSessionLabel)} <code>${escapeHtml(attempt.parentSessionID)}</code></span>`,
|
|
7117
7247
|
"</div>"
|
|
7118
7248
|
].join("");
|
|
@@ -7199,7 +7329,7 @@ function lcOperationHtml(operation, operationIDs, childrenHtml, depth, rootSessi
|
|
|
7199
7329
|
isRoot && operation.kind === "coordinator" ? [
|
|
7200
7330
|
`<div class="lct-session" data-root-session-id="${escapeHtml(rootSessionID ?? "")}">`,
|
|
7201
7331
|
rootSessionID ? `${sessionNameHtml(rootSessionID, consoleDetailMessages.orchestrator)} <small data-session-time="${escapeHtml(rootSessionID)}">${escapeHtml(consoleDetailMessages.timeUnknown)}</small><details><summary>${escapeHtml(consoleDetailMessages.technicalID)}</summary><code>${escapeHtml(rootSessionID)}</code></details>` : `<span>${escapeHtml(consoleDetailMessages.rootUnlinked)}</span>`,
|
|
7202
|
-
`<button type="button" data-inspect-root data-inspect-operation="${escapeHtml(operation.operationID)}"
|
|
7332
|
+
`<button type="button" hidden data-inspect-root data-inspect-operation="${escapeHtml(operation.operationID)}">${escapeHtml(consoleDetailMessages.inspectConversation)}</button>`,
|
|
7203
7333
|
"</div>"
|
|
7204
7334
|
].join("") : "",
|
|
7205
7335
|
`<section class="lct-attempts" aria-label="${escapeHtml(lifecycleMessages.attemptsLabel)}">${attempts}</section>`,
|
|
@@ -7578,11 +7708,11 @@ function renderConsoleHtml(state, options = {}) {
|
|
|
7578
7708
|
const body = [
|
|
7579
7709
|
screenSection("tree", treeCopy.label, treeCopy.heading, treeCopy.description, treeBody, true),
|
|
7580
7710
|
screenSection("routing", "Routing and telemetry", "Routing + telemetry", "Aggregate routing and cost telemetry from <code>GET /api/state</code> across all sessions.", routingScreenBody(state)),
|
|
7581
|
-
screenSection("logs", "Logs and session activity", "Logs / activity",
|
|
7711
|
+
screenSection("logs", "Logs and session activity", "Logs / activity", consoleDetailMessages.logsDescription, `<div data-log-controls><label>${escapeHtml(consoleDetailMessages.filter)} <input type="search" data-log-filter></label> <label><input type="checkbox" data-log-follow> ${escapeHtml(consoleDetailMessages.follow)}</label> <button type="button" data-log-incoming hidden>${escapeHtml(consoleDetailMessages.incoming)}</button></div><div data-log-content>${logsScreenBody(state, terminalEnabled, ptyEnabled)}</div>`),
|
|
7582
7712
|
screenSection("config", "Editable configuration", 'Configuration <span class="pill warn">editable</span>', "Edit the whole openteam JSON configuration. Roles are editable inside the JSON when present; unsupported surfaces are not shown.", configScreenBody(options.configEditor?.hasToken === true))
|
|
7583
7713
|
].join("");
|
|
7584
7714
|
const session = state.session.id === undefined ? "" : ` · session ${escapeHtml(state.session.id)}`;
|
|
7585
|
-
const tokenAttr =
|
|
7715
|
+
const tokenAttr = options.consoleToken !== undefined ? ` data-token="${escapeHtml(options.consoleToken)}"${terminalEnabled ? ' data-terminal="1"' : ""}${terminalEnabled && ptyEnabled ? ' data-pty="1"' : ""}${graphDrilldown ? ' data-drilldown="1"' : ""}${configEnabled ? ' data-config="1"' : ""}` : "";
|
|
7586
7716
|
return [
|
|
7587
7717
|
"<!doctype html>",
|
|
7588
7718
|
`<html lang="en" data-generated="${escapeHtml(state.generatedAt)}" data-refresh="${refreshMs}"${tokenAttr}>`,
|
|
@@ -7591,7 +7721,7 @@ function renderConsoleHtml(state, options = {}) {
|
|
|
7591
7721
|
'<meta name="viewport" content="width=device-width,initial-scale=1">',
|
|
7592
7722
|
"<title>openteam console</title>",
|
|
7593
7723
|
lifecycleEnabled ? `<script>${LIFECYCLE_THEME_BOOT}</script>` : "",
|
|
7594
|
-
`<style>${CONSOLE_STYLE}${graphOptionProvided ? GRAPH_STYLE : ""}${lifecycleEnabled ? LIFECYCLE_STYLE
|
|
7724
|
+
`<style>${CONSOLE_STYLE}${CONVERSATION_STYLE}${graphOptionProvided ? GRAPH_STYLE : ""}${lifecycleEnabled ? LIFECYCLE_STYLE : ""}</style>`,
|
|
7595
7725
|
"</head>",
|
|
7596
7726
|
"<body>",
|
|
7597
7727
|
'<div class="app">',
|
|
@@ -8368,7 +8498,8 @@ async function untilAborted(read, signal) {
|
|
|
8368
8498
|
}
|
|
8369
8499
|
async function handleConversationRoute(request, response, url, deps) {
|
|
8370
8500
|
const labelsOnly = url.pathname === "/api/graph/session-labels";
|
|
8371
|
-
|
|
8501
|
+
const direct = url.pathname === "/api/console/conversation";
|
|
8502
|
+
if (url.pathname !== "/api/graph/conversation" && !labelsOnly && !direct)
|
|
8372
8503
|
return false;
|
|
8373
8504
|
const send = (status, kind, message, extra = {}) => {
|
|
8374
8505
|
response.writeHead(status, {
|
|
@@ -8388,11 +8519,60 @@ async function handleConversationRoute(request, response, url, deps) {
|
|
|
8388
8519
|
send(405, "unavailable", consoleDetailMessages.unauthorized);
|
|
8389
8520
|
return true;
|
|
8390
8521
|
}
|
|
8391
|
-
if (!deps.enabled || !deps.contentEnabled
|
|
8522
|
+
if (!direct && !deps.enabled || !deps.contentEnabled) {
|
|
8392
8523
|
send(403, "disabled", consoleDetailMessages.disabled);
|
|
8393
8524
|
return true;
|
|
8394
8525
|
}
|
|
8395
8526
|
const params = url.searchParams;
|
|
8527
|
+
if (direct) {
|
|
8528
|
+
const sessionID = params.get("session");
|
|
8529
|
+
if (!sessionID || sessionID.length > 256 || params.getAll("session").length !== 1 || ["run", "operation", "attempt", "target"].some((key) => params.has(key))) {
|
|
8530
|
+
send(400, "invalid", consoleDetailMessages.invalid);
|
|
8531
|
+
return true;
|
|
8532
|
+
}
|
|
8533
|
+
if (params.has("cursor")) {
|
|
8534
|
+
send(409, "historical", consoleDetailMessages.historical);
|
|
8535
|
+
return true;
|
|
8536
|
+
}
|
|
8537
|
+
const controller2 = new AbortController;
|
|
8538
|
+
const cancel2 = () => controller2.abort();
|
|
8539
|
+
response.on("close", cancel2);
|
|
8540
|
+
request.on("aborted", cancel2);
|
|
8541
|
+
const timeout2 = setTimeout(cancel2, SESSION_HISTORY_LIMITS.timeoutMs);
|
|
8542
|
+
try {
|
|
8543
|
+
const observed = await untilAborted(deps.observedSessionIDs?.() ?? Promise.resolve([]), controller2.signal);
|
|
8544
|
+
if (!observed.includes(sessionID)) {
|
|
8545
|
+
send(404, "invalid", consoleDetailMessages.invalid);
|
|
8546
|
+
return true;
|
|
8547
|
+
}
|
|
8548
|
+
const endpoint = await untilAborted(deps.resolveEndpoint(sessionID), controller2.signal);
|
|
8549
|
+
if (!endpoint) {
|
|
8550
|
+
send(503, "unavailable", consoleDetailMessages.unavailable);
|
|
8551
|
+
return true;
|
|
8552
|
+
}
|
|
8553
|
+
const conversation = await untilAborted(deps.readConversation(endpoint, sessionID, controller2.signal), controller2.signal);
|
|
8554
|
+
send(200, conversation.messages.length || conversation.truncated ? "conversation" : "empty", `${consoleDetailMessages.current}${conversation.truncated ? `
|
|
8555
|
+
${consoleDetailMessages.truncated}` : conversation.messages.length ? "" : `
|
|
8556
|
+
${consoleDetailMessages.empty}`}`, {
|
|
8557
|
+
scope: "present-day-session",
|
|
8558
|
+
target: "session",
|
|
8559
|
+
sessionID,
|
|
8560
|
+
...conversation
|
|
8561
|
+
});
|
|
8562
|
+
} catch (error) {
|
|
8563
|
+
if (!response.destroyed)
|
|
8564
|
+
send(error instanceof ConversationTooLargeError ? 413 : 503, error instanceof ConversationTooLargeError ? "oversized" : "unavailable", error instanceof ConversationTooLargeError ? consoleDetailMessages.oversized : consoleDetailMessages.unavailable);
|
|
8565
|
+
} finally {
|
|
8566
|
+
clearTimeout(timeout2);
|
|
8567
|
+
response.off("close", cancel2);
|
|
8568
|
+
request.off("aborted", cancel2);
|
|
8569
|
+
}
|
|
8570
|
+
return true;
|
|
8571
|
+
}
|
|
8572
|
+
if (!deps.reader) {
|
|
8573
|
+
send(503, "unavailable", consoleDetailMessages.unavailable);
|
|
8574
|
+
return true;
|
|
8575
|
+
}
|
|
8396
8576
|
const rootTarget = params.get("target") === "root";
|
|
8397
8577
|
if ((labelsOnly ? params.has("run") ? ["run"] : [] : rootTarget ? ["run", "operation"] : ["run", "operation", "attempt"]).some((key) => params.getAll(key).length !== 1 || !params.get(key)) || params.has("session") || params.getAll("target").length > 1 || params.has("target") && !rootTarget && params.get("target") !== "attempt" || rootTarget && params.has("attempt") || labelsOnly && (params.has("operation") || params.has("attempt") || params.has("target"))) {
|
|
8398
8578
|
send(400, "invalid", consoleDetailMessages.invalid);
|
|
@@ -8416,7 +8596,7 @@ async function handleConversationRoute(request, response, url, deps) {
|
|
|
8416
8596
|
if (request.aborted || request.socket.destroyed)
|
|
8417
8597
|
cancel2();
|
|
8418
8598
|
const deadline = Date.now() + SESSION_HISTORY_LIMITS.timeoutMs;
|
|
8419
|
-
const
|
|
8599
|
+
const timeout2 = setTimeout(cancel2, SESSION_HISTORY_LIMITS.timeoutMs);
|
|
8420
8600
|
try {
|
|
8421
8601
|
const history2 = selected?.kind === "view" ? selected : undefined;
|
|
8422
8602
|
const selectedRoot = history2?.runs.find((run) => run.runID === history2.selection.runID)?.rootSessionID;
|
|
@@ -8482,7 +8662,7 @@ ${consoleDetailMessages.partialMetadata}` : consoleDetailMessages.currentMetadat
|
|
|
8482
8662
|
if (!response.destroyed && !request.socket.destroyed)
|
|
8483
8663
|
send(503, "unavailable", consoleDetailMessages.unavailable);
|
|
8484
8664
|
} finally {
|
|
8485
|
-
clearTimeout(
|
|
8665
|
+
clearTimeout(timeout2);
|
|
8486
8666
|
response.off("close", cancel2);
|
|
8487
8667
|
request.off("aborted", cancel2);
|
|
8488
8668
|
request.socket.off("close", cancel2);
|
|
@@ -8507,21 +8687,23 @@ ${consoleDetailMessages.partialMetadata}` : consoleDetailMessages.currentMetadat
|
|
|
8507
8687
|
const controller = new AbortController;
|
|
8508
8688
|
const cancel = () => controller.abort();
|
|
8509
8689
|
response.on("close", cancel);
|
|
8690
|
+
request.on("aborted", cancel);
|
|
8691
|
+
const timeout = setTimeout(cancel, SESSION_HISTORY_LIMITS.timeoutMs);
|
|
8510
8692
|
try {
|
|
8511
8693
|
const run = history.runs.find((item) => item.runID === history.selection.runID);
|
|
8512
8694
|
const recordedRoot = run?.rootSessionID;
|
|
8513
8695
|
const sessionID = rootTarget ? recordedRoot : attempt?.sessionID;
|
|
8514
8696
|
const endpointID = sessionID ?? history.projection.operations.flatMap((op) => op.attempts).filter((item) => item.sessionID).at(-1)?.sessionID ?? "";
|
|
8515
|
-
const endpoint = await deps.resolveEndpoint(endpointID);
|
|
8697
|
+
const endpoint = await untilAborted(deps.resolveEndpoint(endpointID), controller.signal);
|
|
8516
8698
|
if (!endpoint) {
|
|
8517
8699
|
send(503, "unavailable", consoleDetailMessages.unavailable);
|
|
8518
8700
|
return true;
|
|
8519
8701
|
}
|
|
8520
|
-
const recovered = !sessionID && rootTarget && deps.readConversation.root ? await deps.readConversation.root(endpoint, history.projection, controller.signal) : undefined;
|
|
8702
|
+
const recovered = !sessionID && rootTarget && deps.readConversation.root ? await untilAborted(deps.readConversation.root(endpoint, history.projection, controller.signal), controller.signal) : undefined;
|
|
8521
8703
|
const resolvedID = sessionID ?? recovered?.session.id;
|
|
8522
8704
|
if (!resolvedID)
|
|
8523
8705
|
throw new AssociationError("unavailable");
|
|
8524
|
-
const conversation = recovered ?? await deps.readConversation(endpoint, resolvedID, controller.signal);
|
|
8706
|
+
const conversation = recovered ?? await untilAborted(deps.readConversation(endpoint, resolvedID, controller.signal), controller.signal);
|
|
8525
8707
|
const current = rootTarget ? `${consoleDetailMessages.rootCurrent}
|
|
8526
8708
|
${consoleDetailMessages.current}${recovered ? `
|
|
8527
8709
|
${consoleDetailMessages.recovered}` : ""}` : consoleDetailMessages.current;
|
|
@@ -8537,10 +8719,12 @@ ${consoleDetailMessages.empty}`, {
|
|
|
8537
8719
|
...conversation
|
|
8538
8720
|
});
|
|
8539
8721
|
} catch (error) {
|
|
8540
|
-
if (!
|
|
8722
|
+
if (!response.destroyed)
|
|
8541
8723
|
send(error instanceof ConversationTooLargeError ? 413 : 503, error instanceof ConversationTooLargeError ? "oversized" : "unavailable", error instanceof AssociationError ? error.message : error instanceof ConversationTooLargeError ? consoleDetailMessages.oversized : consoleDetailMessages.unavailable);
|
|
8542
8724
|
} finally {
|
|
8725
|
+
clearTimeout(timeout);
|
|
8543
8726
|
response.off("close", cancel);
|
|
8727
|
+
request.off("aborted", cancel);
|
|
8544
8728
|
}
|
|
8545
8729
|
return true;
|
|
8546
8730
|
}
|
|
@@ -8820,15 +9004,19 @@ async function createConsoleServer(deps) {
|
|
|
8820
9004
|
};
|
|
8821
9005
|
const handle = async (request, response) => {
|
|
8822
9006
|
const url2 = new URL(request.url ?? "/", "http://localhost");
|
|
8823
|
-
if ([
|
|
9007
|
+
if ([
|
|
9008
|
+
"/api/graph/conversation",
|
|
9009
|
+
"/api/graph/session-labels",
|
|
9010
|
+
"/api/console/conversation"
|
|
9011
|
+
].includes(url2.pathname) && deps.storageApi && !readAuthorized2(request, url2, deps.storageApi.token)) {
|
|
8824
9012
|
response.writeHead(401, { ...JSON_HEADERS5, "cache-control": "no-store" }).end(JSON.stringify({ version: 1, kind: "unauthorized" }));
|
|
8825
9013
|
return;
|
|
8826
9014
|
}
|
|
8827
|
-
if (deps.console?.readConversation &&
|
|
9015
|
+
if (deps.console?.readConversation && await handleConversationRoute(request, response, url2, {
|
|
8828
9016
|
token: deps.console.token,
|
|
8829
9017
|
enabled: deps.config.graphView?.enabled === true,
|
|
8830
|
-
contentEnabled: deps.console.conversationContentEnabled
|
|
8831
|
-
reader: deps.lifecycleHistoryApi.reader,
|
|
9018
|
+
contentEnabled: deps.console.conversationContentEnabled ?? deps.config.sessionHistory?.contentEnabled ?? true,
|
|
9019
|
+
...deps.lifecycleHistoryApi ? { reader: deps.lifecycleHistoryApi.reader } : {},
|
|
8832
9020
|
resolveEndpoint: async (id) => deps.console?.historyEndpoint ?? await resolveEndpoint(id),
|
|
8833
9021
|
observedSessionIDs: async () => buildConsoleState(await deps.readSnapshot()).sessions.map((session) => session.sessionID),
|
|
8834
9022
|
readConversation: deps.console.readConversation
|
|
@@ -9248,7 +9436,7 @@ function parseOpencodeProviders(opencodeConfig) {
|
|
|
9248
9436
|
function localRuntimeStates(config) {
|
|
9249
9437
|
const map = new Map;
|
|
9250
9438
|
for (const runtime of config.local.runtimes) {
|
|
9251
|
-
map.set(runtime.
|
|
9439
|
+
map.set(runtime.defaultModel.providerID, { enabled: runtime.enabled });
|
|
9252
9440
|
}
|
|
9253
9441
|
return map;
|
|
9254
9442
|
}
|
|
@@ -9256,7 +9444,7 @@ function disabledLocalProviderIDs(config) {
|
|
|
9256
9444
|
const ids = new Set;
|
|
9257
9445
|
for (const runtime of config.local.runtimes) {
|
|
9258
9446
|
if (!runtime.enabled) {
|
|
9259
|
-
ids.add(runtime.
|
|
9447
|
+
ids.add(runtime.defaultModel.providerID);
|
|
9260
9448
|
}
|
|
9261
9449
|
}
|
|
9262
9450
|
return ids;
|
|
@@ -9272,7 +9460,11 @@ function computeLive(model, isLocalProvider, liveModels) {
|
|
|
9272
9460
|
if (!snapshot.reachable) {
|
|
9273
9461
|
return "unreachable";
|
|
9274
9462
|
}
|
|
9275
|
-
|
|
9463
|
+
if (snapshot.modelIDs.has(model.modelID))
|
|
9464
|
+
return "confirmed";
|
|
9465
|
+
if (snapshot.residency?.has(model.modelID))
|
|
9466
|
+
return snapshot.residency.get(model.modelID) === false ? "not-loaded" : "residency-unknown";
|
|
9467
|
+
return "not-advertised";
|
|
9276
9468
|
}
|
|
9277
9469
|
function resolveAgentModel(model, context) {
|
|
9278
9470
|
const isLocalProvider = KNOWN_LOCAL_PROVIDER_IDS.has(model.providerID) || context.localRuntimes.has(model.providerID);
|
|
@@ -11127,7 +11319,7 @@ async function runConsoleServe(deps, options) {
|
|
|
11127
11319
|
ptyEnabled,
|
|
11128
11320
|
createClient: makeClient,
|
|
11129
11321
|
drilldownEnabled: graphViewEnabled,
|
|
11130
|
-
conversationContentEnabled: config.console.sessionHistory?.contentEnabled
|
|
11322
|
+
conversationContentEnabled: config.console.sessionHistory?.contentEnabled !== false,
|
|
11131
11323
|
...config.console.sessionHistory?.endpoint !== undefined ? { historyEndpoint: config.console.sessionHistory.endpoint } : {},
|
|
11132
11324
|
readConversation: createConversationReader({
|
|
11133
11325
|
directory: deps.directory ?? process.cwd(),
|
|
@@ -16012,6 +16204,243 @@ function ensureFoundryV1BaseURL(endpoint) {
|
|
|
16012
16204
|
}
|
|
16013
16205
|
}
|
|
16014
16206
|
|
|
16207
|
+
// src/local/lemonadeResidency.ts
|
|
16208
|
+
import { z as z22 } from "zod";
|
|
16209
|
+
|
|
16210
|
+
// src/messages/modelResidency.ts
|
|
16211
|
+
var reasons = {
|
|
16212
|
+
unknown: "fresh residency metadata is unavailable, malformed, or ambiguous",
|
|
16213
|
+
inactive: "the requested model is not verified as resident and serving",
|
|
16214
|
+
identity: "the requested model identity can be rewritten or is ambiguous",
|
|
16215
|
+
destination: "the request destination does not match its configured runtime",
|
|
16216
|
+
transport: "this provider execution path cannot enforce the residency guard",
|
|
16217
|
+
request: "this is not a supported, explicit model inference request",
|
|
16218
|
+
cancelled: "the request was cancelled before residency could be verified",
|
|
16219
|
+
timeout: "the residency metadata deadline expired",
|
|
16220
|
+
configuration: "the residency guard configuration is invalid"
|
|
16221
|
+
};
|
|
16222
|
+
var modelResidencyMessages = {
|
|
16223
|
+
blocked: (reason) => `[openteam] Lemonade model request blocked: ${reasons[reason]}.`,
|
|
16224
|
+
providerDisabled: (providerID) => `[openteam] Lemonade provider "${providerID}" is disabled because its configured transport or runtime mapping cannot enforce loaded-only requests.`,
|
|
16225
|
+
extractionRuntimeUnavailable: "[openteam] Memory extraction requires one enabled local runtime matching the configured extraction provider."
|
|
16226
|
+
};
|
|
16227
|
+
|
|
16228
|
+
// src/local/lemonadeResidency.ts
|
|
16229
|
+
class ModelResidencyError extends Error {
|
|
16230
|
+
code;
|
|
16231
|
+
statusCode = 400;
|
|
16232
|
+
isRetryable = false;
|
|
16233
|
+
constructor(code) {
|
|
16234
|
+
super(modelResidencyMessages.blocked(code));
|
|
16235
|
+
this.code = code;
|
|
16236
|
+
this.name = "ModelResidencyError";
|
|
16237
|
+
}
|
|
16238
|
+
}
|
|
16239
|
+
var modelName = z22.string().min(1).refine((name) => name === name.trim());
|
|
16240
|
+
var LoadedModelSchema = z22.object({
|
|
16241
|
+
model_name: modelName,
|
|
16242
|
+
loaded: z22.boolean().optional(),
|
|
16243
|
+
status: z22.string().optional(),
|
|
16244
|
+
backend_alive: z22.boolean().optional(),
|
|
16245
|
+
backend_health: z22.string().optional(),
|
|
16246
|
+
watchdog_reset: z22.boolean().optional(),
|
|
16247
|
+
watchdog_reset_reason: z22.string().optional(),
|
|
16248
|
+
residency_class: z22.string().optional(),
|
|
16249
|
+
slot_pool: z22.string().optional(),
|
|
16250
|
+
checkpoint: z22.string().optional(),
|
|
16251
|
+
type: z22.string().optional(),
|
|
16252
|
+
device: z22.string().optional(),
|
|
16253
|
+
backend_url: z22.string().optional(),
|
|
16254
|
+
pid: z22.number().int().optional(),
|
|
16255
|
+
launch_command: z22.unknown().optional(),
|
|
16256
|
+
pinned: z22.boolean().optional(),
|
|
16257
|
+
recipe: z22.string().optional(),
|
|
16258
|
+
recipe_options: z22.unknown().optional(),
|
|
16259
|
+
is_busy: z22.boolean().optional(),
|
|
16260
|
+
is_streaming: z22.boolean().optional(),
|
|
16261
|
+
max_context_window: z22.number().optional(),
|
|
16262
|
+
cost_input_per_million: z22.number().optional(),
|
|
16263
|
+
cost_output_per_million: z22.number().optional(),
|
|
16264
|
+
last_use: z22.number().optional()
|
|
16265
|
+
}).strict();
|
|
16266
|
+
var TelemetrySchema = z22.object({
|
|
16267
|
+
enabled: z22.boolean(),
|
|
16268
|
+
captures: z22.array(z22.string()).optional()
|
|
16269
|
+
}).strict();
|
|
16270
|
+
var HealthSchema = z22.object({
|
|
16271
|
+
status: z22.literal("ok"),
|
|
16272
|
+
all_models_loaded: z22.array(LoadedModelSchema),
|
|
16273
|
+
version: z22.string().optional(),
|
|
16274
|
+
model_loaded: z22.string().nullable().optional(),
|
|
16275
|
+
telemetry: TelemetrySchema.optional(),
|
|
16276
|
+
max_models: z22.record(z22.string(), z22.number().int()).optional(),
|
|
16277
|
+
pinned_models: z22.record(z22.string(), z22.number().int()).optional(),
|
|
16278
|
+
pinned_helper_models: z22.record(z22.string(), z22.number().int()).optional(),
|
|
16279
|
+
websocket_port: z22.number().int().optional(),
|
|
16280
|
+
update_check_done: z22.boolean().optional()
|
|
16281
|
+
}).strict();
|
|
16282
|
+
var AliasSchema = z22.object({
|
|
16283
|
+
alias: modelName,
|
|
16284
|
+
target: modelName,
|
|
16285
|
+
downloaded: z22.boolean().optional(),
|
|
16286
|
+
recipe: z22.string().optional()
|
|
16287
|
+
}).strict();
|
|
16288
|
+
var AliasesSchema = z22.object({
|
|
16289
|
+
aliases: z22.array(AliasSchema)
|
|
16290
|
+
}).strict();
|
|
16291
|
+
var MetadataRecordSchema = z22.record(z22.string(), z22.unknown());
|
|
16292
|
+
var inactiveStates = new Set([
|
|
16293
|
+
"loading",
|
|
16294
|
+
"downsizing",
|
|
16295
|
+
"downsized",
|
|
16296
|
+
"evicting",
|
|
16297
|
+
"unloaded"
|
|
16298
|
+
]);
|
|
16299
|
+
var inactiveHealth = new Set(["stopped", "exited", "watchdog_reset"]);
|
|
16300
|
+
var standardPools = new Set([
|
|
16301
|
+
"standard/llm",
|
|
16302
|
+
"standard/embedding",
|
|
16303
|
+
"standard/reranking",
|
|
16304
|
+
"standard/transcription",
|
|
16305
|
+
"standard/image",
|
|
16306
|
+
"standard/tts",
|
|
16307
|
+
"standard/audio-generation",
|
|
16308
|
+
"standard/classification",
|
|
16309
|
+
"standard/mesh"
|
|
16310
|
+
]);
|
|
16311
|
+
function usableState(entry) {
|
|
16312
|
+
if (entry.loaded === false || entry.backend_alive === false || entry.watchdog_reset === true || typeof entry.status === "string" && inactiveStates.has(entry.status) || typeof entry.backend_health === "string" && inactiveHealth.has(entry.backend_health) || entry.residency_class === "routing_helper" || typeof entry.slot_pool === "string" && entry.slot_pool.startsWith("routing_helper/")) {
|
|
16313
|
+
return false;
|
|
16314
|
+
}
|
|
16315
|
+
if (entry.loaded !== true || entry.backend_alive !== true || entry.watchdog_reset !== false || entry.status !== "ready" && entry.status !== "in_use" || entry.backend_health !== "ready" && entry.backend_health !== "busy" || entry.watchdog_reset_reason !== undefined && entry.watchdog_reset_reason !== "" || entry.residency_class !== undefined && entry.residency_class !== "standard" || entry.slot_pool !== undefined && (typeof entry.slot_pool !== "string" || !standardPools.has(entry.slot_pool))) {
|
|
16316
|
+
return;
|
|
16317
|
+
}
|
|
16318
|
+
return true;
|
|
16319
|
+
}
|
|
16320
|
+
function projectMetadataObject(payload, keys) {
|
|
16321
|
+
const record2 = MetadataRecordSchema.safeParse(payload);
|
|
16322
|
+
if (!record2.success)
|
|
16323
|
+
throw new ModelResidencyError("unknown");
|
|
16324
|
+
return Object.fromEntries(keys.filter((key) => Object.hasOwn(record2.data, key)).map((key) => [key, record2.data[key]]));
|
|
16325
|
+
}
|
|
16326
|
+
function parseResidency(healthPayload, aliasPayload) {
|
|
16327
|
+
const healthFields = projectMetadataObject(healthPayload, Object.keys(HealthSchema.shape));
|
|
16328
|
+
if (Array.isArray(healthFields.all_models_loaded)) {
|
|
16329
|
+
healthFields.all_models_loaded = healthFields.all_models_loaded.map((entry) => projectMetadataObject(entry, Object.keys(LoadedModelSchema.shape)));
|
|
16330
|
+
}
|
|
16331
|
+
if (healthFields.telemetry !== undefined) {
|
|
16332
|
+
healthFields.telemetry = projectMetadataObject(healthFields.telemetry, Object.keys(TelemetrySchema.shape));
|
|
16333
|
+
}
|
|
16334
|
+
const aliasFields = projectMetadataObject(aliasPayload, Object.keys(AliasesSchema.shape));
|
|
16335
|
+
if (Array.isArray(aliasFields.aliases)) {
|
|
16336
|
+
aliasFields.aliases = aliasFields.aliases.map((entry) => projectMetadataObject(entry, Object.keys(AliasSchema.shape)));
|
|
16337
|
+
}
|
|
16338
|
+
const health = HealthSchema.safeParse(healthFields);
|
|
16339
|
+
const aliases = AliasesSchema.safeParse(aliasFields);
|
|
16340
|
+
if (!health.success || !aliases.success)
|
|
16341
|
+
throw new ModelResidencyError("unknown");
|
|
16342
|
+
const result = new Map;
|
|
16343
|
+
for (const entry of health.data.all_models_loaded) {
|
|
16344
|
+
if (result.has(entry.model_name))
|
|
16345
|
+
throw new ModelResidencyError("unknown");
|
|
16346
|
+
result.set(entry.model_name, {
|
|
16347
|
+
loaded: entry.model_name.endsWith(":latest") ? undefined : usableState(entry),
|
|
16348
|
+
metadata: entry
|
|
16349
|
+
});
|
|
16350
|
+
}
|
|
16351
|
+
const seenAliases = new Set;
|
|
16352
|
+
for (const entry of aliases.data.aliases) {
|
|
16353
|
+
if (seenAliases.has(entry.alias))
|
|
16354
|
+
throw new ModelResidencyError("unknown");
|
|
16355
|
+
seenAliases.add(entry.alias);
|
|
16356
|
+
result.set(entry.alias, {
|
|
16357
|
+
loaded: undefined,
|
|
16358
|
+
metadata: result.get(entry.alias)?.metadata ?? {}
|
|
16359
|
+
});
|
|
16360
|
+
}
|
|
16361
|
+
return result;
|
|
16362
|
+
}
|
|
16363
|
+
function lemonadeBaseURL(value) {
|
|
16364
|
+
let url;
|
|
16365
|
+
try {
|
|
16366
|
+
url = new URL(value);
|
|
16367
|
+
} catch {
|
|
16368
|
+
throw new ModelResidencyError("destination");
|
|
16369
|
+
}
|
|
16370
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "" || !/^\/(?:api\/)?v[01]\/?$/.test(url.pathname)) {
|
|
16371
|
+
throw new ModelResidencyError("destination");
|
|
16372
|
+
}
|
|
16373
|
+
return `${url.origin}${url.pathname.replace(/\/$/, "")}`;
|
|
16374
|
+
}
|
|
16375
|
+
async function withResidencyDeadline(operation, options) {
|
|
16376
|
+
const timeoutMs = options.timeoutMs ?? 5000;
|
|
16377
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
16378
|
+
throw new ModelResidencyError("configuration");
|
|
16379
|
+
}
|
|
16380
|
+
const controller = new AbortController;
|
|
16381
|
+
const cancel = () => controller.abort(new ModelResidencyError("cancelled"));
|
|
16382
|
+
if (options.signal?.aborted)
|
|
16383
|
+
throw new ModelResidencyError("cancelled");
|
|
16384
|
+
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
16385
|
+
const schedule = options.scheduleTimeout ?? ((callback, ms2) => {
|
|
16386
|
+
const timer = setTimeout(callback, ms2);
|
|
16387
|
+
return () => clearTimeout(timer);
|
|
16388
|
+
});
|
|
16389
|
+
let onAbort = () => {};
|
|
16390
|
+
const aborted = new Promise((_, reject) => {
|
|
16391
|
+
onAbort = () => reject(controller.signal.reason);
|
|
16392
|
+
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
16393
|
+
});
|
|
16394
|
+
const clearTimer = schedule(() => controller.abort(new ModelResidencyError("timeout")), timeoutMs);
|
|
16395
|
+
try {
|
|
16396
|
+
controller.signal.throwIfAborted();
|
|
16397
|
+
return await Promise.race([operation(controller.signal), aborted]);
|
|
16398
|
+
} finally {
|
|
16399
|
+
clearTimer();
|
|
16400
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
16401
|
+
controller.signal.removeEventListener("abort", onAbort);
|
|
16402
|
+
controller.abort();
|
|
16403
|
+
}
|
|
16404
|
+
}
|
|
16405
|
+
async function metadata(url, fetch2, signal, headers) {
|
|
16406
|
+
signal.throwIfAborted();
|
|
16407
|
+
let payload;
|
|
16408
|
+
try {
|
|
16409
|
+
const response = await fetch2(url, {
|
|
16410
|
+
method: "GET",
|
|
16411
|
+
headers,
|
|
16412
|
+
signal,
|
|
16413
|
+
redirect: "error",
|
|
16414
|
+
cache: "no-store"
|
|
16415
|
+
});
|
|
16416
|
+
signal.throwIfAborted();
|
|
16417
|
+
if (!response.ok || response.redirected || response.url !== "" && response.url !== url) {
|
|
16418
|
+
throw new ModelResidencyError("unknown");
|
|
16419
|
+
}
|
|
16420
|
+
payload = await response.json();
|
|
16421
|
+
} catch {
|
|
16422
|
+
signal.throwIfAborted();
|
|
16423
|
+
throw new ModelResidencyError("unknown");
|
|
16424
|
+
}
|
|
16425
|
+
signal.throwIfAborted();
|
|
16426
|
+
return payload;
|
|
16427
|
+
}
|
|
16428
|
+
async function readLemonadeResidency(baseURL, fetch2, options = {}) {
|
|
16429
|
+
const base = lemonadeBaseURL(baseURL);
|
|
16430
|
+
const headers = new Headers(options.headers);
|
|
16431
|
+
headers.delete("content-type");
|
|
16432
|
+
headers.delete("content-length");
|
|
16433
|
+
headers.set("accept", "application/json");
|
|
16434
|
+
headers.set("cache-control", "no-cache, no-store");
|
|
16435
|
+
headers.delete("if-none-match");
|
|
16436
|
+
headers.delete("if-modified-since");
|
|
16437
|
+
return withResidencyDeadline(async (signal) => {
|
|
16438
|
+
const aliases = await metadata(`${new URL(base).origin}/internal/aliases`, fetch2, signal, headers);
|
|
16439
|
+
const health = await metadata(`${base}/health`, fetch2, signal, headers);
|
|
16440
|
+
return parseResidency(health, aliases);
|
|
16441
|
+
}, options);
|
|
16442
|
+
}
|
|
16443
|
+
|
|
16015
16444
|
// src/local/lemonade.ts
|
|
16016
16445
|
var LEMONADE_DEFAULT_BASE_URL = "http://localhost:13305/api/v1";
|
|
16017
16446
|
var NON_TEXT_LABELS = new Set([
|
|
@@ -16098,36 +16527,19 @@ function isNonTextModel(entry) {
|
|
|
16098
16527
|
return entry.labels.some((label) => typeof label === "string" && NON_TEXT_LABELS.has(label));
|
|
16099
16528
|
}
|
|
16100
16529
|
async function readLoadedModels(baseURL, fetch2) {
|
|
16101
|
-
let payload;
|
|
16102
16530
|
try {
|
|
16103
|
-
const
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16107
|
-
|
|
16108
|
-
|
|
16109
|
-
|
|
16110
|
-
|
|
16531
|
+
const residency = await readLemonadeResidency(baseURL, fetch2);
|
|
16532
|
+
return new Map([...residency].map(([name, entry]) => [
|
|
16533
|
+
name,
|
|
16534
|
+
{
|
|
16535
|
+
loaded: entry.loaded,
|
|
16536
|
+
slots: entry.loaded === true ? readSlotCount(entry.metadata) : undefined,
|
|
16537
|
+
totalContextWindow: entry.loaded === true ? readLoadedContextWindow(entry.metadata) : undefined
|
|
16538
|
+
}
|
|
16539
|
+
]));
|
|
16111
16540
|
} catch {
|
|
16112
16541
|
return;
|
|
16113
16542
|
}
|
|
16114
|
-
if (!isObject2(payload) || !Array.isArray(payload.all_models_loaded)) {
|
|
16115
|
-
return;
|
|
16116
|
-
}
|
|
16117
|
-
const loaded = new Map;
|
|
16118
|
-
for (const entry of payload.all_models_loaded) {
|
|
16119
|
-
if (!isObject2(entry) || typeof entry.model_name !== "string") {
|
|
16120
|
-
continue;
|
|
16121
|
-
}
|
|
16122
|
-
if (entry.loaded === false) {
|
|
16123
|
-
continue;
|
|
16124
|
-
}
|
|
16125
|
-
loaded.set(entry.model_name, {
|
|
16126
|
-
slots: readSlotCount(entry),
|
|
16127
|
-
totalContextWindow: readLoadedContextWindow(entry)
|
|
16128
|
-
});
|
|
16129
|
-
}
|
|
16130
|
-
return loaded;
|
|
16131
16543
|
}
|
|
16132
16544
|
function readSlotCount(entry) {
|
|
16133
16545
|
return slotsFromLlamacppArgs(entry) ?? slotsFromLaunchCommand(entry);
|
|
@@ -16274,6 +16686,9 @@ function enrichWithLoadState(models, loaded) {
|
|
|
16274
16686
|
if (hit === undefined) {
|
|
16275
16687
|
return { ...base, loaded: false };
|
|
16276
16688
|
}
|
|
16689
|
+
if (hit.loaded !== true) {
|
|
16690
|
+
return hit.loaded === false ? { ...base, loaded: false } : base;
|
|
16691
|
+
}
|
|
16277
16692
|
const contextWindow = derivedConservativeContextWindow(model.contextWindow, hit);
|
|
16278
16693
|
return {
|
|
16279
16694
|
...base,
|
|
@@ -16290,6 +16705,11 @@ function isObject2(value) {
|
|
|
16290
16705
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16291
16706
|
}
|
|
16292
16707
|
|
|
16708
|
+
// src/local/modelResidency.ts
|
|
16709
|
+
function hasRequiredModelResidency(kind, model) {
|
|
16710
|
+
return kind !== "lemonade" || model?.loaded === true;
|
|
16711
|
+
}
|
|
16712
|
+
|
|
16293
16713
|
// src/local/lmstudio.ts
|
|
16294
16714
|
var LMSTUDIO_DEFAULT_BASE_URL = "http://localhost:1234/v1";
|
|
16295
16715
|
function createLMStudioAdapter() {
|
|
@@ -16507,50 +16927,36 @@ function createDetect(exec) {
|
|
|
16507
16927
|
foundryDiscovery: foundryDiscoveryFromExec(exec)
|
|
16508
16928
|
});
|
|
16509
16929
|
const snapshots = await registry.probe(DETECTION_RUNTIMES);
|
|
16510
|
-
return
|
|
16511
|
-
|
|
16512
|
-
|
|
16513
|
-
|
|
16514
|
-
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
|
|
16519
|
-
|
|
16520
|
-
|
|
16521
|
-
|
|
16522
|
-
}
|
|
16523
|
-
return detected;
|
|
16524
|
-
});
|
|
16930
|
+
return DETECTION_RUNTIMES.map((runtime) => detectedRuntime(runtime, snapshots.find((snapshot) => snapshot.id === runtime.id)));
|
|
16931
|
+
};
|
|
16932
|
+
}
|
|
16933
|
+
function detectedRuntime(runtime, snapshot) {
|
|
16934
|
+
const modelInfo = snapshot?.models ?? [];
|
|
16935
|
+
return {
|
|
16936
|
+
id: runtime.id,
|
|
16937
|
+
baseURL: snapshot?.baseURL ?? runtime.baseURL ?? "",
|
|
16938
|
+
reachable: snapshot?.reachable ?? false,
|
|
16939
|
+
models: modelInfo.filter((model) => hasRequiredModelResidency(localRuntimeKind(runtime), model)).map((model) => model.modelID),
|
|
16940
|
+
modelInfo,
|
|
16941
|
+
...snapshot?.error === undefined ? {} : { error: snapshot.error }
|
|
16525
16942
|
};
|
|
16526
16943
|
}
|
|
16527
16944
|
function createProbeRuntime(exec) {
|
|
16528
|
-
return async (
|
|
16945
|
+
return async (kind, baseURL) => {
|
|
16529
16946
|
const registry = new RuntimeRegistry({
|
|
16530
16947
|
fetch: globalThis.fetch,
|
|
16531
16948
|
clock: () => new Date().toISOString(),
|
|
16532
16949
|
foundryDiscovery: foundryDiscoveryFromExec(exec)
|
|
16533
16950
|
});
|
|
16534
16951
|
const runtime = {
|
|
16535
|
-
id,
|
|
16952
|
+
id: kind,
|
|
16953
|
+
kind,
|
|
16536
16954
|
enabled: true,
|
|
16537
16955
|
baseURL,
|
|
16538
|
-
defaultModel: { providerID:
|
|
16956
|
+
defaultModel: { providerID: kind, modelID: "probe" }
|
|
16539
16957
|
};
|
|
16540
16958
|
const [snapshot] = await registry.probe([runtime]);
|
|
16541
|
-
|
|
16542
|
-
id,
|
|
16543
|
-
baseURL: snapshot?.baseURL ?? baseURL,
|
|
16544
|
-
reachable: snapshot?.reachable ?? false,
|
|
16545
|
-
models: snapshot?.models.map((model) => model.modelID) ?? []
|
|
16546
|
-
};
|
|
16547
|
-
if (snapshot?.models.some((model) => model.loaded !== undefined) === true) {
|
|
16548
|
-
detected.modelInfo = snapshot.models;
|
|
16549
|
-
}
|
|
16550
|
-
if (snapshot?.error !== undefined) {
|
|
16551
|
-
detected.error = snapshot.error;
|
|
16552
|
-
}
|
|
16553
|
-
return detected;
|
|
16959
|
+
return detectedRuntime(runtime, snapshot);
|
|
16554
16960
|
};
|
|
16555
16961
|
}
|
|
16556
16962
|
|
|
@@ -16663,11 +17069,11 @@ function planWorktreeReconciliation(input) {
|
|
|
16663
17069
|
}
|
|
16664
17070
|
|
|
16665
17071
|
// src/telemetry/otelConfig.ts
|
|
16666
|
-
import { z as
|
|
16667
|
-
var OtelBackendConfigSchema =
|
|
16668
|
-
backend:
|
|
16669
|
-
connectionEnv:
|
|
16670
|
-
serviceName:
|
|
17072
|
+
import { z as z23 } from "zod";
|
|
17073
|
+
var OtelBackendConfigSchema = z23.object({
|
|
17074
|
+
backend: z23.literal("opentelemetry"),
|
|
17075
|
+
connectionEnv: z23.string().min(1),
|
|
17076
|
+
serviceName: z23.string().min(1).optional()
|
|
16671
17077
|
}).strict();
|
|
16672
17078
|
function parseConnectionString(raw) {
|
|
16673
17079
|
const pairs = new Map;
|
|
@@ -17809,7 +18215,7 @@ import { posix as pathPosix, win32 as pathWin32 } from "node:path";
|
|
|
17809
18215
|
// package.json
|
|
17810
18216
|
var package_default = {
|
|
17811
18217
|
name: "@jmanuelcorral/openteam",
|
|
17812
|
-
version: "0.
|
|
18218
|
+
version: "0.25.0",
|
|
17813
18219
|
packageManager: "bun@1.3.14",
|
|
17814
18220
|
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
17815
18221
|
license: "MIT",
|
|
@@ -17953,31 +18359,31 @@ function compareSemver(a, b) {
|
|
|
17953
18359
|
}
|
|
17954
18360
|
|
|
17955
18361
|
// src/graph/soakLedger.ts
|
|
17956
|
-
import { z as
|
|
17957
|
-
var Sha256Schema2 =
|
|
17958
|
-
var SoakPlatformSchema =
|
|
17959
|
-
var PrivacyPairSchema =
|
|
17960
|
-
surfacesScanned:
|
|
17961
|
-
rawFindings:
|
|
18362
|
+
import { z as z24 } from "zod";
|
|
18363
|
+
var Sha256Schema2 = z24.string().regex(/^[0-9a-f]{64}$/);
|
|
18364
|
+
var SoakPlatformSchema = z24.enum(["linux", "win32", "darwin"]);
|
|
18365
|
+
var PrivacyPairSchema = z24.object({
|
|
18366
|
+
surfacesScanned: z24.number().int().nonnegative(),
|
|
18367
|
+
rawFindings: z24.number().int().nonnegative()
|
|
17962
18368
|
}).strict();
|
|
17963
|
-
var DuplicateEffectPairSchema =
|
|
17964
|
-
effectsExamined:
|
|
17965
|
-
duplicatesFound:
|
|
18369
|
+
var DuplicateEffectPairSchema = z24.object({
|
|
18370
|
+
effectsExamined: z24.number().int().nonnegative(),
|
|
18371
|
+
duplicatesFound: z24.number().int().nonnegative()
|
|
17966
18372
|
}).strict();
|
|
17967
|
-
var ModelVerificationPairSchema =
|
|
17968
|
-
nodesChecked:
|
|
17969
|
-
unverified:
|
|
17970
|
-
mismatched:
|
|
18373
|
+
var ModelVerificationPairSchema = z24.object({
|
|
18374
|
+
nodesChecked: z24.number().int().nonnegative(),
|
|
18375
|
+
unverified: z24.number().int().nonnegative(),
|
|
18376
|
+
mismatched: z24.number().int().nonnegative()
|
|
17971
18377
|
}).strict();
|
|
17972
|
-
var SoakObservationSchema =
|
|
17973
|
-
version:
|
|
17974
|
-
seq:
|
|
17975
|
-
timestamp:
|
|
18378
|
+
var SoakObservationSchema = z24.object({
|
|
18379
|
+
version: z24.literal(1),
|
|
18380
|
+
seq: z24.number().int().nonnegative(),
|
|
18381
|
+
timestamp: z24.string().datetime(),
|
|
17976
18382
|
platform: SoakPlatformSchema,
|
|
17977
|
-
opencodeVersion:
|
|
17978
|
-
provenance:
|
|
18383
|
+
opencodeVersion: z24.string().min(1),
|
|
18384
|
+
provenance: z24.enum(["genuine-usage", "ci-synthetic"]),
|
|
17979
18385
|
traceDigest: Sha256Schema2,
|
|
17980
|
-
criticalDivergences:
|
|
18386
|
+
criticalDivergences: z24.number().int().nonnegative().nullable(),
|
|
17981
18387
|
privacy: PrivacyPairSchema.nullable(),
|
|
17982
18388
|
duplicateEffects: DuplicateEffectPairSchema.nullable(),
|
|
17983
18389
|
modelVerification: ModelVerificationPairSchema.nullable(),
|
|
@@ -18259,6 +18665,12 @@ var KNOWN_RUNTIMES = [
|
|
|
18259
18665
|
dynamicPort: true
|
|
18260
18666
|
}
|
|
18261
18667
|
];
|
|
18668
|
+
var LEMONADE_PROJECT_CONFIG_CANDIDATES = [
|
|
18669
|
+
".opencode/opencode.jsonc",
|
|
18670
|
+
".opencode/opencode.json",
|
|
18671
|
+
"opencode.jsonc",
|
|
18672
|
+
"opencode.json"
|
|
18673
|
+
];
|
|
18262
18674
|
function knownRuntime(id) {
|
|
18263
18675
|
const found = KNOWN_RUNTIMES.find((runtime) => runtime.id === id);
|
|
18264
18676
|
if (found === undefined) {
|
|
@@ -18275,7 +18687,44 @@ function choiceKind(choice) {
|
|
|
18275
18687
|
function choiceProviderID(choice) {
|
|
18276
18688
|
return choice.providerID ?? choice.id;
|
|
18277
18689
|
}
|
|
18690
|
+
function selectableModelIDs(models, modelInfo, kind) {
|
|
18691
|
+
const byID = new Map(modelInfo?.map((model) => [model.modelID, model]));
|
|
18692
|
+
return models.filter((id) => hasRequiredModelResidency(kind, byID.get(id)));
|
|
18693
|
+
}
|
|
18694
|
+
function assertRuntimeResidency(choice, primary) {
|
|
18695
|
+
const kind = localRuntimeKind(choice);
|
|
18696
|
+
const references2 = [
|
|
18697
|
+
choice.defaultModelID,
|
|
18698
|
+
choice.thinkingModelID,
|
|
18699
|
+
choice.coderModelID,
|
|
18700
|
+
...primary.providerID === choiceProviderID(choice) ? [primary.modelID] : []
|
|
18701
|
+
];
|
|
18702
|
+
for (const id of references2) {
|
|
18703
|
+
if (id === undefined)
|
|
18704
|
+
continue;
|
|
18705
|
+
const info = choice.models.includes(id) ? choice.modelInfo?.find((model) => model.modelID === id) : undefined;
|
|
18706
|
+
if (!hasRequiredModelResidency(kind, info))
|
|
18707
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${choiceProviderID(choice)}/${id}`));
|
|
18708
|
+
}
|
|
18709
|
+
}
|
|
18710
|
+
function assertSetupResidency(answers) {
|
|
18711
|
+
for (const choice of answers.runtimes) {
|
|
18712
|
+
if (choice.enabled) {
|
|
18713
|
+
assertRuntimeResidency(choice, answers.primaryModel);
|
|
18714
|
+
} else if (choiceProviderID(choice) === answers.primaryModel.providerID && !hasRequiredModelResidency(localRuntimeKind(choice), undefined)) {
|
|
18715
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${answers.primaryModel.providerID}/${answers.primaryModel.modelID}`));
|
|
18716
|
+
}
|
|
18717
|
+
}
|
|
18718
|
+
}
|
|
18719
|
+
function lemonadeV2Policies(providers) {
|
|
18720
|
+
return [...new Set(providers)].sort().map((providerID) => {
|
|
18721
|
+
if (providerID.length === 0 || /[*?\\/\s]/.test(providerID))
|
|
18722
|
+
throw new Error(executionSetupMessages.lemonadeV2InvalidProvider(providerID));
|
|
18723
|
+
return { action: "provider.use", resource: providerID, effect: "deny" };
|
|
18724
|
+
});
|
|
18725
|
+
}
|
|
18278
18726
|
function buildOpenTeamConfig(answers) {
|
|
18727
|
+
assertSetupResidency(answers);
|
|
18279
18728
|
const runtimes = answers.runtimes.filter((choice) => choice.enabled).map((choice) => {
|
|
18280
18729
|
const runtime = {
|
|
18281
18730
|
id: choice.id,
|
|
@@ -18344,6 +18793,8 @@ function orchestratorAgentModel(answers) {
|
|
|
18344
18793
|
return { ...answers.primaryModel };
|
|
18345
18794
|
}
|
|
18346
18795
|
function buildOpencodeConfig(answers) {
|
|
18796
|
+
assertSetupResidency(answers);
|
|
18797
|
+
const policies = lemonadeV2Policies(answers.runtimes.filter((choice) => choice.enabled && choiceKind(choice) === "lemonade").map(choiceProviderID));
|
|
18347
18798
|
const provider = {};
|
|
18348
18799
|
const providerOwner = new Map;
|
|
18349
18800
|
for (const choice of answers.runtimes) {
|
|
@@ -18356,7 +18807,7 @@ function buildOpencodeConfig(answers) {
|
|
|
18356
18807
|
continue;
|
|
18357
18808
|
}
|
|
18358
18809
|
const providerID = choiceProviderID(choice);
|
|
18359
|
-
const modelIDs = new Set(choice.models);
|
|
18810
|
+
const modelIDs = new Set(selectableModelIDs(choice.models, choice.modelInfo, meta.id));
|
|
18360
18811
|
modelIDs.add(choice.defaultModelID);
|
|
18361
18812
|
if (choice.thinkingModelID !== undefined) {
|
|
18362
18813
|
modelIDs.add(choice.thinkingModelID);
|
|
@@ -18412,6 +18863,8 @@ function buildOpencodeConfig(answers) {
|
|
|
18412
18863
|
if (answers.yolo) {
|
|
18413
18864
|
config.permission = { "*": "allow" };
|
|
18414
18865
|
}
|
|
18866
|
+
if (policies.length > 0)
|
|
18867
|
+
config.experimental = { policies };
|
|
18415
18868
|
return config;
|
|
18416
18869
|
}
|
|
18417
18870
|
function serializeOpencodeConfig(config) {
|
|
@@ -18511,10 +18964,11 @@ async function chooseFrontier(prompt, profiles) {
|
|
|
18511
18964
|
}
|
|
18512
18965
|
return parseFrontierRef(selected);
|
|
18513
18966
|
}
|
|
18514
|
-
function orderModelChoices(models, modelInfo) {
|
|
18967
|
+
function orderModelChoices(models, modelInfo, kind) {
|
|
18515
18968
|
const byID = new Map((modelInfo ?? []).map((model) => [model.modelID, model]));
|
|
18516
18969
|
const anyLoadState = (modelInfo ?? []).some((model) => model.loaded !== undefined);
|
|
18517
|
-
const
|
|
18970
|
+
const offered = kind === undefined ? models : selectableModelIDs(models, modelInfo, kind);
|
|
18971
|
+
const decorated = offered.map((modelID, index) => {
|
|
18518
18972
|
const info = byID.get(modelID);
|
|
18519
18973
|
return {
|
|
18520
18974
|
modelID,
|
|
@@ -18540,27 +18994,34 @@ function modelStateSuffix(loaded, slots) {
|
|
|
18540
18994
|
}
|
|
18541
18995
|
return slots === undefined ? "(loaded)" : `(loaded · ${slots} slot${slots === 1 ? "" : "s"})`;
|
|
18542
18996
|
}
|
|
18543
|
-
function preferredModelID(models, modelInfo) {
|
|
18544
|
-
const
|
|
18545
|
-
|
|
18997
|
+
function preferredModelID(models, modelInfo, kind) {
|
|
18998
|
+
const offered = kind === undefined ? models : selectableModelIDs(models, modelInfo, kind);
|
|
18999
|
+
const loaded = (modelInfo ?? []).find((model) => model.loaded === true && offered.includes(model.modelID));
|
|
19000
|
+
return loaded?.modelID ?? offered[0];
|
|
18546
19001
|
}
|
|
18547
19002
|
async function chooseRuntimeModel(prompt, models, meta, modelInfo) {
|
|
18548
|
-
|
|
19003
|
+
const offered = selectableModelIDs(models, modelInfo, meta.id);
|
|
19004
|
+
if (offered.length === 0) {
|
|
19005
|
+
if (meta.id === "lemonade")
|
|
19006
|
+
throw new Error(executionSetupMessages.lemonadeNoLoadedModels);
|
|
18549
19007
|
return prompt.text({
|
|
18550
19008
|
message: `Default model for ${meta.label} (no models detected)`,
|
|
18551
19009
|
placeholder: meta.fallbackModelID,
|
|
18552
19010
|
initial: meta.fallbackModelID
|
|
18553
19011
|
});
|
|
18554
19012
|
}
|
|
18555
|
-
const first = preferredModelID(
|
|
19013
|
+
const first = preferredModelID(offered, modelInfo, meta.id);
|
|
18556
19014
|
const opts = {
|
|
18557
19015
|
message: `Default local model for ${meta.label}`,
|
|
18558
|
-
choices: orderModelChoices(
|
|
19016
|
+
choices: orderModelChoices(offered, modelInfo, meta.id)
|
|
18559
19017
|
};
|
|
18560
19018
|
if (first !== undefined) {
|
|
18561
19019
|
opts.initial = first;
|
|
18562
19020
|
}
|
|
18563
|
-
|
|
19021
|
+
const selected = await prompt.select(opts);
|
|
19022
|
+
if (meta.id === "lemonade" && !offered.includes(selected))
|
|
19023
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(selected));
|
|
19024
|
+
return selected;
|
|
18564
19025
|
}
|
|
18565
19026
|
function remoteBaseURLExample(meta) {
|
|
18566
19027
|
const base = meta.defaultBaseURL ?? "http://localhost:11434/v1";
|
|
@@ -18615,6 +19076,8 @@ async function resolveRuntimeConnection(deps, meta, info) {
|
|
|
18615
19076
|
initial: RUNTIME_LOCATION_LOCAL
|
|
18616
19077
|
});
|
|
18617
19078
|
if (location === RUNTIME_LOCATION_LOCAL) {
|
|
19079
|
+
if (meta.id === "lemonade" && info?.reachable !== true)
|
|
19080
|
+
throw new Error(executionSetupMessages.lemonadeProbeFailed);
|
|
18618
19081
|
const baseURL2 = info?.baseURL !== undefined && info.baseURL.length > 0 ? info.baseURL : meta.defaultBaseURL;
|
|
18619
19082
|
return { baseURL: baseURL2, ...connectionOf(info) };
|
|
18620
19083
|
}
|
|
@@ -18624,16 +19087,26 @@ async function resolveRuntimeConnection(deps, meta, info) {
|
|
|
18624
19087
|
});
|
|
18625
19088
|
const baseURL = normalizeRemoteBaseURL(entered, meta.defaultBaseURL);
|
|
18626
19089
|
let probedRuntime;
|
|
19090
|
+
if (meta.id === "lemonade" && deps.probeRuntime === undefined)
|
|
19091
|
+
throw new Error(executionSetupMessages.lemonadeProbeRequired);
|
|
18627
19092
|
if (deps.probeRuntime !== undefined) {
|
|
18628
19093
|
try {
|
|
18629
19094
|
probedRuntime = await deps.probeRuntime(meta.id, baseURL);
|
|
18630
|
-
} catch {
|
|
19095
|
+
} catch (cause) {
|
|
19096
|
+
if (meta.id === "lemonade")
|
|
19097
|
+
throw new Error(executionSetupMessages.lemonadeProbeFailed, { cause });
|
|
19098
|
+
}
|
|
19099
|
+
if (meta.id === "lemonade" && probedRuntime?.reachable !== true)
|
|
19100
|
+
throw new Error(executionSetupMessages.lemonadeProbeFailed);
|
|
18631
19101
|
}
|
|
18632
19102
|
return { baseURL, ...connectionOf(probedRuntime) };
|
|
18633
19103
|
}
|
|
18634
19104
|
async function chooseClassModel(prompt, models, meta, defaultModelID, modelClass, modelInfo) {
|
|
18635
19105
|
const label = modelClass === "thinking" ? `Thinking model for ${meta.label} (design, analysis, review reasoning)` : `Coder model for ${meta.label} (writing and editing code)`;
|
|
18636
|
-
|
|
19106
|
+
const offered = selectableModelIDs(models, modelInfo, meta.id);
|
|
19107
|
+
if (offered.length === 0) {
|
|
19108
|
+
if (meta.id === "lemonade")
|
|
19109
|
+
throw new Error(executionSetupMessages.lemonadeNoLoadedModels);
|
|
18637
19110
|
const raw = await prompt.text({
|
|
18638
19111
|
message: `${label} — enter to reuse the default`,
|
|
18639
19112
|
placeholder: defaultModelID,
|
|
@@ -18641,14 +19114,17 @@ async function chooseClassModel(prompt, models, meta, defaultModelID, modelClass
|
|
|
18641
19114
|
});
|
|
18642
19115
|
return raw.trim().length > 0 ? raw.trim() : defaultModelID;
|
|
18643
19116
|
}
|
|
18644
|
-
|
|
19117
|
+
const selected = await prompt.select({
|
|
18645
19118
|
message: label,
|
|
18646
|
-
choices: orderModelChoices(
|
|
19119
|
+
choices: orderModelChoices(offered, modelInfo, meta.id).map((choice) => ({
|
|
18647
19120
|
value: choice.value,
|
|
18648
19121
|
label: choice.value === defaultModelID ? `${choice.label} — default` : choice.label
|
|
18649
19122
|
})),
|
|
18650
19123
|
initial: defaultModelID
|
|
18651
19124
|
});
|
|
19125
|
+
if (meta.id === "lemonade" && !offered.includes(selected))
|
|
19126
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(selected));
|
|
19127
|
+
return selected;
|
|
18652
19128
|
}
|
|
18653
19129
|
async function resolveEnabledRuntime(deps, meta, info) {
|
|
18654
19130
|
const connection = await resolveRuntimeConnection(deps, meta, info);
|
|
@@ -18661,7 +19137,8 @@ async function resolveEnabledRuntime(deps, meta, info) {
|
|
|
18661
19137
|
defaultModelID,
|
|
18662
19138
|
thinkingModelID,
|
|
18663
19139
|
coderModelID,
|
|
18664
|
-
models: connection.models
|
|
19140
|
+
models: selectableModelIDs(connection.models, connection.modelInfo, meta.id),
|
|
19141
|
+
...connection.modelInfo === undefined ? {} : { modelInfo: connection.modelInfo }
|
|
18665
19142
|
};
|
|
18666
19143
|
if (connection.baseURL !== undefined) {
|
|
18667
19144
|
choice.baseURL = connection.baseURL;
|
|
@@ -19161,17 +19638,52 @@ async function readExistingOpencodeConfigFiles(paths, deps) {
|
|
|
19161
19638
|
function opencodeFileAt(files, path2) {
|
|
19162
19639
|
return files.find((file) => file.path === path2);
|
|
19163
19640
|
}
|
|
19164
|
-
function mergeExistingOpencodeConfigFiles(files) {
|
|
19641
|
+
function mergeExistingOpencodeConfigFiles(files, paths, planned = new Map) {
|
|
19165
19642
|
let merged;
|
|
19166
|
-
for (const path2 of [...
|
|
19167
|
-
const
|
|
19168
|
-
if (
|
|
19643
|
+
for (const path2 of [...paths].reverse()) {
|
|
19644
|
+
const raw = planned.get(path2) ?? opencodeFileAt(files, path2)?.raw;
|
|
19645
|
+
if (raw === undefined) {
|
|
19169
19646
|
continue;
|
|
19170
19647
|
}
|
|
19171
|
-
merged = merged === undefined ?
|
|
19648
|
+
merged = merged === undefined ? raw : mergeOpencodeConfigs(merged, raw);
|
|
19172
19649
|
}
|
|
19173
19650
|
return merged;
|
|
19174
19651
|
}
|
|
19652
|
+
async function effectiveSetupConfig(portable, files, deps) {
|
|
19653
|
+
const optionsByLoader = new Map;
|
|
19654
|
+
for (const file of files) {
|
|
19655
|
+
if (!Array.isArray(file.raw.plugin))
|
|
19656
|
+
continue;
|
|
19657
|
+
for (const entry of [...file.raw.plugin].reverse()) {
|
|
19658
|
+
const spec = extractPluginSpec(entry);
|
|
19659
|
+
if (spec === undefined)
|
|
19660
|
+
continue;
|
|
19661
|
+
let identity;
|
|
19662
|
+
if (isOpenteamNpmSpec(spec)) {
|
|
19663
|
+
identity = OPENTEAM_PACKAGE_NAME;
|
|
19664
|
+
} else if (isLocalFileSpec(spec) && await classifyLocalPluginSpecForSetup(spec, file.path, deps.classifyLocalPluginSpec) === "ours") {
|
|
19665
|
+
const resolved = resolvePluginSpecPath(spec, file.path);
|
|
19666
|
+
if (resolved === undefined)
|
|
19667
|
+
throw new Error(executionSetupMessages.lemonadeEffectiveConfigAmbiguous);
|
|
19668
|
+
identity = resolved;
|
|
19669
|
+
} else {
|
|
19670
|
+
continue;
|
|
19671
|
+
}
|
|
19672
|
+
if (!optionsByLoader.has(identity)) {
|
|
19673
|
+
optionsByLoader.set(identity, Array.isArray(entry) ? entry[1] : undefined);
|
|
19674
|
+
}
|
|
19675
|
+
}
|
|
19676
|
+
}
|
|
19677
|
+
const overlayText = await deps.readFile(DEFAULT_LOCAL_OVERLAY_PATH);
|
|
19678
|
+
const overlay = overlayText === undefined ? undefined : parseConfigFileJson(DEFAULT_LOCAL_OVERLAY_PATH, overlayText);
|
|
19679
|
+
const resolutions = [
|
|
19680
|
+
...optionsByLoader.size > 0 ? optionsByLoader.values() : [undefined]
|
|
19681
|
+
].map((options) => validateConfigInput(executionSetupMessages.lemonadeEffectiveConfigLabel, mergeConfigInputs(mergeConfigInputs(portable, configOptionsFromPluginOptions(options)), overlay)));
|
|
19682
|
+
const effective = resolutions[0];
|
|
19683
|
+
if (effective === undefined || resolutions.some((config) => JSON.stringify(config) !== JSON.stringify(effective)))
|
|
19684
|
+
throw new Error(executionSetupMessages.lemonadeEffectiveConfigAmbiguous);
|
|
19685
|
+
return effective;
|
|
19686
|
+
}
|
|
19175
19687
|
function relevantLocalProviderIDs(generated, existingOpenTeamConfig) {
|
|
19176
19688
|
const ids = new Set(Object.keys(generated.provider ?? {}));
|
|
19177
19689
|
for (const runtime of existingOpenTeamConfig?.local.runtimes ?? []) {
|
|
@@ -19348,15 +19860,42 @@ function highestExistingPinVersion(files) {
|
|
|
19348
19860
|
}
|
|
19349
19861
|
return highest;
|
|
19350
19862
|
}
|
|
19863
|
+
function reconcileLemonadeV2Policies(raw, denials) {
|
|
19864
|
+
if (denials.length === 0)
|
|
19865
|
+
return raw;
|
|
19866
|
+
const experimental = raw.experimental;
|
|
19867
|
+
if (experimental !== undefined && !isRecord6(experimental))
|
|
19868
|
+
throw new Error(executionSetupMessages.lemonadeV2InvalidPolicies);
|
|
19869
|
+
const policies = experimental?.policies;
|
|
19870
|
+
if (policies !== undefined && !Array.isArray(policies))
|
|
19871
|
+
throw new Error(executionSetupMessages.lemonadeV2InvalidPolicies);
|
|
19872
|
+
const existing = policies ?? [];
|
|
19873
|
+
for (const policy of existing) {
|
|
19874
|
+
if (!isRecord6(policy) || policy.action !== "provider.use" || typeof policy.resource !== "string" || policy.effect !== "allow" && policy.effect !== "deny")
|
|
19875
|
+
throw new Error(executionSetupMessages.lemonadeV2InvalidPolicies);
|
|
19876
|
+
}
|
|
19877
|
+
const terminal = denials.every((denial, index) => {
|
|
19878
|
+
const policy = existing[existing.length - denials.length + index];
|
|
19879
|
+
return isRecord6(policy) && Object.keys(policy).length === 3 && policy.action === denial.action && policy.resource === denial.resource && policy.effect === denial.effect;
|
|
19880
|
+
});
|
|
19881
|
+
if (terminal)
|
|
19882
|
+
return raw;
|
|
19883
|
+
return {
|
|
19884
|
+
...raw,
|
|
19885
|
+
experimental: { ...experimental, policies: [...existing, ...denials] }
|
|
19886
|
+
};
|
|
19887
|
+
}
|
|
19351
19888
|
function mergeOpencodeConfigForRerun(generated, targetRaw, options) {
|
|
19352
19889
|
const effectiveRaw = options.effectiveRaw ?? targetRaw;
|
|
19353
19890
|
const includePlugin = options.includePlugin ?? true;
|
|
19891
|
+
const managesV2Policies = (generated.experimental?.policies.length ?? 0) > 0;
|
|
19354
19892
|
const managedKeys = new Set([
|
|
19355
19893
|
"$schema",
|
|
19356
19894
|
"provider",
|
|
19357
19895
|
"model",
|
|
19358
19896
|
"small_model",
|
|
19359
19897
|
"permission",
|
|
19898
|
+
...managesV2Policies ? ["experimental"] : [],
|
|
19360
19899
|
...includePlugin ? ["plugin"] : []
|
|
19361
19900
|
]);
|
|
19362
19901
|
const unknownFields = {};
|
|
@@ -19419,7 +19958,10 @@ function mergeOpencodeConfigForRerun(generated, targetRaw, options) {
|
|
|
19419
19958
|
if (permission !== undefined) {
|
|
19420
19959
|
result.permission = permission;
|
|
19421
19960
|
}
|
|
19422
|
-
|
|
19961
|
+
if (managesV2Policies && hasOwn2(targetRaw, "experimental")) {
|
|
19962
|
+
result.experimental = targetRaw.experimental;
|
|
19963
|
+
}
|
|
19964
|
+
return reconcileLemonadeV2Policies(result, generated.experimental?.policies ?? []);
|
|
19423
19965
|
}
|
|
19424
19966
|
function mergeOpenTeamConfigForRerun(generated, existing) {
|
|
19425
19967
|
const existingOrch = existing.orchestrator;
|
|
@@ -19469,6 +20011,21 @@ function mergeOpenTeamConfigForRerun(generated, existing) {
|
|
|
19469
20011
|
assertEffectiveConfigModelDomains(merged);
|
|
19470
20012
|
return merged;
|
|
19471
20013
|
}
|
|
20014
|
+
function preserveRetainedLemonadeRuntimes(generated, previous, opencode) {
|
|
20015
|
+
const providers = recordAt2(opencode, "provider") ?? {};
|
|
20016
|
+
const retained = (previous?.local.runtimes ?? []).filter((runtime) => localRuntimeKind(runtime) === "lemonade" && hasOwn2(providers, runtime.defaultModel.providerID));
|
|
20017
|
+
const deselected = retained.filter((runtime) => !generated.local.runtimes.some((selected) => selected.defaultModel.providerID === runtime.defaultModel.providerID)).map((runtime) => ({ ...runtime, enabled: false }));
|
|
20018
|
+
return {
|
|
20019
|
+
config: deselected.length === 0 ? generated : OpenTeamConfigSchema.parse({
|
|
20020
|
+
...generated,
|
|
20021
|
+
local: {
|
|
20022
|
+
...generated.local,
|
|
20023
|
+
runtimes: [...generated.local.runtimes, ...deselected]
|
|
20024
|
+
}
|
|
20025
|
+
}),
|
|
20026
|
+
providerIDs: retained.map((runtime) => runtime.defaultModel.providerID)
|
|
20027
|
+
};
|
|
20028
|
+
}
|
|
19472
20029
|
async function existingPluginOwnerPath(files, classifyLocalPluginSpec) {
|
|
19473
20030
|
let unknownLocalPlugin;
|
|
19474
20031
|
for (const file of files) {
|
|
@@ -19496,6 +20053,86 @@ async function confirmJsonNormalization(prompt, path2, format) {
|
|
|
19496
20053
|
initial: false
|
|
19497
20054
|
});
|
|
19498
20055
|
}
|
|
20056
|
+
function assertPreviousLemonadePrimary(answers, previousConfig) {
|
|
20057
|
+
const priorLemonadePrimary = previousConfig?.local.runtimes.some((runtime) => runtime.defaultModel.providerID === answers.primaryModel.providerID && localRuntimeKind(runtime) === "lemonade");
|
|
20058
|
+
if (priorLemonadePrimary && !answers.runtimes.some((choice) => choice.enabled && choiceProviderID(choice) === answers.primaryModel.providerID)) {
|
|
20059
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${answers.primaryModel.providerID}/${answers.primaryModel.modelID}`));
|
|
20060
|
+
}
|
|
20061
|
+
}
|
|
20062
|
+
async function verifyLemonadeBeforeWrite(deps, answers, config, opencode) {
|
|
20063
|
+
for (const choice of answers.runtimes) {
|
|
20064
|
+
if (choice.enabled && localRuntimeKind(choice) === "lemonade" && !config.local.runtimes.some((runtime) => runtime.enabled && runtime.defaultModel.providerID === choiceProviderID(choice) && localRuntimeKind(runtime) === "lemonade"))
|
|
20065
|
+
throw new Error(executionSetupMessages.lemonadeEndpointMismatch);
|
|
20066
|
+
}
|
|
20067
|
+
for (const runtime of config.local.runtimes) {
|
|
20068
|
+
if (localRuntimeKind(runtime) !== "lemonade")
|
|
20069
|
+
continue;
|
|
20070
|
+
const providerID = runtime.defaultModel.providerID;
|
|
20071
|
+
const provider = isRecord6(opencode.provider) ? opencode.provider[providerID] : undefined;
|
|
20072
|
+
if (!runtime.enabled && provider === undefined)
|
|
20073
|
+
continue;
|
|
20074
|
+
const endpoint = isRecord6(provider) ? (isRecord6(provider.options) ? provider.options.baseURL : undefined) ?? provider.api : undefined;
|
|
20075
|
+
if (typeof endpoint !== "string" || lemonadeBaseURL(endpoint) !== lemonadeBaseURL(runtime.baseURL ?? LEMONADE_DEFAULT_BASE_URL) || config.local.runtimes.filter((candidate) => candidate.defaultModel.providerID === providerID).length !== 1)
|
|
20076
|
+
throw new Error(executionSetupMessages.lemonadeEndpointMismatch);
|
|
20077
|
+
if (!runtime.enabled)
|
|
20078
|
+
continue;
|
|
20079
|
+
if (deps.probeRuntime === undefined)
|
|
20080
|
+
throw new Error(executionSetupMessages.lemonadeProbeRequired);
|
|
20081
|
+
const references2 = new Set([
|
|
20082
|
+
runtime.defaultModel.modelID,
|
|
20083
|
+
runtime.thinkingModel,
|
|
20084
|
+
runtime.coderModel
|
|
20085
|
+
]);
|
|
20086
|
+
for (const choice of answers.runtimes) {
|
|
20087
|
+
if (choice.enabled && choiceProviderID(choice) === providerID) {
|
|
20088
|
+
for (const id of [
|
|
20089
|
+
...choice.models,
|
|
20090
|
+
choice.defaultModelID,
|
|
20091
|
+
choice.thinkingModelID,
|
|
20092
|
+
choice.coderModelID
|
|
20093
|
+
])
|
|
20094
|
+
references2.add(id);
|
|
20095
|
+
}
|
|
20096
|
+
}
|
|
20097
|
+
for (const ref of [
|
|
20098
|
+
answers.primaryModel,
|
|
20099
|
+
config.orchestrator?.primary?.model,
|
|
20100
|
+
config.router.localDefault
|
|
20101
|
+
]) {
|
|
20102
|
+
if (ref !== null && typeof ref === "object" && ref.providerID === providerID)
|
|
20103
|
+
references2.add(ref.modelID);
|
|
20104
|
+
}
|
|
20105
|
+
for (const key of ["model", "small_model"]) {
|
|
20106
|
+
const ref = opencode[key];
|
|
20107
|
+
if (typeof ref === "string" && ref.startsWith(`${providerID}/`))
|
|
20108
|
+
references2.add(ref.slice(providerID.length + 1));
|
|
20109
|
+
}
|
|
20110
|
+
const models = isRecord6(provider) ? recordAt2(provider, "models") : undefined;
|
|
20111
|
+
const wireIDs = new Set;
|
|
20112
|
+
for (const alias of references2) {
|
|
20113
|
+
if (alias === undefined)
|
|
20114
|
+
continue;
|
|
20115
|
+
const declaration = recordAt2(models, alias);
|
|
20116
|
+
const wireID = declaration !== undefined && hasOwn2(declaration, "id") ? declaration.id : alias;
|
|
20117
|
+
if (declaration === undefined || typeof wireID !== "string" || wireID.length === 0 || wireID !== wireID.trim())
|
|
20118
|
+
throw new Error(executionSetupMessages.lemonadeModelIdentityUnknown(`${providerID}/${alias}`));
|
|
20119
|
+
wireIDs.add(wireID);
|
|
20120
|
+
}
|
|
20121
|
+
let fresh;
|
|
20122
|
+
try {
|
|
20123
|
+
fresh = await deps.probeRuntime(localRuntimeKind(runtime), endpoint);
|
|
20124
|
+
} catch (cause) {
|
|
20125
|
+
throw new Error(executionSetupMessages.lemonadeProbeFailed, { cause });
|
|
20126
|
+
}
|
|
20127
|
+
if (!fresh.reachable || fresh.id !== localRuntimeKind(runtime) || fresh.baseURL.replace(/\/+$/, "") !== endpoint.replace(/\/+$/, ""))
|
|
20128
|
+
throw new Error(executionSetupMessages.lemonadeProbeFailed);
|
|
20129
|
+
for (const wireID of wireIDs) {
|
|
20130
|
+
const info = fresh.models.includes(wireID) ? fresh.modelInfo?.find((model) => model.modelID === wireID) : undefined;
|
|
20131
|
+
if (!hasRequiredModelResidency("lemonade", info))
|
|
20132
|
+
throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${providerID}/${wireID}`));
|
|
20133
|
+
}
|
|
20134
|
+
}
|
|
20135
|
+
}
|
|
19499
20136
|
async function runSetup(deps) {
|
|
19500
20137
|
const { prompt } = deps;
|
|
19501
20138
|
try {
|
|
@@ -19507,7 +20144,7 @@ async function runSetup(deps) {
|
|
|
19507
20144
|
return {
|
|
19508
20145
|
value: meta.id,
|
|
19509
20146
|
label: meta.label,
|
|
19510
|
-
hint: info?.reachable ? `detected · ${info.models.length} model(s)` : "not detected (you can point it to another machine)",
|
|
20147
|
+
hint: info?.reachable ? meta.id === "lemonade" ? executionSetupMessages.lemonadeDetectedHint(selectableModelIDs(info.models, info.modelInfo, meta.id).length, info.modelInfo?.length ?? info.models.length) : `detected · ${info.models.length} model(s)` : "not detected (you can point it to another machine)",
|
|
19511
20148
|
selected: info?.reachable ?? false
|
|
19512
20149
|
};
|
|
19513
20150
|
});
|
|
@@ -19624,17 +20261,18 @@ async function runSetup(deps) {
|
|
|
19624
20261
|
};
|
|
19625
20262
|
const openTeamConfig = buildOpenTeamConfig(answers);
|
|
19626
20263
|
const opencodeConfig = buildOpencodeConfig(answers);
|
|
20264
|
+
const opencodeConfigPaths = LEMONADE_PROJECT_CONFIG_CANDIDATES;
|
|
19627
20265
|
const orchestratorAgent = buildOrchestratorAgent(orchestratorAgentModel(answers), { yolo });
|
|
19628
20266
|
const slashCommands = buildOpenteamCommands();
|
|
19629
20267
|
const openTeamPath = DEFAULT_CONFIG_PATH;
|
|
19630
|
-
const existingOpencodePath = await deps.resolveOpencodeWriteTarget(
|
|
20268
|
+
const existingOpencodePath = await deps.resolveOpencodeWriteTarget(opencodeConfigPaths);
|
|
19631
20269
|
const opencodeDataPath = existingOpencodePath ?? OPENCODE_CONFIG_CANDIDATES[0];
|
|
19632
20270
|
const agentPath = ORCHESTRATOR_AGENT_PATH;
|
|
19633
20271
|
let existingOpenTeamConfig;
|
|
19634
20272
|
let existingOpencodeFiles;
|
|
19635
20273
|
try {
|
|
19636
20274
|
existingOpenTeamConfig = await readExistingOpenTeamConfig(openTeamPath, deps);
|
|
19637
|
-
existingOpencodeFiles = await readExistingOpencodeConfigFiles(
|
|
20275
|
+
existingOpencodeFiles = await readExistingOpencodeConfigFiles(opencodeConfigPaths, deps);
|
|
19638
20276
|
} catch (error) {
|
|
19639
20277
|
if (error instanceof ConfigParseError) {
|
|
19640
20278
|
return {
|
|
@@ -19644,7 +20282,29 @@ async function runSetup(deps) {
|
|
|
19644
20282
|
}
|
|
19645
20283
|
throw error;
|
|
19646
20284
|
}
|
|
19647
|
-
|
|
20285
|
+
assertPreviousLemonadePrimary(answers, existingOpenTeamConfig);
|
|
20286
|
+
const effectiveExistingOpencode = mergeExistingOpencodeConfigFiles(existingOpencodeFiles, opencodeConfigPaths);
|
|
20287
|
+
const {
|
|
20288
|
+
config: finalOpenTeamConfig,
|
|
20289
|
+
providerIDs: retainedLemonadeProviderIDs
|
|
20290
|
+
} = preserveRetainedLemonadeRuntimes(existingOpenTeamConfig !== undefined ? mergeOpenTeamConfigForRerun(openTeamConfig, existingOpenTeamConfig) : openTeamConfig, existingOpenTeamConfig, effectiveExistingOpencode);
|
|
20291
|
+
assertEffectiveConfigModelDomains(finalOpenTeamConfig);
|
|
20292
|
+
const effectiveOpenTeamConfig = await effectiveSetupConfig(finalOpenTeamConfig, existingOpencodeFiles, deps);
|
|
20293
|
+
assertEffectiveConfigModelDomains(effectiveOpenTeamConfig);
|
|
20294
|
+
for (const providerID of retainedLemonadeProviderIDs) {
|
|
20295
|
+
const matches = effectiveOpenTeamConfig.local.runtimes.filter((runtime) => runtime.defaultModel.providerID === providerID);
|
|
20296
|
+
if (matches.length !== 1 || matches[0] === undefined || localRuntimeKind(matches[0]) !== "lemonade")
|
|
20297
|
+
throw new Error(executionSetupMessages.lemonadeRetainedProviderUnprotected(providerID));
|
|
20298
|
+
}
|
|
20299
|
+
const v2Denials = lemonadeV2Policies([
|
|
20300
|
+
...opencodeConfig.experimental?.policies.map((policy) => policy.resource) ?? [],
|
|
20301
|
+
...effectiveOpenTeamConfig.local.runtimes.filter((runtime) => localRuntimeKind(runtime) === "lemonade").map((runtime) => runtime.defaultModel.providerID)
|
|
20302
|
+
]);
|
|
20303
|
+
if (v2Denials.length > 0)
|
|
20304
|
+
opencodeConfig.experimental = { policies: v2Denials };
|
|
20305
|
+
const v2Notice = v2Denials.length > 0 ? executionSetupMessages.lemonadeV2Restriction(v2Denials.map((policy) => policy.resource)) : undefined;
|
|
20306
|
+
if (v2Notice !== undefined)
|
|
20307
|
+
prompt.note(v2Notice, executionSetupMessages.lemonadeV2Title);
|
|
19648
20308
|
const relevantProviderIDs = relevantLocalProviderIDs(opencodeConfig, existingOpenTeamConfig);
|
|
19649
20309
|
for (const file of existingOpencodeFiles) {
|
|
19650
20310
|
assertRelevantLimitNumbers(file, relevantProviderIDs);
|
|
@@ -19673,8 +20333,6 @@ async function runSetup(deps) {
|
|
|
19673
20333
|
const pluginOwnerFile = opencodeFileAt(existingOpencodeFiles, pluginOwnerPath);
|
|
19674
20334
|
const pluginPlan = await mergePluginEntriesForRerun(Array.isArray(pluginOwnerFile?.raw.plugin) ? pluginOwnerFile.raw.plugin : [], pluginOwnerPath, preservePlugin, deps.classifyLocalPluginSpec);
|
|
19675
20335
|
const includePluginInDataFile = pluginOwnerPath === opencodeDataPath;
|
|
19676
|
-
const finalOpenTeamConfig = existingOpenTeamConfig !== undefined ? mergeOpenTeamConfigForRerun(openTeamConfig, existingOpenTeamConfig) : openTeamConfig;
|
|
19677
|
-
assertEffectiveConfigModelDomains(finalOpenTeamConfig);
|
|
19678
20336
|
const dataTargetRaw = opencodeFileAt(existingOpencodeFiles, opencodeDataPath)?.raw ?? {};
|
|
19679
20337
|
const mergedOpencodeRaw = mergeOpencodeConfigForRerun(opencodeConfig, dataTargetRaw, {
|
|
19680
20338
|
...effectiveExistingOpencode !== undefined ? { effectiveRaw: effectiveExistingOpencode } : {},
|
|
@@ -19689,7 +20347,7 @@ async function runSetup(deps) {
|
|
|
19689
20347
|
providerIDs: relevantProviderIDs
|
|
19690
20348
|
});
|
|
19691
20349
|
const opencodeWritePlan = new Map([
|
|
19692
|
-
[opencodeDataPath,
|
|
20350
|
+
[opencodeDataPath, repairedDataTarget.raw]
|
|
19693
20351
|
]);
|
|
19694
20352
|
for (const file of existingOpencodeFiles) {
|
|
19695
20353
|
if (file.path === opencodeDataPath) {
|
|
@@ -19701,14 +20359,14 @@ async function runSetup(deps) {
|
|
|
19701
20359
|
generated: opencodeConfig,
|
|
19702
20360
|
providerIDs: relevantProviderIDs
|
|
19703
20361
|
});
|
|
19704
|
-
let plannedRaw = repaired.raw;
|
|
19705
|
-
let changed = repaired.changed;
|
|
20362
|
+
let plannedRaw = reconcileLemonadeV2Policies(repaired.raw, v2Denials);
|
|
20363
|
+
let changed = repaired.changed || plannedRaw !== repaired.raw;
|
|
19706
20364
|
if (file.path === pluginOwnerPath && !includePluginInDataFile && pluginPlan.changed) {
|
|
19707
20365
|
plannedRaw = { ...plannedRaw, plugin: [...pluginPlan.plugins] };
|
|
19708
20366
|
changed = true;
|
|
19709
20367
|
}
|
|
19710
20368
|
if (changed) {
|
|
19711
|
-
opencodeWritePlan.set(file.path,
|
|
20369
|
+
opencodeWritePlan.set(file.path, plannedRaw);
|
|
19712
20370
|
}
|
|
19713
20371
|
}
|
|
19714
20372
|
const opencodeGitignorePath = OPENCODE_GITIGNORE_PATH;
|
|
@@ -19772,9 +20430,13 @@ async function runSetup(deps) {
|
|
|
19772
20430
|
stdout: shouldWriteOpencodeGitignore ? `setup cancelled by user; ${OPENCODE_GITIGNORE_PATH} ensured` : "setup cancelled by user"
|
|
19773
20431
|
};
|
|
19774
20432
|
}
|
|
20433
|
+
const effectivePlannedOpencode = mergeExistingOpencodeConfigFiles(existingOpencodeFiles, opencodeConfigPaths, opencodeWritePlan);
|
|
20434
|
+
if (effectivePlannedOpencode === undefined)
|
|
20435
|
+
throw new Error(executionSetupMessages.lemonadeEndpointMismatch);
|
|
20436
|
+
await verifyLemonadeBeforeWrite(deps, answers, effectiveOpenTeamConfig, effectivePlannedOpencode);
|
|
19775
20437
|
await deps.writeFile(openTeamPath, serializeOpenTeamConfig(finalOpenTeamConfig));
|
|
19776
20438
|
for (const [path2, contents] of opencodeWritePlan) {
|
|
19777
|
-
await deps.writeFile(path2, contents);
|
|
20439
|
+
await deps.writeFile(path2, serializeOpencodeConfig(contents));
|
|
19778
20440
|
}
|
|
19779
20441
|
await deps.writeFile(agentPath, orchestratorAgent);
|
|
19780
20442
|
for (const command of slashCommands) {
|
|
@@ -19805,7 +20467,11 @@ async function runSetup(deps) {
|
|
|
19805
20467
|
prompt.outro(executionSetupMessages.done);
|
|
19806
20468
|
return {
|
|
19807
20469
|
exitCode: 0,
|
|
19808
|
-
stdout:
|
|
20470
|
+
stdout: [
|
|
20471
|
+
executionSetupMessages.complete(`${writtenOpencodePaths}, ${DEFAULT_CONFIG_PATH}, ${ORCHESTRATOR_AGENT_PATH}, ${OPENTEAM_COMMAND_DIR}/*.md, ${OPENCODE_GITIGNORE_PATH}`),
|
|
20472
|
+
...v2Notice === undefined ? [] : [v2Notice]
|
|
20473
|
+
].join(`
|
|
20474
|
+
`)
|
|
19809
20475
|
};
|
|
19810
20476
|
} catch (error) {
|
|
19811
20477
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -20460,7 +21126,7 @@ import {
|
|
|
20460
21126
|
import { basename as basename3, dirname as dirname8, join as join19, relative as relative2, resolve as resolve11, win32 } from "node:path";
|
|
20461
21127
|
import { fileURLToPath } from "node:url";
|
|
20462
21128
|
import { promisify as promisify2 } from "node:util";
|
|
20463
|
-
import { z as
|
|
21129
|
+
import { z as z25 } from "zod";
|
|
20464
21130
|
var NPM_ORIGIN = "https://registry.npmjs.org";
|
|
20465
21131
|
var NPM_PACKAGE_PATH = "/@jmanuelcorral%2Fopenteam";
|
|
20466
21132
|
var NPM_LATEST_URL = `${NPM_ORIGIN}${NPM_PACKAGE_PATH}/latest`;
|
|
@@ -20479,9 +21145,9 @@ var UPGRADE_BACKUP_DIRECTORY = ".opencode/openteam-local/upgrade-backups";
|
|
|
20479
21145
|
function npmVersionUrl(version) {
|
|
20480
21146
|
return `${NPM_ORIGIN}${NPM_PACKAGE_PATH}/${version}`;
|
|
20481
21147
|
}
|
|
20482
|
-
var RegistryPackageIdentitySchema =
|
|
20483
|
-
name:
|
|
20484
|
-
version:
|
|
21148
|
+
var RegistryPackageIdentitySchema = z25.object({
|
|
21149
|
+
name: z25.string(),
|
|
21150
|
+
version: z25.string()
|
|
20485
21151
|
}).strict();
|
|
20486
21152
|
|
|
20487
21153
|
class TransientFetchError extends Error {
|
|
@@ -22140,12 +22806,19 @@ function defaultModelFromOpencode(opencodeConfig) {
|
|
|
22140
22806
|
}
|
|
22141
22807
|
return;
|
|
22142
22808
|
}
|
|
22143
|
-
function liveModelsFromSnapshots(snapshots) {
|
|
22809
|
+
function liveModelsFromSnapshots(snapshots, config) {
|
|
22144
22810
|
const map = new Map;
|
|
22145
22811
|
for (const snapshot of snapshots) {
|
|
22146
|
-
|
|
22812
|
+
const runtime = config.local.runtimes.find((runtime2) => runtime2.id === snapshot.id);
|
|
22813
|
+
if (runtime === undefined || !runtime.enabled)
|
|
22814
|
+
continue;
|
|
22815
|
+
const kind = localRuntimeKind(runtime);
|
|
22816
|
+
map.set(runtime.defaultModel.providerID, {
|
|
22147
22817
|
reachable: snapshot.reachable,
|
|
22148
|
-
modelIDs: new Set(snapshot.models.map((model) => model.modelID))
|
|
22818
|
+
modelIDs: new Set(snapshot.models.filter((model) => hasRequiredModelResidency(kind, model)).map((model) => model.modelID)),
|
|
22819
|
+
...kind === "lemonade" ? {
|
|
22820
|
+
residency: new Map(snapshot.models.map((model) => [model.modelID, model.loaded]))
|
|
22821
|
+
} : {}
|
|
22149
22822
|
});
|
|
22150
22823
|
}
|
|
22151
22824
|
return map;
|
|
@@ -22431,7 +23104,7 @@ async function runCli(argv, deps) {
|
|
|
22431
23104
|
const agentModels = diagnoseAgentModels(agentFiles, {
|
|
22432
23105
|
opencodeProviders: parseOpencodeProviders(opencodeConfig),
|
|
22433
23106
|
localRuntimes: localRuntimeStates(config),
|
|
22434
|
-
liveModels: liveModelsFromSnapshots(snapshots),
|
|
23107
|
+
liveModels: liveModelsFromSnapshots(snapshots, config),
|
|
22435
23108
|
sourceDir: deps.agentDir,
|
|
22436
23109
|
...defaultModel !== undefined ? { defaultModel } : {}
|
|
22437
23110
|
});
|
|
@@ -22470,29 +23143,53 @@ async function runCli(argv, deps) {
|
|
|
22470
23143
|
const rosterMissing = deps.loadRosterForDoctor !== undefined && roster === undefined && rosterLoadError === undefined;
|
|
22471
23144
|
const orchestratorAgentName = ORCHESTRATOR_AGENT_PATH.slice(ORCHESTRATOR_AGENT_PATH.lastIndexOf("/") + 1).replace(/\.md$/, "");
|
|
22472
23145
|
const orchestratorAgentMissing = !agentFiles.some((file) => file.name === orchestratorAgentName);
|
|
23146
|
+
const inventoryNotes = [];
|
|
23147
|
+
const readySnapshots = snapshots.map((snapshot) => {
|
|
23148
|
+
const runtime = config.local.runtimes.find((runtime2) => runtime2.id === snapshot.id);
|
|
23149
|
+
if (runtime === undefined || localRuntimeKind(runtime) !== "lemonade")
|
|
23150
|
+
return snapshot;
|
|
23151
|
+
inventoryNotes.push(executionSetupMessages.lemonadeInventory(runtime.id, runtime.defaultModel.providerID, snapshot.models));
|
|
23152
|
+
return {
|
|
23153
|
+
...snapshot,
|
|
23154
|
+
models: snapshot.models.filter((model) => hasRequiredModelResidency(localRuntimeKind(runtime), model))
|
|
23155
|
+
};
|
|
23156
|
+
});
|
|
23157
|
+
const residencyNotes = agentModels.flatMap((agent) => {
|
|
23158
|
+
const live = agent.resolution?.live;
|
|
23159
|
+
if (agent.model === undefined || live !== "not-loaded" && live !== "residency-unknown")
|
|
23160
|
+
return [];
|
|
23161
|
+
return [
|
|
23162
|
+
executionSetupMessages.lemonadeAgentResidency(agent.name, `${agent.model.providerID}/${agent.model.modelID}`, live)
|
|
23163
|
+
];
|
|
23164
|
+
});
|
|
22473
23165
|
return {
|
|
22474
23166
|
exitCode: 0,
|
|
22475
|
-
stdout:
|
|
22476
|
-
|
|
22477
|
-
|
|
22478
|
-
|
|
22479
|
-
|
|
22480
|
-
|
|
22481
|
-
|
|
22482
|
-
|
|
22483
|
-
|
|
22484
|
-
|
|
22485
|
-
|
|
22486
|
-
|
|
22487
|
-
|
|
22488
|
-
|
|
22489
|
-
|
|
22490
|
-
|
|
22491
|
-
|
|
22492
|
-
|
|
22493
|
-
|
|
22494
|
-
|
|
22495
|
-
|
|
23167
|
+
stdout: [
|
|
23168
|
+
renderDoctor({
|
|
23169
|
+
config,
|
|
23170
|
+
snapshots: readySnapshots,
|
|
23171
|
+
telemetryPath,
|
|
23172
|
+
telemetryRecords: records.length,
|
|
23173
|
+
agentModels,
|
|
23174
|
+
opencodeConfigPaths,
|
|
23175
|
+
...opencodeConfig !== undefined ? { opencodeConfig } : {},
|
|
23176
|
+
...queueWait !== undefined ? { queueWait } : {},
|
|
23177
|
+
...rosterAudit !== undefined ? { rosterAudit } : {},
|
|
23178
|
+
...rosterRoleCount !== undefined ? { rosterRoleCount } : {},
|
|
23179
|
+
...rosterLoadError !== undefined ? { rosterLoadError } : {},
|
|
23180
|
+
...rosterMissing ? { rosterMissing } : {},
|
|
23181
|
+
...orchestratorAgentMissing ? { orchestratorAgentMissing } : {},
|
|
23182
|
+
...diagnostics !== undefined && diagnostics.length > 0 ? { diagnostics } : {},
|
|
23183
|
+
...opencodeConfigError !== undefined ? { opencodeConfigError } : {},
|
|
23184
|
+
...cacheEntries !== undefined ? { cacheEntries, cliVersion: deps.version } : {},
|
|
23185
|
+
...legacyLayout !== undefined && legacyLayout.length > 0 ? { legacyLayout } : {},
|
|
23186
|
+
...otelBackend !== undefined ? { otelBackend } : {},
|
|
23187
|
+
...gitignoreCoverage !== undefined ? { gitignore: gitignoreCoverage } : {}
|
|
23188
|
+
}),
|
|
23189
|
+
...inventoryNotes,
|
|
23190
|
+
...residencyNotes
|
|
23191
|
+
].join(`
|
|
23192
|
+
`)
|
|
22496
23193
|
};
|
|
22497
23194
|
}
|
|
22498
23195
|
if (command === "migrate") {
|
|
@@ -22609,14 +23306,14 @@ ${HELP}`
|
|
|
22609
23306
|
}
|
|
22610
23307
|
|
|
22611
23308
|
// src/orchestrator/roster.ts
|
|
22612
|
-
import { z as
|
|
22613
|
-
var RosterEntrySchema =
|
|
22614
|
-
roleID:
|
|
22615
|
-
agentName:
|
|
23309
|
+
import { z as z26 } from "zod";
|
|
23310
|
+
var RosterEntrySchema = z26.object({
|
|
23311
|
+
roleID: z26.string().min(1),
|
|
23312
|
+
agentName: z26.string().min(1)
|
|
22616
23313
|
}).strict();
|
|
22617
|
-
var RosterSchema =
|
|
22618
|
-
universe:
|
|
22619
|
-
entries:
|
|
23314
|
+
var RosterSchema = z26.object({
|
|
23315
|
+
universe: z26.string().min(1),
|
|
23316
|
+
entries: z26.array(RosterEntrySchema)
|
|
22620
23317
|
}).strict();
|
|
22621
23318
|
var ROSTER_JSON_FENCE = /```json\s*([\s\S]*?)```/;
|
|
22622
23319
|
|
|
@@ -23170,7 +23867,7 @@ import { readFile as readFile4 } from "node:fs/promises";
|
|
|
23170
23867
|
import { basename as basename4, dirname as dirname9 } from "node:path";
|
|
23171
23868
|
|
|
23172
23869
|
// src/graph/certificate.ts
|
|
23173
|
-
import { z as
|
|
23870
|
+
import { z as z27 } from "zod";
|
|
23174
23871
|
|
|
23175
23872
|
// src/contract/opencode.ts
|
|
23176
23873
|
var SUPPORTED_OPENCODE_VERSIONS = [
|
|
@@ -23211,7 +23908,7 @@ function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
|
|
|
23211
23908
|
|
|
23212
23909
|
// src/graph/certificate.ts
|
|
23213
23910
|
var SHADOW_CERTIFICATE_MIN_RUNS = 1000;
|
|
23214
|
-
var DivergenceCodeSchema =
|
|
23911
|
+
var DivergenceCodeSchema = z27.enum([
|
|
23215
23912
|
"status",
|
|
23216
23913
|
"order",
|
|
23217
23914
|
"roles",
|
|
@@ -23219,50 +23916,50 @@ var DivergenceCodeSchema = z26.enum([
|
|
|
23219
23916
|
"fixes",
|
|
23220
23917
|
"outcome"
|
|
23221
23918
|
]);
|
|
23222
|
-
var ProvenanceSchema =
|
|
23919
|
+
var ProvenanceSchema = z27.enum([
|
|
23223
23920
|
"recomputed",
|
|
23224
23921
|
"compiled",
|
|
23225
23922
|
"validated",
|
|
23226
23923
|
"carried"
|
|
23227
23924
|
]);
|
|
23228
|
-
var EvidenceSchema =
|
|
23229
|
-
opencodeVersion:
|
|
23230
|
-
parity:
|
|
23231
|
-
runs:
|
|
23232
|
-
match:
|
|
23233
|
-
divergent:
|
|
23234
|
-
inconclusive:
|
|
23235
|
-
divergences:
|
|
23925
|
+
var EvidenceSchema = z27.object({
|
|
23926
|
+
opencodeVersion: z27.string().min(1),
|
|
23927
|
+
parity: z27.object({
|
|
23928
|
+
runs: z27.number().int().nonnegative(),
|
|
23929
|
+
match: z27.number().int().nonnegative(),
|
|
23930
|
+
divergent: z27.number().int().nonnegative(),
|
|
23931
|
+
inconclusive: z27.number().int().nonnegative(),
|
|
23932
|
+
divergences: z27.array(DivergenceCodeSchema)
|
|
23236
23933
|
}).strict(),
|
|
23237
|
-
legacy:
|
|
23238
|
-
observed:
|
|
23239
|
-
duplicated:
|
|
23934
|
+
legacy: z27.object({
|
|
23935
|
+
observed: z27.number().int().nonnegative(),
|
|
23936
|
+
duplicated: z27.number().int().nonnegative()
|
|
23240
23937
|
}).strict(),
|
|
23241
|
-
privacy:
|
|
23242
|
-
surfacesScanned:
|
|
23243
|
-
rawFindings:
|
|
23938
|
+
privacy: z27.object({
|
|
23939
|
+
surfacesScanned: z27.number().int().nonnegative(),
|
|
23940
|
+
rawFindings: z27.number().int().nonnegative()
|
|
23244
23941
|
}).strict(),
|
|
23245
|
-
overhead:
|
|
23246
|
-
p95Millis:
|
|
23247
|
-
budgetMillis:
|
|
23248
|
-
samples:
|
|
23942
|
+
overhead: z27.object({
|
|
23943
|
+
p95Millis: z27.number().nonnegative(),
|
|
23944
|
+
budgetMillis: z27.number().positive(),
|
|
23945
|
+
samples: z27.number().int().nonnegative()
|
|
23249
23946
|
}).strict(),
|
|
23250
|
-
provenance:
|
|
23947
|
+
provenance: z27.record(DivergenceCodeSchema, ProvenanceSchema)
|
|
23251
23948
|
}).strict();
|
|
23252
|
-
var CertificateSchema =
|
|
23253
|
-
version:
|
|
23254
|
-
certificate:
|
|
23255
|
-
opencodeVersion:
|
|
23949
|
+
var CertificateSchema = z27.object({
|
|
23950
|
+
version: z27.literal(1),
|
|
23951
|
+
certificate: z27.literal("graph-shadow"),
|
|
23952
|
+
opencodeVersion: z27.string().min(1),
|
|
23256
23953
|
evidence: EvidenceSchema,
|
|
23257
|
-
verdict:
|
|
23258
|
-
failedGates:
|
|
23954
|
+
verdict: z27.enum(["pass", "fail"]),
|
|
23955
|
+
failedGates: z27.array(z27.enum([
|
|
23259
23956
|
"sample",
|
|
23260
23957
|
"parity",
|
|
23261
23958
|
"one-legacy-execution",
|
|
23262
23959
|
"privacy",
|
|
23263
23960
|
"overhead"
|
|
23264
23961
|
])),
|
|
23265
|
-
digest:
|
|
23962
|
+
digest: z27.string().regex(/^[0-9a-f]{64}$/)
|
|
23266
23963
|
}).strict();
|
|
23267
23964
|
|
|
23268
23965
|
class ShadowCertificateError extends Error {
|
|
@@ -23377,37 +24074,37 @@ function parseShadowCertificate(value, opencodeVersion) {
|
|
|
23377
24074
|
}
|
|
23378
24075
|
return certificate;
|
|
23379
24076
|
}
|
|
23380
|
-
var ReleaseDeterminismSchema =
|
|
23381
|
-
var ReleaseCrashRecoverySchema =
|
|
23382
|
-
scenarios:
|
|
23383
|
-
allConverge:
|
|
24077
|
+
var ReleaseDeterminismSchema = z27.object({ runs: z27.number().int().nonnegative(), allMatch: z27.boolean() }).strict();
|
|
24078
|
+
var ReleaseCrashRecoverySchema = z27.object({
|
|
24079
|
+
scenarios: z27.number().int().nonnegative(),
|
|
24080
|
+
allConverge: z27.boolean()
|
|
23384
24081
|
}).strict();
|
|
23385
|
-
var ReleaseReplayEquivalenceSchema =
|
|
23386
|
-
checks:
|
|
23387
|
-
allEquivalent:
|
|
24082
|
+
var ReleaseReplayEquivalenceSchema = z27.object({
|
|
24083
|
+
checks: z27.number().int().nonnegative(),
|
|
24084
|
+
allEquivalent: z27.boolean()
|
|
23388
24085
|
}).strict();
|
|
23389
|
-
var ReleasePrivacySchema =
|
|
23390
|
-
surfacesScanned:
|
|
23391
|
-
rawFindings:
|
|
24086
|
+
var ReleasePrivacySchema = z27.object({
|
|
24087
|
+
surfacesScanned: z27.number().int().nonnegative(),
|
|
24088
|
+
rawFindings: z27.number().int().nonnegative()
|
|
23392
24089
|
}).strict();
|
|
23393
|
-
var ReleaseContractSchema =
|
|
23394
|
-
roundTrips:
|
|
23395
|
-
allSettled:
|
|
24090
|
+
var ReleaseContractSchema = z27.object({
|
|
24091
|
+
roundTrips: z27.number().int().nonnegative(),
|
|
24092
|
+
allSettled: z27.boolean()
|
|
23396
24093
|
}).strict();
|
|
23397
|
-
var ReleaseHealthSchema =
|
|
23398
|
-
samples:
|
|
23399
|
-
bounded:
|
|
23400
|
-
idempotent:
|
|
24094
|
+
var ReleaseHealthSchema = z27.object({
|
|
24095
|
+
samples: z27.number().int().nonnegative(),
|
|
24096
|
+
bounded: z27.boolean(),
|
|
24097
|
+
idempotent: z27.boolean()
|
|
23401
24098
|
}).strict();
|
|
23402
|
-
var ReleasePerformanceSchema =
|
|
23403
|
-
p95Millis:
|
|
23404
|
-
budgetMillis:
|
|
23405
|
-
samples:
|
|
24099
|
+
var ReleasePerformanceSchema = z27.object({
|
|
24100
|
+
p95Millis: z27.number().nonnegative(),
|
|
24101
|
+
budgetMillis: z27.number().positive(),
|
|
24102
|
+
samples: z27.number().int().nonnegative()
|
|
23406
24103
|
}).strict();
|
|
23407
|
-
var ReleaseEvidenceSchema =
|
|
23408
|
-
opencodeVersion:
|
|
23409
|
-
platform:
|
|
23410
|
-
shadowCertificateDigest:
|
|
24104
|
+
var ReleaseEvidenceSchema = z27.object({
|
|
24105
|
+
opencodeVersion: z27.string().min(1),
|
|
24106
|
+
platform: z27.enum(["linux", "win32"]),
|
|
24107
|
+
shadowCertificateDigest: z27.string().regex(/^[0-9a-f]{64}$/),
|
|
23411
24108
|
determinism: ReleaseDeterminismSchema,
|
|
23412
24109
|
crashRecovery: ReleaseCrashRecoverySchema,
|
|
23413
24110
|
replayEquivalence: ReleaseReplayEquivalenceSchema,
|
|
@@ -23416,15 +24113,15 @@ var ReleaseEvidenceSchema = z26.object({
|
|
|
23416
24113
|
health: ReleaseHealthSchema,
|
|
23417
24114
|
performance: ReleasePerformanceSchema
|
|
23418
24115
|
}).strict();
|
|
23419
|
-
var ReleaseCertificateSchema =
|
|
23420
|
-
version:
|
|
23421
|
-
certificate:
|
|
23422
|
-
platform:
|
|
23423
|
-
opencodeVersion:
|
|
23424
|
-
shadowCertificateDigest:
|
|
24116
|
+
var ReleaseCertificateSchema = z27.object({
|
|
24117
|
+
version: z27.literal(2),
|
|
24118
|
+
certificate: z27.literal("graph-release"),
|
|
24119
|
+
platform: z27.enum(["linux", "win32"]),
|
|
24120
|
+
opencodeVersion: z27.string().min(1),
|
|
24121
|
+
shadowCertificateDigest: z27.string().regex(/^[0-9a-f]{64}$/),
|
|
23425
24122
|
evidence: ReleaseEvidenceSchema,
|
|
23426
|
-
verdict:
|
|
23427
|
-
failedGates:
|
|
24123
|
+
verdict: z27.enum(["pass", "fail"]),
|
|
24124
|
+
failedGates: z27.array(z27.enum([
|
|
23428
24125
|
"shadow-valid",
|
|
23429
24126
|
"determinism",
|
|
23430
24127
|
"crash-recovery",
|
|
@@ -23434,7 +24131,7 @@ var ReleaseCertificateSchema = z26.object({
|
|
|
23434
24131
|
"health",
|
|
23435
24132
|
"performance"
|
|
23436
24133
|
])),
|
|
23437
|
-
digest:
|
|
24134
|
+
digest: z27.string().regex(/^[0-9a-f]{64}$/)
|
|
23438
24135
|
}).strict();
|
|
23439
24136
|
|
|
23440
24137
|
class ReleaseCertificateError extends Error {
|
|
@@ -23562,7 +24259,7 @@ function parseReleaseCertificate(value, opencodeVersion, expectedShadowDigest) {
|
|
|
23562
24259
|
}
|
|
23563
24260
|
return certificate;
|
|
23564
24261
|
}
|
|
23565
|
-
var ShadowDivergenceCodeSchema =
|
|
24262
|
+
var ShadowDivergenceCodeSchema = z27.enum([
|
|
23566
24263
|
"status",
|
|
23567
24264
|
"order",
|
|
23568
24265
|
"roles",
|
|
@@ -23571,13 +24268,13 @@ var ShadowDivergenceCodeSchema = z26.enum([
|
|
|
23571
24268
|
"outcome"
|
|
23572
24269
|
]);
|
|
23573
24270
|
var RECOMPUTED_DIVERGENCE_CODES = ["fixes"];
|
|
23574
|
-
var RecomputedDivergenceCodeSchema =
|
|
23575
|
-
var SoakPolicySchema =
|
|
23576
|
-
minimumGenuineObservations:
|
|
23577
|
-
minimumDistinctDays:
|
|
23578
|
-
requireGenuineUsageOnAllPlatforms:
|
|
23579
|
-
supportedOpencodeVersions:
|
|
23580
|
-
criticalDivergenceCodes:
|
|
24271
|
+
var RecomputedDivergenceCodeSchema = z27.enum(RECOMPUTED_DIVERGENCE_CODES);
|
|
24272
|
+
var SoakPolicySchema = z27.object({
|
|
24273
|
+
minimumGenuineObservations: z27.number().int().positive(),
|
|
24274
|
+
minimumDistinctDays: z27.number().int().positive(),
|
|
24275
|
+
requireGenuineUsageOnAllPlatforms: z27.boolean(),
|
|
24276
|
+
supportedOpencodeVersions: z27.array(z27.string().min(1)).min(1),
|
|
24277
|
+
criticalDivergenceCodes: z27.array(RecomputedDivergenceCodeSchema).min(1)
|
|
23581
24278
|
}).strict();
|
|
23582
24279
|
var DEFAULT_SOAK_POLICY = {
|
|
23583
24280
|
minimumGenuineObservations: 100,
|
|
@@ -23586,46 +24283,46 @@ var DEFAULT_SOAK_POLICY = {
|
|
|
23586
24283
|
supportedOpencodeVersions: [...SUPPORTED_OPENCODE_VERSIONS],
|
|
23587
24284
|
criticalDivergenceCodes: ["fixes"]
|
|
23588
24285
|
};
|
|
23589
|
-
var SoakPlatformEnumSchema =
|
|
23590
|
-
var SoakPrivacyPairEvidenceSchema =
|
|
23591
|
-
surfacesScanned:
|
|
23592
|
-
rawFindings:
|
|
24286
|
+
var SoakPlatformEnumSchema = z27.enum(["linux", "win32", "darwin"]);
|
|
24287
|
+
var SoakPrivacyPairEvidenceSchema = z27.object({
|
|
24288
|
+
surfacesScanned: z27.number().int().nonnegative(),
|
|
24289
|
+
rawFindings: z27.number().int().nonnegative()
|
|
23593
24290
|
}).strict();
|
|
23594
|
-
var SoakDuplicateEffectPairEvidenceSchema =
|
|
23595
|
-
effectsExamined:
|
|
23596
|
-
duplicatesFound:
|
|
24291
|
+
var SoakDuplicateEffectPairEvidenceSchema = z27.object({
|
|
24292
|
+
effectsExamined: z27.number().int().nonnegative(),
|
|
24293
|
+
duplicatesFound: z27.number().int().nonnegative()
|
|
23597
24294
|
}).strict();
|
|
23598
|
-
var SoakModelVerificationPairEvidenceSchema =
|
|
23599
|
-
nodesChecked:
|
|
23600
|
-
unverified:
|
|
23601
|
-
mismatched:
|
|
24295
|
+
var SoakModelVerificationPairEvidenceSchema = z27.object({
|
|
24296
|
+
nodesChecked: z27.number().int().nonnegative(),
|
|
24297
|
+
unverified: z27.number().int().nonnegative(),
|
|
24298
|
+
mismatched: z27.number().int().nonnegative()
|
|
23602
24299
|
}).strict();
|
|
23603
|
-
var SoakEvidenceSchema =
|
|
23604
|
-
totalObservations:
|
|
23605
|
-
genuineUsageObservations:
|
|
23606
|
-
ciSyntheticObservations:
|
|
23607
|
-
recorderCount:
|
|
23608
|
-
ineligibleObservations:
|
|
23609
|
-
firstTimestamp:
|
|
23610
|
-
lastTimestamp:
|
|
23611
|
-
distinctDays:
|
|
23612
|
-
criticalDivergences:
|
|
24300
|
+
var SoakEvidenceSchema = z27.object({
|
|
24301
|
+
totalObservations: z27.number().int().nonnegative(),
|
|
24302
|
+
genuineUsageObservations: z27.number().int().nonnegative(),
|
|
24303
|
+
ciSyntheticObservations: z27.number().int().nonnegative(),
|
|
24304
|
+
recorderCount: z27.number().int().nonnegative(),
|
|
24305
|
+
ineligibleObservations: z27.number().int().nonnegative(),
|
|
24306
|
+
firstTimestamp: z27.string().datetime().nullable(),
|
|
24307
|
+
lastTimestamp: z27.string().datetime().nullable(),
|
|
24308
|
+
distinctDays: z27.number().int().nonnegative(),
|
|
24309
|
+
criticalDivergences: z27.number().int().nonnegative().nullable(),
|
|
23613
24310
|
privacy: SoakPrivacyPairEvidenceSchema.nullable(),
|
|
23614
24311
|
duplicateEffects: SoakDuplicateEffectPairEvidenceSchema.nullable(),
|
|
23615
24312
|
modelVerification: SoakModelVerificationPairEvidenceSchema.nullable(),
|
|
23616
|
-
platformsGenuine:
|
|
23617
|
-
platformsSynthetic:
|
|
23618
|
-
opencodeVersionsObserved:
|
|
23619
|
-
invalidChains:
|
|
24313
|
+
platformsGenuine: z27.array(SoakPlatformEnumSchema),
|
|
24314
|
+
platformsSynthetic: z27.array(SoakPlatformEnumSchema),
|
|
24315
|
+
opencodeVersionsObserved: z27.array(z27.string().min(1)),
|
|
24316
|
+
invalidChains: z27.number().int().nonnegative()
|
|
23620
24317
|
}).strict();
|
|
23621
|
-
var SoakCertificateSchema =
|
|
23622
|
-
version:
|
|
23623
|
-
certificate:
|
|
23624
|
-
trustBoundary:
|
|
24318
|
+
var SoakCertificateSchema = z27.object({
|
|
24319
|
+
version: z27.literal(1),
|
|
24320
|
+
certificate: z27.literal("graph-soak"),
|
|
24321
|
+
trustBoundary: z27.literal("contributors"),
|
|
23625
24322
|
policy: SoakPolicySchema,
|
|
23626
24323
|
evidence: SoakEvidenceSchema,
|
|
23627
|
-
verdict:
|
|
23628
|
-
failedGates:
|
|
24324
|
+
verdict: z27.enum(["pass", "fail"]),
|
|
24325
|
+
failedGates: z27.array(z27.enum([
|
|
23629
24326
|
"minimum-observations",
|
|
23630
24327
|
"minimum-duration",
|
|
23631
24328
|
"chain-integrity",
|
|
@@ -23636,8 +24333,8 @@ var SoakCertificateSchema = z26.object({
|
|
|
23636
24333
|
"os-diversity",
|
|
23637
24334
|
"opencode-pin"
|
|
23638
24335
|
])),
|
|
23639
|
-
ledgerDigest:
|
|
23640
|
-
digest:
|
|
24336
|
+
ledgerDigest: z27.string().regex(/^[0-9a-f]{64}$/),
|
|
24337
|
+
digest: z27.string().regex(/^[0-9a-f]{64}$/)
|
|
23641
24338
|
}).strict();
|
|
23642
24339
|
|
|
23643
24340
|
class SoakCertificateError extends Error {
|
|
@@ -24285,62 +24982,62 @@ var realCacheAdapter = {
|
|
|
24285
24982
|
};
|
|
24286
24983
|
|
|
24287
24984
|
// src/memory/types.ts
|
|
24288
|
-
import { z as
|
|
24985
|
+
import { z as z28 } from "zod";
|
|
24289
24986
|
var SHARED_OWNER_KEY = "*";
|
|
24290
|
-
var OwnerKeySchema =
|
|
24291
|
-
var MemoryKindSchema =
|
|
24292
|
-
var MemoryBaseSchema =
|
|
24293
|
-
id:
|
|
24987
|
+
var OwnerKeySchema = z28.string().min(1);
|
|
24988
|
+
var MemoryKindSchema = z28.enum(["fact", "preference", "entity"]);
|
|
24989
|
+
var MemoryBaseSchema = z28.object({
|
|
24990
|
+
id: z28.string().min(1),
|
|
24294
24991
|
ownerKey: OwnerKeySchema,
|
|
24295
|
-
confidence:
|
|
24296
|
-
validFrom:
|
|
24297
|
-
validUntil:
|
|
24298
|
-
createdAt:
|
|
24299
|
-
invalidatedAt:
|
|
24300
|
-
sourceHash:
|
|
24301
|
-
supersededBy:
|
|
24992
|
+
confidence: z28.number().min(0).max(1),
|
|
24993
|
+
validFrom: z28.number().finite(),
|
|
24994
|
+
validUntil: z28.number().finite().nullable().default(null),
|
|
24995
|
+
createdAt: z28.number().finite(),
|
|
24996
|
+
invalidatedAt: z28.number().finite().nullable().default(null),
|
|
24997
|
+
sourceHash: z28.string().min(1),
|
|
24998
|
+
supersededBy: z28.string().min(1).nullable().default(null)
|
|
24302
24999
|
}).strict();
|
|
24303
25000
|
var FactSchema = MemoryBaseSchema.extend({
|
|
24304
|
-
kind:
|
|
24305
|
-
subject:
|
|
24306
|
-
predicate:
|
|
24307
|
-
object:
|
|
24308
|
-
category:
|
|
25001
|
+
kind: z28.literal("fact"),
|
|
25002
|
+
subject: z28.string().min(1),
|
|
25003
|
+
predicate: z28.string().min(1),
|
|
25004
|
+
object: z28.string().min(1),
|
|
25005
|
+
category: z28.string().min(1).nullable().default(null)
|
|
24309
25006
|
});
|
|
24310
25007
|
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
24311
|
-
kind:
|
|
24312
|
-
category:
|
|
24313
|
-
preference:
|
|
24314
|
-
context:
|
|
24315
|
-
lastAccessedAt:
|
|
24316
|
-
accessCount:
|
|
25008
|
+
kind: z28.literal("preference"),
|
|
25009
|
+
category: z28.string().min(1),
|
|
25010
|
+
preference: z28.string().min(1),
|
|
25011
|
+
context: z28.string().min(1).nullable().default(null),
|
|
25012
|
+
lastAccessedAt: z28.number().finite().nullable().default(null),
|
|
25013
|
+
accessCount: z28.number().int().min(0).default(0)
|
|
24317
25014
|
});
|
|
24318
25015
|
var EntitySchema = MemoryBaseSchema.extend({
|
|
24319
|
-
kind:
|
|
24320
|
-
canonicalName:
|
|
24321
|
-
type:
|
|
24322
|
-
aliases:
|
|
25016
|
+
kind: z28.literal("entity"),
|
|
25017
|
+
canonicalName: z28.string().min(1),
|
|
25018
|
+
type: z28.string().min(1),
|
|
25019
|
+
aliases: z28.array(z28.string().min(1)).default([])
|
|
24323
25020
|
});
|
|
24324
25021
|
var RelationSchema = MemoryBaseSchema.extend({
|
|
24325
|
-
kind:
|
|
24326
|
-
from:
|
|
24327
|
-
to:
|
|
24328
|
-
predicate:
|
|
24329
|
-
annotation:
|
|
25022
|
+
kind: z28.literal("relation"),
|
|
25023
|
+
from: z28.string().min(1),
|
|
25024
|
+
to: z28.string().min(1),
|
|
25025
|
+
predicate: z28.string().min(1),
|
|
25026
|
+
annotation: z28.string().min(1).nullable().default(null)
|
|
24330
25027
|
});
|
|
24331
|
-
var MemoryRecordSchema =
|
|
25028
|
+
var MemoryRecordSchema = z28.discriminatedUnion("kind", [
|
|
24332
25029
|
FactSchema,
|
|
24333
25030
|
PreferenceSchema,
|
|
24334
25031
|
EntitySchema,
|
|
24335
25032
|
RelationSchema
|
|
24336
25033
|
]);
|
|
24337
|
-
var RecallQuerySchema =
|
|
25034
|
+
var RecallQuerySchema = z28.object({
|
|
24338
25035
|
ownerKey: OwnerKeySchema,
|
|
24339
|
-
kinds:
|
|
24340
|
-
asOf:
|
|
24341
|
-
limit:
|
|
24342
|
-
minSimilarity:
|
|
24343
|
-
includeShared:
|
|
25036
|
+
kinds: z28.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
|
|
25037
|
+
asOf: z28.number().finite().nullable().default(null),
|
|
25038
|
+
limit: z28.number().int().positive().default(8),
|
|
25039
|
+
minSimilarity: z28.number().min(0).max(1).default(0.2),
|
|
25040
|
+
includeShared: z28.boolean().default(true)
|
|
24344
25041
|
}).strict();
|
|
24345
25042
|
|
|
24346
25043
|
// src/memory/rank.ts
|