oasis_test_v2 2.2.69 → 2.2.70
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/dist/index.js +1451 -531
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1465,6 +1465,22 @@ var init_chat = __esm({
|
|
|
1465
1465
|
});
|
|
1466
1466
|
|
|
1467
1467
|
// ../contract/src/session-outputs.ts
|
|
1468
|
+
function sessionOutputFilesOfParts(parts) {
|
|
1469
|
+
if (!Array.isArray(parts)) return [];
|
|
1470
|
+
const out = [];
|
|
1471
|
+
for (const raw of parts) {
|
|
1472
|
+
if (!raw || typeof raw !== "object") continue;
|
|
1473
|
+
const p2 = raw;
|
|
1474
|
+
if (p2.type !== "outputs" || !Array.isArray(p2.outputs)) continue;
|
|
1475
|
+
for (const f2 of p2.outputs) {
|
|
1476
|
+
if (!f2 || typeof f2 !== "object") continue;
|
|
1477
|
+
const file = f2;
|
|
1478
|
+
if (typeof file.path !== "string" || !file.path) continue;
|
|
1479
|
+
out.push({ path: file.path, name: typeof file.name === "string" && file.name ? file.name : file.path });
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
return out;
|
|
1483
|
+
}
|
|
1468
1484
|
function diffSessionOutputs(scanned, previous3) {
|
|
1469
1485
|
const prev = previous3 ?? {};
|
|
1470
1486
|
const changed = [];
|
|
@@ -1485,11 +1501,13 @@ function basenameOf(path44) {
|
|
|
1485
1501
|
const i = path44.lastIndexOf("/");
|
|
1486
1502
|
return i >= 0 ? path44.slice(i + 1) : path44;
|
|
1487
1503
|
}
|
|
1488
|
-
var SESSION_OUTPUTS_DIR;
|
|
1504
|
+
var SESSION_OUTPUTS_DIR, SESSION_OUTPUTS_ITEM_CODE, sessionOutputsItemId;
|
|
1489
1505
|
var init_session_outputs = __esm({
|
|
1490
1506
|
"../contract/src/session-outputs.ts"() {
|
|
1491
1507
|
"use strict";
|
|
1492
1508
|
SESSION_OUTPUTS_DIR = "outputs";
|
|
1509
|
+
SESSION_OUTPUTS_ITEM_CODE = "session_outputs";
|
|
1510
|
+
sessionOutputsItemId = (messageId) => `oasis-outputs:${messageId}`;
|
|
1493
1511
|
}
|
|
1494
1512
|
});
|
|
1495
1513
|
|
|
@@ -1677,6 +1695,24 @@ var init_chat_turn = __esm({
|
|
|
1677
1695
|
});
|
|
1678
1696
|
|
|
1679
1697
|
// ../contract/src/delegation.ts
|
|
1698
|
+
function hasDelegationDelivery(ev) {
|
|
1699
|
+
if (!ev) return false;
|
|
1700
|
+
return (ev.movedFiles ?? 0) > 0 || (ev.unchangedFiles ?? 0) > 0 || (ev.artifacts ?? 0) > 0 || Boolean(ev.roundText?.trim());
|
|
1701
|
+
}
|
|
1702
|
+
function delegationEnding(record9, evidence) {
|
|
1703
|
+
if (record9.state === "done") return "done";
|
|
1704
|
+
if (record9.state !== "failed") return "done";
|
|
1705
|
+
if (record9.failureKind !== "timeout") return "failed";
|
|
1706
|
+
return hasDelegationDelivery(evidence) ? "timeout-delivered" : "timeout-empty";
|
|
1707
|
+
}
|
|
1708
|
+
function delegationEndingOfRecord(record9, artifacts = []) {
|
|
1709
|
+
const last = record9.roundSummaries[record9.roundSummaries.length - 1];
|
|
1710
|
+
const lastRound = last?.round;
|
|
1711
|
+
return delegationEnding(record9, {
|
|
1712
|
+
...last?.text ? { roundText: last.text } : {},
|
|
1713
|
+
artifacts: lastRound === void 0 ? 0 : artifacts.filter((a) => a.round === lastRound).length
|
|
1714
|
+
});
|
|
1715
|
+
}
|
|
1680
1716
|
function trimRoundSummariesForReturn(summaries, recentRounds = DELEGATION_RETURN_RECENT_ROUNDS) {
|
|
1681
1717
|
const keep = Math.max(0, recentRounds);
|
|
1682
1718
|
const cut = Math.max(0, summaries.length - keep);
|
|
@@ -2046,6 +2082,94 @@ var init_chunked_message = __esm({
|
|
|
2046
2082
|
}
|
|
2047
2083
|
});
|
|
2048
2084
|
|
|
2085
|
+
// ../contract/src/command-card-copy.ts
|
|
2086
|
+
function stripInternalIds(text7, placeholder = "\u2026") {
|
|
2087
|
+
if (!text7) return text7;
|
|
2088
|
+
let out = text7;
|
|
2089
|
+
for (const re of [PREFIXED_ID_RE, UUID_RE, SHORT_ID_RE]) {
|
|
2090
|
+
out = out.replace(re, placeholder);
|
|
2091
|
+
}
|
|
2092
|
+
return out.replace(new RegExp(`[ \\t]+${placeholder}`, "gu"), placeholder);
|
|
2093
|
+
}
|
|
2094
|
+
function firstSentenceSummary(text7, max = CARD_SUMMARY_MAX) {
|
|
2095
|
+
const raw = (text7 ?? "").trim();
|
|
2096
|
+
if (!raw) return "";
|
|
2097
|
+
const cut = raw.split(/[。!?\n]|——/u)[0].trim() || raw.trim();
|
|
2098
|
+
const clean = stripInternalIds(cut).trim();
|
|
2099
|
+
const cps = [...clean];
|
|
2100
|
+
return cps.length > max ? `${cps.slice(0, max).join("")}\u2026` : clean;
|
|
2101
|
+
}
|
|
2102
|
+
function nodePhrase(args, refs) {
|
|
2103
|
+
const id = argStr(args, "artifactId");
|
|
2104
|
+
const title = id ? refs.nodeTitle?.(id)?.trim() : void 0;
|
|
2105
|
+
return title ? `\u300A${title}\u300B` : NEUTRAL_NODE;
|
|
2106
|
+
}
|
|
2107
|
+
function targetPhrase(naming, neutral) {
|
|
2108
|
+
const summary = firstSentenceSummary(naming?.summary);
|
|
2109
|
+
const nodeTitle = naming?.nodeTitle?.trim();
|
|
2110
|
+
if (summary) {
|
|
2111
|
+
return { phrase: nodeTitle && !summary.includes(nodeTitle) ? `\u300A${nodeTitle}\u300B\u2014\u2014${summary}` : summary, named: true };
|
|
2112
|
+
}
|
|
2113
|
+
if (nodeTitle) return { phrase: `\u300A${nodeTitle}\u300B\u4E0A\u7684${neutral}`, named: true };
|
|
2114
|
+
return { phrase: neutral, named: false };
|
|
2115
|
+
}
|
|
2116
|
+
function escalationPhraseOf(refs, escalationId) {
|
|
2117
|
+
return targetPhrase(escalationId ? refs.escalation?.(escalationId) : void 0, NEUTRAL_ESCALATION);
|
|
2118
|
+
}
|
|
2119
|
+
function gapPhraseOf(refs, gapId) {
|
|
2120
|
+
return targetPhrase(gapId ? refs.gap?.(gapId) : void 0, NEUTRAL_GAP);
|
|
2121
|
+
}
|
|
2122
|
+
function actionPhrase(verb, noun, target, neutralVerb = verb) {
|
|
2123
|
+
return target.named ? `${verb}${noun}\uFF1A${target.phrase}` : `${neutralVerb}${target.phrase}`;
|
|
2124
|
+
}
|
|
2125
|
+
function describeCommandForHuman(command2, args, refs = {}) {
|
|
2126
|
+
const reason = argStr(args, "reason");
|
|
2127
|
+
const reasonTail = reason ? `\uFF08\u7406\u7531\uFF1A${stripInternalIds(reason)}\uFF09` : "";
|
|
2128
|
+
switch (command2) {
|
|
2129
|
+
case "forceConclude":
|
|
2130
|
+
return `\u5F3A\u5236\u6536\u53E3${nodePhrase(args, refs)}${reasonTail}\u2014\u2014\u7ED5\u8FC7\u8BC4\u5BA1\u76F4\u63A5\u76D6\u91CC\u7A0B\u7891\u3002`;
|
|
2131
|
+
case "promote":
|
|
2132
|
+
return `\u628A${nodePhrase(args, refs)}\u8F6C\u4E3A\u957F\u671F\u4FDD\u7559\u7684\u8282\u70B9\uFF08\u4E0D\u518D\u968F\u4EFB\u52A1\u7ED3\u675F\u56DE\u6536\uFF09\u3002`;
|
|
2133
|
+
// continueBatch(续跑额度卡)**故意不在这里**:它的文案由引擎写好放在 `continuationBudget.request.summary`
|
|
2134
|
+
// 里,本来就是「《节点名》尚未完成,已达到自动派发上限。累计已运行 N 轮…」这种名称式写法,没有 id。
|
|
2135
|
+
// 重写一遍只会让同一句话有两个事实源,交给 {@link commandCardDisplayLabel} 的兜底清洗即可。
|
|
2136
|
+
case "resolveEscalation": {
|
|
2137
|
+
const escalation = escalationPhraseOf(refs, argStr(args, "escalationId"));
|
|
2138
|
+
const gapId = argStr(args, "gapId");
|
|
2139
|
+
if (!gapId) return `${actionPhrase("\u5173\u95ED", "\u6C42\u52A9", escalation)}${reasonTail}`;
|
|
2140
|
+
return [
|
|
2141
|
+
reason ? `\u91C7\u7528\u65B9\u6848\uFF1A${stripInternalIds(reason)}` : "\u786E\u8BA4\u6062\u590D\u65B9\u6848",
|
|
2142
|
+
actionPhrase("\u89E3\u51B3", "\u7F3A\u53E3", gapPhraseOf(refs, gapId)),
|
|
2143
|
+
actionPhrase("\u5173\u95ED\u5173\u8054", "\u6C42\u52A9", escalation, "\u5173\u95ED\u5173\u8054\u7684"),
|
|
2144
|
+
"\u7EE7\u7EED\u6267\u884C\uFF1A\u662F\uFF08\u4ECD\u987B\u6EE1\u8DB3\u5176\u4ED6\u963B\u585E\u6761\u4EF6\uFF09"
|
|
2145
|
+
].join("\uFF1B");
|
|
2146
|
+
}
|
|
2147
|
+
default:
|
|
2148
|
+
return void 0;
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
function commandCardDisplayLabel(command2, args, storedLabel, refs = {}) {
|
|
2152
|
+
const described = command2 ? describeCommandForHuman(command2, args ?? {}, refs) : void 0;
|
|
2153
|
+
return described ?? stripInternalIds(storedLabel ?? "");
|
|
2154
|
+
}
|
|
2155
|
+
var PREFIXED_ID_RE, UUID_RE, SHORT_ID_RE, CARD_SUMMARY_MAX, NEUTRAL_NODE, NEUTRAL_ESCALATION, NEUTRAL_GAP, argStr;
|
|
2156
|
+
var init_command_card_copy = __esm({
|
|
2157
|
+
"../contract/src/command-card-copy.ts"() {
|
|
2158
|
+
"use strict";
|
|
2159
|
+
PREFIXED_ID_RE = /(?:artifact|esc|gap|wk|ws|actor|draft|issue|review|rev|work|node|company|chat|sess|int|blob|run|continuation)[::][A-Za-z0-9][A-Za-z0-9:._#-]*/gu;
|
|
2160
|
+
UUID_RE = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/giu;
|
|
2161
|
+
SHORT_ID_RE = /\b(?=[0-9a-f-]*[0-9])(?=[0-9a-f-]*[a-f])[0-9a-f]{8,}(?:-[0-9a-f]{4,})*\b/giu;
|
|
2162
|
+
CARD_SUMMARY_MAX = 48;
|
|
2163
|
+
NEUTRAL_NODE = "\u8FD9\u4E00\u6B65";
|
|
2164
|
+
NEUTRAL_ESCALATION = "\u8FD9\u6761\u6C42\u52A9";
|
|
2165
|
+
NEUTRAL_GAP = "\u8FD9\u4E2A\u7F3A\u53E3";
|
|
2166
|
+
argStr = (args, key2) => {
|
|
2167
|
+
const v2 = args[key2];
|
|
2168
|
+
return typeof v2 === "string" && v2.trim() ? v2.trim() : void 0;
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
});
|
|
2172
|
+
|
|
2049
2173
|
// ../contract/src/index.ts
|
|
2050
2174
|
var init_src = __esm({
|
|
2051
2175
|
"../contract/src/index.ts"() {
|
|
@@ -2108,6 +2232,7 @@ var init_src = __esm({
|
|
|
2108
2232
|
init_chat_turn();
|
|
2109
2233
|
init_delegation();
|
|
2110
2234
|
init_delegation();
|
|
2235
|
+
init_delegation();
|
|
2111
2236
|
init_delegation_prompts();
|
|
2112
2237
|
init_knowledge();
|
|
2113
2238
|
init_knowledge_governance();
|
|
@@ -2115,6 +2240,7 @@ var init_src = __esm({
|
|
|
2115
2240
|
init_file_preview();
|
|
2116
2241
|
init_file_limits();
|
|
2117
2242
|
init_chunked_message();
|
|
2243
|
+
init_command_card_copy();
|
|
2118
2244
|
}
|
|
2119
2245
|
});
|
|
2120
2246
|
|
|
@@ -2264,6 +2390,21 @@ function sessionRuntimeOverride(session) {
|
|
|
2264
2390
|
if (!nodeId || !runtimeKind) return null;
|
|
2265
2391
|
return { nodeId, runtimeKind };
|
|
2266
2392
|
}
|
|
2393
|
+
function chatSessionInitialRuntime(input) {
|
|
2394
|
+
const trimmed = (v2) => typeof v2 === "string" && v2.trim() ? v2.trim() : null;
|
|
2395
|
+
const binding = input.binding?.nodeId && input.binding?.runtimeKind ? { nodeId: input.binding.nodeId, runtimeKind: input.binding.runtimeKind } : null;
|
|
2396
|
+
const requestedOverride = input.requested?.override;
|
|
2397
|
+
const picked = requestedOverride?.nodeId && requestedOverride?.runtimeKind ? { nodeId: requestedOverride.nodeId, runtimeKind: requestedOverride.runtimeKind } : null;
|
|
2398
|
+
const target = picked ?? binding;
|
|
2399
|
+
const followsAgentTarget = !picked || !!binding && picked.nodeId === binding.nodeId && picked.runtimeKind === binding.runtimeKind;
|
|
2400
|
+
const requestedModel = input.requested?.model;
|
|
2401
|
+
const model = requestedModel !== void 0 ? trimmed(requestedModel) : followsAgentTarget ? trimmed(input.agentModel) : null;
|
|
2402
|
+
return {
|
|
2403
|
+
overrideNodeId: target?.nodeId ?? null,
|
|
2404
|
+
overrideRuntimeKind: target?.runtimeKind ?? null,
|
|
2405
|
+
model
|
|
2406
|
+
};
|
|
2407
|
+
}
|
|
2267
2408
|
function sessionRuntimeOverrideChangesTarget(session, binding) {
|
|
2268
2409
|
const override = sessionRuntimeOverride(session);
|
|
2269
2410
|
if (!override) return false;
|
|
@@ -2323,7 +2464,7 @@ var init_session_runtime_target = __esm({
|
|
|
2323
2464
|
this.name = "SessionRuntimeOverrideError";
|
|
2324
2465
|
}
|
|
2325
2466
|
};
|
|
2326
|
-
CLEAR_SESSION_RUNTIME_HINT = "\
|
|
2467
|
+
CLEAR_SESSION_RUNTIME_HINT = "\u5728\u8FD0\u884C\u65F6\u9009\u62E9\u91CC\u70B9\u300C\u6062\u590D\u4E3A\u5458\u5DE5\u9ED8\u8BA4\u8FD0\u884C\u914D\u7F6E\u300D\u5373\u53EF\u7EE7\u7EED\uFF08\u4F1A\u628A\u8FD9\u4F4D Agent \u6B64\u523B\u7684\u9ED8\u8BA4\u914D\u7F6E\u6284\u8FDB\u8FD9\u6761\u4F1A\u8BDD\uFF09\u3002";
|
|
2327
2468
|
}
|
|
2328
2469
|
});
|
|
2329
2470
|
|
|
@@ -3905,9 +4046,57 @@ function newClaudeUsageAcc() {
|
|
|
3905
4046
|
costUsd: null,
|
|
3906
4047
|
messageUsageById: /* @__PURE__ */ new Map(),
|
|
3907
4048
|
finalUsage: null,
|
|
4049
|
+
restored: null,
|
|
3908
4050
|
saw: false
|
|
3909
4051
|
};
|
|
3910
4052
|
}
|
|
4053
|
+
function findClaudeSessionFile(configDir, cwd, runtimeSessionId) {
|
|
4054
|
+
const root = path7.join(configDir, "projects");
|
|
4055
|
+
const name = `${runtimeSessionId}.jsonl`;
|
|
4056
|
+
const direct = path7.join(root, cwd.replace(/[^a-zA-Z0-9]/g, "-"), name);
|
|
4057
|
+
if (fs7.existsSync(direct)) return direct;
|
|
4058
|
+
try {
|
|
4059
|
+
for (const slug6 of fs7.readdirSync(root)) {
|
|
4060
|
+
const candidate = path7.join(root, slug6, name);
|
|
4061
|
+
if (fs7.existsSync(candidate)) return candidate;
|
|
4062
|
+
}
|
|
4063
|
+
} catch {
|
|
4064
|
+
}
|
|
4065
|
+
return void 0;
|
|
4066
|
+
}
|
|
4067
|
+
function readClaudeRestoredCost(sessionFile) {
|
|
4068
|
+
try {
|
|
4069
|
+
const stat4 = fs7.statSync(sessionFile);
|
|
4070
|
+
if (!stat4.isFile() || stat4.size === 0) return null;
|
|
4071
|
+
const length = Math.min(stat4.size, RESTORED_COST_TAIL_BYTES);
|
|
4072
|
+
const buf = Buffer.alloc(length);
|
|
4073
|
+
const fd = fs7.openSync(sessionFile, "r");
|
|
4074
|
+
try {
|
|
4075
|
+
fs7.readSync(fd, buf, 0, length, stat4.size - length);
|
|
4076
|
+
} finally {
|
|
4077
|
+
fs7.closeSync(fd);
|
|
4078
|
+
}
|
|
4079
|
+
const lines = buf.toString("utf8").split("\n");
|
|
4080
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
4081
|
+
const line2 = lines[i];
|
|
4082
|
+
if (!line2.includes('"cost-state"')) continue;
|
|
4083
|
+
let parsed;
|
|
4084
|
+
try {
|
|
4085
|
+
parsed = JSON.parse(line2);
|
|
4086
|
+
} catch {
|
|
4087
|
+
continue;
|
|
4088
|
+
}
|
|
4089
|
+
if (parsed["type"] !== "cost-state") continue;
|
|
4090
|
+
const cost = parsed["totalCostUSD"];
|
|
4091
|
+
return {
|
|
4092
|
+
usage: parseModelUsage(parsed["modelUsage"]),
|
|
4093
|
+
costUsd: typeof cost === "number" && Number.isFinite(cost) && cost >= 0 ? cost : null
|
|
4094
|
+
};
|
|
4095
|
+
}
|
|
4096
|
+
} catch {
|
|
4097
|
+
}
|
|
4098
|
+
return null;
|
|
4099
|
+
}
|
|
3911
4100
|
function usageNum(v2) {
|
|
3912
4101
|
return typeof v2 === "number" && Number.isFinite(v2) && v2 >= 0 ? v2 : void 0;
|
|
3913
4102
|
}
|
|
@@ -3981,14 +4170,34 @@ function accumulateClaudeUsage(acc, p2) {
|
|
|
3981
4170
|
acc.saw = true;
|
|
3982
4171
|
}
|
|
3983
4172
|
} else if (type === "result") {
|
|
3984
|
-
acc.finalUsage = mergeFinalUsage(parseModelUsage(p2["modelUsage"]), parseResultUsage(p2["usage"]));
|
|
3985
4173
|
const c = p2["total_cost_usd"];
|
|
3986
|
-
|
|
3987
|
-
|
|
4174
|
+
const cost = typeof c === "number" && Number.isFinite(c) ? c : null;
|
|
4175
|
+
const { usage: modelUsage, costUsd } = sinceRestored(acc.restored, parseModelUsage(p2["modelUsage"]), cost);
|
|
4176
|
+
acc.finalUsage = mergeFinalUsage(modelUsage, parseResultUsage(p2["usage"]));
|
|
4177
|
+
if (costUsd != null) {
|
|
4178
|
+
acc.costUsd = costUsd;
|
|
3988
4179
|
}
|
|
3989
4180
|
if (acc.finalUsage || acc.costUsd != null) acc.saw = true;
|
|
3990
4181
|
}
|
|
3991
4182
|
}
|
|
4183
|
+
function sinceRestored(restored, usage, costUsd) {
|
|
4184
|
+
if (!restored) return { usage, costUsd };
|
|
4185
|
+
const out = usage ? { ...usage } : null;
|
|
4186
|
+
if (out && restored.usage) {
|
|
4187
|
+
for (const k2 of ["input", "output", "cacheRead", "cacheCreation"]) {
|
|
4188
|
+
const base = restored.usage[k2];
|
|
4189
|
+
const total = out[k2];
|
|
4190
|
+
if (total == null || base == null) continue;
|
|
4191
|
+
if (total < base) return { usage, costUsd };
|
|
4192
|
+
out[k2] = total - base;
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
if (costUsd != null && restored.costUsd != null) {
|
|
4196
|
+
if (costUsd < restored.costUsd) return { usage, costUsd };
|
|
4197
|
+
return { usage: out, costUsd: costUsd - restored.costUsd };
|
|
4198
|
+
}
|
|
4199
|
+
return { usage: out, costUsd };
|
|
4200
|
+
}
|
|
3992
4201
|
function newClaudeRunningUsage() {
|
|
3993
4202
|
return { byMessage: /* @__PURE__ */ new Map(), currentMessageId: null, lastKey: "" };
|
|
3994
4203
|
}
|
|
@@ -4089,13 +4298,14 @@ function classifyExit(result) {
|
|
|
4089
4298
|
if (status === 429 || status === 529) return "rate-limit";
|
|
4090
4299
|
return "error";
|
|
4091
4300
|
}
|
|
4092
|
-
var import_node_child_process3, import_node_crypto6, fs7, path7, readline, CLAUDE_BLOCKED_FLAGS, SUBAGENT_TRANSCRIPT_MAX_BYTES, SUBAGENT_TERMINAL, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
4301
|
+
var import_node_child_process3, import_node_crypto6, fs7, os4, path7, readline, CLAUDE_BLOCKED_FLAGS, SUBAGENT_TRANSCRIPT_MAX_BYTES, SUBAGENT_TERMINAL, RESTORED_COST_TAIL_BYTES, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
4093
4302
|
var init_claude_code = __esm({
|
|
4094
4303
|
"../adapters/src/claude-code/index.ts"() {
|
|
4095
4304
|
"use strict";
|
|
4096
4305
|
import_node_child_process3 = require("node:child_process");
|
|
4097
4306
|
import_node_crypto6 = require("node:crypto");
|
|
4098
4307
|
fs7 = __toESM(require("node:fs"), 1);
|
|
4308
|
+
os4 = __toESM(require("node:os"), 1);
|
|
4099
4309
|
path7 = __toESM(require("node:path"), 1);
|
|
4100
4310
|
readline = __toESM(require("node:readline"), 1);
|
|
4101
4311
|
init_sync_skills();
|
|
@@ -4142,6 +4352,7 @@ var init_claude_code = __esm({
|
|
|
4142
4352
|
killed: "stopped",
|
|
4143
4353
|
stopped: "stopped"
|
|
4144
4354
|
};
|
|
4355
|
+
RESTORED_COST_TAIL_BYTES = 4 * 1024 * 1024;
|
|
4145
4356
|
ONE_SHOT_UNSAFE_TOOLS = ["ScheduleWakeup", "CronCreate", "CronDelete", "CronList"];
|
|
4146
4357
|
ClaudeCodeAdapter = class {
|
|
4147
4358
|
constructor(opts = {}) {
|
|
@@ -4238,6 +4449,9 @@ var init_claude_code = __esm({
|
|
|
4238
4449
|
{ runtime: "claude-code", actor: job.actor, ...job.dispatchId ? { dispatchId: job.dispatchId } : {} }
|
|
4239
4450
|
)
|
|
4240
4451
|
];
|
|
4452
|
+
const claudeConfigDir = job.env?.["CLAUDE_CONFIG_DIR"] || this.opts.env?.["CLAUDE_CONFIG_DIR"] || process.env["CLAUDE_CONFIG_DIR"] || path7.join(os4.homedir(), ".claude");
|
|
4453
|
+
const resumedSessionFile = job.runtimeSessionId && job.resumeRuntimeSession ? findClaudeSessionFile(claudeConfigDir, dir, job.runtimeSessionId) : void 0;
|
|
4454
|
+
const restoredCost = resumedSessionFile ? readClaudeRestoredCost(resumedSessionFile) : null;
|
|
4241
4455
|
const otelEnv = this.resolveOtelEnv(job, id);
|
|
4242
4456
|
const containerized = await maybeContainerize({
|
|
4243
4457
|
bin: this.opts.claudeBin ?? "claude",
|
|
@@ -4365,6 +4579,7 @@ var init_claude_code = __esm({
|
|
|
4365
4579
|
const STDERR_MAX_LINES = 40;
|
|
4366
4580
|
const STDERR_MAX_BYTES = 4e3;
|
|
4367
4581
|
const usageAcc = newClaudeUsageAcc();
|
|
4582
|
+
usageAcc.restored = restoredCost;
|
|
4368
4583
|
const runningUsage = newClaudeRunningUsage();
|
|
4369
4584
|
const usageCheckpointCbs = [];
|
|
4370
4585
|
let sessionModel;
|
|
@@ -4834,7 +5049,7 @@ var init_resilient = __esm({
|
|
|
4834
5049
|
|
|
4835
5050
|
// ../adapters/src/_core/skill-cache.ts
|
|
4836
5051
|
function defaultCacheRoot() {
|
|
4837
|
-
return path8.join(
|
|
5052
|
+
return path8.join(os5.homedir(), ".oasis", "skill-cache");
|
|
4838
5053
|
}
|
|
4839
5054
|
function sessionSkillsSubdir(runtimeKind) {
|
|
4840
5055
|
switch (runtimeKind) {
|
|
@@ -5239,13 +5454,13 @@ async function verifyPendingLink(skillsDir, name, pend, log3) {
|
|
|
5239
5454
|
}
|
|
5240
5455
|
return true;
|
|
5241
5456
|
}
|
|
5242
|
-
var import_node_crypto7, fsp,
|
|
5457
|
+
var import_node_crypto7, fsp, os5, path8, MANIFEST_SCHEMA_VERSION, STALE_LOCK_MS, LOCK_ACQUIRE_TIMEOUT_MS, LOCK_POLL_MS;
|
|
5243
5458
|
var init_skill_cache = __esm({
|
|
5244
5459
|
"../adapters/src/_core/skill-cache.ts"() {
|
|
5245
5460
|
"use strict";
|
|
5246
5461
|
import_node_crypto7 = require("node:crypto");
|
|
5247
5462
|
fsp = __toESM(require("node:fs/promises"), 1);
|
|
5248
|
-
|
|
5463
|
+
os5 = __toESM(require("node:os"), 1);
|
|
5249
5464
|
path8 = __toESM(require("node:path"), 1);
|
|
5250
5465
|
MANIFEST_SCHEMA_VERSION = 2;
|
|
5251
5466
|
STALE_LOCK_MS = 6e4;
|
|
@@ -6435,7 +6650,7 @@ function codexSessionsRoot() {
|
|
|
6435
6650
|
const candidates = [];
|
|
6436
6651
|
const ch = process.env["CODEX_HOME"];
|
|
6437
6652
|
if (ch) candidates.push(path10.join(ch, "sessions"));
|
|
6438
|
-
const home2 = process.env["HOME"] ||
|
|
6653
|
+
const home2 = process.env["HOME"] || os6.homedir();
|
|
6439
6654
|
if (home2) candidates.push(path10.join(home2, ".codex", "sessions"));
|
|
6440
6655
|
for (const c of candidates) {
|
|
6441
6656
|
try {
|
|
@@ -6758,7 +6973,7 @@ function codexTurnErrorMessage(value2) {
|
|
|
6758
6973
|
const detail = typeof error2?.additionalDetails === "string" ? error2.additionalDetails.trim() : "";
|
|
6759
6974
|
return [summary, detail].filter(Boolean).join("\n").slice(0, 4e3);
|
|
6760
6975
|
}
|
|
6761
|
-
var import_node_child_process7, import_node_crypto9, fs8,
|
|
6976
|
+
var import_node_child_process7, import_node_crypto9, fs8, os6, path10, readline2, CODEX_BLOCKED_FLAGS, CODEX_ARGV_PROMPT_MAX_BYTES, CodexRolloutUsageTail, CODEX_APP_SERVER_BLOCKED_FLAGS, CodexAdapter;
|
|
6762
6977
|
var init_codex = __esm({
|
|
6763
6978
|
"../adapters/src/codex/index.ts"() {
|
|
6764
6979
|
"use strict";
|
|
@@ -6766,7 +6981,7 @@ var init_codex = __esm({
|
|
|
6766
6981
|
init_container_runtime();
|
|
6767
6982
|
import_node_crypto9 = require("node:crypto");
|
|
6768
6983
|
fs8 = __toESM(require("node:fs"), 1);
|
|
6769
|
-
|
|
6984
|
+
os6 = __toESM(require("node:os"), 1);
|
|
6770
6985
|
path10 = __toESM(require("node:path"), 1);
|
|
6771
6986
|
readline2 = __toESM(require("node:readline"), 1);
|
|
6772
6987
|
init_sync_skills();
|
|
@@ -9372,7 +9587,7 @@ function pdeathsigAvailable(probe = defaultProbe) {
|
|
|
9372
9587
|
return cachedAvailable;
|
|
9373
9588
|
}
|
|
9374
9589
|
function defaultProbe() {
|
|
9375
|
-
if (
|
|
9590
|
+
if (os7.platform() !== "linux") return false;
|
|
9376
9591
|
try {
|
|
9377
9592
|
const help = (0, import_node_child_process9.execFileSync)("setpriv", ["--help"], { stdio: ["ignore", "pipe", "ignore"], timeout: 2e3 }).toString();
|
|
9378
9593
|
return help.includes("--pdeathsig");
|
|
@@ -9386,12 +9601,12 @@ function pdeathsigWrap(bin, args) {
|
|
|
9386
9601
|
function shouldBindRuntimePdeathsig() {
|
|
9387
9602
|
return process.env["OASIS_BIND_RUNTIME_PDEATHSIG"] === "1" && pdeathsigAvailable();
|
|
9388
9603
|
}
|
|
9389
|
-
var import_node_child_process9,
|
|
9604
|
+
var import_node_child_process9, os7, cachedAvailable;
|
|
9390
9605
|
var init_pdeathsig = __esm({
|
|
9391
9606
|
"../adapters/src/_core/pdeathsig.ts"() {
|
|
9392
9607
|
"use strict";
|
|
9393
9608
|
import_node_child_process9 = require("node:child_process");
|
|
9394
|
-
|
|
9609
|
+
os7 = __toESM(require("node:os"), 1);
|
|
9395
9610
|
}
|
|
9396
9611
|
});
|
|
9397
9612
|
|
|
@@ -12832,7 +13047,13 @@ async function reconcileChatTurn(turn, deps) {
|
|
|
12832
13047
|
...status === "succeeded" || !restartCause ? {} : { cancelledBy: restartCause }
|
|
12833
13048
|
});
|
|
12834
13049
|
if (!ok3) return raced;
|
|
12835
|
-
return {
|
|
13050
|
+
return {
|
|
13051
|
+
settled: true,
|
|
13052
|
+
turnId: turn.id,
|
|
13053
|
+
status,
|
|
13054
|
+
reason: `run \u7EC8\u6001 ${run.status}`,
|
|
13055
|
+
...run.exitReason ? { exitReason: run.exitReason } : {}
|
|
13056
|
+
};
|
|
12836
13057
|
}
|
|
12837
13058
|
async function sweepStaleChatTurns(deps) {
|
|
12838
13059
|
const before = new Date(deps.now - (deps.staleAfterMs ?? 2 * 6e4)).toISOString();
|
|
@@ -12854,7 +13075,8 @@ async function sweepStaleChatTurns(deps) {
|
|
|
12854
13075
|
chatSessionId: turn.chatSessionId,
|
|
12855
13076
|
turnId: turn.id,
|
|
12856
13077
|
status: settledStatus,
|
|
12857
|
-
reason: outcome.reason ?? `\u8F6E\u6B21\u6536\u53E3\u4E3A ${settledStatus}
|
|
13078
|
+
reason: outcome.reason ?? `\u8F6E\u6B21\u6536\u53E3\u4E3A ${settledStatus}`,
|
|
13079
|
+
...outcome.settled && outcome.exitReason ? { exitReason: outcome.exitReason } : {}
|
|
12858
13080
|
}).catch((e) => {
|
|
12859
13081
|
deps.log?.(`[chat-turn-sweep] \u8F6E\u6B21 ${turn.id} \u6536\u53E3\u540E\u7684\u56DE\u8C03\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u672C\u62CD\uFF09: ${String(e)}`);
|
|
12860
13082
|
});
|
|
@@ -138139,6 +138361,13 @@ function openBackpressureOf(model, id) {
|
|
|
138139
138361
|
function unresolvedGapsOf(model, id) {
|
|
138140
138362
|
return (model.gaps.get(id) ?? []).filter((g2) => !g2.resolved);
|
|
138141
138363
|
}
|
|
138364
|
+
function findGap(model, gapId) {
|
|
138365
|
+
for (const [artifactId, list2] of model.gaps) {
|
|
138366
|
+
const gap = list2.find((g2) => g2.gapId === gapId);
|
|
138367
|
+
if (gap) return { artifactId, gap };
|
|
138368
|
+
}
|
|
138369
|
+
return null;
|
|
138370
|
+
}
|
|
138142
138371
|
function unresolvedEscalationsOf(model, id) {
|
|
138143
138372
|
return (model.escalations.get(id) ?? []).filter((e) => !e.resolved).map((e) => ({
|
|
138144
138373
|
// ADR 0079 D4:把稳定 id 一并带出——inbox / 卡片要靠它指明「关哪一条」(现状 resolve 是 artifact 级全清)。
|
|
@@ -142189,9 +142418,6 @@ ${supplemental.taskAppend.trim()}
|
|
|
142189
142418
|
`;
|
|
142190
142419
|
}
|
|
142191
142420
|
}
|
|
142192
|
-
if (this.opts.executionContinuityInstructions && continuityExposureOn && (spec.action === "produce" || spec.action === "integrate") && continuityArtifact) {
|
|
142193
|
-
bundle.files["execution/CONTINUITY.md"] = this.opts.executionContinuityInstructions;
|
|
142194
|
-
}
|
|
142195
142421
|
if (this.opts.resolveExecutionResumePack && continuityExposureOn && (spec.action === "produce" || spec.action === "integrate") && continuityArtifact) {
|
|
142196
142422
|
let resumePack = null;
|
|
142197
142423
|
try {
|
|
@@ -142799,6 +143025,9 @@ ${supplemental.taskAppend.trim()}
|
|
|
142799
143025
|
});
|
|
142800
143026
|
|
|
142801
143027
|
// ../core/src/session-limits.ts
|
|
143028
|
+
function sessionWallClockMs(kind) {
|
|
143029
|
+
return SESSION_WALL_CLOCK_MS[kind];
|
|
143030
|
+
}
|
|
142802
143031
|
var SESSION_WALL_CLOCK_MS;
|
|
142803
143032
|
var init_session_limits = __esm({
|
|
142804
143033
|
"../core/src/session-limits.ts"() {
|
|
@@ -142929,6 +143158,41 @@ ${lines.join("\n")}`, "rejected-proposal-repeat");
|
|
|
142929
143158
|
}
|
|
142930
143159
|
});
|
|
142931
143160
|
|
|
143161
|
+
// ../core/src/command-card-naming.ts
|
|
143162
|
+
function commandCardRefsOf(model) {
|
|
143163
|
+
const nodeTitle = (id) => model.artifacts.get(id)?.title?.trim() || void 0;
|
|
143164
|
+
return {
|
|
143165
|
+
nodeTitle,
|
|
143166
|
+
escalation: (escalationId) => {
|
|
143167
|
+
const found2 = escalationById(model, escalationId);
|
|
143168
|
+
if (!found2) return void 0;
|
|
143169
|
+
return { summary: found2.reason, ...nodeTitle(found2.artifactId) ? { nodeTitle: nodeTitle(found2.artifactId) } : {} };
|
|
143170
|
+
},
|
|
143171
|
+
gap: (gapId) => {
|
|
143172
|
+
const found2 = findGap(model, gapId);
|
|
143173
|
+
if (!found2) return void 0;
|
|
143174
|
+
return { summary: found2.gap.description, ...nodeTitle(found2.artifactId) ? { nodeTitle: nodeTitle(found2.artifactId) } : {} };
|
|
143175
|
+
}
|
|
143176
|
+
};
|
|
143177
|
+
}
|
|
143178
|
+
function annotateCommandCardLabels(model) {
|
|
143179
|
+
const refs = commandCardRefsOf(model);
|
|
143180
|
+
for (const review of model.pendingReviews.values()) {
|
|
143181
|
+
if (!review.command) continue;
|
|
143182
|
+
review.command = {
|
|
143183
|
+
...review.command,
|
|
143184
|
+
displayLabel: commandCardDisplayLabel(review.command.command, review.command.args, review.command.effectLabel, refs)
|
|
143185
|
+
};
|
|
143186
|
+
}
|
|
143187
|
+
}
|
|
143188
|
+
var init_command_card_naming = __esm({
|
|
143189
|
+
"../core/src/command-card-naming.ts"() {
|
|
143190
|
+
"use strict";
|
|
143191
|
+
init_src();
|
|
143192
|
+
init_read_model();
|
|
143193
|
+
}
|
|
143194
|
+
});
|
|
143195
|
+
|
|
142932
143196
|
// ../core/src/queue-retirement.ts
|
|
142933
143197
|
function isSettledProduction(w2) {
|
|
142934
143198
|
if (w2.lane === "reply") return false;
|
|
@@ -144244,6 +144508,7 @@ var init_kernel_bridge = __esm({
|
|
|
144244
144508
|
init_closure_gate2();
|
|
144245
144509
|
init_kernel();
|
|
144246
144510
|
init_bridge_readmodel();
|
|
144511
|
+
init_command_card_naming();
|
|
144247
144512
|
init_propose_guard();
|
|
144248
144513
|
init_src6();
|
|
144249
144514
|
init_src6();
|
|
@@ -144569,6 +144834,7 @@ var init_kernel_bridge = __esm({
|
|
|
144569
144834
|
...card2.priorRejections && card2.priorRejections.length > 0 ? { priorRejections: card2.priorRejections } : {}
|
|
144570
144835
|
});
|
|
144571
144836
|
}
|
|
144837
|
+
annotateCommandCardLabels(fresh);
|
|
144572
144838
|
Object.assign(this.model, fresh);
|
|
144573
144839
|
if (!this.sweepingStaleDrafts && this.draftCards.size > 0) {
|
|
144574
144840
|
this.sweepingStaleDrafts = true;
|
|
@@ -146675,6 +146941,7 @@ var init_src7 = __esm({
|
|
|
146675
146941
|
init_dispatcher();
|
|
146676
146942
|
init_session_limits();
|
|
146677
146943
|
init_rejected_proposals();
|
|
146944
|
+
init_command_card_naming();
|
|
146678
146945
|
init_kernel_bridge();
|
|
146679
146946
|
init_bridge_readmodel();
|
|
146680
146947
|
init_queue_retirement();
|
|
@@ -165233,6 +165500,23 @@ async function waitForInflightInsert(rowId, timeoutMs) {
|
|
|
165233
165500
|
})]);
|
|
165234
165501
|
if (timer) clearTimeout(timer);
|
|
165235
165502
|
}
|
|
165503
|
+
async function waitForAdmittedTurnStart(chatSessionId, deps) {
|
|
165504
|
+
if (deps.liveChat.isRunning(chatSessionId)) return;
|
|
165505
|
+
if (!await deps.ledgerTurnRunning()) return;
|
|
165506
|
+
await new Promise((resolve11) => {
|
|
165507
|
+
let stop = () => {
|
|
165508
|
+
};
|
|
165509
|
+
const timer = setTimeout(() => {
|
|
165510
|
+
stop();
|
|
165511
|
+
resolve11();
|
|
165512
|
+
}, deps.timeoutMs);
|
|
165513
|
+
timer.unref?.();
|
|
165514
|
+
stop = deps.liveChat.onNextTurn(chatSessionId, () => {
|
|
165515
|
+
clearTimeout(timer);
|
|
165516
|
+
resolve11();
|
|
165517
|
+
});
|
|
165518
|
+
});
|
|
165519
|
+
}
|
|
165236
165520
|
async function appendNowThroughQueue(chatSessionId, text7, deps, clientKey, attachments, retainLocallyOnFailure = false, opts) {
|
|
165237
165521
|
const newId = deps.newId ?? import_node_crypto22.randomUUID;
|
|
165238
165522
|
const now = deps.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -200780,6 +201064,150 @@ var init_knowledge2 = __esm({
|
|
|
200780
201064
|
}
|
|
200781
201065
|
});
|
|
200782
201066
|
|
|
201067
|
+
// ../server/src/chat-exit.ts
|
|
201068
|
+
function transcriptTail(ref2) {
|
|
201069
|
+
try {
|
|
201070
|
+
const stat4 = fs17.statSync(ref2);
|
|
201071
|
+
const size = Math.min(stat4.size, 4e3);
|
|
201072
|
+
const buf = Buffer.alloc(size);
|
|
201073
|
+
const fd = fs17.openSync(ref2, "r");
|
|
201074
|
+
try {
|
|
201075
|
+
fs17.readSync(fd, buf, 0, size, Math.max(0, stat4.size - size));
|
|
201076
|
+
} finally {
|
|
201077
|
+
fs17.closeSync(fd);
|
|
201078
|
+
}
|
|
201079
|
+
return buf.toString("utf8").trim();
|
|
201080
|
+
} catch {
|
|
201081
|
+
return "";
|
|
201082
|
+
}
|
|
201083
|
+
}
|
|
201084
|
+
function clipLine(line2) {
|
|
201085
|
+
return line2.length > SUMMARY_MAX_CHARS ? `${line2.slice(0, SUMMARY_MAX_CHARS)}\u2026` : line2;
|
|
201086
|
+
}
|
|
201087
|
+
function providerMessage(line2) {
|
|
201088
|
+
const m2 = /['"]message['"]\s*:\s*(?:'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)")/.exec(line2);
|
|
201089
|
+
const text7 = (m2?.[1] ?? m2?.[2])?.trim();
|
|
201090
|
+
return text7 ? text7 : void 0;
|
|
201091
|
+
}
|
|
201092
|
+
function failureKind(reason, line2) {
|
|
201093
|
+
if (line2.startsWith(SESSION_STARTUP_FAILED_PREFIX)) return "startup-failed";
|
|
201094
|
+
switch (reason) {
|
|
201095
|
+
case "auth-error":
|
|
201096
|
+
return "auth";
|
|
201097
|
+
case "server-unreachable":
|
|
201098
|
+
return "node-unreachable";
|
|
201099
|
+
case "timeout":
|
|
201100
|
+
return "timeout";
|
|
201101
|
+
case "output-limit":
|
|
201102
|
+
return "output-limit";
|
|
201103
|
+
case "rate-limit":
|
|
201104
|
+
return QUOTA_RE3.test(line2) ? "quota" : "rate-limit";
|
|
201105
|
+
default:
|
|
201106
|
+
break;
|
|
201107
|
+
}
|
|
201108
|
+
if (!line2) return "unknown";
|
|
201109
|
+
if (DISK_FULL_RE.test(line2)) return "disk-full";
|
|
201110
|
+
if (QUOTA_RE3.test(line2)) return "quota";
|
|
201111
|
+
if (AUTH_RE2.test(line2)) return "auth";
|
|
201112
|
+
if (RATE_LIMIT_RE.test(line2)) return "rate-limit";
|
|
201113
|
+
if (MODEL_RE.test(line2)) return "model";
|
|
201114
|
+
if (UNREACHABLE_RE2.test(line2)) return "node-unreachable";
|
|
201115
|
+
return "unknown";
|
|
201116
|
+
}
|
|
201117
|
+
function setChatWallClockMs(ms) {
|
|
201118
|
+
effectiveChatWallClockMs = typeof ms === "number" && ms > 0 ? ms : void 0;
|
|
201119
|
+
}
|
|
201120
|
+
function wallClockText(ms = effectiveChatWallClockMs ?? sessionWallClockMs("chat")) {
|
|
201121
|
+
const minutes = Math.round(ms / 6e4);
|
|
201122
|
+
return minutes > 0 && minutes % 60 === 0 ? `${minutes / 60} \u5C0F\u65F6` : `${minutes} \u5206\u949F`;
|
|
201123
|
+
}
|
|
201124
|
+
function resetTime(line2) {
|
|
201125
|
+
return extractResetHint(line2)?.replace(/^(?:resets?|try again at)\s+/i, "").trim() || void 0;
|
|
201126
|
+
}
|
|
201127
|
+
function failureSummary(kind, ctx) {
|
|
201128
|
+
switch (kind) {
|
|
201129
|
+
case "auth":
|
|
201130
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u7684\u767B\u5F55\u5DF2\u8FC7\u671F\u6216\u51ED\u8BC1\u65E0\u6548\uFF0C\u8C03\u7528\u4E0D\u4E86\u6A21\u578B\u3002\u8BF7\u8282\u70B9\u7BA1\u7406\u5458\u5728\u90A3\u53F0\u673A\u5668\u4E0A\u91CD\u65B0\u767B\u5F55\u8FD9\u4E2A\u8FD0\u884C\u65F6\uFF08\u6216\u66F4\u65B0 API Key\uFF09\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u53EF\u7528\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
201131
|
+
case "quota": {
|
|
201132
|
+
const at = resetTime(ctx.line);
|
|
201133
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u989D\u5EA6\u5DF2\u7528\u5B8C${at ? `\uFF0C\u9884\u8BA1 ${at} \u6062\u590D` : ""}\u3002\u8BF7\u7B49\u989D\u5EA6\u6062\u590D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u989D\u5EA6\u5145\u8DB3\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
201134
|
+
}
|
|
201135
|
+
case "rate-limit":
|
|
201136
|
+
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u670D\u52A1\u6682\u65F6\u9650\u6D41\u6216\u7E41\u5FD9\u3002\u8BF7\u7B49\u4E00\u4E24\u5206\u949F\u518D\u53D1\u4E00\u6B21\u3002";
|
|
201137
|
+
case "node-unreachable":
|
|
201138
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u8FD9\u4F4D Agent \u7684\u8282\u70B9\u79BB\u7EBF\u6216\u8FDE\u63A5\u4E2D\u65AD\u3002\u8BF7\u786E\u8BA4\u90A3\u53F0\u673A\u5668\u5F00\u7740\u3001\u8282\u70B9\u7A0B\u5E8F\u5728\u8FD0\u884C\u3001\u7F51\u7EDC\u6B63\u5E38\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u5728\u7EBF\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
201139
|
+
case "model":
|
|
201140
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD9\u4E2A\u8FD0\u884C\u65F6\u7528\u4E0D\u4E86\u5F53\u524D\u914D\u7F6E\u7684\u6A21\u578B\u3002\u8BF7${chatRebindHint("\u6362\u4E00\u4E2A\u53EF\u7528\u7684\u6A21\u578B")}\u540E\u518D\u53D1\u4E00\u6B21\u3002`;
|
|
201141
|
+
case "timeout":
|
|
201142
|
+
return `\u8FD9\u4E00\u6B21\u6267\u884C\u8DD1\u6EE1\u4E86\u5355\u6B21\u8FD0\u884C\u7684\u65F6\u95F4\u4E0A\u9650\uFF08${wallClockText()}\uFF09\uFF0C\u88AB\u7CFB\u7EDF\u505C\u4E0B\u4E86\u3002\u5DF2\u7ECF\u505A\u5B8C\u7684\u90E8\u5206\u4E0D\u4F1A\u4E22\uFF1B\u8981\u63A5\u7740\u505A\u7684\u8BDD\uFF0C\u628A\u5269\u4E0B\u7684\u90E8\u5206\u62C6\u5C0F\u4E00\u4E9B\u518D\u53D1\u4E00\u6B21\u3002`;
|
|
201143
|
+
case "startup-failed":
|
|
201144
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A${ctx.readable || SESSION_STARTUP_FAILED_PREFIX}\u3002\u8FD9\u4E00\u8F6E\u6CA1\u6709\u5F00\u59CB\u8FD0\u884C\uFF0C\u53EF\u4EE5\u76F4\u63A5\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u591A\u534A\u662F\u90A3\u53F0\u8282\u70B9\u8D1F\u8F7D\u8FC7\u9AD8\uFF0C\u8BF7\u7BA1\u7406\u5458\u7ED9\u5B83\u51CF\u8D1F\u6216${chatRebindHint("\u6362\u4E00\u4E2A\u8FD0\u884C\u65F6")}\u3002`;
|
|
201145
|
+
case "disk-full":
|
|
201146
|
+
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u8FD9\u4F4D Agent \u7684\u8282\u70B9\u78C1\u76D8\u7A7A\u95F4\u6EE1\u4E86\uFF0C\u8FD9\u4E00\u8F6E\u5199\u4E0D\u4E86\u6587\u4EF6\u3002\u8BF7\u8282\u70B9\u7BA1\u7406\u5458\u6E05\u7406\u90A3\u53F0\u673A\u5668\u7684\u78C1\u76D8\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u8FD0\u884C\u65F6")}\u3002`;
|
|
201147
|
+
case "output-limit":
|
|
201148
|
+
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u8F93\u51FA\u8D85\u51FA\u957F\u5EA6\u4E0A\u9650\uFF0C\u56DE\u590D\u88AB\u622A\u65AD\u4E86\u3002\u53EF\u4EE5\u8BA9\u5B83\u5206\u51E0\u6B21\u8F93\u51FA\uFF0C\u6216\u628A\u4EFB\u52A1\u62C6\u5C0F\u4E00\u4E9B\u518D\u53D1\u3002";
|
|
201149
|
+
case "unknown":
|
|
201150
|
+
if (ctx.line) {
|
|
201151
|
+
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u62A5\u9519\u4E86\uFF0C\u6682\u65F6\u6CA1\u8BA4\u51FA\u662F\u4EC0\u4E48\u539F\u56E0\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u70B9\u300C\u5C55\u5F00\u8BE6\u60C5\u300D\u628A\u539F\u59CB\u62A5\u9519\u53D1\u7ED9\u7BA1\u7406\u5458\u3002";
|
|
201152
|
+
}
|
|
201153
|
+
return ctx.hasDetail ? "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u5F02\u5E38\u9000\u51FA\uFF0C\u6CA1\u6709\u7ED9\u51FA\u62A5\u9519\u539F\u56E0\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u70B9\u300C\u5C55\u5F00\u8BE6\u60C5\u300D\u628A\u539F\u59CB\u8BB0\u5F55\u53D1\u7ED9\u7BA1\u7406\u5458\u3002" : `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u5F02\u5E38\u9000\u51FA\uFF08\u9000\u51FA\u7801 ${ctx.code ?? "\u65E0"}\uFF09\uFF0C\u6CA1\u6709\u7559\u4E0B\u62A5\u9519\u4FE1\u606F\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u7BA1\u7406\u5458\u5230\u300C\u8FD0\u884C\u8F68\u8FF9\u300D\u91CC\u67E5\u8FD9\u4E00\u8F6E\u3002`;
|
|
201154
|
+
}
|
|
201155
|
+
}
|
|
201156
|
+
function buildChatExitError(info) {
|
|
201157
|
+
const chatExit = chatExitSummary(info);
|
|
201158
|
+
return Object.assign(new Error(chatExit.summary), { chatExit });
|
|
201159
|
+
}
|
|
201160
|
+
function chatExitSummary(info) {
|
|
201161
|
+
const genericLine = `runtime exited with code ${info.code ?? "null"}${info.reason ? ` (${info.reason})` : ""}`;
|
|
201162
|
+
let detail = "";
|
|
201163
|
+
if (info.reason !== "cancelled") {
|
|
201164
|
+
detail = info.errorMessage?.trim() ?? "";
|
|
201165
|
+
if (!detail && info.transcriptRef) detail = transcriptTail(info.transcriptRef);
|
|
201166
|
+
}
|
|
201167
|
+
let summary;
|
|
201168
|
+
let cancelledBy;
|
|
201169
|
+
if (info.reason === "cancelled") {
|
|
201170
|
+
cancelledBy = cancelCauseFromExitMessage(info.errorMessage);
|
|
201171
|
+
summary = chatCancelNote(cancelledBy);
|
|
201172
|
+
} else {
|
|
201173
|
+
const firstErrorLine = (info.errorMessage?.split("\n").map((line2) => line2.trim()).find(Boolean) ?? "").replace(INTERNAL_PREFIX_RE, "");
|
|
201174
|
+
const readable = firstErrorLine ? clipLine(providerMessage(firstErrorLine) ?? firstErrorLine) : "";
|
|
201175
|
+
summary = failureSummary(failureKind(info.reason, firstErrorLine), {
|
|
201176
|
+
readable,
|
|
201177
|
+
line: firstErrorLine,
|
|
201178
|
+
hasDetail: Boolean(detail),
|
|
201179
|
+
code: info.code
|
|
201180
|
+
});
|
|
201181
|
+
}
|
|
201182
|
+
return {
|
|
201183
|
+
...info.reason ? { reason: info.reason } : {},
|
|
201184
|
+
summary,
|
|
201185
|
+
...cancelledBy ? { cancelledBy } : {},
|
|
201186
|
+
...info.reason !== "cancelled" ? { detail: (detail ? `${genericLine}
|
|
201187
|
+
|
|
201188
|
+
${detail}` : genericLine).slice(0, 4200) } : {}
|
|
201189
|
+
};
|
|
201190
|
+
}
|
|
201191
|
+
var fs17, SUMMARY_MAX_CHARS, INTERNAL_PREFIX_RE, QUOTA_RE3, RATE_LIMIT_RE, AUTH_RE2, MODEL_RE, DISK_FULL_RE, UNREACHABLE_RE2, effectiveChatWallClockMs, chatRebindHint;
|
|
201192
|
+
var init_chat_exit = __esm({
|
|
201193
|
+
"../server/src/chat-exit.ts"() {
|
|
201194
|
+
"use strict";
|
|
201195
|
+
fs17 = __toESM(require("node:fs"), 1);
|
|
201196
|
+
init_src();
|
|
201197
|
+
init_src7();
|
|
201198
|
+
init_chat_cancel_attribution();
|
|
201199
|
+
SUMMARY_MAX_CHARS = 500;
|
|
201200
|
+
INTERNAL_PREFIX_RE = /^\[[a-z][a-z0-9_]*\]\s*/;
|
|
201201
|
+
QUOTA_RE3 = /hit your (?:\w+ )?limit|usage limit|quota|insufficient[_ ](?:balance|credit|funds)|credit balance|billing|\b402\b|额度|余额/i;
|
|
201202
|
+
RATE_LIMIT_RE = /rate.?limit|too many requests|\b429\b|\b529\b|overloaded|限流/i;
|
|
201203
|
+
AUTH_RE2 = /\b401\b|\b403\b|unauthori[sz]ed|authenticat|oauth|invalid[_ -]?(?:api[_ -]?key|token|x-api-key)|api[_ -]?key[^\n]{0,40}\b(?:invalid|expired|revoked)|token[^\n]{0,30}\b(?:expired|invalid|revoked)|not logged in|\/login|credential|凭证|登录/i;
|
|
201204
|
+
MODEL_RE = /\bmodel\b[^\n]{0,120}?\b(?:not found|not exist|does not exist|not available|not supported|unavailable|unknown)\b|\b(?:unknown|invalid|unsupported) model\b|model_not_found/i;
|
|
201205
|
+
DISK_FULL_RE = /\bENOSPC\b|no space left on device|\bEDQUOT\b|disk quota exceeded|\[Errno 28\]|disk (?:is )?full|磁盘(?:空间)?(?:已满|不足)/i;
|
|
201206
|
+
UNREACHABLE_RE2 = /不在线|socket 非 OPEN|帧未送达|失联/;
|
|
201207
|
+
chatRebindHint = (what) => `\u5728\u7EC4\u7EC7\u9875\u8FD9\u4F4D Agent \u7684\u300C\u6A21\u578B\u300D\u9875\u7B7E\u91CC${what}`;
|
|
201208
|
+
}
|
|
201209
|
+
});
|
|
201210
|
+
|
|
200783
201211
|
// ../server/src/domains/delegations/parent-conversation.ts
|
|
200784
201212
|
function firstLine2(content3) {
|
|
200785
201213
|
const line2 = content3.split("\n").map((s2) => s2.trim()).find((s2) => s2.length > 0);
|
|
@@ -201180,6 +201608,14 @@ var init_files = __esm({
|
|
|
201180
201608
|
});
|
|
201181
201609
|
|
|
201182
201610
|
// ../server/src/domains/delegations/service.ts
|
|
201611
|
+
function exitReasonOf(err) {
|
|
201612
|
+
if (!(err instanceof Error)) return void 0;
|
|
201613
|
+
const chatExit = err.chatExit;
|
|
201614
|
+
return chatExit?.reason;
|
|
201615
|
+
}
|
|
201616
|
+
function roundFailureText(kind, error2) {
|
|
201617
|
+
return kind === "timeout" ? `\u8FD9\u4E00\u6B21\u6267\u884C\u8DD1\u6EE1\u4E86\u5355\u6B21\u8FD0\u884C\u7684\u65F6\u95F4\u4E0A\u9650\uFF08${wallClockText()}\uFF09\uFF0C\u88AB\u7CFB\u7EDF\u505C\u4E0B\u4E86\uFF08${error2}\uFF09` : `\u8FD9\u4E00\u8F6E\u6CA1\u8DD1\u5B8C\uFF1A${error2}`;
|
|
201618
|
+
}
|
|
201183
201619
|
function deterministicUuid2(seed) {
|
|
201184
201620
|
const h = (0, import_node_crypto36.createHash)("sha256").update(seed).digest();
|
|
201185
201621
|
const b2 = Buffer.from(h.subarray(0, 16));
|
|
@@ -201242,6 +201678,7 @@ var init_service3 = __esm({
|
|
|
201242
201678
|
"use strict";
|
|
201243
201679
|
import_node_crypto36 = require("node:crypto");
|
|
201244
201680
|
init_src();
|
|
201681
|
+
init_chat_exit();
|
|
201245
201682
|
init_parent_conversation();
|
|
201246
201683
|
init_title();
|
|
201247
201684
|
init_deletion();
|
|
@@ -201929,7 +202366,7 @@ var init_service3 = __esm({
|
|
|
201929
202366
|
try {
|
|
201930
202367
|
await dispatched.done;
|
|
201931
202368
|
} catch (err) {
|
|
201932
|
-
failureKind2 = "interrupted";
|
|
202369
|
+
failureKind2 = exitReasonOf(err) === "timeout" ? "timeout" : "interrupted";
|
|
201933
202370
|
error2 = err instanceof Error ? err.message : String(err);
|
|
201934
202371
|
}
|
|
201935
202372
|
const at = this.now();
|
|
@@ -201946,7 +202383,11 @@ var init_service3 = __esm({
|
|
|
201946
202383
|
const round = (fresh.roundSummaries[fresh.roundSummaries.length - 1]?.round ?? 0) + 1;
|
|
201947
202384
|
const newSummary = {
|
|
201948
202385
|
round,
|
|
201949
|
-
|
|
202386
|
+
/* ⚠️ 到点被停下那一档**不往摘要里合成句子**(Bug 0221):`text` 从此是「专家这一轮到底
|
|
202387
|
+
写出没写出正文」的判据——回流通告据它判「有没有可验证的交付」(`hasDelegationDelivery`)。
|
|
202388
|
+
合成的那句话仍写进下面子会话的占位行(用户在子会话里要看到一句交代),
|
|
202389
|
+
通告里空正文由 `delegationReturnText` 渲染成「(这一轮没有文本产出)」。 */
|
|
202390
|
+
text: text7 || (failureKind2 && failureKind2 !== "timeout" ? roundFailureText(failureKind2, error2) : ""),
|
|
201950
202391
|
at,
|
|
201951
202392
|
// 本轮的键 = 派发这一轮时的 dispatchSeq(`record` 就是派发时那一份,轮次账本业务键也由它算)。
|
|
201952
202393
|
dispatchSeq: record9.dispatchSeq ?? 0
|
|
@@ -201956,7 +202397,7 @@ var init_service3 = __esm({
|
|
|
201956
202397
|
const stopLoss = consecutiveFails >= CONSECUTIVE_FAIL_LIMIT;
|
|
201957
202398
|
const chatStore = await this.options.resolveChatSessions(companyId).catch(() => null);
|
|
201958
202399
|
await chatStore?.updateMessage(childRoundMessageIds(fresh.childSessionId, round).placeholderId, {
|
|
201959
|
-
content: text7 || (failureKind2 ?
|
|
202400
|
+
content: text7 || (failureKind2 ? roundFailureText(failureKind2, error2) : ""),
|
|
201960
202401
|
status: failureKind2 ? "error" : "done",
|
|
201961
202402
|
completedAt: at
|
|
201962
202403
|
}).catch(() => void 0);
|
|
@@ -202029,9 +202470,11 @@ var init_service3 = __esm({
|
|
|
202029
202470
|
if (opts?.outcome === "succeeded") return this.settleSucceededFromSweep(record9, dispatchSeq, companyId);
|
|
202030
202471
|
const at = this.now();
|
|
202031
202472
|
const settledSeqAtRound = record9.settledSeq + 1;
|
|
202473
|
+
const timedOut = opts?.exitReason === "timeout";
|
|
202474
|
+
const partialAnswer = timedOut ? await this.readChildRoundAnswer(record9, dispatchSeq + 1, companyId).catch(() => "") : "";
|
|
202032
202475
|
const newSummary = {
|
|
202033
202476
|
round: (record9.roundSummaries[record9.roundSummaries.length - 1]?.round ?? 0) + 1,
|
|
202034
|
-
text: `\u8FD9\u4E00\u8F6E\u88AB\u65F6\u949F\u95ED\u5408\uFF1A${reason}`,
|
|
202477
|
+
text: timedOut ? partialAnswer : `\u8FD9\u4E00\u8F6E\u88AB\u65F6\u949F\u95ED\u5408\uFF1A${reason}`,
|
|
202035
202478
|
at,
|
|
202036
202479
|
settledSeq: settledSeqAtRound,
|
|
202037
202480
|
dispatchSeq
|
|
@@ -202039,7 +202482,8 @@ var init_service3 = __esm({
|
|
|
202039
202482
|
const settled = await store.appendRoundSummary(record9.id, newSummary, {
|
|
202040
202483
|
state: "failed",
|
|
202041
202484
|
// 退出帧丢失后被时钟闭合 = `interrupted`(§9),不是 `not-started`——它确实起来过。
|
|
202042
|
-
|
|
202485
|
+
// run 报的是墙钟超时时归 `timeout`(Bug 0221):同样起来过,但「到点被停」与「断了」说法不同。
|
|
202486
|
+
failureKind: timedOut ? "timeout" : "interrupted",
|
|
202043
202487
|
consecutiveFails: record9.consecutiveFails + 1,
|
|
202044
202488
|
settledSeq: settledSeqAtRound,
|
|
202045
202489
|
settledAt: at
|
|
@@ -202640,11 +203084,11 @@ var init_routes2 = __esm({
|
|
|
202640
203084
|
});
|
|
202641
203085
|
|
|
202642
203086
|
// ../server/src/domains/delegations/store.ts
|
|
202643
|
-
var
|
|
203087
|
+
var fs18, path18, touchKey, settlesTerminal, MemoryDelegationStore, FileDelegationStore;
|
|
202644
203088
|
var init_store2 = __esm({
|
|
202645
203089
|
"../server/src/domains/delegations/store.ts"() {
|
|
202646
203090
|
"use strict";
|
|
202647
|
-
|
|
203091
|
+
fs18 = __toESM(require("node:fs"), 1);
|
|
202648
203092
|
path18 = __toESM(require("node:path"), 1);
|
|
202649
203093
|
init_src();
|
|
202650
203094
|
touchKey = (delegationId, messageId) => `${delegationId}\0${messageId}`;
|
|
@@ -202788,13 +203232,13 @@ var init_store2 = __esm({
|
|
|
202788
203232
|
}
|
|
202789
203233
|
static async open(file) {
|
|
202790
203234
|
const store = new _FileDelegationStore(file);
|
|
202791
|
-
if (
|
|
202792
|
-
const snap = JSON.parse(
|
|
203235
|
+
if (fs18.existsSync(file)) {
|
|
203236
|
+
const snap = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
202793
203237
|
for (const d of snap.delegations ?? []) store.rows.set(d.id, d);
|
|
202794
203238
|
for (const t of snap.touches ?? []) store.touches.set(touchKey(t.delegationId, t.messageId), t);
|
|
202795
203239
|
} else {
|
|
202796
|
-
|
|
202797
|
-
|
|
203240
|
+
fs18.mkdirSync(path18.dirname(file), { recursive: true });
|
|
203241
|
+
fs18.writeFileSync(file, JSON.stringify({ delegations: [], touches: [] }, null, 2));
|
|
202798
203242
|
}
|
|
202799
203243
|
return store;
|
|
202800
203244
|
}
|
|
@@ -202803,7 +203247,7 @@ var init_store2 = __esm({
|
|
|
202803
203247
|
delegations: [...this.rows.values()],
|
|
202804
203248
|
touches: [...this.touches.values()]
|
|
202805
203249
|
};
|
|
202806
|
-
|
|
203250
|
+
fs18.writeFileSync(this.file, JSON.stringify(snapshot, null, 2));
|
|
202807
203251
|
}
|
|
202808
203252
|
async create(record9) {
|
|
202809
203253
|
const r = await super.create(record9);
|
|
@@ -203007,8 +203451,18 @@ function delegationReturnText(terminal, opts) {
|
|
|
203007
203451
|
const { record: record9 } = terminal;
|
|
203008
203452
|
const who = terminal.expertName ?? record9.expertActorId;
|
|
203009
203453
|
const name = record9.label ? `${who}\uFF08${record9.label}\uFF09` : who;
|
|
203010
|
-
const
|
|
203011
|
-
const
|
|
203454
|
+
const lastRoundText = record9.roundSummaries[record9.roundSummaries.length - 1]?.text;
|
|
203455
|
+
const ending = delegationEnding(record9, {
|
|
203456
|
+
movedFiles: opts.movedPaths.length,
|
|
203457
|
+
unchangedFiles: opts.unchangedPaths?.length ?? 0,
|
|
203458
|
+
...lastRoundText ? { roundText: lastRoundText } : {}
|
|
203459
|
+
});
|
|
203460
|
+
const cap = wallClockText();
|
|
203461
|
+
const head = ending === "done" ? `\u3010\u7CFB\u7EDF\u3011${name} \u5DF2\u5B8C\u6210\u3002` : ending === "timeout-delivered" ? `\u3010\u7CFB\u7EDF\u3011${name} \u8FD9\u4E00\u6B21\u6267\u884C\u8DD1\u6EE1\u4E86\u5355\u6B21\u8FD0\u884C\u7684\u65F6\u95F4\u4E0A\u9650\uFF08${cap}\uFF09\uFF0C\u88AB\u7CFB\u7EDF\u505C\u4E0B\u4E86\u2014\u2014\u5DF2\u7ECF\u4EA4\u56DE\u7684\u5185\u5BB9\u89C1\u4E0B\u3002` : ending === "timeout-empty" ? `\u3010\u7CFB\u7EDF\u3011${name} \u8FD9\u4E00\u6B21\u6267\u884C\u8DD1\u6EE1\u4E86\u5355\u6B21\u8FD0\u884C\u7684\u65F6\u95F4\u4E0A\u9650\uFF08${cap}\uFF09\uFF0C\u88AB\u7CFB\u7EDF\u505C\u4E0B\u4E86\uFF0C\u8FD9\u4E00\u8F6E\u6CA1\u6709\u4EA4\u56DE\u4EFB\u4F55\u5185\u5BB9\u3002` : `\u3010\u7CFB\u7EDF\u3011${name} \u65E0\u6CD5\u5B8C\u6210\u3002`;
|
|
203462
|
+
const lines = [
|
|
203463
|
+
head,
|
|
203464
|
+
`\u59D4\u6D3E id\uFF1A${record9.id.slice(0, 8)}\u3000label\uFF1A${record9.label ?? "\uFF08\u65E0\uFF09"}` + (record9.failureKind ? `\u3000\u7ED3\u675F\u539F\u56E0\uFF1A${record9.failureKind}` : "")
|
|
203465
|
+
];
|
|
203012
203466
|
const trimmed = trimRoundSummariesForReturn(record9.roundSummaries, opts.recentRounds);
|
|
203013
203467
|
if (trimmed.length > 0) {
|
|
203014
203468
|
lines.push("", `\u4E13\u5BB6\u5404\u8F6E\u5C0F\u7ED3\uFF08\u5171 ${trimmed.length} \u8F6E\uFF1B\u6700\u8FD1 ${opts.recentRounds} \u8F6E\u7ED9\u5168\u6587\uFF0C\u66F4\u65E9\u7684\u53EA\u7559\u9996\u884C\uFF0C\u5168\u6587\u7528 \`oasis delegate --status\` \u770B\uFF09\uFF1A`);
|
|
@@ -203043,7 +203497,7 @@ function delegationReturnText(terminal, opts) {
|
|
|
203043
203497
|
}
|
|
203044
203498
|
lines.push(
|
|
203045
203499
|
"",
|
|
203046
|
-
record9.state === "done" ? "\u8FD9\u4E9B\u662F\u6750\u6599\uFF0C\u4E0D\u662F\u7ED9\u7528\u6237\u7684\u6210\u54C1\uFF1A\u4F60\u6709\u8FD9\u6761\u5BF9\u8BDD\u7684\u5B8C\u6574\u4E0A\u4E0B\u6587\uFF0C\u81EA\u5DF1\u5224\u65AD\u8BE5\u8BB2\u54EA\u4E00\u53E5\u3001\u8981\u4E0D\u8981\u63A5\u7740\u5F80\u4E0B\u505A\u3002" : "\u5148\u81EA\u5DF1\u5224\u65AD\u80FD\u4E0D\u80FD\u63A5\u4F4F\uFF1A\u63A5\u7BA1\u3001\u6362\u4E2A\u505A\u6CD5\u3001\u8FD8\u662F\u91CD\u6D3E\u3002**\u522B\u628A\u4E13\u4E1A\u5931\u8D25\u539F\u6837\u4E22\u56DE\u7ED9\u7528\u6237**\u3002"
|
|
203500
|
+
record9.state === "done" ? "\u8FD9\u4E9B\u662F\u6750\u6599\uFF0C\u4E0D\u662F\u7ED9\u7528\u6237\u7684\u6210\u54C1\uFF1A\u4F60\u6709\u8FD9\u6761\u5BF9\u8BDD\u7684\u5B8C\u6574\u4E0A\u4E0B\u6587\uFF0C\u81EA\u5DF1\u5224\u65AD\u8BE5\u8BB2\u54EA\u4E00\u53E5\u3001\u8981\u4E0D\u8981\u63A5\u7740\u5F80\u4E0B\u505A\u3002" : ending === "timeout-delivered" ? "**\u8FD9\u4E0D\u662F\u4E13\u4E1A\u5931\u8D25\uFF0C\u662F\u65F6\u95F4\u5230\u4E86**\uFF1A\u5148\u770B\u4E0A\u9762\u5DF2\u7ECF\u4EA4\u56DE\u7684\u4E1C\u897F\uFF0C\u80FD\u7528\u5C31\u63A5\u7740\u7528\uFF1B\u8FD8\u6CA1\u505A\u5B8C\u7684\u90E8\u5206\uFF0C\u62C6\u6210\u4E00\u8F6E\u8DD1\u5F97\u5B8C\u7684\u91CF\u518D\u6D3E\u4E00\u6B21\u3002\u7ED9\u7528\u6237\u4EA4\u4EE3\u65F6\u522B\u8BF4\u300C\u65E0\u6CD5\u5B8C\u6210\u300D\u2014\u2014\u5DF2\u7ECF\u505A\u6210\u7684\u90E8\u5206\u7167\u5B9E\u8BF4\u3002" : ending === "timeout-empty" ? "**\u8FD9\u4E0D\u662F\u4E13\u4E1A\u5931\u8D25\uFF0C\u662F\u65F6\u95F4\u5230\u4E86**\uFF1A\u8FD9\u4E00\u8F6E\u6CA1\u6709\u7559\u4E0B\u53EF\u7528\u7684\u4EA7\u51FA\uFF0C\u628A\u4EFB\u52A1\u62C6\u5C0F\u4E00\u4E9B\u518D\u6D3E\u4E00\u6B21\u3002" : "\u5148\u81EA\u5DF1\u5224\u65AD\u80FD\u4E0D\u80FD\u63A5\u4F4F\uFF1A\u63A5\u7BA1\u3001\u6362\u4E2A\u505A\u6CD5\u3001\u8FD8\u662F\u91CD\u6D3E\u3002**\u522B\u628A\u4E13\u4E1A\u5931\u8D25\u539F\u6837\u4E22\u56DE\u7ED9\u7528\u6237**\u3002"
|
|
203047
203501
|
);
|
|
203048
203502
|
if (opts.movedPaths.length > 0 || (opts.unchangedPaths?.length ?? 0) > 0) {
|
|
203049
203503
|
lines.push(
|
|
@@ -203197,6 +203651,7 @@ var init_return_flow = __esm({
|
|
|
203197
203651
|
"use strict";
|
|
203198
203652
|
init_chat_session();
|
|
203199
203653
|
init_src();
|
|
203654
|
+
init_chat_exit();
|
|
203200
203655
|
init_chat_system_message();
|
|
203201
203656
|
init_chat_broadcast();
|
|
203202
203657
|
init_files();
|
|
@@ -208338,7 +208793,7 @@ async function resolveProposeContent(kernel, blobs, args, artifactId, ctx) {
|
|
|
208338
208793
|
}
|
|
208339
208794
|
return resolveContent2(blobs, args);
|
|
208340
208795
|
}
|
|
208341
|
-
function authorizedCommandReceipt(command2, args, actor) {
|
|
208796
|
+
function authorizedCommandReceipt(command2, args, actor, refs = {}) {
|
|
208342
208797
|
switch (command2) {
|
|
208343
208798
|
case "continueBatch":
|
|
208344
208799
|
return { message: `\u5DF2\u6388\u6743\u518D\u8FD0\u884C ${args.rounds} \u8F6E\uFF1B\u5176\u4ED6\u963B\u585E\u89E3\u9664\u540E\u7EE7\u7EED\u3002` };
|
|
@@ -208347,7 +208802,7 @@ function authorizedCommandReceipt(command2, args, actor) {
|
|
|
208347
208802
|
case "promote":
|
|
208348
208803
|
return { message: "promoted to persistent" };
|
|
208349
208804
|
case "resolveEscalation":
|
|
208350
|
-
return { message: optStr(args, "gapId") ? `\u5DF2\u786E\u8BA4\u6062\u590D\u65B9\u6848\uFF0C\u89E3\u51B3\u7F3A\u53E3
|
|
208805
|
+
return { message: optStr(args, "gapId") ? `\u5DF2\u786E\u8BA4\u6062\u590D\u65B9\u6848\uFF0C${actionPhrase("\u89E3\u51B3", "\u7F3A\u53E3", gapPhraseOf(refs, optStr(args, "gapId")))}\u3001${actionPhrase("\u5173\u95ED\u5173\u8054", "\u6C42\u52A9", escalationPhraseOf(refs, optStr(args, "escalationId")), "\u5173\u95ED\u5173\u8054\u7684")}\uFF1B\u8C03\u5EA6\u5668\u5C06\u5728\u5176\u4ED6\u963B\u585E\u89E3\u9664\u540E\u7EE7\u7EED\u6267\u884C\u3002` : `\u5DF2${actionPhrase("\u5173\u95ED", "\u6C42\u52A9", escalationPhraseOf(refs, optStr(args, "escalationId")))}\u3002` };
|
|
208351
208806
|
default:
|
|
208352
208807
|
throw new Error(`\u547D\u4EE4\u6388\u6743\uFF1A\u6682\u65E0\u56DE\u6267\u6784\u9020 ${command2}`);
|
|
208353
208808
|
}
|
|
@@ -209069,7 +209524,7 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}`] : []
|
|
|
209069
209524
|
...optStr(args, "reason") !== void 0 ? { reason: optStr(args, "reason") } : {},
|
|
209070
209525
|
...escId !== void 0 ? { escalationId: escId } : {}
|
|
209071
209526
|
});
|
|
209072
|
-
return { message: escId !== void 0 ? `\u5DF2\u5173\u95ED\
|
|
209527
|
+
return { message: escId !== void 0 ? `\u5DF2${actionPhrase("\u5173\u95ED", "\u6C42\u52A9", escalationPhraseOf(commandCardRefsOf(kernel.model), escId))}\u3002` : "\u8BE5\u8282\u70B9\u7684\u672A\u89E3\u4E0A\u62A5\u5DF2\u5168\u90E8\u5173\u95ED\u3002" };
|
|
209073
209528
|
}
|
|
209074
209529
|
case "addRevision": {
|
|
209075
209530
|
const addRevId = str(args, "artifactId");
|
|
@@ -209135,7 +209590,7 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}`] : []
|
|
|
209135
209590
|
}
|
|
209136
209591
|
case "promote": {
|
|
209137
209592
|
await kernel.promote({ artifactId: str(args, "artifactId"), actor });
|
|
209138
|
-
return authorizedCommandReceipt(command2, args, actor);
|
|
209593
|
+
return authorizedCommandReceipt(command2, args, actor, commandCardRefsOf(kernel.model));
|
|
209139
209594
|
}
|
|
209140
209595
|
case "hold": {
|
|
209141
209596
|
const artifactId = str(args, "artifactId");
|
|
@@ -209179,7 +209634,7 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}`] : []
|
|
|
209179
209634
|
reason: str(args, "reason"),
|
|
209180
209635
|
note: optStr(args, "note")
|
|
209181
209636
|
});
|
|
209182
|
-
return authorizedCommandReceipt(command2, args, actor);
|
|
209637
|
+
return authorizedCommandReceipt(command2, args, actor, commandCardRefsOf(kernel.model));
|
|
209183
209638
|
}
|
|
209184
209639
|
case "unlink": {
|
|
209185
209640
|
await kernel.unlinkInput({ artifactId: str(args, "artifactId"), to: str(args, "to"), actor });
|
|
@@ -209705,19 +210160,20 @@ async function startOasisServer(opts) {
|
|
|
209705
210160
|
return { accepted: r.accepted, ...r.reason ? { reason: r.reason } : {}, queued: r.queued, insertStatus: r.insertStatus };
|
|
209706
210161
|
};
|
|
209707
210162
|
const GRAPH_EDIT_SUMMARY_MAX = 60;
|
|
210163
|
+
const NEUTRAL_APPROVER = "\u8D1F\u8D23\u4EBA";
|
|
209708
210164
|
const truncateSummary = (s2) => {
|
|
209709
210165
|
const cps = [...s2];
|
|
209710
210166
|
return cps.length > GRAPH_EDIT_SUMMARY_MAX ? `${cps.slice(0, GRAPH_EDIT_SUMMARY_MAX).join("")}\u2026` : s2;
|
|
209711
210167
|
};
|
|
209712
210168
|
const authorizationStatusText = (resolution, ctx) => {
|
|
209713
210169
|
const approved = resolution.status === "approved";
|
|
209714
|
-
const by = ctx.
|
|
210170
|
+
const by = ctx.authorizedByName?.trim() || NEUTRAL_APPROVER;
|
|
209715
210171
|
const reason = resolution.status === "denied" ? resolution.reason ?? ctx.reason : ctx.reason;
|
|
209716
210172
|
if (ctx.kind === "graph-edit") {
|
|
209717
210173
|
const summary = truncateSummary((ctx.effectLabel ?? "").trim()) || "\uFF08\u672A\u586B\u5199\u7406\u7531\u7684\u56FE\u53D8\u66F4\uFF09";
|
|
209718
210174
|
return approved ? `\u300C${summary}\u300D\u7684\u53D8\u66F4\u5DF2\u7531 ${by} \u6279\u51C6\u5E76\u843D\u5730\u3002` : `\u300C${summary}\u300D\u7684\u53D8\u66F4\u5DF2\u88AB ${by} \u9A73\u56DE${reason ? `\uFF1B\u7406\u7531\uFF1A${reason}` : ""}\u3002`;
|
|
209719
210175
|
}
|
|
209720
|
-
const label2 = ctx.effectLabel || ctx.command || "";
|
|
210176
|
+
const label2 = ctx.displayLabel || stripInternalIds(ctx.effectLabel ?? "") || ctx.command || "";
|
|
209721
210177
|
return approved ? `\u547D\u4EE4\u5DF2\u7531 ${by} \u6279\u51C6\u5E76\u4EE5\u5176\u540D\u4E49\u6267\u884C${label2 ? `\uFF1A${label2}` : ""}\u3002` : `\u547D\u4EE4\u5DF2\u88AB ${by} \u9A73\u56DE${reason ? `\uFF1A${reason}` : ""}\u3002`;
|
|
209722
210178
|
};
|
|
209723
210179
|
const GRAPH_EDIT_IN_FLIGHT_SUFFIX = "\uFF08\u8FD9\u6761\u662F\u5728\u4F60\u672C\u8F6E\u8FDB\u884C\u4E2D\u63D2\u5165\u7684\u901A\u77E5\uFF1A\u56DE\u5E94\u5B8C\u540E\u63A5\u7740\u505A\u4F60\u624B\u4E0A\u8FD8\u6CA1\u505A\u5B8C\u7684\u4E8B\uFF0C\u522B\u5C31\u6B64\u6536\u5C3E\u3002\uFF09";
|
|
@@ -211140,13 +211596,23 @@ async function startOasisServer(opts) {
|
|
|
211140
211596
|
const { draftId } = JSON.parse(rawBody);
|
|
211141
211597
|
const review = engine.kernel.model.pendingReviews.get(draftId);
|
|
211142
211598
|
if (!review) throw new Error(`\u8349\u6848\u4E0D\u5B58\u5728\u6216\u5DF2\u5904\u7406\uFF1A${draftId}`);
|
|
211599
|
+
const authorizedByName = (await (engine.registry ?? opts.registry)?.getActor(actor).catch(() => null))?.name?.trim();
|
|
211143
211600
|
if (review.kind === "command" && review.command) {
|
|
211144
211601
|
const { command: command2, artifactId } = await engine.kernel.applyAuthorizedCommand({ draftId, actor });
|
|
211145
|
-
const receipt = authorizedCommandReceipt(command2, review.command.args, actor);
|
|
211602
|
+
const receipt = authorizedCommandReceipt(command2, review.command.args, actor, commandCardRefsOf(engine.kernel.model));
|
|
211146
211603
|
notifyReviewResolved(
|
|
211147
211604
|
draftId,
|
|
211148
211605
|
{ status: "approved", command: command2, effectLabel: review.command.effectLabel, authorizedBy: actor, receipt },
|
|
211149
|
-
{
|
|
211606
|
+
{
|
|
211607
|
+
origin: review.origin,
|
|
211608
|
+
kind: "command",
|
|
211609
|
+
authorizedBy: actor,
|
|
211610
|
+
...authorizedByName ? { authorizedByName } : {},
|
|
211611
|
+
// effectLabel 带 id:RESUME 提示词给起草 agent 用;displayLabel 是状态条(给人)那句。
|
|
211612
|
+
effectLabel: review.command.effectLabel,
|
|
211613
|
+
...review.command.displayLabel ? { displayLabel: review.command.displayLabel } : {},
|
|
211614
|
+
command: command2
|
|
211615
|
+
},
|
|
211150
211616
|
chatStoreNowOrNull,
|
|
211151
211617
|
currentCompanyId
|
|
211152
211618
|
);
|
|
@@ -211165,7 +211631,7 @@ async function startOasisServer(opts) {
|
|
|
211165
211631
|
{ status: "approved", command: "", effectLabel: review.plan.reason, authorizedBy: actor },
|
|
211166
211632
|
// 状态条要的两样也得进 resume 上下文(不能只放在 resolution 里):`effectLabel` 是改图卡的
|
|
211167
211633
|
// 「改动摘要」(= plan.reason,见 diagnosis 口径 1),`authorizedBy` 是「谁批的」。
|
|
211168
|
-
{ origin: review.origin, kind: review.kind ?? "graph-edit", authorizedBy: actor, effectLabel: review.plan.reason },
|
|
211634
|
+
{ origin: review.origin, kind: review.kind ?? "graph-edit", authorizedBy: actor, ...authorizedByName ? { authorizedByName } : {}, effectLabel: review.plan.reason },
|
|
211169
211635
|
chatStoreNowOrNull,
|
|
211170
211636
|
// 续跑那一轮照样可能往 outputs/ 写东西——按公司出产出卡(与命令卡那支同口径)。
|
|
211171
211637
|
currentCompanyId
|
|
@@ -211195,6 +211661,7 @@ async function startOasisServer(opts) {
|
|
|
211195
211661
|
return;
|
|
211196
211662
|
}
|
|
211197
211663
|
const { recorded } = await engine.kernel.rejectIntervention({ draftId, anchor: review.anchor, actor, ...reason !== void 0 ? { reason } : {} });
|
|
211664
|
+
const authorizedByName = (await (engine.registry ?? opts.registry)?.getActor(actor).catch(() => null))?.name?.trim();
|
|
211198
211665
|
notifyReviewResolved(
|
|
211199
211666
|
draftId,
|
|
211200
211667
|
{ status: "denied", ...reason !== void 0 ? { reason } : {} },
|
|
@@ -211202,10 +211669,13 @@ async function startOasisServer(opts) {
|
|
|
211202
211669
|
origin: review.origin,
|
|
211203
211670
|
kind: review.kind ?? "graph-edit",
|
|
211204
211671
|
authorizedBy: actor,
|
|
211672
|
+
...authorizedByName ? { authorizedByName } : {},
|
|
211205
211673
|
// 状态条要的那段「效果标签 / 改动摘要」:命令卡用命令的效果标签,改图卡用 `plan.reason`
|
|
211206
211674
|
// ——与 apply-draft 改图那一支同源(那里传的就是 `review.plan.reason`),否则驳回档的
|
|
211207
211675
|
// 改图卡状态条会永远拿不到摘要、只能落占位符(diagnosis 口径 1)。
|
|
211208
211676
|
...review.command?.effectLabel || review.plan.reason ? { effectLabel: review.command?.effectLabel || review.plan.reason } : {},
|
|
211677
|
+
// Bug 0215:驳回档的状态条同样走人读那句(命令卡才有;改图卡的摘要仍是 plan.reason)。
|
|
211678
|
+
...review.command?.displayLabel ? { displayLabel: review.command.displayLabel } : {},
|
|
211209
211679
|
...review.command?.command ? { command: review.command.command } : {},
|
|
211210
211680
|
...reason !== void 0 ? { reason } : {}
|
|
211211
211681
|
},
|
|
@@ -212036,6 +212506,15 @@ async function startOasisServer(opts) {
|
|
|
212036
212506
|
res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ error: "EMPTY_TEXT" }));
|
|
212037
212507
|
return;
|
|
212038
212508
|
}
|
|
212509
|
+
await waitForAdmittedTurnStart(sid, {
|
|
212510
|
+
liveChat,
|
|
212511
|
+
ledgerTurnRunning: async () => {
|
|
212512
|
+
const turns = opts.resolveChatTurns ? await opts.resolveChatTurns(currentCompanyId) : opts.chatTurns;
|
|
212513
|
+
const status = (await turns?.activeTurn(sid).catch(() => null))?.status;
|
|
212514
|
+
return status === "reserved" || status === "running";
|
|
212515
|
+
},
|
|
212516
|
+
timeoutMs: APPEND_TURN_START_WAIT_MS
|
|
212517
|
+
});
|
|
212039
212518
|
await respondAppend(res, wantsAppendProgress(req), (onAwaitingConsumption) => appendNowThroughQueue2(sid, text7, clientKey, insertAttachments, perCompanyStore, retainLocallyOnFailure, onAwaitingConsumption, resend));
|
|
212040
212519
|
return;
|
|
212041
212520
|
}
|
|
@@ -214107,7 +214586,7 @@ async function markDeliveredWithRetry(store, messageId, attempts = 3) {
|
|
|
214107
214586
|
}
|
|
214108
214587
|
return false;
|
|
214109
214588
|
}
|
|
214110
|
-
var http, import_node_crypto41, githubAppPending, connectorAuthSnapshots, CONNECTOR_AUTH_SNAPSHOT_TTL_MS, defaultResolveActor, enc, CHAT_OUTPUT_LIMIT, STREAMING_PATHS, PLANNER_BLOCKING_CODES, WILL_VERBS, GOVERNANCE_COMMANDS, READ_ONLY_COMMANDS, isAgent, isHuman;
|
|
214589
|
+
var http, import_node_crypto41, githubAppPending, connectorAuthSnapshots, CONNECTOR_AUTH_SNAPSHOT_TTL_MS, defaultResolveActor, enc, CHAT_OUTPUT_LIMIT, APPEND_TURN_START_WAIT_MS, STREAMING_PATHS, PLANNER_BLOCKING_CODES, WILL_VERBS, GOVERNANCE_COMMANDS, READ_ONLY_COMMANDS, isAgent, isHuman;
|
|
214111
214590
|
var init_server3 = __esm({
|
|
214112
214591
|
"../server/src/server.ts"() {
|
|
214113
214592
|
"use strict";
|
|
@@ -214122,6 +214601,7 @@ var init_server3 = __esm({
|
|
|
214122
214601
|
init_src();
|
|
214123
214602
|
init_src();
|
|
214124
214603
|
init_src();
|
|
214604
|
+
init_src();
|
|
214125
214605
|
init_file_http();
|
|
214126
214606
|
init_build_info();
|
|
214127
214607
|
init_artifact_content2();
|
|
@@ -214181,6 +214661,7 @@ var init_server3 = __esm({
|
|
|
214181
214661
|
defaultResolveActor = (token) => token.startsWith("token:") ? token.slice("token:".length) : null;
|
|
214182
214662
|
enc = (s2) => new TextEncoder().encode(s2);
|
|
214183
214663
|
CHAT_OUTPUT_LIMIT = 16e3;
|
|
214664
|
+
APPEND_TURN_START_WAIT_MS = 1e4;
|
|
214184
214665
|
STREAMING_PATHS = ["/api/events", "/api/chat", "/api/trajectory/events", "/api/intervention/wait"];
|
|
214185
214666
|
PLANNER_BLOCKING_CODES = /* @__PURE__ */ new Set([
|
|
214186
214667
|
"title_collision",
|
|
@@ -214271,12 +214752,12 @@ function createTokenIssuer(opts = {}) {
|
|
|
214271
214752
|
function createNodeTokenStore(file) {
|
|
214272
214753
|
const read3 = () => {
|
|
214273
214754
|
try {
|
|
214274
|
-
return JSON.parse(
|
|
214755
|
+
return JSON.parse(fs19.readFileSync(file, "utf8"));
|
|
214275
214756
|
} catch {
|
|
214276
214757
|
return {};
|
|
214277
214758
|
}
|
|
214278
214759
|
};
|
|
214279
|
-
const write = (table) =>
|
|
214760
|
+
const write = (table) => fs19.writeFileSync(file, JSON.stringify(table, null, 2), { mode: 384 });
|
|
214280
214761
|
return {
|
|
214281
214762
|
issue(nodeId) {
|
|
214282
214763
|
const table = read3();
|
|
@@ -214302,14 +214783,14 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
|
|
|
214302
214783
|
const read3 = () => {
|
|
214303
214784
|
if (!file) return table;
|
|
214304
214785
|
try {
|
|
214305
|
-
return new Map(Object.entries(JSON.parse(
|
|
214786
|
+
return new Map(Object.entries(JSON.parse(fs19.readFileSync(file, "utf8"))));
|
|
214306
214787
|
} catch {
|
|
214307
214788
|
return /* @__PURE__ */ new Map();
|
|
214308
214789
|
}
|
|
214309
214790
|
};
|
|
214310
214791
|
const write = (m2) => {
|
|
214311
214792
|
if (!file) return;
|
|
214312
|
-
|
|
214793
|
+
fs19.writeFileSync(file, JSON.stringify(Object.fromEntries(m2), null, 2), { mode: 384 });
|
|
214313
214794
|
};
|
|
214314
214795
|
const table = /* @__PURE__ */ new Map();
|
|
214315
214796
|
const prune = () => {
|
|
@@ -214371,12 +214852,12 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
|
|
|
214371
214852
|
}
|
|
214372
214853
|
};
|
|
214373
214854
|
}
|
|
214374
|
-
var import_node_crypto42,
|
|
214855
|
+
var import_node_crypto42, fs19, path19, SESSION_TOKEN_PREFIX, b64url2, fromB64url, readOrCreateSecret, sign, signatureMatches, isTokenClaims;
|
|
214375
214856
|
var init_tokens = __esm({
|
|
214376
214857
|
"../server/src/tokens.ts"() {
|
|
214377
214858
|
"use strict";
|
|
214378
214859
|
import_node_crypto42 = require("node:crypto");
|
|
214379
|
-
|
|
214860
|
+
fs19 = __toESM(require("node:fs"), 1);
|
|
214380
214861
|
path19 = __toESM(require("node:path"), 1);
|
|
214381
214862
|
SESSION_TOKEN_PREFIX = "oat_v2_";
|
|
214382
214863
|
b64url2 = (value2) => Buffer.from(value2).toString("base64url");
|
|
@@ -214384,13 +214865,13 @@ var init_tokens = __esm({
|
|
|
214384
214865
|
readOrCreateSecret = (file) => {
|
|
214385
214866
|
if (!file) return (0, import_node_crypto42.randomBytes)(32);
|
|
214386
214867
|
try {
|
|
214387
|
-
const raw =
|
|
214868
|
+
const raw = fs19.readFileSync(file, "utf8").trim();
|
|
214388
214869
|
if (raw) return Buffer.from(raw, "base64url");
|
|
214389
214870
|
} catch {
|
|
214390
214871
|
}
|
|
214391
214872
|
const secret = (0, import_node_crypto42.randomBytes)(32);
|
|
214392
|
-
|
|
214393
|
-
|
|
214873
|
+
fs19.mkdirSync(path19.dirname(file), { recursive: true });
|
|
214874
|
+
fs19.writeFileSync(file, secret.toString("base64url"), { mode: 384 });
|
|
214394
214875
|
return secret;
|
|
214395
214876
|
};
|
|
214396
214877
|
sign = (secret, payload2) => (0, import_node_crypto42.createHmac)("sha256", secret).update(payload2).digest("base64url");
|
|
@@ -214456,12 +214937,12 @@ function createDataplaneTokenIssuer(opts = {}) {
|
|
|
214456
214937
|
}
|
|
214457
214938
|
};
|
|
214458
214939
|
}
|
|
214459
|
-
var import_node_crypto43,
|
|
214940
|
+
var import_node_crypto43, fs20, path20, PREFIX2, b64url3, fromB64url2, sign2, sigMatches, readOrCreateSecret2, isClaims, isDataplaneToken;
|
|
214460
214941
|
var init_session_dataplane_token = __esm({
|
|
214461
214942
|
"../server/src/session-dataplane-token.ts"() {
|
|
214462
214943
|
"use strict";
|
|
214463
214944
|
import_node_crypto43 = require("node:crypto");
|
|
214464
|
-
|
|
214945
|
+
fs20 = __toESM(require("node:fs"), 1);
|
|
214465
214946
|
path20 = __toESM(require("node:path"), 1);
|
|
214466
214947
|
init_src();
|
|
214467
214948
|
PREFIX2 = "osd_";
|
|
@@ -214476,13 +214957,13 @@ var init_session_dataplane_token = __esm({
|
|
|
214476
214957
|
readOrCreateSecret2 = (file) => {
|
|
214477
214958
|
if (!file) return (0, import_node_crypto43.randomBytes)(32);
|
|
214478
214959
|
try {
|
|
214479
|
-
const raw =
|
|
214960
|
+
const raw = fs20.readFileSync(file, "utf8").trim();
|
|
214480
214961
|
if (raw) return Buffer.from(raw, "base64url");
|
|
214481
214962
|
} catch {
|
|
214482
214963
|
}
|
|
214483
214964
|
const secret = (0, import_node_crypto43.randomBytes)(32);
|
|
214484
|
-
|
|
214485
|
-
|
|
214965
|
+
fs20.mkdirSync(path20.dirname(file), { recursive: true });
|
|
214966
|
+
fs20.writeFileSync(file, secret.toString("base64url"), { mode: 384 });
|
|
214486
214967
|
return secret;
|
|
214487
214968
|
};
|
|
214488
214969
|
isClaims = (v2) => {
|
|
@@ -220080,13 +220561,13 @@ function applyTurnPatch(t, patch) {
|
|
|
220080
220561
|
...patch.lastError !== void 0 ? { lastError: patch.lastError } : {}
|
|
220081
220562
|
};
|
|
220082
220563
|
}
|
|
220083
|
-
var import_node_crypto46,
|
|
220564
|
+
var import_node_crypto46, fs21, path21, NdjsonOplogStore, DirBlobStore, MUTATORS, FileTypeRegistryStore, FileRoleRegistryStore, FileRegistryStore, FileAssistantBindStore, FileHumanPrefsStore, FileProjectStateStore, FileArtifactStateStore, FileTraceStore, MemoryChatSessionStore, FileChatSessionStore, MemoryChatTurnStore, FileChatTurnStore, MemoryReadMarkerStore, FileReadMarkerStore;
|
|
220084
220565
|
var init_dev_store = __esm({
|
|
220085
220566
|
"../server/src/dev-store.ts"() {
|
|
220086
220567
|
"use strict";
|
|
220087
220568
|
init_src();
|
|
220088
220569
|
import_node_crypto46 = require("node:crypto");
|
|
220089
|
-
|
|
220570
|
+
fs21 = __toESM(require("node:fs"), 1);
|
|
220090
220571
|
path21 = __toESM(require("node:path"), 1);
|
|
220091
220572
|
init_src();
|
|
220092
220573
|
init_src9();
|
|
@@ -220100,8 +220581,8 @@ var init_dev_store = __esm({
|
|
|
220100
220581
|
}
|
|
220101
220582
|
static async open(file) {
|
|
220102
220583
|
const memory = new MemoryOplogStore();
|
|
220103
|
-
if (
|
|
220104
|
-
for (const line2 of
|
|
220584
|
+
if (fs21.existsSync(file)) {
|
|
220585
|
+
for (const line2 of fs21.readFileSync(file, "utf8").split("\n")) {
|
|
220105
220586
|
if (!line2.trim()) continue;
|
|
220106
220587
|
const stored = JSON.parse(line2);
|
|
220107
220588
|
const { artifactId, seq, ...op } = stored;
|
|
@@ -220109,15 +220590,15 @@ var init_dev_store = __esm({
|
|
|
220109
220590
|
if (assigned !== seq) throw new Error(`corrupt ndjson log: seq mismatch at ${line2}`);
|
|
220110
220591
|
}
|
|
220111
220592
|
} else {
|
|
220112
|
-
|
|
220113
|
-
|
|
220593
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
220594
|
+
fs21.writeFileSync(file, "");
|
|
220114
220595
|
}
|
|
220115
220596
|
return new _NdjsonOplogStore(file, memory);
|
|
220116
220597
|
}
|
|
220117
220598
|
async append(artifactId, op, expectedSeq) {
|
|
220118
220599
|
const seq = await this.memory.append(artifactId, op, expectedSeq);
|
|
220119
220600
|
const stored = { ...op, artifactId, seq };
|
|
220120
|
-
|
|
220601
|
+
fs21.appendFileSync(this.file, JSON.stringify(stored) + "\n");
|
|
220121
220602
|
return seq;
|
|
220122
220603
|
}
|
|
220123
220604
|
read(artifactId, fromSeq) {
|
|
@@ -220133,7 +220614,7 @@ var init_dev_store = __esm({
|
|
|
220133
220614
|
DirBlobStore = class {
|
|
220134
220615
|
constructor(dir) {
|
|
220135
220616
|
this.dir = dir;
|
|
220136
|
-
|
|
220617
|
+
fs21.mkdirSync(dir, { recursive: true });
|
|
220137
220618
|
}
|
|
220138
220619
|
fileOf(hash3) {
|
|
220139
220620
|
return path21.join(this.dir, hash3);
|
|
@@ -220141,31 +220622,31 @@ var init_dev_store = __esm({
|
|
|
220141
220622
|
async put(bytes2) {
|
|
220142
220623
|
const hash3 = (0, import_node_crypto46.createHash)("sha256").update(bytes2).digest("hex");
|
|
220143
220624
|
const file = this.fileOf(hash3);
|
|
220144
|
-
if (!
|
|
220625
|
+
if (!fs21.existsSync(file)) fs21.writeFileSync(file, bytes2);
|
|
220145
220626
|
return hash3;
|
|
220146
220627
|
}
|
|
220147
220628
|
async meta(hash3) {
|
|
220148
220629
|
const file = this.fileOf(hash3);
|
|
220149
|
-
if (!
|
|
220150
|
-
const size =
|
|
220151
|
-
const fd =
|
|
220630
|
+
if (!fs21.existsSync(file)) return null;
|
|
220631
|
+
const size = fs21.statSync(file).size;
|
|
220632
|
+
const fd = fs21.openSync(file, "r");
|
|
220152
220633
|
const head = Buffer.alloc(16);
|
|
220153
|
-
|
|
220154
|
-
|
|
220634
|
+
fs21.readSync(fd, head, 0, 16, 0);
|
|
220635
|
+
fs21.closeSync(fd);
|
|
220155
220636
|
const contentType = sniffContentType(new Uint8Array(head));
|
|
220156
220637
|
return { size, ...contentType ? { contentType } : {} };
|
|
220157
220638
|
}
|
|
220158
220639
|
async get(hash3) {
|
|
220159
220640
|
const file = this.fileOf(hash3);
|
|
220160
|
-
if (!
|
|
220161
|
-
return new Uint8Array(
|
|
220641
|
+
if (!fs21.existsSync(file)) throw new BlobNotFoundError(hash3);
|
|
220642
|
+
return new Uint8Array(fs21.readFileSync(file));
|
|
220162
220643
|
}
|
|
220163
220644
|
async has(hash3) {
|
|
220164
|
-
return
|
|
220645
|
+
return fs21.existsSync(this.fileOf(hash3));
|
|
220165
220646
|
}
|
|
220166
220647
|
async sweep(reachable) {
|
|
220167
|
-
for (const name of
|
|
220168
|
-
if (!reachable.has(name))
|
|
220648
|
+
for (const name of fs21.readdirSync(this.dir)) {
|
|
220649
|
+
if (!reachable.has(name)) fs21.unlinkSync(this.fileOf(name));
|
|
220169
220650
|
}
|
|
220170
220651
|
}
|
|
220171
220652
|
};
|
|
@@ -220194,7 +220675,7 @@ var init_dev_store = __esm({
|
|
|
220194
220675
|
this.file = file;
|
|
220195
220676
|
}
|
|
220196
220677
|
static async open(file) {
|
|
220197
|
-
const seed =
|
|
220678
|
+
const seed = fs21.existsSync(file) ? JSON.parse(fs21.readFileSync(file, "utf8")) : [];
|
|
220198
220679
|
return new _FileTypeRegistryStore(file, seed);
|
|
220199
220680
|
}
|
|
220200
220681
|
async put(def) {
|
|
@@ -220207,8 +220688,8 @@ var init_dev_store = __esm({
|
|
|
220207
220688
|
}
|
|
220208
220689
|
async save() {
|
|
220209
220690
|
const tmp = `${this.file}.tmp`;
|
|
220210
|
-
|
|
220211
|
-
|
|
220691
|
+
fs21.writeFileSync(tmp, JSON.stringify(await this.list(), null, 2));
|
|
220692
|
+
fs21.renameSync(tmp, this.file);
|
|
220212
220693
|
}
|
|
220213
220694
|
};
|
|
220214
220695
|
FileRoleRegistryStore = class _FileRoleRegistryStore extends MemoryRoleRegistryStore {
|
|
@@ -220217,7 +220698,7 @@ var init_dev_store = __esm({
|
|
|
220217
220698
|
this.file = file;
|
|
220218
220699
|
}
|
|
220219
220700
|
static async open(file) {
|
|
220220
|
-
const seed =
|
|
220701
|
+
const seed = fs21.existsSync(file) ? JSON.parse(fs21.readFileSync(file, "utf8")) : [];
|
|
220221
220702
|
return new _FileRoleRegistryStore(file, seed);
|
|
220222
220703
|
}
|
|
220223
220704
|
async put(def) {
|
|
@@ -220230,8 +220711,8 @@ var init_dev_store = __esm({
|
|
|
220230
220711
|
}
|
|
220231
220712
|
async save() {
|
|
220232
220713
|
const tmp = `${this.file}.tmp`;
|
|
220233
|
-
|
|
220234
|
-
|
|
220714
|
+
fs21.writeFileSync(tmp, JSON.stringify(await this.list(), null, 2));
|
|
220715
|
+
fs21.renameSync(tmp, this.file);
|
|
220235
220716
|
}
|
|
220236
220717
|
};
|
|
220237
220718
|
FileRegistryStore = class _FileRegistryStore extends MemoryRegistryStore {
|
|
@@ -220249,8 +220730,8 @@ var init_dev_store = __esm({
|
|
|
220249
220730
|
}
|
|
220250
220731
|
static async open(file) {
|
|
220251
220732
|
const store = new _FileRegistryStore(file);
|
|
220252
|
-
if (
|
|
220253
|
-
const snap = JSON.parse(
|
|
220733
|
+
if (fs21.existsSync(file)) {
|
|
220734
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
220254
220735
|
for (const a of snap.actors) await MemoryRegistryStore.prototype.upsertActor.call(store, a);
|
|
220255
220736
|
for (const c of snap.configs) await MemoryRegistryStore.prototype.appendConfig.call(store, c);
|
|
220256
220737
|
for (const t of snap.teams) await MemoryRegistryStore.prototype.upsertTeam.call(store, t);
|
|
@@ -220291,7 +220772,7 @@ var init_dev_store = __esm({
|
|
|
220291
220772
|
skillFiles: skillFilesEntries,
|
|
220292
220773
|
connections
|
|
220293
220774
|
};
|
|
220294
|
-
|
|
220775
|
+
fs21.writeFileSync(this.file, JSON.stringify(snap, null, 2));
|
|
220295
220776
|
}
|
|
220296
220777
|
};
|
|
220297
220778
|
FileAssistantBindStore = class _FileAssistantBindStore extends MemoryAssistantBindStore {
|
|
@@ -220309,11 +220790,11 @@ var init_dev_store = __esm({
|
|
|
220309
220790
|
}
|
|
220310
220791
|
static async open(file) {
|
|
220311
220792
|
const store = new _FileAssistantBindStore(file);
|
|
220312
|
-
if (
|
|
220793
|
+
if (fs21.existsSync(file)) store._load(JSON.parse(fs21.readFileSync(file, "utf8")));
|
|
220313
220794
|
return store;
|
|
220314
220795
|
}
|
|
220315
220796
|
async save() {
|
|
220316
|
-
|
|
220797
|
+
fs21.writeFileSync(this.file, JSON.stringify(this._dump(), null, 2));
|
|
220317
220798
|
}
|
|
220318
220799
|
};
|
|
220319
220800
|
FileHumanPrefsStore = class _FileHumanPrefsStore extends MemoryHumanPrefsStore {
|
|
@@ -220331,11 +220812,11 @@ var init_dev_store = __esm({
|
|
|
220331
220812
|
}
|
|
220332
220813
|
static async open(file) {
|
|
220333
220814
|
const store = new _FileHumanPrefsStore(file);
|
|
220334
|
-
if (
|
|
220815
|
+
if (fs21.existsSync(file)) store._load(JSON.parse(fs21.readFileSync(file, "utf8")));
|
|
220335
220816
|
return store;
|
|
220336
220817
|
}
|
|
220337
220818
|
async save() {
|
|
220338
|
-
|
|
220819
|
+
fs21.writeFileSync(this.file, JSON.stringify(this._dump(), null, 2));
|
|
220339
220820
|
}
|
|
220340
220821
|
};
|
|
220341
220822
|
FileProjectStateStore = class _FileProjectStateStore extends MemoryProjectStateStore {
|
|
@@ -220345,8 +220826,8 @@ var init_dev_store = __esm({
|
|
|
220345
220826
|
}
|
|
220346
220827
|
static async open(file) {
|
|
220347
220828
|
const store = new _FileProjectStateStore(file);
|
|
220348
|
-
if (
|
|
220349
|
-
const snap = JSON.parse(
|
|
220829
|
+
if (fs21.existsSync(file)) {
|
|
220830
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
220350
220831
|
for (const project of snap.projects ?? []) await MemoryProjectStateStore.prototype.upsertProject.call(store, project);
|
|
220351
220832
|
const membersByProject = /* @__PURE__ */ new Map();
|
|
220352
220833
|
for (const member of snap.members ?? []) {
|
|
@@ -220358,8 +220839,8 @@ var init_dev_store = __esm({
|
|
|
220358
220839
|
await MemoryProjectStateStore.prototype.replaceProjectMembers.call(store, projectId2, members);
|
|
220359
220840
|
}
|
|
220360
220841
|
} else {
|
|
220361
|
-
|
|
220362
|
-
|
|
220842
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
220843
|
+
fs21.writeFileSync(file, JSON.stringify({ projects: [], members: [] }, null, 2));
|
|
220363
220844
|
}
|
|
220364
220845
|
return store;
|
|
220365
220846
|
}
|
|
@@ -220378,7 +220859,7 @@ var init_dev_store = __esm({
|
|
|
220378
220859
|
async save() {
|
|
220379
220860
|
const projects = await this.listProjects();
|
|
220380
220861
|
const members = (await Promise.all(projects.map((project) => this.listProjectMembers(project.id)))).flat();
|
|
220381
|
-
|
|
220862
|
+
fs21.writeFileSync(this.file, JSON.stringify({ projects, members }, null, 2));
|
|
220382
220863
|
}
|
|
220383
220864
|
};
|
|
220384
220865
|
FileArtifactStateStore = class _FileArtifactStateStore extends MemoryArtifactStateStore {
|
|
@@ -220388,8 +220869,8 @@ var init_dev_store = __esm({
|
|
|
220388
220869
|
}
|
|
220389
220870
|
static async open(file) {
|
|
220390
220871
|
const store = new _FileArtifactStateStore(file);
|
|
220391
|
-
if (
|
|
220392
|
-
const snap = JSON.parse(
|
|
220872
|
+
if (fs21.existsSync(file)) {
|
|
220873
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
220393
220874
|
for (const artifact of snap.artifacts ?? []) await MemoryArtifactStateStore.prototype.upsertArtifact.call(store, artifact);
|
|
220394
220875
|
for (const revision of snap.revisions ?? []) await MemoryArtifactStateStore.prototype.upsertRevision.call(store, revision);
|
|
220395
220876
|
for (const event of snap.events ?? []) await MemoryArtifactStateStore.prototype.appendEvent.call(store, event);
|
|
@@ -220399,8 +220880,8 @@ var init_dev_store = __esm({
|
|
|
220399
220880
|
for (const ws of snap.workspaceDispatchHeld ?? []) await MemoryArtifactStateStore.prototype.setWorkspaceDispatchHold.call(store, ws, true);
|
|
220400
220881
|
for (const f2 of snap.workOrderFiles ?? []) await MemoryArtifactStateStore.prototype.addWorkOrderFile.call(store, f2);
|
|
220401
220882
|
} else {
|
|
220402
|
-
|
|
220403
|
-
|
|
220883
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
220884
|
+
fs21.writeFileSync(file, JSON.stringify({ artifacts: [], revisions: [], events: [], annotations: [], nodeOutputs: [], workspaceBindings: [], workspaceDispatchHeld: [], workOrderFiles: [] }, null, 2));
|
|
220404
220885
|
}
|
|
220405
220886
|
return store;
|
|
220406
220887
|
}
|
|
@@ -220437,7 +220918,7 @@ var init_dev_store = __esm({
|
|
|
220437
220918
|
await this.save();
|
|
220438
220919
|
}
|
|
220439
220920
|
async save() {
|
|
220440
|
-
|
|
220921
|
+
fs21.writeFileSync(this.file, JSON.stringify(await this.listAll(), null, 2));
|
|
220441
220922
|
}
|
|
220442
220923
|
};
|
|
220443
220924
|
FileTraceStore = class _FileTraceStore extends MemoryTraceStore {
|
|
@@ -220464,25 +220945,25 @@ var init_dev_store = __esm({
|
|
|
220464
220945
|
return path21.join(this.eventsDir, `${encodeURIComponent(runId)}.ndjson`);
|
|
220465
220946
|
}
|
|
220466
220947
|
appendLine(file, obj2) {
|
|
220467
|
-
|
|
220948
|
+
fs21.appendFileSync(file, JSON.stringify(obj2) + "\n");
|
|
220468
220949
|
}
|
|
220469
220950
|
static replay(file, fn) {
|
|
220470
|
-
if (!
|
|
220471
|
-
for (const line2 of
|
|
220951
|
+
if (!fs21.existsSync(file)) return;
|
|
220952
|
+
for (const line2 of fs21.readFileSync(file, "utf8").split("\n")) {
|
|
220472
220953
|
if (!line2.trim()) continue;
|
|
220473
220954
|
fn(JSON.parse(line2));
|
|
220474
220955
|
}
|
|
220475
220956
|
}
|
|
220476
220957
|
static async open(dir) {
|
|
220477
220958
|
const store = new _FileTraceStore(dir);
|
|
220478
|
-
|
|
220959
|
+
fs21.mkdirSync(store.eventsDir, { recursive: true });
|
|
220479
220960
|
_FileTraceStore.replay(store.runsFile, (r) => store.restoreRun(r));
|
|
220480
|
-
for (const name of
|
|
220961
|
+
for (const name of fs21.readdirSync(store.eventsDir)) {
|
|
220481
220962
|
_FileTraceStore.replay(path21.join(store.eventsDir, name), (e) => store.restoreEvent(e));
|
|
220482
220963
|
}
|
|
220483
220964
|
_FileTraceStore.replay(store.toolCallsFile, (c) => store.restoreToolCall(c));
|
|
220484
220965
|
_FileTraceStore.replay(store.linksFile, (l) => store.restoreLink(l));
|
|
220485
|
-
store.restoreContinuity(
|
|
220966
|
+
store.restoreContinuity(fs21.existsSync(store.continuityFile) ? JSON.parse(fs21.readFileSync(store.continuityFile, "utf8")) : {});
|
|
220486
220967
|
return store;
|
|
220487
220968
|
}
|
|
220488
220969
|
async createRun(input) {
|
|
@@ -220534,8 +221015,8 @@ var init_dev_store = __esm({
|
|
|
220534
221015
|
}
|
|
220535
221016
|
saveContinuity() {
|
|
220536
221017
|
const tmp = `${this.continuityFile}.tmp`;
|
|
220537
|
-
|
|
220538
|
-
|
|
221018
|
+
fs21.writeFileSync(tmp, JSON.stringify(this.continuitySnapshot(), null, 2));
|
|
221019
|
+
fs21.renameSync(tmp, this.continuityFile);
|
|
220539
221020
|
}
|
|
220540
221021
|
async appendEvents(runId, inputs) {
|
|
220541
221022
|
const existing = await super.listEvents(runId, {});
|
|
@@ -220996,8 +221477,8 @@ var init_dev_store = __esm({
|
|
|
220996
221477
|
}
|
|
220997
221478
|
static async open(file) {
|
|
220998
221479
|
const store = new _FileChatSessionStore(file);
|
|
220999
|
-
if (
|
|
221000
|
-
const snap = JSON.parse(
|
|
221480
|
+
if (fs21.existsSync(file)) {
|
|
221481
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
221001
221482
|
for (const [sid, copies] of Object.entries(snap.outputCopies ?? {})) store.outputCopies.set(sid, copies);
|
|
221002
221483
|
for (const [sid, fps] of Object.entries(snap.outputFingerprints ?? {})) store.outputFingerprints.set(sid, fps);
|
|
221003
221484
|
for (const [sid, issues] of Object.entries(snap.fileIssues ?? {})) store.fileIssues.set(sid, issues);
|
|
@@ -221007,8 +221488,8 @@ var init_dev_store = __esm({
|
|
|
221007
221488
|
for (const [sid, kinds] of Object.entries(snap.sessionWorkOrderKinds ?? {})) store.sessionWorkOrderKinds.set(sid, new Map(Object.entries(kinds)));
|
|
221008
221489
|
for (const [sid, list2] of Object.entries(snap.pending ?? {})) store.pending.set(sid, list2);
|
|
221009
221490
|
} else {
|
|
221010
|
-
|
|
221011
|
-
|
|
221491
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
221492
|
+
fs21.writeFileSync(file, JSON.stringify({ sessions: [], messages: {}, sessionWorkOrders: {} }, null, 2));
|
|
221012
221493
|
}
|
|
221013
221494
|
return store;
|
|
221014
221495
|
}
|
|
@@ -221102,7 +221583,7 @@ var init_dev_store = __esm({
|
|
|
221102
221583
|
sessionWorkOrderKinds: Object.fromEntries([...this.sessionWorkOrderKinds].map(([k2, v2]) => [k2, Object.fromEntries(v2)])),
|
|
221103
221584
|
pending: Object.fromEntries(this.pending)
|
|
221104
221585
|
};
|
|
221105
|
-
|
|
221586
|
+
fs21.writeFileSync(this.file, JSON.stringify(snap, null, 2));
|
|
221106
221587
|
}
|
|
221107
221588
|
};
|
|
221108
221589
|
MemoryChatTurnStore = class {
|
|
@@ -221185,17 +221666,17 @@ var init_dev_store = __esm({
|
|
|
221185
221666
|
}
|
|
221186
221667
|
static async open(file) {
|
|
221187
221668
|
const store = new _FileChatTurnStore(file);
|
|
221188
|
-
if (
|
|
221189
|
-
const snap = JSON.parse(
|
|
221669
|
+
if (fs21.existsSync(file)) {
|
|
221670
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
221190
221671
|
for (const t of snap.turns ?? []) store.turns.set(t.id, t);
|
|
221191
221672
|
} else {
|
|
221192
|
-
|
|
221193
|
-
|
|
221673
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
221674
|
+
fs21.writeFileSync(file, JSON.stringify({ turns: [] }, null, 2));
|
|
221194
221675
|
}
|
|
221195
221676
|
return store;
|
|
221196
221677
|
}
|
|
221197
221678
|
persist() {
|
|
221198
|
-
|
|
221679
|
+
fs21.writeFileSync(this.file, JSON.stringify({ turns: [...this.turns.values()] }, null, 2));
|
|
221199
221680
|
}
|
|
221200
221681
|
};
|
|
221201
221682
|
MemoryReadMarkerStore = class _MemoryReadMarkerStore {
|
|
@@ -221221,12 +221702,12 @@ var init_dev_store = __esm({
|
|
|
221221
221702
|
}
|
|
221222
221703
|
static async open(file) {
|
|
221223
221704
|
const store = new _FileReadMarkerStore(file);
|
|
221224
|
-
if (
|
|
221225
|
-
const snap = JSON.parse(
|
|
221705
|
+
if (fs21.existsSync(file)) {
|
|
221706
|
+
const snap = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
221226
221707
|
for (const m2 of snap.markers ?? []) store.markers.set(`${m2.actorId}\0${m2.scope}`, m2);
|
|
221227
221708
|
} else {
|
|
221228
|
-
|
|
221229
|
-
|
|
221709
|
+
fs21.mkdirSync(path21.dirname(file), { recursive: true });
|
|
221710
|
+
fs21.writeFileSync(file, JSON.stringify({ markers: [] }, null, 2));
|
|
221230
221711
|
}
|
|
221231
221712
|
return store;
|
|
221232
221713
|
}
|
|
@@ -221235,18 +221716,18 @@ var init_dev_store = __esm({
|
|
|
221235
221716
|
this.save();
|
|
221236
221717
|
}
|
|
221237
221718
|
save() {
|
|
221238
|
-
|
|
221719
|
+
fs21.writeFileSync(this.file, JSON.stringify({ markers: [...this.markers.values()] }, null, 2));
|
|
221239
221720
|
}
|
|
221240
221721
|
};
|
|
221241
221722
|
}
|
|
221242
221723
|
});
|
|
221243
221724
|
|
|
221244
221725
|
// ../server/src/control-plane-file-store.ts
|
|
221245
|
-
var
|
|
221726
|
+
var fs22, path22, MUTATORS2, SNAPSHOT_VERSION, FileControlPlaneStore;
|
|
221246
221727
|
var init_control_plane_file_store = __esm({
|
|
221247
221728
|
"../server/src/control-plane-file-store.ts"() {
|
|
221248
221729
|
"use strict";
|
|
221249
|
-
|
|
221730
|
+
fs22 = __toESM(require("node:fs"), 1);
|
|
221250
221731
|
path22 = __toESM(require("node:path"), 1);
|
|
221251
221732
|
init_src9();
|
|
221252
221733
|
MUTATORS2 = [
|
|
@@ -221289,8 +221770,8 @@ var init_control_plane_file_store = __esm({
|
|
|
221289
221770
|
}
|
|
221290
221771
|
static async open(file) {
|
|
221291
221772
|
const store = new _FileControlPlaneStore(file);
|
|
221292
|
-
if (
|
|
221293
|
-
const snap = JSON.parse(
|
|
221773
|
+
if (fs22.existsSync(file)) {
|
|
221774
|
+
const snap = JSON.parse(fs22.readFileSync(file, "utf8"));
|
|
221294
221775
|
const needsOnboardingBackfill = (snap.version ?? 1) < 2;
|
|
221295
221776
|
const backfillAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
221296
221777
|
for (const c of snap.companies ?? []) await MemoryControlPlaneStore.prototype.createCompany.call(store, c);
|
|
@@ -221308,7 +221789,7 @@ var init_control_plane_file_store = __esm({
|
|
|
221308
221789
|
for (const op of snap.offboardings ?? []) store.offboardings.set(`${op.companyId}\0${op.operationId}`, op);
|
|
221309
221790
|
if (needsOnboardingBackfill) await store.save();
|
|
221310
221791
|
} else {
|
|
221311
|
-
|
|
221792
|
+
fs22.mkdirSync(path22.dirname(file), { recursive: true });
|
|
221312
221793
|
}
|
|
221313
221794
|
return store;
|
|
221314
221795
|
}
|
|
@@ -221345,7 +221826,7 @@ var init_control_plane_file_store = __esm({
|
|
|
221345
221826
|
// 交接操作无按公司列举的读面(按 operationId / accountId 定位),直接读 protected map。
|
|
221346
221827
|
offboardings: [...this.offboardings.values()]
|
|
221347
221828
|
};
|
|
221348
|
-
|
|
221829
|
+
fs22.writeFileSync(this.file, JSON.stringify(snap, null, 2));
|
|
221349
221830
|
}
|
|
221350
221831
|
};
|
|
221351
221832
|
}
|
|
@@ -223517,8 +223998,12 @@ var init_dispatch_binding_diagnosis = __esm({
|
|
|
223517
223998
|
});
|
|
223518
223999
|
|
|
223519
224000
|
// ../server/src/zero-output-breaker.ts
|
|
224001
|
+
function roundKeyOfZeroOutputRun(run) {
|
|
224002
|
+
return run.workId ?? run.id.replace(PROTOCOL_RECOVERY_SUFFIX, "");
|
|
224003
|
+
}
|
|
223520
224004
|
function absorb(b2, r, startedMs) {
|
|
223521
224005
|
b2.count += 1;
|
|
224006
|
+
b2.rounds.add(roundKeyOfZeroOutputRun(r));
|
|
223522
224007
|
b2.costUsdMicros += r.costUsdMicros ?? 0;
|
|
223523
224008
|
if (startedMs >= b2.latestStartedMs) {
|
|
223524
224009
|
b2.latestStartedMs = startedMs;
|
|
@@ -223586,6 +224071,7 @@ async function scanZeroOutputBreaker(deps) {
|
|
|
223586
224071
|
actorId: axis === "count" ? b2.actorId : null,
|
|
223587
224072
|
cls: axis === "count" ? b2.cls : null,
|
|
223588
224073
|
count: b2.count,
|
|
224074
|
+
workCount: b2.rounds.size,
|
|
223589
224075
|
costUsdMicros: b2.costUsdMicros,
|
|
223590
224076
|
windowMs: deps.windowMs,
|
|
223591
224077
|
latestRunId: b2.latestRunId,
|
|
@@ -223595,7 +224081,7 @@ async function scanZeroOutputBreaker(deps) {
|
|
|
223595
224081
|
const who = axis === "count" ? `${b2.actorId}\uFF08${b2.cls}\uFF09` : "\u8BE5\u8282\u70B9\u5168\u90E8\u6267\u884C\u4EBA\u5408\u8BA1";
|
|
223596
224082
|
const cidTag = deps.defaultCompanyId && b2.companyId !== deps.defaultCompanyId ? ` [${b2.companyId}]` : "";
|
|
223597
224083
|
deps.log?.(
|
|
223598
|
-
`[zero-output-breaker] ${b2.artifactId}${cidTag}\uFF1A\u6700\u8FD1 ${Math.round(deps.windowMs / 6e4)} \u5206\u949F\u5185 ${who} \u7D2F\u8BA1 ${b2.count} \u6B21\u96F6\u4EA7\u51FA\uFF08\u7EA6 $${(b2.costUsdMicros / 1e6).toFixed(1)}\uFF09\u2192 ${axis} \u8F74\u8DF3\u95F8`
|
|
224084
|
+
`[zero-output-breaker] ${b2.artifactId}${cidTag}\uFF1A\u6700\u8FD1 ${Math.round(deps.windowMs / 6e4)} \u5206\u949F\u5185 ${who} \u7D2F\u8BA1 ${b2.count} \u6B21\u96F6\u4EA7\u51FA\uFF08${b2.rounds.size} \u8F6E\uFF0C\u7EA6 $${(b2.costUsdMicros / 1e6).toFixed(1)}\uFF09\u2192 ${axis} \u8F74\u8DF3\u95F8`
|
|
223599
224085
|
);
|
|
223600
224086
|
};
|
|
223601
224087
|
const byKey = (a, b2) => a.artifactId.localeCompare(b2.artifactId) || (a.actorId ?? "").localeCompare(b2.actorId ?? "");
|
|
@@ -223621,32 +224107,35 @@ async function scanZeroOutputBreaker(deps) {
|
|
|
223621
224107
|
function formatZeroOutputNotice(t) {
|
|
223622
224108
|
const usd2 = (t.costUsdMicros / 1e6).toFixed(1);
|
|
223623
224109
|
const mins = Math.round(t.windowMs / 6e4);
|
|
224110
|
+
const runs = t.count > t.workCount ? `\u5171 ${t.count} \u6B21\u8FD0\u884C\uFF0C\u542B\u540C\u4E00\u8F6E\u5185\u7684\u81EA\u52A8\u7EED\u8DD1\uFF1B` : "";
|
|
223624
224111
|
const remark = t.closingRemark && t.closingRemark.trim() ? `
|
|
223625
224112
|
|
|
223626
224113
|
\u6700\u8FD1\u4E00\u6B21\u8FD0\u884C\u7684\u6536\u5C3E\u53D1\u8A00\uFF08\u5F80\u5F80\u76F4\u63A5\u5199\u7740\u5361\u5728\u54EA\uFF09\uFF1A
|
|
223627
224114
|
${t.closingRemark.trim()}` : "";
|
|
223628
224115
|
const tail = `\u8FD9\u4E0D\u662F\u5728\u5224\u67D0\u4E00\u6B21\u8FD0\u884C\u5931\u8D25\u2014\u2014\u662F\u5728\u8FD9\u6BB5\u65F6\u95F4\u91CC\u53CD\u590D\u96F6\u4EA7\u51FA\u3002\u65E0\u8BBA\u6BCF\u4E00\u6B21\u9000\u51FA\u591A\u4E48\u300C\u6B63\u5E38\u300D\uFF0C\u53CD\u590D\u5230\u8FD9\u4E2A\u6B21\u6570\u901A\u5E38\u610F\u5473\u7740\u5361\u5728\u4E00\u4E2A\u53CD\u590D\u91CD\u8BD5\u4E5F\u8FC7\u4E0D\u53BB\u7684\u574E\u4E0A\uFF08\u7F3A\u51ED\u636E\u3001\u4E0A\u6E38\u670D\u52A1\u8FDE\u4E0D\u4E0A\u3001\u6216\u649E\u4E0A\u4E86\u522B\u7684\u6B7B\u5FAA\u73AF\uFF09\u3002\u8BF7\u770B\u4E00\u773C\u6839\u56E0\uFF1B\u5904\u7406\u5B8C\u7528 \`oasis release\` \u6062\u590D\u3002` + remark;
|
|
223629
224116
|
if (t.axis === "cost") {
|
|
223630
|
-
return `\u8FD9\u4E2A\u4EA7\u7269\u5728\u6700\u8FD1 ${mins} \u5206\u949F\u5185\
|
|
224117
|
+
return `\u8FD9\u4E2A\u4EA7\u7269\u5728\u6700\u8FD1 ${mins} \u5206\u949F\u5185\u6709 ${t.workCount} \u8F6E**\u4EC0\u4E48\u90FD\u6CA1\u4EA4\u51FA\u6765**\uFF08${runs}\u8FD9\u4E9B\u7A7A\u8DD1\u5408\u8BA1\u5DF2\u7ECF\u82B1\u6389\u7EA6 $${usd2}\uFF09\uFF0C\u5DF2\u81EA\u52A8\u6682\u505C\u6D3E\u53D1\u4EE5\u6B62\u635F\u3002
|
|
223631
224118
|
|
|
223632
224119
|
` + tail;
|
|
223633
224120
|
}
|
|
223634
224121
|
const who = t.cls === "review" ? `\u8BC4\u5BA1\u5458 ${t.actorId}` : `\u6267\u884C\u4EBA ${t.actorId}`;
|
|
223635
224122
|
const what = t.cls === "review" ? `\u5DF2\u505C\u6389\u8FD9\u540D\u8BC4\u5BA1\u5458\u5728\u672C\u8282\u70B9\u4E0A\u7684\u8BC4\u5BA1\uFF08**\u4EA4\u4ED8\u5185\u5BB9\u539F\u6837\u4FDD\u7559**\uFF0C\u6062\u590D\u540E\u53EF\u7EE7\u7EED\u6295\u7968\uFF09` : `\u5DF2\u81EA\u52A8\u6682\u505C\u8BE5\u4EA7\u7269\u7684\u6D3E\u53D1\u4EE5\u6B62\u635F`;
|
|
223636
|
-
return `${who} \u5728\u6700\u8FD1 ${mins} \u5206\u949F\u5185\u4E3A\u8FD9\u4E2A\u4EA7\u7269\u8DD1\u4E86 ${t.
|
|
224123
|
+
return `${who} \u5728\u6700\u8FD1 ${mins} \u5206\u949F\u5185\u4E3A\u8FD9\u4E2A\u4EA7\u7269\u8DD1\u4E86 ${t.workCount} \u8F6E\uFF0C**\u6BCF\u4E00\u8F6E\u90FD\u4EC0\u4E48\u90FD\u6CA1\u4EA4\u51FA\u6765**\uFF08${runs}\u8FD9\u4E9B\u7A7A\u8DD1\u7D2F\u8BA1\u82B1\u8D39\u7EA6 $${usd2}\uFF09\uFF0C${what}\u3002
|
|
223637
224124
|
|
|
223638
224125
|
` + tail;
|
|
223639
224126
|
}
|
|
223640
|
-
var emptyBucket;
|
|
224127
|
+
var PROTOCOL_RECOVERY_SUFFIX, emptyBucket;
|
|
223641
224128
|
var init_zero_output_breaker = __esm({
|
|
223642
224129
|
"../server/src/zero-output-breaker.ts"() {
|
|
223643
224130
|
"use strict";
|
|
224131
|
+
PROTOCOL_RECOVERY_SUFFIX = /(?::protocol-recovery)+$/;
|
|
223644
224132
|
emptyBucket = (artifactId, companyId, actorId, cls) => ({
|
|
223645
224133
|
artifactId,
|
|
223646
224134
|
companyId,
|
|
223647
224135
|
actorId,
|
|
223648
224136
|
cls,
|
|
223649
224137
|
count: 0,
|
|
224138
|
+
rounds: /* @__PURE__ */ new Set(),
|
|
223650
224139
|
costUsdMicros: 0,
|
|
223651
224140
|
latestRunId: "",
|
|
223652
224141
|
latestStartedMs: -Infinity
|
|
@@ -224046,6 +224535,11 @@ function chatRunLedgerFields(req) {
|
|
|
224046
224535
|
if (req.executionProfile === "discussion-background") return { chatSessionId: null, chatTurnId: null };
|
|
224047
224536
|
return { chatSessionId: req.chatSessionId ?? null, chatTurnId: req.chatTurnId ?? null };
|
|
224048
224537
|
}
|
|
224538
|
+
function chatExitModelFields(runtimeReportedModel, dispatchedModel, dispatchedModelSource) {
|
|
224539
|
+
const effectiveModel = runtimeReportedModel || dispatchedModel || null;
|
|
224540
|
+
if (!effectiveModel) return {};
|
|
224541
|
+
return { effectiveModel, modelSource: runtimeReportedModel ? "runtime" : dispatchedModelSource };
|
|
224542
|
+
}
|
|
224049
224543
|
function createUsageLedgerResolver(deps) {
|
|
224050
224544
|
const safeCompanyOfRun = (runId) => deps.companyOfRun(runId).catch(() => null);
|
|
224051
224545
|
return async (dispatchId) => {
|
|
@@ -224061,6 +224555,15 @@ function createUsageLedgerResolver(deps) {
|
|
|
224061
224555
|
return chatCid ? { runId: stable, store: await deps.storeFor(chatCid) } : null;
|
|
224062
224556
|
};
|
|
224063
224557
|
}
|
|
224558
|
+
async function backfillRunModel(target, run, model, warn) {
|
|
224559
|
+
if (!model || model.trim().length === 0) return;
|
|
224560
|
+
if (run.effectiveModel && run.effectiveModel.trim().length > 0) return;
|
|
224561
|
+
try {
|
|
224562
|
+
await target.store.updateRun(target.runId, { effectiveModel: model, modelSource: "runtime" });
|
|
224563
|
+
} catch (err) {
|
|
224564
|
+
warn(`[usage-ledger] run ${target.runId} \u7684\u6A21\u578B\u540D\u8865\u5199\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u4F1A\u8BDD\uFF09\uFF1A${String(err)}`);
|
|
224565
|
+
}
|
|
224566
|
+
}
|
|
224064
224567
|
function createUsageLedgerFrameHandler(deps) {
|
|
224065
224568
|
const warn = deps.warn ?? defaultWarn;
|
|
224066
224569
|
const marker = deps.marker ?? new RuntimeStartMarker({ warn });
|
|
@@ -224122,6 +224625,7 @@ function createUsageLedgerFrameHandler(deps) {
|
|
|
224122
224625
|
usage: msg.usage,
|
|
224123
224626
|
model: msg.model ?? null
|
|
224124
224627
|
});
|
|
224628
|
+
await backfillRunModel(target, run, msg.model, warn);
|
|
224125
224629
|
} catch (err) {
|
|
224126
224630
|
warn(`[usage-ledger] \u5904\u7406 ${msg.type} dispatch=${dispatchId} \u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u4F1A\u8BDD\uFF09\uFF1A${String(err)}`);
|
|
224127
224631
|
}
|
|
@@ -225124,18 +225628,27 @@ function wireRecoveredChatTurn(deps) {
|
|
|
225124
225628
|
log3(`[chat-recovery] \u4F1A\u8BDD ${plan.chatSessionId} \u91CD\u6302\uFF1A\u8865\u53D1\u6709 ${droppedFrames} \u5E27\u6CA1\u63A5\u4F4F\uFF08run ${plan.runId}\uFF09\uFF0C\u672C\u8F6E\u6309\u300C\u8F93\u51FA\u4E0D\u5B8C\u6574\u300D\u6536\u5C3E${exitIsFailure ? "\uFF08\u9000\u51FA\u5E27\u672C\u8EAB\u4E5F\u662F\u5931\u8D25\uFF09" : "\uFF0C\u4E0D\u8BB0\u6210\u6210\u529F"}`);
|
|
225125
225629
|
}
|
|
225126
225630
|
if (failed) {
|
|
225127
|
-
const
|
|
225128
|
-
|
|
225129
|
-
...
|
|
225631
|
+
const exitSummary = exitIsFailure ? chatExitSummary(info) : void 0;
|
|
225632
|
+
const exitAttribution = exitSummary ? attributeChatExit(exitSummary.summary, {
|
|
225633
|
+
...exitSummary.reason ? { reason: exitSummary.reason } : {},
|
|
225634
|
+
...exitSummary.detail ? { detail: exitSummary.detail } : {},
|
|
225635
|
+
...exitSummary.cancelledBy ? { cancelledBy: exitSummary.cancelledBy } : {}
|
|
225130
225636
|
}, live.cancelCause()) : void 0;
|
|
225131
225637
|
const errText2 = [
|
|
225132
225638
|
exitAttribution?.text,
|
|
225133
225639
|
droppedFrames > 0 ? outputGapNotice(droppedFrames) : void 0
|
|
225134
225640
|
].filter((t) => Boolean(t)).join("\n\n");
|
|
225135
|
-
live.emit({
|
|
225641
|
+
live.emit({
|
|
225642
|
+
type: "error",
|
|
225643
|
+
text: errText2,
|
|
225644
|
+
...exitAttribution?.extra.detail ? { detail: exitAttribution.extra.detail } : {},
|
|
225645
|
+
...exitAttribution?.extra.cancelledBy ? { cancelledBy: exitAttribution.extra.cancelledBy } : {}
|
|
225646
|
+
});
|
|
225136
225647
|
const errReason = exitIsFailure ? info.reason : OUTPUT_GAP_ERROR_CODE;
|
|
225137
225648
|
const errExtra = {
|
|
225138
225649
|
...errReason ? { reason: errReason } : {},
|
|
225650
|
+
/* 运行时原文只进 detail:刷新后读的是这一行,「展开详情」要能翻出退出码与原始报错。 */
|
|
225651
|
+
...exitAttribution?.extra.detail ? { detail: exitAttribution.extra.detail } : {},
|
|
225139
225652
|
...exitAttribution?.extra.cancelledBy ? { cancelledBy: exitAttribution.extra.cancelledBy } : {}
|
|
225140
225653
|
};
|
|
225141
225654
|
const errorOutcome = itemLedger.recordError(errText2, errExtra);
|
|
@@ -225176,7 +225689,7 @@ function wireRecoveredChatTurn(deps) {
|
|
|
225176
225689
|
touchedAt: finishedAt
|
|
225177
225690
|
}).catch(() => void 0);
|
|
225178
225691
|
if (deps.onTurnSettled) {
|
|
225179
|
-
await deps.onTurnSettled(failed ? "failed" : "succeeded", finishedAt).catch((err) => {
|
|
225692
|
+
await deps.onTurnSettled(failed ? "failed" : "succeeded", finishedAt, info.reason ?? void 0).catch((err) => {
|
|
225180
225693
|
log3(`[chat-recovery] \u4F1A\u8BDD ${plan.chatSessionId} \u6536\u53E3\u8BB0\u8D26\u5931\u8D25\uFF08\u9000\u56DE\u6E05\u626B\u62CD\u515C\u5E95\uFF09: ${String(err)}`);
|
|
225181
225694
|
});
|
|
225182
225695
|
}
|
|
@@ -225373,13 +225886,26 @@ async function reconcileChatExitFrame(deps) {
|
|
|
225373
225886
|
if (part) parts.push({ ...part, seq: ++seq });
|
|
225374
225887
|
}
|
|
225375
225888
|
if (failed) {
|
|
225889
|
+
const exitSummary = exitIsFailure ? chatExitSummary(info) : void 0;
|
|
225376
225890
|
const errText2 = [
|
|
225377
|
-
|
|
225891
|
+
exitSummary?.summary,
|
|
225378
225892
|
droppedFrames > 0 ? outputGapNotice(droppedFrames) : void 0
|
|
225379
225893
|
].filter((t) => Boolean(t)).join("\n\n");
|
|
225380
225894
|
const errReason = exitIsFailure ? info.reason : OUTPUT_GAP_ERROR_CODE;
|
|
225381
|
-
|
|
225382
|
-
|
|
225895
|
+
const errExtra = {
|
|
225896
|
+
...errReason ? { reason: errReason } : {},
|
|
225897
|
+
...exitSummary?.detail ? { detail: exitSummary.detail } : {},
|
|
225898
|
+
...exitSummary?.cancelledBy ? { cancelledBy: exitSummary.cancelledBy } : {}
|
|
225899
|
+
};
|
|
225900
|
+
itemLedger.recordError(errText2, errExtra);
|
|
225901
|
+
parts.push({
|
|
225902
|
+
type: "error",
|
|
225903
|
+
seq: ++seq,
|
|
225904
|
+
text: errText2,
|
|
225905
|
+
...exitIsFailure && info.reason ? { reason: info.reason } : {},
|
|
225906
|
+
...exitSummary?.detail ? { detail: exitSummary.detail } : {},
|
|
225907
|
+
...exitSummary?.cancelledBy ? { cancelledBy: exitSummary.cancelledBy } : {}
|
|
225908
|
+
});
|
|
225383
225909
|
}
|
|
225384
225910
|
normalizer.turnFinished(failed ? "failed" : "completed");
|
|
225385
225911
|
itemLedger.finish(failed ? "failed" : "completed");
|
|
@@ -225440,7 +225966,8 @@ async function reconcileChatExitFrame(deps) {
|
|
|
225440
225966
|
chatSessionId: row.sessionId,
|
|
225441
225967
|
turnId: turn.id,
|
|
225442
225968
|
status,
|
|
225443
|
-
reason: `\u505C\u673A\u7A97\u53E3\u5185\u7ED3\u675F\u7684\u8F6E\u4EE5 ${status} \u6536\u5C3E
|
|
225969
|
+
reason: `\u505C\u673A\u7A97\u53E3\u5185\u7ED3\u675F\u7684\u8F6E\u4EE5 ${status} \u6536\u5C3E`,
|
|
225970
|
+
...info.reason ? { exitReason: info.reason } : {}
|
|
225444
225971
|
});
|
|
225445
225972
|
} catch (err) {
|
|
225446
225973
|
deps.log?.(`[chat-recovery] \u8F6E\u6B21 ${turn.id} \u6536\u53E3\u540E\u7684\u8BB0\u8D26/\u5916\u62A5\u5931\u8D25\uFF08\u884C\u5DF2\u6536\u5C3E\uFF09: ${String(err)}`);
|
|
@@ -225596,7 +226123,7 @@ async function recoverChatTurnsAcrossCompanies(deps) {
|
|
|
225596
226123
|
}
|
|
225597
226124
|
const handle = deps.recover(plan);
|
|
225598
226125
|
const settleTurnId = turn?.id;
|
|
225599
|
-
const onTurnSettled = settleTurnId && stores.settleTurn ? async (status, completedAt) => {
|
|
226126
|
+
const onTurnSettled = settleTurnId && stores.settleTurn ? async (status, completedAt, exitReason) => {
|
|
225600
226127
|
await stores.settleTurn(settleTurnId, {
|
|
225601
226128
|
status,
|
|
225602
226129
|
completedAt,
|
|
@@ -225608,6 +226135,7 @@ async function recoverChatTurnsAcrossCompanies(deps) {
|
|
|
225608
226135
|
turnId: settleTurnId,
|
|
225609
226136
|
status,
|
|
225610
226137
|
reason: `\u91CD\u6302\u7684\u8F6E\u4EE5 ${status} \u6536\u5C3E`,
|
|
226138
|
+
...exitReason ? { exitReason } : {},
|
|
225611
226139
|
...companyId ? { companyId } : {}
|
|
225612
226140
|
});
|
|
225613
226141
|
} : void 0;
|
|
@@ -225653,6 +226181,7 @@ var init_chat_recovery = __esm({
|
|
|
225653
226181
|
init_chat_assistant_turn();
|
|
225654
226182
|
init_src2();
|
|
225655
226183
|
init_session_exit_outcome();
|
|
226184
|
+
init_chat_exit();
|
|
225656
226185
|
init_chat_cancel_attribution();
|
|
225657
226186
|
asObj3 = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
|
|
225658
226187
|
partsOf = (parts) => Array.isArray(parts) ? parts.filter((p2) => p2 && typeof p2 === "object" && typeof p2.type === "string") : [];
|
|
@@ -225902,6 +226431,8 @@ var init_daemon_hub = __esm({
|
|
|
225902
226431
|
sessionMeta = /* @__PURE__ */ new Map();
|
|
225903
226432
|
sessionConnectListeners = [];
|
|
225904
226433
|
sessionDisconnectListeners = [];
|
|
226434
|
+
/** Bug 0224:等某条会话连上数据面的一次性等待者(dispatchId → 兑现函数)。见 {@link waitForSession}。 */
|
|
226435
|
+
sessionReadyWaiters = /* @__PURE__ */ new Map();
|
|
225905
226436
|
// ── ADR 0300 D2「日志复制」:帧号 + 累积 ackSeq + 幂等摄入 ────────────────────────────
|
|
225906
226437
|
// 只对自报 supportsFrameSeq 的会话生效;老会话这三张表始终为空、逐字走原 outbox 语义。
|
|
225907
226438
|
/** 自报支持帧号的 dispatchId。 */
|
|
@@ -226165,6 +226696,11 @@ var init_daemon_hub = __esm({
|
|
|
226165
226696
|
...msg.jobArtifactId ? { jobArtifactId: msg.jobArtifactId } : {}
|
|
226166
226697
|
});
|
|
226167
226698
|
for (const l of this.sessionConnectListeners) l({ dispatchId, sessionId: msg.sessionId, nodeId });
|
|
226699
|
+
const readyWaiters = this.sessionReadyWaiters.get(dispatchId);
|
|
226700
|
+
if (readyWaiters) {
|
|
226701
|
+
this.sessionReadyWaiters.delete(dispatchId);
|
|
226702
|
+
for (const w2 of readyWaiters) w2(true);
|
|
226703
|
+
}
|
|
226168
226704
|
void this.judgeSession(dispatchId, ws);
|
|
226169
226705
|
}
|
|
226170
226706
|
if (msg.supportsFrameSeq) {
|
|
@@ -226336,6 +226872,35 @@ var init_daemon_hub = __esm({
|
|
|
226336
226872
|
addSessionDisconnectListener(l) {
|
|
226337
226873
|
this.sessionDisconnectListeners.push(l);
|
|
226338
226874
|
}
|
|
226875
|
+
/**
|
|
226876
|
+
* Bug 0224:等这次派发的会话进程连上数据面(`session_hello` 登记完),最多等 `timeoutMs`。
|
|
226877
|
+
* 已连着立即回 true;等到了回 true;超时回 false。
|
|
226878
|
+
*
|
|
226879
|
+
* 为什么要等:每一轮开始时节点另起一个会话进程,它自己连回来、在 hello 里报「能回报插话读到的位置」。
|
|
226880
|
+
* 连上之前 {@link supportsInputConsumptionReceipts} 只能答 false——那不是「不支持」,是「还没到」。
|
|
226881
|
+
*/
|
|
226882
|
+
waitForSession(dispatchId, timeoutMs) {
|
|
226883
|
+
if (this.hasSession(dispatchId)) return Promise.resolve(true);
|
|
226884
|
+
return new Promise((resolve11) => {
|
|
226885
|
+
let waiters = this.sessionReadyWaiters.get(dispatchId);
|
|
226886
|
+
if (!waiters) {
|
|
226887
|
+
waiters = /* @__PURE__ */ new Set();
|
|
226888
|
+
this.sessionReadyWaiters.set(dispatchId, waiters);
|
|
226889
|
+
}
|
|
226890
|
+
const done = (connected) => {
|
|
226891
|
+
clearTimeout(timer);
|
|
226892
|
+
resolve11(connected);
|
|
226893
|
+
};
|
|
226894
|
+
const timer = setTimeout(() => {
|
|
226895
|
+
const set = this.sessionReadyWaiters.get(dispatchId);
|
|
226896
|
+
set?.delete(done);
|
|
226897
|
+
if (set && set.size === 0) this.sessionReadyWaiters.delete(dispatchId);
|
|
226898
|
+
resolve11(false);
|
|
226899
|
+
}, timeoutMs);
|
|
226900
|
+
timer.unref?.();
|
|
226901
|
+
waiters.add(done);
|
|
226902
|
+
});
|
|
226903
|
+
}
|
|
226339
226904
|
/** 这次派发有没有一根活着的数据面连接(有 = 会话自己在说话,不必再问节点)。 */
|
|
226340
226905
|
hasSession(dispatchId) {
|
|
226341
226906
|
return this.sessionSockets.get(dispatchId)?.readyState === import_websocket.default.OPEN;
|
|
@@ -231312,7 +231877,7 @@ function createRegistryAuditSink(file) {
|
|
|
231312
231877
|
return {
|
|
231313
231878
|
/** 登记审计:落盘 + 推 registry 通知(前端据此重拉登记类投影)。 */
|
|
231314
231879
|
registryAudit: (record9) => {
|
|
231315
|
-
|
|
231880
|
+
fs23.appendFile(file, JSON.stringify(record9) + "\n", () => {
|
|
231316
231881
|
});
|
|
231317
231882
|
notify({ kind: record9.kind, actor: record9.actor, target: record9.target, timestamp: record9.timestamp });
|
|
231318
231883
|
},
|
|
@@ -231326,7 +231891,7 @@ function createRegistryAuditSink(file) {
|
|
|
231326
231891
|
* 得先让通知带组织、`/api/events` 按组织过滤(recvvzbhOGiS7l 的完整修复),再放回来。
|
|
231327
231892
|
*/
|
|
231328
231893
|
credentialAudit: (record9) => {
|
|
231329
|
-
|
|
231894
|
+
fs23.appendFile(file, JSON.stringify(record9) + "\n", () => {
|
|
231330
231895
|
});
|
|
231331
231896
|
},
|
|
231332
231897
|
/** runtime 状态变了:只发无内容的失效提示(ADR 0576)。 */
|
|
@@ -231343,11 +231908,11 @@ function createRegistryAuditSink(file) {
|
|
|
231343
231908
|
}
|
|
231344
231909
|
};
|
|
231345
231910
|
}
|
|
231346
|
-
var
|
|
231911
|
+
var fs23;
|
|
231347
231912
|
var init_registry_audit_sink = __esm({
|
|
231348
231913
|
"../server/src/domains/actors/registry-audit-sink.ts"() {
|
|
231349
231914
|
"use strict";
|
|
231350
|
-
|
|
231915
|
+
fs23 = __toESM(require("node:fs"), 1);
|
|
231351
231916
|
}
|
|
231352
231917
|
});
|
|
231353
231918
|
|
|
@@ -233277,6 +233842,15 @@ var init_review_requirement_activity = __esm({
|
|
|
233277
233842
|
});
|
|
233278
233843
|
|
|
233279
233844
|
// ../server/src/domains/collab/activity.ts
|
|
233845
|
+
function coordinatorCardGapId(cardId) {
|
|
233846
|
+
return cardId.startsWith(COORDINATOR_CARD_PREFIX) ? cardId.slice(COORDINATOR_CARD_PREFIX.length) : void 0;
|
|
233847
|
+
}
|
|
233848
|
+
function coordinatorRunOfGap(gap, runs) {
|
|
233849
|
+
const opensAt = gap.createdAt;
|
|
233850
|
+
const closesAt = gap.resolvedAt ?? null;
|
|
233851
|
+
const overlapping = runs.filter((r) => (!closesAt || r.startedAt <= closesAt) && (!r.endedAt || r.endedAt >= opensAt)).sort((a, b2) => a.startedAt.localeCompare(b2.startedAt) || a.id.localeCompare(b2.id));
|
|
233852
|
+
return overlapping.find((r) => r.startedAt >= opensAt) ?? overlapping.at(-1);
|
|
233853
|
+
}
|
|
233280
233854
|
function escalationKindOf(issueId, authorActorId) {
|
|
233281
233855
|
if (issueId.startsWith(RETRY_EXHAUSTED_ESC_PREFIX)) return "retry_exhausted";
|
|
233282
233856
|
if (issueId.startsWith(REVIEW_EXHAUSTED_ESC_PREFIX2)) return "review_exhausted";
|
|
@@ -233288,7 +233862,7 @@ function parseStopLossFacts(kind, body2) {
|
|
|
233288
233862
|
const reason = /末次失败原因(原文):([^\n]+)/.exec(body2)?.[1]?.trim();
|
|
233289
233863
|
return { ...n2 ? { count: Number(n2) } : {}, ...reason ? { lastReason: firstSentence(reason) } : {} };
|
|
233290
233864
|
}
|
|
233291
|
-
const n = /(?:跑了|累计有)\s*(\d+)\s*次/.exec(body2)?.[1];
|
|
233865
|
+
const n = /(?:跑了|有)\s*(\d+)\s*轮/.exec(body2)?.[1] ?? /(?:跑了|累计有)\s*(\d+)\s*次/.exec(body2)?.[1];
|
|
233292
233866
|
const rawCost = /约\s*\$([\d.]+)/.exec(body2)?.[1];
|
|
233293
233867
|
const cost = rawCost !== void 0 && Number.isFinite(Number(rawCost)) ? `$${Number(rawCost).toFixed(2)}` : void 0;
|
|
233294
233868
|
return { ...n ? { count: Number(n) } : {}, ...cost ? { cost } : {} };
|
|
@@ -233646,7 +234220,7 @@ function buildWorkorderActivity(input) {
|
|
|
233646
234220
|
card2.segmentOpen = false;
|
|
233647
234221
|
card2.status = interrupt.kind === "gap" ? ACTIVITY_COPY.interruptedByGap(name, nameOf(managerId ?? ownerId)) : ACTIVITY_COPY.interruptedByIssue(name);
|
|
233648
234222
|
if (interrupt.kind === "gap" && interrupt.authorId) {
|
|
233649
|
-
card2.actions = [{ kind: "open_thread", label: BUTTON.
|
|
234223
|
+
card2.actions = [{ kind: "open_thread", label: BUTTON.view, target: gapThreadSessionId(interrupt.authorId) }];
|
|
233650
234224
|
}
|
|
233651
234225
|
if (interrupt.at > card2.updatedAt) card2.updatedAt = interrupt.at;
|
|
233652
234226
|
} else if (supersededBy) {
|
|
@@ -233700,6 +234274,7 @@ function buildWorkorderActivity(input) {
|
|
|
233700
234274
|
const recoveryLetterIssueIds = /* @__PURE__ */ new Set();
|
|
233701
234275
|
const plainComments = [];
|
|
233702
234276
|
const escalations = [];
|
|
234277
|
+
const gapCreatedSeq = /* @__PURE__ */ new Map();
|
|
233703
234278
|
const plainResolveEvents = /* @__PURE__ */ new Map();
|
|
233704
234279
|
const acceptCards = /* @__PURE__ */ new Map();
|
|
233705
234280
|
const standalone = [];
|
|
@@ -233956,7 +234531,10 @@ function buildWorkorderActivity(input) {
|
|
|
233956
234531
|
});
|
|
233957
234532
|
break;
|
|
233958
234533
|
}
|
|
233959
|
-
if (isGap)
|
|
234534
|
+
if (isGap) {
|
|
234535
|
+
gapCreatedSeq.set(issueId, rec2.seq);
|
|
234536
|
+
break;
|
|
234537
|
+
}
|
|
233960
234538
|
if (isRecoveryLetter) recoveryLetterIssueIds.add(issueId);
|
|
233961
234539
|
const nodeAssignee = nodeId ? nodeById.get(nodeId)?.assigneeActorId : void 0;
|
|
233962
234540
|
const commentCounterpart = nodeAssignee ?? ownerId;
|
|
@@ -233982,7 +234560,7 @@ function buildWorkorderActivity(input) {
|
|
|
233982
234560
|
全库实测最长 8096 字印两遍(`ws:wo-56bba3c1`),一张卡顶掉整屏。 */
|
|
233983
234561
|
artifacts: [],
|
|
233984
234562
|
/* 缺口不出按钮(处置在缺口线上,由「任务内沟通」那一列进);
|
|
233985
|
-
|
|
234563
|
+
留言给「查看留言」直达留言线——线是投影出来的、恒存在,id 这里就能算;
|
|
233986
234564
|
回压仍给「去处理」落到产物预览栏(那儿才有批注的处置面)。
|
|
233987
234565
|
留言算不出对面是谁(该产物没负责人)时退回「去处理」,别给一个开不了的落点。 */
|
|
233988
234566
|
actions: isBackpressure || !commentTargetId ? [{ kind: "open_issue", label: BUTTON.handle, target: issueId }] : [{ kind: "open_thread", label: BUTTON.view, target: commentThreadSessionId(authorId, commentTargetId) }]
|
|
@@ -234156,154 +234734,135 @@ function buildWorkorderActivity(input) {
|
|
|
234156
234734
|
commentIssueIds: ids2
|
|
234157
234735
|
});
|
|
234158
234736
|
}
|
|
234159
|
-
{
|
|
234160
|
-
const
|
|
234161
|
-
const
|
|
234162
|
-
|
|
234163
|
-
|
|
234164
|
-
|
|
234165
|
-
|
|
234166
|
-
|
|
234167
|
-
|
|
234168
|
-
|
|
234169
|
-
|
|
234170
|
-
|
|
234171
|
-
|
|
234172
|
-
|
|
234173
|
-
|
|
234174
|
-
|
|
234175
|
-
|
|
234176
|
-
|
|
234177
|
-
|
|
234178
|
-
|
|
234179
|
-
|
|
234180
|
-
|
|
234181
|
-
|
|
234182
|
-
|
|
234183
|
-
|
|
234184
|
-
|
|
234185
|
-
|
|
234186
|
-
|
|
234187
|
-
|
|
234188
|
-
|
|
234189
|
-
|
|
234190
|
-
|
|
234191
|
-
|
|
234192
|
-
|
|
234193
|
-
|
|
234194
|
-
|
|
234195
|
-
|
|
234196
|
-
|
|
234197
|
-
|
|
234198
|
-
|
|
234199
|
-
|
|
234200
|
-
|
|
234201
|
-
|
|
234202
|
-
|
|
234203
|
-
|
|
234204
|
-
|
|
234205
|
-
|
|
234206
|
-
|
|
234207
|
-
|
|
234208
|
-
|
|
234209
|
-
|
|
234210
|
-
|
|
234211
|
-
|
|
234212
|
-
|
|
234213
|
-
|
|
234214
|
-
|
|
234215
|
-
|
|
234216
|
-
|
|
234217
|
-
|
|
234218
|
-
|
|
234219
|
-
|
|
234220
|
-
|
|
234221
|
-
|
|
234222
|
-
|
|
234223
|
-
|
|
234224
|
-
|
|
234225
|
-
|
|
234226
|
-
|
|
234227
|
-
|
|
234228
|
-
|
|
234229
|
-
|
|
234230
|
-
|
|
234231
|
-
必须是要人处理的那一条,不是第一条。房间不在这里造:前端拿 escalationId 去打
|
|
234232
|
-
`POST /api/inbox/discuss`,那个端点按项幂等(ADR 0079 D1「一上报一房」)。
|
|
234233
|
-
按钮文案按**查看者**分两态(Bug 0151 / PR #2003 / 用例 T-31):不是收件人就写「去查看」
|
|
234234
|
-
——他点进去只有只读视图,按钮不该承诺一件他做不到的事。查看者取不到时保持「去处理」。
|
|
234235
|
-
关掉之后按钮不收走、只换成「去查看」:那间讨论房是这条上报唯一的来龙去脉。 */
|
|
234236
|
-
actions: open3.length === 0 ? [{ kind: "discuss_escalation", label: BUTTON.view, target: latest.id }] : offerRerun ? [
|
|
234237
|
-
{ kind: "rerun_node", label: BUTTON.rerun, target: active.id, variant: "primary" },
|
|
234238
|
-
{ kind: "discuss_escalation", label: BUTTON.handle, target: active.id, variant: "secondary" }
|
|
234239
|
-
] : [{
|
|
234240
|
-
kind: "discuss_escalation",
|
|
234241
|
-
label: viewerIsTarget ? BUTTON.handle : BUTTON.view,
|
|
234242
|
-
target: active.id
|
|
234243
|
-
}]
|
|
234244
|
-
});
|
|
234245
|
-
}
|
|
234737
|
+
for (const e of [...escalations].sort((a, b2) => a.at.localeCompare(b2.at) || a.seq - b2.seq)) {
|
|
234738
|
+
const kind = escalationKindOf(e.id, issueById.get(e.id)?.authorActorId ?? e.authorId);
|
|
234739
|
+
const resolvedAt = (id) => issueById.get(id)?.resolvedAt ?? null;
|
|
234740
|
+
const closedAt = resolvedAt(e.id);
|
|
234741
|
+
const open3 = !closedAt;
|
|
234742
|
+
const target = resolveEscalationRecipient({
|
|
234743
|
+
recipients: e.recipients,
|
|
234744
|
+
authorActorId: e.authorId,
|
|
234745
|
+
stuckActorId: e.stuckActorId,
|
|
234746
|
+
ownerActorId: ownerId,
|
|
234747
|
+
managerActorId: managerId
|
|
234748
|
+
});
|
|
234749
|
+
const stuckActor = (isStopLoss(kind) ? e.nodeId ? nodeById.get(e.nodeId)?.assigneeActorId : void 0 : void 0) ?? e.stuckActorId;
|
|
234750
|
+
const inDiscussion = open3 && !!input.escalationsInDiscussion?.has(e.id);
|
|
234751
|
+
const gapBehind = (id) => {
|
|
234752
|
+
const gapId = issueById.get(id)?.gapId;
|
|
234753
|
+
return typeof gapId === "string" && !!issueById.get(gapId);
|
|
234754
|
+
};
|
|
234755
|
+
const head = kind === "retry_exhausted" ? ACTIVITY_COPY.escalationHeadRetryExhausted(nodeName(e.nodeId)) : kind === "review_exhausted" ? ACTIVITY_COPY.escalationHeadReviewExhausted(nodeName(e.nodeId)) : kind === "output_stall" ? ACTIVITY_COPY.escalationHeadOutputStall(nodeName(e.nodeId)) : gapBehind(e.id) ? ACTIVITY_COPY.escalationHeadGapEscalated(nameOf(e.authorId), nodeName(e.nodeId)) : ACTIVITY_COPY.escalationHeadManual(nameOf(stuckActor));
|
|
234756
|
+
const howTo = kind === "retry_exhausted" ? ACTIVITY_COPY.escalationHowToRetryExhausted : kind === "review_exhausted" ? ACTIVITY_COPY.escalationHowToReviewExhausted : kind === "output_stall" ? ACTIVITY_COPY.escalationHowToOutputStall : void 0;
|
|
234757
|
+
const closing = issueById.get(e.id);
|
|
234758
|
+
const closeEvent = plainResolveEvents.get(e.id);
|
|
234759
|
+
const closedBy = text5(closing?.resolvedBy) ?? closeEvent?.by ?? target;
|
|
234760
|
+
const closingNote = text5(closing?.resolvedNote) ?? text5(closeEvent?.note);
|
|
234761
|
+
const noteOf = (id) => text5(issueById.get(id)?.resolvedNote) ?? text5(plainResolveEvents.get(id)?.note);
|
|
234762
|
+
const rerunClosed = closingNote === ESCALATION_RERUN_NOTE;
|
|
234763
|
+
const rerunOrdinal = escalations.filter((x2) => x2.nodeId === e.nodeId && noteOf(x2.id) === ESCALATION_RERUN_NOTE && (resolvedAt(x2.id) ?? "") <= (closedAt ?? "")).length;
|
|
234764
|
+
const doneStatus = rerunClosed ? ACTIVITY_COPY.escalationRerun(nameOf(closedBy), Math.max(rerunOrdinal, 1)) : ACTIVITY_COPY.escalationHandled(head, nameOf(closedBy), closingNote);
|
|
234765
|
+
const retryExhaustedSoFar = escalations.filter((x2) => x2.nodeId === e.nodeId && escalationKindOf(x2.id, issueById.get(x2.id)?.authorActorId ?? x2.authorId) === "retry_exhausted" && x2.at <= e.at).length;
|
|
234766
|
+
const viewerIsTarget = !input.viewerActorId || input.viewerActorId === target;
|
|
234767
|
+
const offerRerun = kind === "retry_exhausted" && viewerIsTarget && retryExhaustedSoFar < 2 && !!e.nodeId;
|
|
234768
|
+
issueCards.set(e.id, {
|
|
234769
|
+
id: `issue:${e.id}`,
|
|
234770
|
+
seq: e.seq,
|
|
234771
|
+
at: e.at,
|
|
234772
|
+
updatedAt: closedAt ?? e.at,
|
|
234773
|
+
...e.nodeId ? { nodeId: e.nodeId } : {},
|
|
234774
|
+
executorId: target,
|
|
234775
|
+
/* 代操作人只在**还没关**的时候带:那是「谁替谁把这条上报派成待办」的事实。
|
|
234776
|
+
关掉之后归因只认这次收口(`resolvedBy`),不沿用派发待办时的代操作者。 */
|
|
234777
|
+
...open3 && e.handActorId ? { handActorId: e.handActorId } : {},
|
|
234778
|
+
escalationKind: kind,
|
|
234779
|
+
/* 大状态三档(F5):待处理 → 处理中(讨论房里已经有人说过话)→ 已完成。
|
|
234780
|
+
关掉那一档不覆写 `phaseLabel`,用四档默认的「已完成」。 */
|
|
234781
|
+
phase: !open3 ? "done" : inDiscussion ? "running" : "not_started",
|
|
234782
|
+
segmentOpen: open3,
|
|
234783
|
+
/* 颜色(奕璇 2026-09-22 定的判据「是不是在等人动手」):**上报没关 ⇒ 砖红**——这一段就卡在人
|
|
234784
|
+
身上,卡面给的正是「去处理」/「重新运行」。关了 ⇒ 不再等人,`segmentOpen` 也随之为假 ⇒ 灰。
|
|
234785
|
+
⚠ **不按查看者分**:非收件人看到的按钮词是「查看留言」(Bug 0151 / 用例 T-31),但这件事照样
|
|
234786
|
+
卡在人身上——颜色说的是这一段的状态,不是「轮到你了没有」。 */
|
|
234787
|
+
awaitingHuman: open3,
|
|
234788
|
+
...open3 ? { phaseLabel: inDiscussion ? PHASE_LABEL.escalationInProgress : PHASE_LABEL.escalationPending } : {},
|
|
234789
|
+
status: open3 ? ACTIVITY_COPY.escalationPendingWith(head, nameOf(target), howTo) : doneStatus,
|
|
234790
|
+
/* 上报正文**不上卡**——与缺口 / 回压同一条口径。此前这里把整封信塞进展开区,
|
|
234791
|
+
`ws:wo-635d7add` 那条渲染出的是一屏字,连内部 artifact id 都印在卡面上。
|
|
234792
|
+
全文的去处,就是那个「去处理」按钮。 */
|
|
234793
|
+
artifacts: [],
|
|
234794
|
+
/* 「去处理」进**这条上报自己的**讨论房(`discuss_escalation`)——卡与房一一对应(ADR 0079 D1
|
|
234795
|
+
「一上报一房」),所以关掉之后这张卡仍然指着当初处理它的那间房,不会被后来新开的上报改指。
|
|
234796
|
+
房间不在这里造:前端拿 escalationId 去打 `POST /api/inbox/discuss`,那个端点按项幂等。
|
|
234797
|
+
按钮文案按**查看者**分两态(Bug 0151 / PR #2003 / 用例 T-31):不是收件人就写「查看留言」
|
|
234798
|
+
——他点进去只有只读视图,按钮不该承诺一件他做不到的事。查看者取不到时保持「去处理」。
|
|
234799
|
+
关掉之后按钮不收走、只换成「查看留言」:那间讨论房是这条上报唯一的来龙去脉。 */
|
|
234800
|
+
actions: !open3 ? [{ kind: "discuss_escalation", label: BUTTON.view, target: e.id }] : offerRerun ? [
|
|
234801
|
+
{ kind: "rerun_node", label: BUTTON.rerun, target: e.id, variant: "primary" },
|
|
234802
|
+
{ kind: "discuss_escalation", label: BUTTON.handle, target: e.id, variant: "secondary" }
|
|
234803
|
+
] : [{
|
|
234804
|
+
kind: "discuss_escalation",
|
|
234805
|
+
label: viewerIsTarget ? BUTTON.handle : BUTTON.view,
|
|
234806
|
+
target: e.id
|
|
234807
|
+
}]
|
|
234808
|
+
});
|
|
234246
234809
|
}
|
|
234247
234810
|
const coordinatorCards = [];
|
|
234811
|
+
const gapsClosedByCoordinatorCard = /* @__PURE__ */ new Set();
|
|
234248
234812
|
{
|
|
234249
|
-
const
|
|
234250
|
-
const
|
|
234251
|
-
|
|
234252
|
-
const
|
|
234253
|
-
const
|
|
234254
|
-
|
|
234255
|
-
|
|
234256
|
-
|
|
234257
|
-
|
|
234258
|
-
|
|
234259
|
-
|
|
234260
|
-
|
|
234261
|
-
|
|
234262
|
-
|
|
234263
|
-
|
|
234264
|
-
endedAt: r.endedAt ?? null,
|
|
234265
|
-
statuses: [r.status ?? null]
|
|
234266
|
-
});
|
|
234267
|
-
}
|
|
234268
|
-
for (const run of episodes) {
|
|
234269
|
-
const name = nodeName(run.nodeId);
|
|
234270
|
-
const endedAt = run.endedAt;
|
|
234271
|
-
const inWindow2 = (at) => !!at && at >= run.startedAt && (!endedAt || at <= endedAt);
|
|
234272
|
-
const escalated = snap.issues.find((i) => i.kind === "escalation" && (i.aboutNodeId ?? i.raisedByNodeId) === run.nodeId && escalationKindOf(i.id, i.authorActorId) === "manual" && inWindow2(i.createdAt));
|
|
234273
|
-
const fixedGap = snap.issues.find((i) => i.kind === "gap" && (i.aboutNodeId ?? i.raisedByNodeId) === run.nodeId && inWindow2(i.resolvedAt));
|
|
234274
|
-
const gapOnNode = snap.issues.find((i) => i.kind === "gap" && (i.aboutNodeId ?? i.raisedByNodeId) === run.nodeId && i.createdAt <= (endedAt ?? run.startedAt));
|
|
234275
|
-
const failedRun = !!endedAt && run.statuses.every((st) => !!st && st !== "succeeded");
|
|
234813
|
+
const gaps = [...snap.issues].filter((i) => i.kind === "gap" && !!(i.aboutNodeId ?? i.raisedByNodeId)).sort((a, b2) => a.createdAt.localeCompare(b2.createdAt) || a.id.localeCompare(b2.id));
|
|
234814
|
+
for (const gap of gaps) {
|
|
234815
|
+
const gapId = gap.id;
|
|
234816
|
+
const nodeId = gap.aboutNodeId ?? gap.raisedByNodeId;
|
|
234817
|
+
const name = nodeName(nodeId);
|
|
234818
|
+
const resolvedAt = gap.resolvedAt ?? null;
|
|
234819
|
+
const inWindow2 = (at) => !!at && at >= gap.createdAt && (!resolvedAt || at <= resolvedAt);
|
|
234820
|
+
const escalated = snap.issues.find((i) => i.kind === "escalation" && escalationKindOf(i.id, i.authorActorId) === "manual" && (i.gapId === gapId || (i.aboutNodeId ?? i.raisedByNodeId) === nodeId && inWindow2(i.createdAt)));
|
|
234821
|
+
const run = coordinatorRunOfGap(
|
|
234822
|
+
{ createdAt: gap.createdAt, resolvedAt },
|
|
234823
|
+
(input.coordinatorRuns ?? []).filter((r) => !!r.id && r.nodeId === nodeId)
|
|
234824
|
+
);
|
|
234825
|
+
const failedRun = !!run?.endedAt && !!run.status && run.status !== "succeeded";
|
|
234826
|
+
const coordinatorId = gap.resolvedBy ?? run?.actorId ?? managerId ?? ownerId;
|
|
234827
|
+
const executorId = gap.authorActorId;
|
|
234276
234828
|
const recipient = escalated ? resolveEscalationRecipient({
|
|
234277
234829
|
recipients: (snap.issueRecipients ?? []).filter((r) => r.issueId === escalated.id).map((r) => r.actorId),
|
|
234278
234830
|
authorActorId: escalated.authorActorId,
|
|
234279
|
-
stuckActorId:
|
|
234831
|
+
stuckActorId: executorId,
|
|
234280
234832
|
ownerActorId: ownerId,
|
|
234281
234833
|
managerActorId: managerId
|
|
234282
234834
|
}) : void 0;
|
|
234283
|
-
|
|
234284
|
-
|
|
234285
|
-
|
|
234286
|
-
|
|
234287
|
-
|
|
234288
|
-
|
|
234289
|
-
|
|
234290
|
-
|
|
234291
|
-
|
|
234292
|
-
|
|
234293
|
-
segmentOpen:
|
|
234294
|
-
|
|
234835
|
+
const segmentOpen = !resolvedAt && !escalated;
|
|
234836
|
+
const draft = {
|
|
234837
|
+
id: coordinatorCardId(gapId),
|
|
234838
|
+
seq: gapCreatedSeq.get(gapId) ?? 0,
|
|
234839
|
+
at: gap.createdAt,
|
|
234840
|
+
updatedAt: [gap.createdAt, resolvedAt, escalated?.createdAt, run?.endedAt].filter((t) => !!t).sort().at(-1),
|
|
234841
|
+
nodeId,
|
|
234842
|
+
executorId: coordinatorId,
|
|
234843
|
+
/* 大状态用四档默认词(进行中 / 已完成 / 执行中断),不覆写 `phaseLabel`——「补上了还是升级了」
|
|
234844
|
+
在小状态那句话里说得比一个词清楚。颜色跟着 `segmentOpen` 走。 */
|
|
234845
|
+
phase: !segmentOpen ? "done" : failedRun ? "stuck" : "running",
|
|
234846
|
+
segmentOpen,
|
|
234847
|
+
/* 协调者卡**从不砖红**:缺口的第一接手人恒是协调者本人,这一段没有人在等着动手
|
|
234848
|
+
(奕璇 2026-09-22 的判据)。连它自己那一段跑挂了(`failedRun` ⇒ `phase: "stuck"`)也一样,
|
|
234849
|
+
那时按 `segmentOpen` 走暖橙——真要人动手的是它升级出去的那张升级卡,红归那一张。
|
|
234850
|
+
显式写 `false` 而不是省略:省略 = 不表态,前端会退回老规则(`stuck` + 开着 ⇒ 砖红)。 */
|
|
234851
|
+
awaitingHuman: false,
|
|
234852
|
+
status: resolvedAt ? ACTIVITY_COPY.coordinatorFixedGap(nameOf(coordinatorId), nameOf(executorId)) : escalated ? ACTIVITY_COPY.coordinatorEscalated(nameOf(coordinatorId), name, nameOf(recipient)) : failedRun ? ACTIVITY_COPY.coordinatorFailed(name) : ACTIVITY_COPY.coordinatingGap(nameOf(coordinatorId), name),
|
|
234295
234853
|
artifacts: [],
|
|
234296
|
-
/* 点进去 = **这段协调轨迹**(run 在 `agent_runs` 里,`runId` 直接给)+ 缺口线。
|
|
234297
|
-
|
|
234298
|
-
runId: run.id,
|
|
234299
|
-
actions:
|
|
234300
|
-
}
|
|
234854
|
+
/* 点进去 = **这段协调轨迹**(run 在 `agent_runs` 里,`runId` 直接给)+ 缺口线。
|
|
234855
|
+
查不到那一段运行 ⇒ 不给轨迹入口,卡与那颗「查看留言」照旧。 */
|
|
234856
|
+
...run ? { traceAvailable: true, runId: run.id } : {},
|
|
234857
|
+
actions: [{ kind: "open_thread", label: BUTTON.view, target: gapThreadSessionId(executorId) }]
|
|
234858
|
+
};
|
|
234859
|
+
coordinatorCards.push(draft);
|
|
234860
|
+
if (resolvedAt) gapsClosedByCoordinatorCard.add(gapId);
|
|
234301
234861
|
}
|
|
234302
234862
|
}
|
|
234303
|
-
for (const
|
|
234863
|
+
for (const issueId of [...issueCards.keys()]) {
|
|
234304
234864
|
if (!issueId.startsWith(REWORK_ANNOTATION_PREFIX)) continue;
|
|
234305
|
-
|
|
234306
|
-
if (covered) issueCards.delete(issueId);
|
|
234865
|
+
if (gapsClosedByCoordinatorCard.has(issueId.slice(REWORK_ANNOTATION_PREFIX.length))) issueCards.delete(issueId);
|
|
234307
234866
|
}
|
|
234308
234867
|
const lastFailureOf = (card2, trip) => {
|
|
234309
234868
|
const message = (input.runFailures ?? []).filter((f2) => f2.nodeId === card2.nodeId && f2.startedAt >= card2.at && f2.startedAt <= trip.at && f2.message.trim()).sort((a, b2) => a.startedAt.localeCompare(b2.startedAt)).at(-1)?.message;
|
|
@@ -234430,6 +234989,7 @@ function buildWorkorderActivity(input) {
|
|
|
234430
234989
|
d.phase = "done";
|
|
234431
234990
|
delete d.phaseLabel;
|
|
234432
234991
|
d.segmentOpen = false;
|
|
234992
|
+
d.awaitingHuman = false;
|
|
234433
234993
|
d.status = ACTIVITY_COPY.closedNoAction(terminal);
|
|
234434
234994
|
if (!d.commentIssueIds) d.actions = [];
|
|
234435
234995
|
}
|
|
@@ -234498,6 +235058,7 @@ function buildWorkorderActivity(input) {
|
|
|
234498
235058
|
phase: d.phase,
|
|
234499
235059
|
...d.phaseLabel ? { phaseLabel: d.phaseLabel } : {},
|
|
234500
235060
|
...d.segmentOpen === void 0 ? {} : { segmentOpen: d.segmentOpen },
|
|
235061
|
+
...d.awaitingHuman === void 0 ? {} : { awaitingHuman: d.awaitingHuman },
|
|
234501
235062
|
...d.escalationKind ? { escalationKind: d.escalationKind } : {},
|
|
234502
235063
|
...d.noticeTitle ? { noticeTitle: d.noticeTitle } : {},
|
|
234503
235064
|
status: d.status,
|
|
@@ -234515,7 +235076,7 @@ function buildWorkorderActivity(input) {
|
|
|
234515
235076
|
cards.sort((a, b2) => a.at.localeCompare(b2.at) || a.seq - b2.seq || a.id.localeCompare(b2.id));
|
|
234516
235077
|
return { workorderId, cards, truncated };
|
|
234517
235078
|
}
|
|
234518
|
-
var ACTIVITY_EVENT_KINDS, LEGACY_PAUSE_REASON, ACTIVITY_EVENT_LIMIT, UPSTREAM_ACK_NOTE_CAP, ACTIVITY_COPY, REWORK_ANNOTATION_PREFIX, RECOVERY_ANNOTATION_PREFIX, ENGINE_RETRY_EXHAUSTED, BUTTON, PHASE_LABEL, COORDINATOR_CARD_PREFIX, RETRY_EXHAUSTED_ESC_PREFIX, REVIEW_EXHAUSTED_ESC_PREFIX2, isStopLoss;
|
|
235079
|
+
var ACTIVITY_EVENT_KINDS, LEGACY_PAUSE_REASON, ACTIVITY_EVENT_LIMIT, UPSTREAM_ACK_NOTE_CAP, ACTIVITY_COPY, REWORK_ANNOTATION_PREFIX, RECOVERY_ANNOTATION_PREFIX, ENGINE_RETRY_EXHAUSTED, BUTTON, PHASE_LABEL, COORDINATOR_CARD_PREFIX, coordinatorCardId, RETRY_EXHAUSTED_ESC_PREFIX, REVIEW_EXHAUSTED_ESC_PREFIX2, isStopLoss;
|
|
234519
235080
|
var init_activity2 = __esm({
|
|
234520
235081
|
"../server/src/domains/collab/activity.ts"() {
|
|
234521
235082
|
"use strict";
|
|
@@ -234648,9 +235209,10 @@ var init_activity2 = __esm({
|
|
|
234648
235209
|
改完之后两种止损的**执行者是一样的**(执行卡挂执行人、升级卡挂等处理的那个人),
|
|
234649
235210
|
能不能分辨全落在这几句话上。投影侧怎么判是哪一种见 {@link escalationKindOf}。
|
|
234650
235211
|
次数与花费**取上报正文里系统自己算出来的那个数**(引擎 `activate.ts` 的 `连续 N 次执行失败`、
|
|
234651
|
-
serve `zero-output-breaker.ts` 的 `跑了 N
|
|
234652
|
-
|
|
234653
|
-
|
|
235212
|
+
serve `zero-output-breaker.ts` 的 `跑了 N 轮 … 约 $X`)——本投影手上没有第二份可信来源,
|
|
235213
|
+
上报正文是唯一事实源(奕璇 2026-09-22 定)。两头的口径都已经是**轮**:引擎那条本来就数
|
|
235214
|
+
work,保险丝那条 Bug 0211 起把同一轮里的协议续唤 run 折回去再数(老正文不回填,见
|
|
235215
|
+
{@link parseStopLossFacts})。 */
|
|
234654
235216
|
retryExhausted: (executor, node2, n, lastReason) => `${executor} \u8FDE\u7EED ${n} \u6B21\u6CA1\u8DD1\u6210\u300A${node2}\u300B\uFF0C\u91CD\u8BD5\u5DF2\u7528\u5C3D${lastReason ? `\uFF08\u672B\u6B21\uFF1A${lastReason}\uFF09` : ""}\u3002`,
|
|
234655
235217
|
outputStalled: (executor, node2, n, cost) => `${executor} \u8FDE\u7EED ${n} \u6B21\u6CA1\u4EA4\u51FA\u300A${node2}\u300B\u7684\u4EFB\u4F55\u6210\u679C${cost ? `\uFF08\u7EA6 ${cost}\uFF09` : ""}\uFF0C\u7CFB\u7EDF\u5DF2\u6B62\u635F\u3002`,
|
|
234656
235218
|
/* ── 升级卡(上报)的整句 ───────────────────────────────────────────────────────────
|
|
@@ -234659,8 +235221,16 @@ var init_activity2 = __esm({
|
|
|
234659
235221
|
同一件事,只换后半句(「等 @X 处理」→「X 已处理:…」)。 */
|
|
234660
235222
|
escalationHeadRetryExhausted: (node2) => `\u300A${node2}\u300B\u91CD\u8BD5\u5DF2\u7528\u5C3D\uFF0C`,
|
|
234661
235223
|
escalationHeadOutputStall: (node2) => `\u7CFB\u7EDF\u6B62\u635F\uFF1A\u300A${node2}\u300B\u505C\u4F4F\u4E86\uFF0C`,
|
|
234662
|
-
/**
|
|
234663
|
-
|
|
235224
|
+
/**
|
|
235225
|
+
* 评审连败熔断(Bug 0212):卡住的是**这一轮评审**,不是那一版活——话不能写成「执行异常」。
|
|
235226
|
+
*
|
|
235227
|
+
* 🚨 **这里没有「(末次:…)」**,与连败熔断卡不同:报错原话只在 `agent_runs.error_message`,
|
|
235228
|
+
* 而**评审派发的 run 行 `node_id` 与 `work_order_id` 双双为 null**(v2 `ws:wo-65841524` 实测:
|
|
235229
|
+
* qa-quality 连败那 4 条只有 `artifact_id`)——`listRunFailures` 按 `work_order_id` 圈范围,
|
|
235230
|
+
* 这批行根本取不到。硬拼一句取不到值的模板只会永远不出现,不如不写。
|
|
235231
|
+
* 要补这半句,得先让评审派发把 `work_order_id` / `node_id` 记进 `agent_runs`(另开单)。
|
|
235232
|
+
*/
|
|
235233
|
+
escalationHeadReviewExhausted: (node2) => `\u300A${node2}\u300B\u7684\u8BC4\u5BA1\u8FDE\u7740\u6CA1\u8DD1\u6210\uFF0C\u8FD9\u4E00\u8F6E\u6536\u4E0D\u9F50\uFF0C`,
|
|
234664
235234
|
/** 人工上报里**关联着缺口**的那一档:协调者接了缺口、补不了,于是升级给人(四种停法的第二种)。 */
|
|
234665
235235
|
escalationHeadGapEscalated: (coordinator, node2) => `${coordinator} \u8865\u4E0D\u4E86\u300A${node2}\u300B\u7684\u7F3A\u53E3\uFF0C`,
|
|
234666
235236
|
/** 其余人工上报:主语是卡住的那个执行人(异常是它的,不是上报作者的)。 */
|
|
@@ -234686,15 +235256,20 @@ var init_activity2 = __esm({
|
|
|
234686
235256
|
* ——人并没有写说明,说明是这颗按钮替他写的。次数是**这个节点上第几次这么重试**。
|
|
234687
235257
|
*/
|
|
234688
235258
|
escalationRerun: (by, n) => `${by} \u91CD\u65B0\u8FD0\u884C\u4E86\u8FD9\u4E00\u6B65\uFF08\u7B2C ${n} \u6B21\u91CD\u8BD5\uFF09\u3002`,
|
|
234689
|
-
/* ── 协调者卡(F2
|
|
234690
|
-
|
|
234691
|
-
|
|
234692
|
-
|
|
235259
|
+
/* ── 协调者卡(F2)──────────────────────────────────────────────────────────────────
|
|
235260
|
+
「协调者处理**某条缺口**的那一段」。三句话对应缺口的三种去向(已补齐 / 补不了升级给人 /
|
|
235261
|
+
还开着),判据全在缺口这条 issue 上,不看旁账那条 `coordinate:` 运行有没有留下结论
|
|
235262
|
+
(Bug 0213;前两句 T-104 / T-113 已验收,逐字不动)。 */
|
|
235263
|
+
coordinatingGap: (coordinator, node2) => `${coordinator} \u6B63\u5728\u5904\u7406\u300A${node2}\u300B\u7684\u7F3A\u53E3\u3002`,
|
|
234693
235264
|
coordinatorFixedGap: (coordinator, executor) => `${coordinator} \u5DF2\u8865\u9F50\u7F3A\u53E3\uFF0C${executor} \u7EE7\u7EED\u6267\u884C\u3002`,
|
|
234694
235265
|
coordinatorEscalated: (coordinator, node2, target) => `${coordinator} \u8865\u4E0D\u4E86\u300A${node2}\u300B\u7684\u7F3A\u53E3\uFF0C\u5DF2\u5347\u7EA7\u7ED9 @${target} \u5904\u7406\u3002`,
|
|
234695
|
-
/**
|
|
234696
|
-
|
|
234697
|
-
|
|
235266
|
+
/**
|
|
235267
|
+
* 缺口还开着、也没升级给人,而这一段协调运行已经结束且没跑成(failed / orphaned / timeout)——
|
|
235268
|
+
* 如实说这一轮没跑成,别说「正在处理」(没人在处理),也别替它宣布一个没发生的结局。
|
|
235269
|
+
*
|
|
235270
|
+
* 🚨 兜底句「{协调者} 处理《X》的缺口,这一段没有结论」**已删**(Bug 0213):那句是拿 run 的结论
|
|
235271
|
+
* 拼卡时的产物——取不到结论就替这一段下一个空结论。缺口自己的状态永远答得出「补上了没有」。
|
|
235272
|
+
*/
|
|
234698
235273
|
coordinatorFailed: (node2) => `\u5904\u7406\u300A${node2}\u300B\u7684\u7F3A\u53E3\u65F6\u8FD9\u4E00\u8F6E\u6CA1\u8DD1\u6210\u3002`,
|
|
234699
235274
|
/**
|
|
234700
235275
|
* 这一轮**被计划变更打断**(P15)。与卡点中断同级:计划一动,这一轮就不再是「还在跑」,
|
|
@@ -234809,7 +235384,7 @@ var init_activity2 = __esm({
|
|
|
234809
235384
|
*
|
|
234810
235385
|
* 此前走 `issueOpen`:正文整段当小状态,`detail` 又是同一段。全库实测最长
|
|
234811
235386
|
* **8096 字印两遍**(`ws:wo-56bba3c1`),一张卡顶掉整屏。正文的去处是「留言线」——
|
|
234812
|
-
* 与缺口线同一套投影(`gap-thread.ts` 的 `buildCommentThread
|
|
235387
|
+
* 与缺口线同一套投影(`gap-thread.ts` 的 `buildCommentThread`),卡上给「查看留言」。
|
|
234813
235388
|
*/
|
|
234814
235389
|
commentRaised: (author, target, node2) => `${author} \u5728\u300A${node2}\u300B\u7559\u8A00\uFF0C\u9700\u8981 @${target} \u67E5\u770B\u3002`,
|
|
234815
235390
|
/* ── 普通留言卡(奕璇 2026-09-18 定,ADR 0594)────────────────────────────────────────
|
|
@@ -234851,9 +235426,17 @@ var init_activity2 = __esm({
|
|
|
234851
235426
|
acceptPass: "\u9A8C\u6536\u901A\u8FC7",
|
|
234852
235427
|
acceptFail: "\u9A8C\u6536\u4E0D\u901A\u8FC7",
|
|
234853
235428
|
handle: "\u53BB\u5904\u7406",
|
|
234854
|
-
|
|
234855
|
-
|
|
234856
|
-
|
|
235429
|
+
/**
|
|
235430
|
+
* **只读进房**那一档:留言线、缺口线(执行人 ↔ 协调者)、上报讨论房(旁观者 / 已关掉)共用这一个词。
|
|
235431
|
+
*
|
|
235432
|
+
* 2026-09-22 奕璇拍板把旧的两个名字**并成一个**:缺口线那两处原来写「去缺口线」
|
|
235433
|
+
* (`BUTTON.gapThread`),其余只读入口原来写「去查看」——三处点进去做的是同一件事:
|
|
235434
|
+
* **进这条线看聊天记录**,用户视角没有第二、第三个名字。目标(`open_thread` /
|
|
235435
|
+
* `discuss_escalation` 与 target)一个字没动,只是不再自造第二个词。
|
|
235436
|
+
* 于是卡上只剩三种按钮:「去处理」(等人动手)、「查看留言」(只读进房)、
|
|
235437
|
+
* 「重新运行」(连败熔断升级卡的主按钮)。
|
|
235438
|
+
*/
|
|
235439
|
+
view: "\u67E5\u770B\u7559\u8A00",
|
|
234857
235440
|
/** 连败熔断升级卡的主按钮(F7):重开这一步,并把那条上报一并关掉。 */
|
|
234858
235441
|
rerun: "\u91CD\u65B0\u8FD0\u884C"
|
|
234859
235442
|
};
|
|
@@ -234866,6 +235449,7 @@ var init_activity2 = __esm({
|
|
|
234866
235449
|
escalationInProgress: "\u5904\u7406\u4E2D"
|
|
234867
235450
|
};
|
|
234868
235451
|
COORDINATOR_CARD_PREFIX = "coordinator:";
|
|
235452
|
+
coordinatorCardId = (gapId) => `${COORDINATOR_CARD_PREFIX}${gapId}`;
|
|
234869
235453
|
RETRY_EXHAUSTED_ESC_PREFIX = "esc:retry-exhausted:";
|
|
234870
235454
|
REVIEW_EXHAUSTED_ESC_PREFIX2 = "esc:review-exhausted:";
|
|
234871
235455
|
isStopLoss = (kind) => kind === "retry_exhausted" || kind === "output_stall";
|
|
@@ -234886,10 +235470,12 @@ function buildWorkorderActivityTrace(input) {
|
|
|
234886
235470
|
const reviews = activityReviews(snap, input.events ?? []);
|
|
234887
235471
|
const reviewTarget = reviewCardTarget(cardId, reviews);
|
|
234888
235472
|
if (reviewTarget) return buildReviewHistory(input, reviewTarget.targetWorkId, reviewTarget.reviewerActorId, reviews);
|
|
234889
|
-
|
|
234890
|
-
|
|
234891
|
-
const
|
|
234892
|
-
|
|
235473
|
+
const coordinatorGapId = coordinatorCardGapId(cardId);
|
|
235474
|
+
if (coordinatorGapId !== void 0) {
|
|
235475
|
+
const gap2 = snap.issues.find((i) => i.id === coordinatorGapId && i.kind === "gap");
|
|
235476
|
+
const gapNodeId = gap2 ? gap2.aboutNodeId ?? gap2.raisedByNodeId : null;
|
|
235477
|
+
const run = gap2 && gapNodeId ? coordinatorRunOfGap(gap2, (input.coordinatorRuns ?? []).filter((r) => r.nodeId === gapNodeId)) : void 0;
|
|
235478
|
+
if (!run) return { ...empty2, notice: "\u534F\u8C03\u8005\u5904\u7406\u8FD9\u6761\u7F3A\u53E3\u7684\u90A3\u4E00\u6BB5\u6CA1\u6709\u7559\u4E0B\u8FD0\u884C\u8BB0\u5F55\uFF0C\u6682\u65F6\u65E0\u6CD5\u786E\u8BA4\u8FD0\u884C\u8F68\u8FF9\u3002" };
|
|
234893
235479
|
const node2 = snap.nodes.find((n) => n.id === run.nodeId);
|
|
234894
235480
|
const spec = node2?.spec?.trim();
|
|
234895
235481
|
return {
|
|
@@ -235166,11 +235752,14 @@ var init_activity_trace = __esm({
|
|
|
235166
235752
|
});
|
|
235167
235753
|
|
|
235168
235754
|
// ../server/src/domains/collab/inbox.ts
|
|
235755
|
+
function commandCardLine(command2) {
|
|
235756
|
+
return command2.displayLabel?.trim() || stripInternalIds(command2.effectLabel ?? "");
|
|
235757
|
+
}
|
|
235169
235758
|
function changeConfirmSummary(r) {
|
|
235170
235759
|
if (r.continuation) return `\u81EA\u52A8\u7EED\u8DD1\u5DF2\u5230\u9650\uFF0C\u7B49\u5F85\u4F60\u5BA1\u6838\uFF1A${r.plan.reason}`;
|
|
235171
235760
|
const why = r.plan.reason.slice(0, 100);
|
|
235172
235761
|
if (r.kind === "command" && r.command) {
|
|
235173
|
-
return `\u7BA1\u7406\u8005\u8BF7\u6C42\u6267\u884C\u4E00\u4E2A\u9AD8\u5371\u64CD\u4F5C\uFF0C\u7B49\u4F60\u6388\u6743\uFF1A${r.command
|
|
235762
|
+
return `\u7BA1\u7406\u8005\u8BF7\u6C42\u6267\u884C\u4E00\u4E2A\u9AD8\u5371\u64CD\u4F5C\uFF0C\u7B49\u4F60\u6388\u6743\uFF1A${commandCardLine(r.command)}`;
|
|
235174
235763
|
}
|
|
235175
235764
|
const ops = r.plan.ops ?? [];
|
|
235176
235765
|
if (ops.length > 0 && ops.every((o) => o.action === "resolveEscalation")) {
|
|
@@ -235346,7 +235935,7 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
|
|
|
235346
235935
|
// 仍回落工单详情。
|
|
235347
235936
|
...r.origin ? { chatSessionId: r.origin } : {},
|
|
235348
235937
|
...anchorArt ? { title: nodeLabel(anchorArt) } : {},
|
|
235349
|
-
detail: `${actorName(r.proposedBy) || "\u7BA1\u7406\u8005"}\uFF1A${r.command
|
|
235938
|
+
detail: `${actorName(r.proposedBy) || "\u7BA1\u7406\u8005"}\uFF1A${r.command ? commandCardLine(r.command) : firstSentence2(r.plan.reason)}`,
|
|
235350
235939
|
...r.kind !== "command" && opCount > 0 ? { impact: `\u6D89\u53CA ${opCount} \u5904\u6539\u52A8${r.nonMonotonicOps.length > 0 ? " \xB7 \u542B\u9500\u6BC1\u6027" : ""}` } : {},
|
|
235351
235940
|
actor: actorRef2(r.proposedBy),
|
|
235352
235941
|
...overdueField(r.at)
|
|
@@ -237118,6 +237707,16 @@ function effectivePoints(run) {
|
|
|
237118
237707
|
}
|
|
237119
237708
|
return points;
|
|
237120
237709
|
}
|
|
237710
|
+
function ledgerRunModel(run) {
|
|
237711
|
+
const onRow = resolvedModel(run.effectiveModel);
|
|
237712
|
+
if (onRow) return onRow;
|
|
237713
|
+
let best = null;
|
|
237714
|
+
for (const p2 of run.points) {
|
|
237715
|
+
const m2 = resolvedModel(p2.model);
|
|
237716
|
+
if (m2 && (!best || p2.seq < best.seq)) best = { seq: p2.seq, model: m2 };
|
|
237717
|
+
}
|
|
237718
|
+
return best?.model ?? null;
|
|
237719
|
+
}
|
|
237121
237720
|
function distribute(total, weights) {
|
|
237122
237721
|
const sum = weights.reduce((s2, w2) => s2 + w2, 0);
|
|
237123
237722
|
if (sum <= 0) return weights.map(() => 0);
|
|
@@ -237460,14 +238059,15 @@ function runtimeRows(facts, relations) {
|
|
|
237460
238059
|
if (!v2.relevant) continue;
|
|
237461
238060
|
const key2 = keyOf4(v2.run.runtimeInstanceId, v2.run.runtimeKind);
|
|
237462
238061
|
getCell(cells, key2).addView(v2);
|
|
237463
|
-
modelsOf(key2).cell(v2.run
|
|
238062
|
+
modelsOf(key2).cell(ledgerRunModel(v2.run)).addView(v2);
|
|
237464
238063
|
}
|
|
237465
238064
|
for (const r of facts.rounds) {
|
|
237466
238065
|
const key2 = keyOf4(r.runtimeInstanceId, r.runtimeKind);
|
|
237467
238066
|
const c = getCell(cells, key2);
|
|
237468
238067
|
c.active = true;
|
|
237469
238068
|
c.runCount += 1;
|
|
237470
|
-
const
|
|
238069
|
+
const firstRun = runById.get(r.firstRunId);
|
|
238070
|
+
const m2 = modelsOf(key2).cell(firstRun ? ledgerRunModel(firstRun) : null);
|
|
237471
238071
|
m2.active = true;
|
|
237472
238072
|
m2.runCount += 1;
|
|
237473
238073
|
}
|
|
@@ -241900,9 +242500,17 @@ function bucketLabelOf(slice, index2) {
|
|
|
241900
242500
|
function runtimeUsageFromLedger(runtimeInstanceId, slice) {
|
|
241901
242501
|
const rows = /* @__PURE__ */ new Map();
|
|
241902
242502
|
const runById = new Map(slice.runs.map((r) => [r.id, r]));
|
|
242503
|
+
const modelByRun = /* @__PURE__ */ new Map();
|
|
242504
|
+
const modelOf = (run) => {
|
|
242505
|
+
const hit = modelByRun.get(run.id);
|
|
242506
|
+
if (hit !== void 0) return hit;
|
|
242507
|
+
const m2 = ledgerRunModel(run);
|
|
242508
|
+
modelByRun.set(run.id, m2);
|
|
242509
|
+
return m2;
|
|
242510
|
+
};
|
|
241903
242511
|
const rowOf = (bucketIndex2, run) => {
|
|
241904
242512
|
const bucket2 = bucketLabelOf(slice, bucketIndex2);
|
|
241905
|
-
const model =
|
|
242513
|
+
const model = modelOf(run);
|
|
241906
242514
|
const key2 = `${bucket2}\0${run.actorId}\0${model ?? ""}`;
|
|
241907
242515
|
let row = rows.get(key2);
|
|
241908
242516
|
if (!row) {
|
|
@@ -242898,11 +243506,11 @@ var init_roles = __esm({
|
|
|
242898
243506
|
});
|
|
242899
243507
|
|
|
242900
243508
|
// ../server/src/node-store.ts
|
|
242901
|
-
var
|
|
243509
|
+
var fs26, MemoryNodeStore, FileNodeStore;
|
|
242902
243510
|
var init_node_store = __esm({
|
|
242903
243511
|
"../server/src/node-store.ts"() {
|
|
242904
243512
|
"use strict";
|
|
242905
|
-
|
|
243513
|
+
fs26 = __toESM(require("node:fs"), 1);
|
|
242906
243514
|
MemoryNodeStore = class {
|
|
242907
243515
|
nodes = /* @__PURE__ */ new Map();
|
|
242908
243516
|
runtimes = /* @__PURE__ */ new Map();
|
|
@@ -243027,16 +243635,16 @@ var init_node_store = __esm({
|
|
|
243027
243635
|
static async open(file) {
|
|
243028
243636
|
const s2 = new _FileNodeStore(file);
|
|
243029
243637
|
try {
|
|
243030
|
-
const snap = JSON.parse(
|
|
243638
|
+
const snap = JSON.parse(fs26.readFileSync(file, "utf8"));
|
|
243031
243639
|
for (const n of snap.nodes ?? []) s2.nodes.set(n.id, n);
|
|
243032
243640
|
for (const r of snap.runtimes ?? []) s2.runtimes.set(r.id, r);
|
|
243033
243641
|
} catch {
|
|
243034
|
-
|
|
243642
|
+
fs26.writeFileSync(file, JSON.stringify({ nodes: [], runtimes: [] }, null, 2));
|
|
243035
243643
|
}
|
|
243036
243644
|
return s2;
|
|
243037
243645
|
}
|
|
243038
243646
|
flush() {
|
|
243039
|
-
|
|
243647
|
+
fs26.writeFileSync(this.file, JSON.stringify({
|
|
243040
243648
|
nodes: [...this.nodes.values()],
|
|
243041
243649
|
runtimes: [...this.runtimes.values()]
|
|
243042
243650
|
}, null, 2));
|
|
@@ -243827,9 +244435,9 @@ function prepareReadonlyGitBundles(input) {
|
|
|
243827
244435
|
if (repos.length === 0) return null;
|
|
243828
244436
|
const targets = collectTargets(repos, input.pinnedRevisions);
|
|
243829
244437
|
if (targets.length === 0) return null;
|
|
243830
|
-
const bundleRoot = input.bundleRoot ??
|
|
243831
|
-
|
|
243832
|
-
const root =
|
|
244438
|
+
const bundleRoot = input.bundleRoot ?? os8.tmpdir();
|
|
244439
|
+
fs27.mkdirSync(bundleRoot, { recursive: true });
|
|
244440
|
+
const root = fs27.mkdtempSync(path24.join(bundleRoot, "oasis-git-bundles-"));
|
|
243833
244441
|
const files = {};
|
|
243834
244442
|
const binaryFiles = {};
|
|
243835
244443
|
const metas = [];
|
|
@@ -243837,7 +244445,7 @@ function prepareReadonlyGitBundles(input) {
|
|
|
243837
244445
|
for (const target of targets) {
|
|
243838
244446
|
const generated = createBundle(root, target, input);
|
|
243839
244447
|
files[generated.metaPath] = JSON.stringify(generated.meta, null, 2) + "\n";
|
|
243840
|
-
binaryFiles[generated.bundlePath] =
|
|
244448
|
+
binaryFiles[generated.bundlePath] = fs27.readFileSync(generated.absoluteBundlePath).toString("base64");
|
|
243841
244449
|
metas.push(generated.meta);
|
|
243842
244450
|
}
|
|
243843
244451
|
files["inputs/git-bundles/MANIFEST.json"] = JSON.stringify({
|
|
@@ -243858,10 +244466,10 @@ function prepareReadonlyGitBundles(input) {
|
|
|
243858
244466
|
return {
|
|
243859
244467
|
files,
|
|
243860
244468
|
binaryFiles,
|
|
243861
|
-
cleanup: () =>
|
|
244469
|
+
cleanup: () => fs27.rmSync(root, { recursive: true, force: true })
|
|
243862
244470
|
};
|
|
243863
244471
|
} catch (err) {
|
|
243864
|
-
|
|
244472
|
+
fs27.rmSync(root, { recursive: true, force: true });
|
|
243865
244473
|
throw err;
|
|
243866
244474
|
}
|
|
243867
244475
|
}
|
|
@@ -243920,7 +244528,7 @@ function createBundle(root, target, input) {
|
|
|
243920
244528
|
if (!HEX40.test(commit)) throw new GitReadonlyBundleError("COMMIT_NOT_FOUND", `commit \u683C\u5F0F\u4E0D\u662F 40 \u4F4D sha: ${commit.slice(0, 48)}`);
|
|
243921
244529
|
const safeRepo = repo.id.replace(/[^a-zA-Z0-9_-]+/g, "_");
|
|
243922
244530
|
const work = path24.join(root, safeRepo);
|
|
243923
|
-
|
|
244531
|
+
fs27.mkdirSync(work, { recursive: true });
|
|
243924
244532
|
const source = ensureSourceRepo(work, repo, commit, input.env);
|
|
243925
244533
|
const tree = git2(source, ["rev-parse", `${commit}^{tree}`], input.env, "COMMIT_NOT_FOUND").trim();
|
|
243926
244534
|
if (target.expectedTree && target.expectedTree.toLowerCase() !== tree.toLowerCase()) {
|
|
@@ -243947,8 +244555,8 @@ function createBundle(root, target, input) {
|
|
|
243947
244555
|
} catch {
|
|
243948
244556
|
}
|
|
243949
244557
|
}
|
|
243950
|
-
const bytes2 =
|
|
243951
|
-
const digest = (0, import_node_crypto62.createHash)("sha256").update(
|
|
244558
|
+
const bytes2 = fs27.statSync(absBundle).size;
|
|
244559
|
+
const digest = (0, import_node_crypto62.createHash)("sha256").update(fs27.readFileSync(absBundle)).digest("hex");
|
|
243952
244560
|
const relBase = `inputs/git-bundles/${safeRepo}-${commit.slice(0, 12)}`;
|
|
243953
244561
|
return {
|
|
243954
244562
|
absoluteBundlePath: absBundle,
|
|
@@ -243972,7 +244580,7 @@ function createBundle(root, target, input) {
|
|
|
243972
244580
|
};
|
|
243973
244581
|
}
|
|
243974
244582
|
function verifyBundleReadable(dir, bundlePath, _bundleRef, commit, expectedTree, env) {
|
|
243975
|
-
|
|
244583
|
+
fs27.rmSync(dir, { recursive: true, force: true });
|
|
243976
244584
|
try {
|
|
243977
244585
|
(0, import_node_child_process16.execFileSync)("git", ["clone", bundlePath, dir], { stdio: "ignore", ...env ? { env } : {} });
|
|
243978
244586
|
git2(dir, ["cat-file", "-e", `${commit}^{commit}`], env, "COMMIT_NOT_FOUND");
|
|
@@ -244014,8 +244622,8 @@ function ensureSourceRepo(work, repo, commit, env) {
|
|
|
244014
244622
|
}
|
|
244015
244623
|
}
|
|
244016
244624
|
function gitInitBare(dir, env) {
|
|
244017
|
-
if (
|
|
244018
|
-
|
|
244625
|
+
if (fs27.existsSync(path24.join(dir, "objects"))) return;
|
|
244626
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
244019
244627
|
(0, import_node_child_process16.execFileSync)("git", ["init", "--bare", dir], { stdio: "ignore", ...env ? { env } : {} });
|
|
244020
244628
|
}
|
|
244021
244629
|
function git2(cwd, args, env, fallback, timeout) {
|
|
@@ -244044,14 +244652,14 @@ function classifyGitError(fallback, err, where) {
|
|
|
244044
244652
|
function oneLine(msg) {
|
|
244045
244653
|
return msg.split("\n").map((s2) => s2.trim()).filter(Boolean).slice(0, 3).join(" ");
|
|
244046
244654
|
}
|
|
244047
|
-
var import_node_child_process16, import_node_crypto62,
|
|
244655
|
+
var import_node_child_process16, import_node_crypto62, fs27, os8, path24, GitReadonlyBundleError, HEX40, FETCH_TIMEOUT_MS2;
|
|
244048
244656
|
var init_readonly_bundle = __esm({
|
|
244049
244657
|
"../server/src/git/readonly-bundle.ts"() {
|
|
244050
244658
|
"use strict";
|
|
244051
244659
|
import_node_child_process16 = require("node:child_process");
|
|
244052
244660
|
import_node_crypto62 = require("node:crypto");
|
|
244053
|
-
|
|
244054
|
-
|
|
244661
|
+
fs27 = __toESM(require("node:fs"), 1);
|
|
244662
|
+
os8 = __toESM(require("node:os"), 1);
|
|
244055
244663
|
path24 = __toESM(require("node:path"), 1);
|
|
244056
244664
|
init_remote_util();
|
|
244057
244665
|
GitReadonlyBundleError = class extends Error {
|
|
@@ -246776,6 +247384,19 @@ function createChatSessionsDomain(opts) {
|
|
|
246776
247384
|
const binding = await bindingFor(companyId, aiActorId).catch(() => null);
|
|
246777
247385
|
return binding?.nodeId ?? null;
|
|
246778
247386
|
}
|
|
247387
|
+
async function agentDefaultRuntime(companyId, aiActorId) {
|
|
247388
|
+
const binding = await bindingFor(companyId, aiActorId).catch(() => null);
|
|
247389
|
+
let model = null;
|
|
247390
|
+
try {
|
|
247391
|
+
model = opts.resolveActorModel ? await opts.resolveActorModel(companyId, aiActorId) : (await registry2.latestConfig(aiActorId))?.model ?? null;
|
|
247392
|
+
} catch {
|
|
247393
|
+
model = null;
|
|
247394
|
+
}
|
|
247395
|
+
return {
|
|
247396
|
+
binding: binding ? { nodeId: binding.nodeId, runtimeKind: binding.runtimeKind } : null,
|
|
247397
|
+
model: normalizeModel(model)
|
|
247398
|
+
};
|
|
247399
|
+
}
|
|
246779
247400
|
function normalizeModel(raw) {
|
|
246780
247401
|
return typeof raw === "string" && raw.trim() ? raw.trim() : null;
|
|
246781
247402
|
}
|
|
@@ -246943,7 +247564,16 @@ function createChatSessionsDomain(opts) {
|
|
|
246943
247564
|
if (isDeletedActor(aiActor)) {
|
|
246944
247565
|
throw new ApiError(409, ACTOR_DELETED_ERROR_CODE, ACTOR_DELETED_CHAT_MESSAGE);
|
|
246945
247566
|
}
|
|
246946
|
-
const
|
|
247567
|
+
const agentDefault = await agentDefaultRuntime(req.auth.companyId, body2.aiActorId);
|
|
247568
|
+
const initial = chatSessionInitialRuntime({
|
|
247569
|
+
binding: agentDefault.binding,
|
|
247570
|
+
agentModel: agentDefault.model,
|
|
247571
|
+
requested: {
|
|
247572
|
+
override: normalizeOverride(body2.overrideNodeId) && normalizeOverride(body2.overrideRuntimeKind) ? { nodeId: normalizeOverride(body2.overrideNodeId), runtimeKind: normalizeOverride(body2.overrideRuntimeKind) } : null,
|
|
247573
|
+
...Object.prototype.hasOwnProperty.call(body2, "model") ? { model: normalizeModel(body2.model) } : {}
|
|
247574
|
+
}
|
|
247575
|
+
});
|
|
247576
|
+
const runtimeId = agentDefault.binding?.nodeId ?? "unknown";
|
|
246947
247577
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
246948
247578
|
const session = {
|
|
246949
247579
|
id: (0, import_node_crypto65.randomUUID)(),
|
|
@@ -246960,12 +247590,12 @@ function createChatSessionsDomain(opts) {
|
|
|
246960
247590
|
// 两个入口页面行为一致。区别于 linkWorkOrder(出处关联,建单脑暴也有、不构成绑定)。
|
|
246961
247591
|
workspace: sessionWorkspaceToStore(body2.workspace),
|
|
246962
247592
|
projectId: sessionProjectIdToStore(body2.projectId),
|
|
246963
|
-
|
|
246964
|
-
|
|
246965
|
-
|
|
246966
|
-
|
|
246967
|
-
overrideNodeId:
|
|
246968
|
-
overrideRuntimeKind:
|
|
247593
|
+
/* 三列一起由 `chatSessionInitialRuntime` 给(ADR 0613):用户在欢迎态挑过就用他挑的,
|
|
247594
|
+
没挑就抄员工此刻的默认运行配置。**员工没绑定 = 三列留空**,逐字回到 ADR 0604 的旧语义
|
|
247595
|
+
(跟随员工 binding),绑上之后那条路照旧管用。 */
|
|
247596
|
+
model: initial.model,
|
|
247597
|
+
overrideNodeId: initial.overrideNodeId,
|
|
247598
|
+
overrideRuntimeKind: initial.overrideRuntimeKind,
|
|
246969
247599
|
// ADR-0058:分析会话指向被分析 run;非空即"这是分析会话"(不进主聊天列表、进 trace 分析视图)。
|
|
246970
247600
|
analyzedRunId: body2.analyzedRunId ?? null
|
|
246971
247601
|
};
|
|
@@ -247065,6 +247695,19 @@ function createChatSessionsDomain(opts) {
|
|
|
247065
247695
|
});
|
|
247066
247696
|
return { status: 200, body: await store2.getSession(req.params.id) };
|
|
247067
247697
|
});
|
|
247698
|
+
router.post("/api/chat-sessions/:id/runtime/reset-to-agent-default", async (req) => {
|
|
247699
|
+
const store2 = await storeFor(req);
|
|
247700
|
+
const session = await store2.getSession(req.params.id);
|
|
247701
|
+
if (!session || session.humanActorId !== req.auth.actor) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
247702
|
+
const agentDefault = await agentDefaultRuntime(req.auth.companyId, session.aiActorId);
|
|
247703
|
+
const initial = chatSessionInitialRuntime({ binding: agentDefault.binding, agentModel: agentDefault.model });
|
|
247704
|
+
await store2.updateSession(req.params.id, {
|
|
247705
|
+
overrideNodeId: initial.overrideNodeId,
|
|
247706
|
+
overrideRuntimeKind: initial.overrideRuntimeKind,
|
|
247707
|
+
model: initial.model
|
|
247708
|
+
});
|
|
247709
|
+
return { status: 200, body: await store2.getSession(req.params.id) };
|
|
247710
|
+
});
|
|
247068
247711
|
router.delete("/api/chat-sessions/:id", async (req) => {
|
|
247069
247712
|
const store2 = await storeFor(req);
|
|
247070
247713
|
const session = await store2.getSession(req.params.id);
|
|
@@ -247226,6 +247869,14 @@ function createChatSessionsDomain(opts) {
|
|
|
247226
247869
|
snapshotEntries.splice(at + 1, 0, entry);
|
|
247227
247870
|
}
|
|
247228
247871
|
}
|
|
247872
|
+
const outputCards = await sessionOutputCards(snapshotEntries, store2, chatSessionId).catch((e) => {
|
|
247873
|
+
console.warn(`[chat] \u4EA7\u51FA\u5361\u73B0\u62FC\u5931\u8D25\uFF08session=${chatSessionId}\uFF09\uFF0C\u8FD9\u6B21\u5FEB\u7167\u4E0D\u5E26\u5361: ${String(e)}`);
|
|
247874
|
+
return [];
|
|
247875
|
+
});
|
|
247876
|
+
for (const { after, entry } of outputCards) {
|
|
247877
|
+
const at = snapshotEntries.findIndex((e) => e.itemId === after);
|
|
247878
|
+
snapshotEntries.splice(at + 1, 0, entry);
|
|
247879
|
+
}
|
|
247229
247880
|
const oldestOrd = snapshotEntries.find((e) => e.ord !== null)?.ord ?? null;
|
|
247230
247881
|
const body2 = {
|
|
247231
247882
|
chatSessionId,
|
|
@@ -247343,6 +247994,9 @@ function createChatSessionsDomain(opts) {
|
|
|
247343
247994
|
...expert?.avatar ? { expertAvatar: expert.avatar } : {},
|
|
247344
247995
|
state: record9.state,
|
|
247345
247996
|
...record9.failureKind ? { failureKind: record9.failureKind } : {},
|
|
247997
|
+
/* 给人看的那一档由服务端算(Bug 0221):委派卡、徽章、子会话面板三处渲染同一个值。 */
|
|
247998
|
+
ending: delegationEndingOfRecord(record9, delegationArtifactsView(record9)),
|
|
247999
|
+
settledSeq: record9.settledSeq,
|
|
247346
248000
|
...record9.label ? { label: record9.label } : {},
|
|
247347
248001
|
...record9.taskDigest ? { taskDigest: record9.taskDigest } : {},
|
|
247348
248002
|
parentMessageId: record9.parentMessageId,
|
|
@@ -247748,6 +248402,44 @@ function createChatSessionsDomain(opts) {
|
|
|
247748
248402
|
});
|
|
247749
248403
|
};
|
|
247750
248404
|
}
|
|
248405
|
+
async function sessionOutputCards(entries, store, chatSessionId) {
|
|
248406
|
+
const lastEntryOf = /* @__PURE__ */ new Map();
|
|
248407
|
+
for (const e of entries) {
|
|
248408
|
+
if (e.role === "assistant" && e.messageId) lastEntryOf.set(e.messageId, e);
|
|
248409
|
+
}
|
|
248410
|
+
if (lastEntryOf.size === 0) return [];
|
|
248411
|
+
const ids2 = [...lastEntryOf.keys()];
|
|
248412
|
+
const rows = store.listMessageOutputParts ? await store.listMessageOutputParts(chatSessionId, ids2) : (await store.listMessages(chatSessionId)).filter((m2) => m2.role === "assistant" && lastEntryOf.has(m2.id)).map((m2) => ({ messageId: m2.id, outputs: Array.isArray(m2.parts) ? m2.parts.filter((p2) => p2?.type === "outputs") : [] }));
|
|
248413
|
+
const out = [];
|
|
248414
|
+
for (const { messageId, outputs } of rows) {
|
|
248415
|
+
const anchor = lastEntryOf.get(messageId);
|
|
248416
|
+
const files = sessionOutputFilesOfParts(outputs);
|
|
248417
|
+
if (!anchor || files.length === 0) continue;
|
|
248418
|
+
const anchorPayload = anchor.payload && typeof anchor.payload === "object" && !Array.isArray(anchor.payload) ? anchor.payload : {};
|
|
248419
|
+
out.push({
|
|
248420
|
+
after: anchor.itemId,
|
|
248421
|
+
entry: {
|
|
248422
|
+
itemId: sessionOutputsItemId(messageId),
|
|
248423
|
+
turnId: anchor.turnId,
|
|
248424
|
+
itemType: "control",
|
|
248425
|
+
role: "assistant",
|
|
248426
|
+
status: "completed",
|
|
248427
|
+
itemVersion: anchor.itemVersion,
|
|
248428
|
+
seq: anchor.seq,
|
|
248429
|
+
ord: anchor.ord,
|
|
248430
|
+
messageId,
|
|
248431
|
+
updatedAt: anchor.updatedAt,
|
|
248432
|
+
payload: {
|
|
248433
|
+
code: SESSION_OUTPUTS_ITEM_CODE,
|
|
248434
|
+
files: files.map((f2) => ({ path: f2.path, name: f2.name })),
|
|
248435
|
+
...anchorPayload.createdAt !== void 0 ? { createdAt: anchorPayload.createdAt } : {},
|
|
248436
|
+
...anchorPayload.completedAt !== void 0 ? { completedAt: anchorPayload.completedAt } : {}
|
|
248437
|
+
}
|
|
248438
|
+
}
|
|
248439
|
+
});
|
|
248440
|
+
}
|
|
248441
|
+
return out;
|
|
248442
|
+
}
|
|
247751
248443
|
async function submissionCardProjection(entries, deps) {
|
|
247752
248444
|
const out = { add: [], resolved: [] };
|
|
247753
248445
|
const turns = deps.turns;
|
|
@@ -247906,6 +248598,7 @@ var init_chat_sessions2 = __esm({
|
|
|
247906
248598
|
init_company_data_store_router();
|
|
247907
248599
|
init_workorder_terminal();
|
|
247908
248600
|
init_session_workdir();
|
|
248601
|
+
init_session_runtime_target();
|
|
247909
248602
|
init_uncategorized_project();
|
|
247910
248603
|
init_chat_submission();
|
|
247911
248604
|
init_project_bundle();
|
|
@@ -251741,14 +252434,41 @@ function daemonMetaOf(hub, nodeId) {
|
|
|
251741
252434
|
if (typeof connectedDaemons !== "function") return void 0;
|
|
251742
252435
|
return connectedDaemons.call(hub).find((candidate) => candidate.daemonId === nodeId)?.meta;
|
|
251743
252436
|
}
|
|
251744
|
-
function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, confirm) {
|
|
252437
|
+
function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessionReadyWaitMs, confirm) {
|
|
251745
252438
|
const key2 = input.requireConsumptionReceipt ? input.clientMessageKey : void 0;
|
|
251746
|
-
if (!key2 || !confirm) return sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs);
|
|
251747
|
-
return sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs).then((result) => ({ ...result, receiptProbe: { nodeId, dispatchId, confirm: () => confirm(key2) } }));
|
|
252439
|
+
if (!key2 || !confirm) return sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessionReadyWaitMs);
|
|
252440
|
+
return sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessionReadyWaitMs).then((result) => ({ ...result, receiptProbe: { nodeId, dispatchId, confirm: () => confirm(key2) } }));
|
|
252441
|
+
}
|
|
252442
|
+
async function waitSessionReady(hub, dispatchId, entry, timeoutMs) {
|
|
252443
|
+
const deadline = Date.now() + timeoutMs;
|
|
252444
|
+
const ready = () => hub.hasSession?.(dispatchId) === true && entry.deliveryState === "started";
|
|
252445
|
+
while (!entry.exited && !ready()) {
|
|
252446
|
+
const left = deadline - Date.now();
|
|
252447
|
+
if (left <= 0) return;
|
|
252448
|
+
await new Promise((resolve11) => {
|
|
252449
|
+
let settled = false;
|
|
252450
|
+
const finish = () => {
|
|
252451
|
+
if (settled) return;
|
|
252452
|
+
settled = true;
|
|
252453
|
+
const i = entry.readyWaiters?.indexOf(finish) ?? -1;
|
|
252454
|
+
if (i >= 0) entry.readyWaiters.splice(i, 1);
|
|
252455
|
+
resolve11();
|
|
252456
|
+
};
|
|
252457
|
+
(entry.readyWaiters ??= []).push(finish);
|
|
252458
|
+
if (hub.hasSession?.(dispatchId) !== true) void hub.waitForSession(dispatchId, left).then(finish, finish);
|
|
252459
|
+
else {
|
|
252460
|
+
const t = setTimeout(finish, left);
|
|
252461
|
+
t.unref?.();
|
|
252462
|
+
}
|
|
252463
|
+
});
|
|
252464
|
+
}
|
|
251748
252465
|
}
|
|
251749
|
-
function sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
252466
|
+
function sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, sessionReadyWaitMs) {
|
|
251750
252467
|
const unknownIfInterrupting = input.interrupt ? { interrupt: "unknown" } : {};
|
|
251751
252468
|
if (entry.exited) return Promise.resolve({ accepted: false, reason: "session-closing", ...unknownIfInterrupting });
|
|
252469
|
+
if (input.requireConsumptionReceipt && sessionReadyWaitMs > 0 && (hub.hasSession?.(dispatchId) === false || entry.deliveryState !== "started") && typeof hub.waitForSession === "function" && daemonMetaOf(hub, nodeId)?.supportsInputReceiptQuery === true) {
|
|
252470
|
+
return waitSessionReady(hub, dispatchId, entry, sessionReadyWaitMs).then(() => sendAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs, 0));
|
|
252471
|
+
}
|
|
251752
252472
|
if (input.requireConsumptionReceipt && !hub.supportsInputConsumptionReceipts?.(dispatchId)) {
|
|
251753
252473
|
return Promise.resolve({ accepted: false, reason: "consumption-unsupported" });
|
|
251754
252474
|
}
|
|
@@ -251785,6 +252505,7 @@ var init_daemon_adapter = __esm({
|
|
|
251785
252505
|
this.nodeLostGraceMs = opts.nodeLostGraceMs ?? graceFromEnv(12e4);
|
|
251786
252506
|
this.ackTimeoutMs = opts.ackTimeoutMs ?? ackMsFromEnv(15e3);
|
|
251787
252507
|
this.appendTimeoutMs = opts.appendTimeoutMs ?? 1e4;
|
|
252508
|
+
this.sessionReadyWaitMs = opts.sessionReadyWaitMs ?? 1e4;
|
|
251788
252509
|
this.receiptQueryTimeoutMs = opts.receiptQueryTimeoutMs ?? 5e3;
|
|
251789
252510
|
this.log = opts.log ?? ((m2) => console.warn(m2));
|
|
251790
252511
|
this.health = opts.health;
|
|
@@ -251806,6 +252527,7 @@ var init_daemon_adapter = __esm({
|
|
|
251806
252527
|
ackTimeoutMs;
|
|
251807
252528
|
/** ADR-0093:append_input 回执时限;超时(老节点忽略帧)→ unsupported,上层降级 kill+resume。 */
|
|
251808
252529
|
appendTimeoutMs;
|
|
252530
|
+
sessionReadyWaitMs;
|
|
251809
252531
|
log;
|
|
251810
252532
|
health;
|
|
251811
252533
|
stashEnabled;
|
|
@@ -251958,6 +252680,7 @@ var init_daemon_adapter = __esm({
|
|
|
251958
252680
|
clearTimeout(w2.timer);
|
|
251959
252681
|
w2.resolve({ accepted: false, reason: w2.requireConsumptionReceipt ? "unconfirmed" : "session-closing" });
|
|
251960
252682
|
}
|
|
252683
|
+
for (const w2 of entry.readyWaiters?.splice(0) ?? []) w2();
|
|
251961
252684
|
if (info.reason === "server-unreachable") this.health?.recordUnreachable(entry.nodeId, info.reason);
|
|
251962
252685
|
else this.health?.recordReachable(entry.nodeId);
|
|
251963
252686
|
for (const cb of entry.exitCbs.splice(0)) cb(info);
|
|
@@ -252017,6 +252740,7 @@ var init_daemon_adapter = __esm({
|
|
|
252017
252740
|
entry.ackTimer = void 0;
|
|
252018
252741
|
}
|
|
252019
252742
|
if (entry) entry.deliveryState = state;
|
|
252743
|
+
if (entry && state === "started") for (const w2 of entry.readyWaiters?.splice(0) ?? []) w2();
|
|
252020
252744
|
}
|
|
252021
252745
|
onNodeDown(daemonId) {
|
|
252022
252746
|
if (this.reapTimers.has(daemonId)) return;
|
|
@@ -252225,6 +252949,7 @@ var init_daemon_adapter = __esm({
|
|
|
252225
252949
|
}
|
|
252226
252950
|
const hub = this.hub;
|
|
252227
252951
|
const appendTimeoutMs = this.appendTimeoutMs;
|
|
252952
|
+
const sessionReadyWaitMs = this.sessionReadyWaitMs;
|
|
252228
252953
|
const confirm = (key2) => this.confirmInputReceipt(nodeId, dispatchId, key2);
|
|
252229
252954
|
return {
|
|
252230
252955
|
id: dispatchId,
|
|
@@ -252258,7 +252983,7 @@ var init_daemon_adapter = __esm({
|
|
|
252258
252983
|
} : {},
|
|
252259
252984
|
// ADR-0093 对话追加:经 WS 把输入送到节点上的会话,等 append_result 回执;节点不认帧
|
|
252260
252985
|
// (老节点)则超时 unsupported,上层降级 kill+resume。
|
|
252261
|
-
appendInput: (input) => remoteAppendInput(hub, nodeId, dispatchId, entry, input, appendTimeoutMs, confirm)
|
|
252986
|
+
appendInput: (input) => remoteAppendInput(hub, nodeId, dispatchId, entry, input, appendTimeoutMs, sessionReadyWaitMs, confirm)
|
|
252262
252987
|
};
|
|
252263
252988
|
}
|
|
252264
252989
|
recover(dispatchId, nodeId, runtimeKind, actorId) {
|
|
@@ -252316,6 +253041,7 @@ var init_daemon_adapter = __esm({
|
|
|
252316
253041
|
};
|
|
252317
253042
|
const hub = this.hub;
|
|
252318
253043
|
const appendTimeoutMs = this.appendTimeoutMs;
|
|
253044
|
+
const sessionReadyWaitMs = this.sessionReadyWaitMs;
|
|
252319
253045
|
const confirm = (key2) => this.confirmInputReceipt(nodeId, dispatchId, key2);
|
|
252320
253046
|
return {
|
|
252321
253047
|
id: dispatchId,
|
|
@@ -252355,7 +253081,7 @@ var init_daemon_adapter = __esm({
|
|
|
252355
253081
|
}
|
|
252356
253082
|
} : {},
|
|
252357
253083
|
// ADR-0093 对话追加(重挂句柄同 spawn 句柄)。
|
|
252358
|
-
appendInput: (input) => remoteAppendInput(hub, nodeId, dispatchId, entry, input, appendTimeoutMs, confirm)
|
|
253084
|
+
appendInput: (input) => remoteAppendInput(hub, nodeId, dispatchId, entry, input, appendTimeoutMs, sessionReadyWaitMs, confirm)
|
|
252359
253085
|
};
|
|
252360
253086
|
}
|
|
252361
253087
|
};
|
|
@@ -252669,22 +253395,22 @@ var init_engine = __esm({
|
|
|
252669
253395
|
});
|
|
252670
253396
|
|
|
252671
253397
|
// ../server/src/mirror/fs-state.ts
|
|
252672
|
-
var
|
|
253398
|
+
var fs30, FsMirrorStateStore;
|
|
252673
253399
|
var init_fs_state = __esm({
|
|
252674
253400
|
"../server/src/mirror/fs-state.ts"() {
|
|
252675
253401
|
"use strict";
|
|
252676
|
-
|
|
253402
|
+
fs30 = __toESM(require("node:fs"), 1);
|
|
252677
253403
|
FsMirrorStateStore = class {
|
|
252678
253404
|
constructor(file) {
|
|
252679
253405
|
this.file = file;
|
|
252680
|
-
if (
|
|
252681
|
-
const obj2 = JSON.parse(
|
|
253406
|
+
if (fs30.existsSync(file)) {
|
|
253407
|
+
const obj2 = JSON.parse(fs30.readFileSync(file, "utf8"));
|
|
252682
253408
|
for (const [k2, v2] of Object.entries(obj2)) this.map.set(k2, v2);
|
|
252683
253409
|
}
|
|
252684
253410
|
}
|
|
252685
253411
|
map = /* @__PURE__ */ new Map();
|
|
252686
253412
|
flush() {
|
|
252687
|
-
|
|
253413
|
+
fs30.writeFileSync(this.file, JSON.stringify(Object.fromEntries(this.map), null, 2));
|
|
252688
253414
|
}
|
|
252689
253415
|
async get(artifactId) {
|
|
252690
253416
|
return this.map.get(artifactId) ?? null;
|
|
@@ -258781,7 +259507,7 @@ var init_postgres_trace = __esm({
|
|
|
258781
259507
|
*/
|
|
258782
259508
|
async listRunFailures(workOrderId) {
|
|
258783
259509
|
const r = await this.pool.query(
|
|
258784
|
-
`SELECT node_id,
|
|
259510
|
+
`SELECT node_id, error_message, COALESCE(started_at, created_at) AS at
|
|
258785
259511
|
FROM ${this.s}.agent_runs
|
|
258786
259512
|
WHERE work_order_id = $1 AND node_id IS NOT NULL
|
|
258787
259513
|
AND error_message IS NOT NULL AND error_message <> ''
|
|
@@ -258790,7 +259516,6 @@ var init_postgres_trace = __esm({
|
|
|
258790
259516
|
);
|
|
258791
259517
|
return r.rows.map((row) => ({
|
|
258792
259518
|
nodeId: row.node_id,
|
|
258793
|
-
actorId: row.actor_id ?? null,
|
|
258794
259519
|
startedAt: new Date(row.at).toISOString(),
|
|
258795
259520
|
message: row.error_message
|
|
258796
259521
|
}));
|
|
@@ -262064,6 +262789,34 @@ var init_postgres_chat_sessions = __esm({
|
|
|
262064
262789
|
attachments: row.attachments ?? []
|
|
262065
262790
|
}));
|
|
262066
262791
|
}
|
|
262792
|
+
/**
|
|
262793
|
+
* `/items` 快照出产出卡的窄读(Bug 0217):按主键批量命中,在库里把 `parts` 展开、只挑 `type='outputs'`
|
|
262794
|
+
* 那几段聚回一个数组送出来——整轮过程时间线不出库。只看 assistant 行(outputs 段只在助手轮收尾写)。
|
|
262795
|
+
*/
|
|
262796
|
+
async listMessageOutputParts(sessionId, messageIds) {
|
|
262797
|
+
if (messageIds.length === 0) return [];
|
|
262798
|
+
const r = await this.pool.query(
|
|
262799
|
+
`SELECT m.id, o.outputs
|
|
262800
|
+
FROM ${this.s}.chat_messages m
|
|
262801
|
+
JOIN ${this.s}.chat_sessions s ON s.id = m.session_id
|
|
262802
|
+
CROSS JOIN LATERAL (
|
|
262803
|
+
SELECT jsonb_agg(p ORDER BY i) AS outputs
|
|
262804
|
+
FROM jsonb_array_elements(CASE WHEN jsonb_typeof(m.parts) = 'array' THEN m.parts ELSE '[]'::jsonb END)
|
|
262805
|
+
WITH ORDINALITY AS e(p, i)
|
|
262806
|
+
WHERE p->>'type' = 'outputs'
|
|
262807
|
+
) o
|
|
262808
|
+
WHERE m.id = ANY($1::text[])
|
|
262809
|
+
AND m.session_id = $2
|
|
262810
|
+
AND s.company_id = $3
|
|
262811
|
+
AND m.role = 'assistant'
|
|
262812
|
+
AND o.outputs IS NOT NULL`,
|
|
262813
|
+
[[...messageIds], sessionId, this.companyId]
|
|
262814
|
+
);
|
|
262815
|
+
return r.rows.map((row) => ({
|
|
262816
|
+
messageId: row.id,
|
|
262817
|
+
outputs: Array.isArray(row.outputs) ? row.outputs : []
|
|
262818
|
+
}));
|
|
262819
|
+
}
|
|
262067
262820
|
/**
|
|
262068
262821
|
* 末尾 N 轮视窗(详情读侧默认):先定位「从尾部数第 N 条 user 消息」的 seq 作为窗口起点,再取
|
|
262069
262822
|
* seq >= 起点的全部消息。语义与内存版 windowMessagesByTurns 一致,但把裁剪下推到 SQL——长会话
|
|
@@ -263501,6 +264254,68 @@ var init_chat_items_ord_backfill = __esm({
|
|
|
263501
264254
|
}
|
|
263502
264255
|
});
|
|
263503
264256
|
|
|
264257
|
+
// ../storage/src/chat-session-runtime-pin-backfill.ts
|
|
264258
|
+
async function hasChatSessions(pool, schema) {
|
|
264259
|
+
const r = await pool.query(`SELECT to_regclass($1) IS NOT NULL AS ok`, [`${schema}.chat_sessions`]);
|
|
264260
|
+
return r.rows[0]?.ok === true;
|
|
264261
|
+
}
|
|
264262
|
+
async function pinChatSessionsToAgentDefault(pool, schema, opts) {
|
|
264263
|
+
const s2 = quoteIdent2(schema);
|
|
264264
|
+
const dryRun = opts.dryRun === true;
|
|
264265
|
+
const base = {
|
|
264266
|
+
schema,
|
|
264267
|
+
companyId: opts.companyId,
|
|
264268
|
+
scanned: 0,
|
|
264269
|
+
pinned: 0,
|
|
264270
|
+
leftUnbound: 0,
|
|
264271
|
+
unresolved: 0,
|
|
264272
|
+
dryRun
|
|
264273
|
+
};
|
|
264274
|
+
if (!await hasChatSessions(pool, schema)) return base;
|
|
264275
|
+
const pending = await pool.query(
|
|
264276
|
+
`SELECT ai_actor_id, count(*)::int AS n
|
|
264277
|
+
FROM ${s2}.chat_sessions
|
|
264278
|
+
WHERE company_id = $1
|
|
264279
|
+
AND (override_node_id IS NULL OR override_runtime_kind IS NULL)
|
|
264280
|
+
GROUP BY ai_actor_id`,
|
|
264281
|
+
[opts.companyId]
|
|
264282
|
+
);
|
|
264283
|
+
for (const row of pending.rows) {
|
|
264284
|
+
base.scanned += row.n;
|
|
264285
|
+
let binding;
|
|
264286
|
+
try {
|
|
264287
|
+
binding = await opts.resolveBinding(row.ai_actor_id);
|
|
264288
|
+
} catch {
|
|
264289
|
+
base.unresolved += row.n;
|
|
264290
|
+
continue;
|
|
264291
|
+
}
|
|
264292
|
+
if (!binding?.nodeId || !binding?.runtimeKind) {
|
|
264293
|
+
base.leftUnbound += row.n;
|
|
264294
|
+
continue;
|
|
264295
|
+
}
|
|
264296
|
+
if (dryRun) {
|
|
264297
|
+
base.pinned += row.n;
|
|
264298
|
+
continue;
|
|
264299
|
+
}
|
|
264300
|
+
const upd = await pool.query(
|
|
264301
|
+
`UPDATE ${s2}.chat_sessions
|
|
264302
|
+
SET override_node_id = $3, override_runtime_kind = $4
|
|
264303
|
+
WHERE company_id = $1
|
|
264304
|
+
AND ai_actor_id = $2
|
|
264305
|
+
AND (override_node_id IS NULL OR override_runtime_kind IS NULL)`,
|
|
264306
|
+
[opts.companyId, row.ai_actor_id, binding.nodeId, binding.runtimeKind]
|
|
264307
|
+
);
|
|
264308
|
+
base.pinned += upd.rowCount ?? 0;
|
|
264309
|
+
}
|
|
264310
|
+
return base;
|
|
264311
|
+
}
|
|
264312
|
+
var init_chat_session_runtime_pin_backfill = __esm({
|
|
264313
|
+
"../storage/src/chat-session-runtime-pin-backfill.ts"() {
|
|
264314
|
+
"use strict";
|
|
264315
|
+
init_pg_ident();
|
|
264316
|
+
}
|
|
264317
|
+
});
|
|
264318
|
+
|
|
263504
264319
|
// ../storage/src/postgres-delegations.ts
|
|
263505
264320
|
function toRecord2(row) {
|
|
263506
264321
|
return {
|
|
@@ -267869,7 +268684,7 @@ var init_cutover_aware_trace = __esm({
|
|
|
267869
268684
|
const s2 = await this.pick();
|
|
267870
268685
|
return typeof s2.runtimeRunActivity === "function" ? s2.runtimeRunActivity(runtimeInstanceId) : null;
|
|
267871
268686
|
}
|
|
267872
|
-
/**
|
|
268687
|
+
/** 协调运行(协调者卡的轨迹入口):落点 store 没实现就当没有这份数据,卡照出、只是没图标,不报错。 */
|
|
267873
268688
|
async listCoordinatorRuns(workOrderId) {
|
|
267874
268689
|
const store = await this.pick();
|
|
267875
268690
|
return await store.listCoordinatorRuns?.(workOrderId) ?? [];
|
|
@@ -268196,7 +269011,7 @@ var init_cutover_aware_trace = __esm({
|
|
|
268196
269011
|
/**
|
|
268197
269012
|
* 协调运行按工单扇出(任务动态协调者卡)。与 `FanOutDispatchLedger.listByWorkorder` 同理:
|
|
268198
269013
|
* **一张工单只属于一家公司**,所以逐家查出来的并集恰好就是那一家的行;漏扇会让非默认公司的
|
|
268199
|
-
*
|
|
269014
|
+
* 协调者卡全都点不进轨迹。某家查不动只记一笔,不让整块读失败。
|
|
268200
269015
|
*/
|
|
268201
269016
|
async listCoordinatorRuns(workOrderId) {
|
|
268202
269017
|
const out = [];
|
|
@@ -271148,7 +271963,8 @@ async function backfillUsageLedger(ledger, opts) {
|
|
|
271148
271963
|
manifestId: opts.dryRun ? null : opts.manifestId,
|
|
271149
271964
|
usagePoints: emptyStep(),
|
|
271150
271965
|
runtimeStartedAt: emptyStep(),
|
|
271151
|
-
chat: { ...emptyStep(), notFound: 0, ambiguous: 0, turnFilled: 0 }
|
|
271966
|
+
chat: { ...emptyStep(), notFound: 0, ambiguous: 0, turnFilled: 0 },
|
|
271967
|
+
claudeResume: null
|
|
271152
271968
|
};
|
|
271153
271969
|
const sample = (step, id) => {
|
|
271154
271970
|
if (step.samples.length < sampleSize) step.samples.push(id);
|
|
@@ -271286,8 +272102,134 @@ async function backfillUsageLedger(ledger, opts) {
|
|
|
271286
272102
|
}
|
|
271287
272103
|
});
|
|
271288
272104
|
}
|
|
272105
|
+
if (opts.claudeResumeBefore) {
|
|
272106
|
+
report.claudeResume = await fixClaudeResumeUsage(ledger.pool, s2, opts.claudeResumeBefore, {
|
|
272107
|
+
dryRun: opts.dryRun,
|
|
272108
|
+
manifestId: opts.manifestId,
|
|
272109
|
+
batch,
|
|
272110
|
+
sample: (step, id) => sample(step, id),
|
|
272111
|
+
now
|
|
272112
|
+
});
|
|
272113
|
+
}
|
|
271289
272114
|
return report;
|
|
271290
272115
|
}
|
|
272116
|
+
function claudeResumeNetUsage(raw) {
|
|
272117
|
+
const out = [];
|
|
272118
|
+
let prev = null;
|
|
272119
|
+
for (const u of raw) {
|
|
272120
|
+
const cost = reportedCost(u["costUsdMicros"]);
|
|
272121
|
+
if (cost === null) {
|
|
272122
|
+
out.push(u);
|
|
272123
|
+
continue;
|
|
272124
|
+
}
|
|
272125
|
+
const prevCost = prev ? reportedCost(prev["costUsdMicros"]) : null;
|
|
272126
|
+
const cumulative = prev !== null && prevCost !== null && cost >= prevCost && BUCKETS.every(([k2]) => usageBucket(u[k2]) >= usageBucket(prev[k2]));
|
|
272127
|
+
if (!cumulative) {
|
|
272128
|
+
out.push(u);
|
|
272129
|
+
prev = u;
|
|
272130
|
+
continue;
|
|
272131
|
+
}
|
|
272132
|
+
const input = usageBucket(u["inputTokens"]) - usageBucket(prev["inputTokens"]);
|
|
272133
|
+
const output = usageBucket(u["outputTokens"]) - usageBucket(prev["outputTokens"]);
|
|
272134
|
+
out.push({
|
|
272135
|
+
...u,
|
|
272136
|
+
inputTokens: input,
|
|
272137
|
+
outputTokens: output,
|
|
272138
|
+
totalTokens: input + output,
|
|
272139
|
+
cacheReadTokens: usageBucket(u["cacheReadTokens"]) - usageBucket(prev["cacheReadTokens"]),
|
|
272140
|
+
cacheCreationTokens: usageBucket(u["cacheCreationTokens"]) - usageBucket(prev["cacheCreationTokens"]),
|
|
272141
|
+
costUsdMicros: cost - prevCost
|
|
272142
|
+
});
|
|
272143
|
+
prev = u;
|
|
272144
|
+
}
|
|
272145
|
+
return out;
|
|
272146
|
+
}
|
|
272147
|
+
async function fixClaudeResumeUsage(pool, s2, before, o) {
|
|
272148
|
+
const report = { ...emptyStep(), sessions: 0, costBefore: 0, costAfter: 0 };
|
|
272149
|
+
const audited = /* @__PURE__ */ new Map();
|
|
272150
|
+
const auditRows = await pool.query(
|
|
272151
|
+
`SELECT run_id, manifest_id, before, after FROM ${s2}.agent_run_usage_backfill_audit
|
|
272152
|
+
WHERE field = 'claude_resume_usage' ORDER BY id`
|
|
272153
|
+
);
|
|
272154
|
+
for (const a of auditRows.rows) {
|
|
272155
|
+
audited.set(a.run_id, { manifest: a.manifest_id, before: a.before, after: a.after });
|
|
272156
|
+
}
|
|
272157
|
+
const { rows } = await pool.query(
|
|
272158
|
+
`SELECT r.id, r.usage, COALESCE(r.runtime_session_id, r.metadata->>'runtimeSessionId') AS rt
|
|
272159
|
+
FROM ${s2}.agent_runs r
|
|
272160
|
+
WHERE r.runtime_kind = 'claude-code' AND ${ENDED_SQL} AND jsonb_typeof(r.usage) = 'object'
|
|
272161
|
+
AND COALESCE(r.runtime_session_id, r.metadata->>'runtimeSessionId') IS NOT NULL
|
|
272162
|
+
AND r.started_at < $1
|
|
272163
|
+
ORDER BY rt, r.started_at, r.id`,
|
|
272164
|
+
[before]
|
|
272165
|
+
);
|
|
272166
|
+
const chains = /* @__PURE__ */ new Map();
|
|
272167
|
+
for (const row of rows) {
|
|
272168
|
+
const current = row.usage;
|
|
272169
|
+
let raw = current;
|
|
272170
|
+
const last = audited.get(row.id);
|
|
272171
|
+
if (last && !last.manifest.endsWith(":undo")) {
|
|
272172
|
+
const after = last.after?.usage;
|
|
272173
|
+
const prior = last.before?.usage;
|
|
272174
|
+
if (after && prior && sameUsage(after, current)) raw = prior;
|
|
272175
|
+
}
|
|
272176
|
+
const rt = row.rt;
|
|
272177
|
+
const chain = chains.get(rt) ?? [];
|
|
272178
|
+
chains.set(rt, chain);
|
|
272179
|
+
chain.push({ id: row.id, current, raw });
|
|
272180
|
+
}
|
|
272181
|
+
report.sessions = chains.size;
|
|
272182
|
+
const plan = [];
|
|
272183
|
+
for (const chain of chains.values()) {
|
|
272184
|
+
const net = claudeResumeNetUsage(chain.map((r) => r.raw));
|
|
272185
|
+
chain.forEach((r, i) => {
|
|
272186
|
+
if (sameUsage(net[i], r.current)) return;
|
|
272187
|
+
plan.push({ id: r.id, current: r.current, next: net[i] });
|
|
272188
|
+
});
|
|
272189
|
+
}
|
|
272190
|
+
report.candidates = plan.length;
|
|
272191
|
+
for (const p2 of plan) {
|
|
272192
|
+
o.sample(report, p2.id);
|
|
272193
|
+
report.costBefore += reportedCost(p2.current["costUsdMicros"]) ?? 0;
|
|
272194
|
+
report.costAfter += reportedCost(p2.next["costUsdMicros"]) ?? 0;
|
|
272195
|
+
}
|
|
272196
|
+
if (o.dryRun) return report;
|
|
272197
|
+
for (let i = 0; i < plan.length; i += o.batch) {
|
|
272198
|
+
const slice = plan.slice(i, i + o.batch);
|
|
272199
|
+
await inTx(pool, async (c) => {
|
|
272200
|
+
const at = o.now();
|
|
272201
|
+
for (const p2 of slice) {
|
|
272202
|
+
const r = await c.query(
|
|
272203
|
+
`UPDATE ${s2}.agent_runs SET usage = $2::jsonb WHERE id = $1 AND usage = $3::jsonb RETURNING id`,
|
|
272204
|
+
[p2.id, JSON.stringify(p2.next), JSON.stringify(p2.current)]
|
|
272205
|
+
);
|
|
272206
|
+
if (!r.rowCount) continue;
|
|
272207
|
+
await setFinalPoint(c, s2, p2.id, p2.next);
|
|
272208
|
+
report.changed += 1;
|
|
272209
|
+
await audit(
|
|
272210
|
+
c,
|
|
272211
|
+
s2,
|
|
272212
|
+
o.manifestId,
|
|
272213
|
+
p2.id,
|
|
272214
|
+
"claude_resume_usage",
|
|
272215
|
+
{ usage: p2.current },
|
|
272216
|
+
{ usage: p2.next },
|
|
272217
|
+
at
|
|
272218
|
+
);
|
|
272219
|
+
}
|
|
272220
|
+
});
|
|
272221
|
+
}
|
|
272222
|
+
return report;
|
|
272223
|
+
}
|
|
272224
|
+
async function setFinalPoint(c, s2, runId, usage) {
|
|
272225
|
+
const f2 = fourOf(usage);
|
|
272226
|
+
await c.query(
|
|
272227
|
+
`UPDATE ${s2}.agent_run_usage_points
|
|
272228
|
+
SET input_tokens = $3, output_tokens = $4, cache_read_tokens = $5, cache_creation_tokens = $6, cost_usd_micros = $7
|
|
272229
|
+
WHERE run_id = $1 AND seq = $2`,
|
|
272230
|
+
[runId, USAGE_POINT_FINAL_SEQ, f2.inputTokens, f2.outputTokens, f2.cacheReadTokens, f2.cacheCreationTokens, reportedCost(usage["costUsdMicros"])]
|
|
272231
|
+
);
|
|
272232
|
+
}
|
|
271291
272233
|
function usageLedgerViolationCount(r) {
|
|
271292
272234
|
return Object.values(r.violations).reduce((n, ids2) => n + ids2.length, 0);
|
|
271293
272235
|
}
|
|
@@ -271381,6 +272323,17 @@ async function undoUsageLedgerBackfill(ledger, manifestId, opts = {}) {
|
|
|
271381
272323
|
} else if (before !== null) {
|
|
271382
272324
|
ok3 = await insertPoint(c, s2, runId, before);
|
|
271383
272325
|
}
|
|
272326
|
+
} else if (field === "claude_resume_usage") {
|
|
272327
|
+
const prior = before?.usage;
|
|
272328
|
+
const cur = after?.usage;
|
|
272329
|
+
if (prior && cur) {
|
|
272330
|
+
const r = await c.query(
|
|
272331
|
+
`UPDATE ${s2}.agent_runs SET usage = $2::jsonb WHERE id = $1 AND usage = $3::jsonb RETURNING id`,
|
|
272332
|
+
[runId, JSON.stringify(prior), JSON.stringify(cur)]
|
|
272333
|
+
);
|
|
272334
|
+
ok3 = (r.rowCount ?? 0) > 0;
|
|
272335
|
+
if (ok3) await setFinalPoint(c, s2, runId, prior);
|
|
272336
|
+
}
|
|
271384
272337
|
} else if (field === "runtime_started_at" || field === "chat_session_id" || field === "chat_turn_id") {
|
|
271385
272338
|
const r = await c.query(
|
|
271386
272339
|
`UPDATE ${s2}.agent_runs SET ${field} = $2 WHERE id = $1 AND ${field} IS NOT DISTINCT FROM $3`,
|
|
@@ -271429,7 +272382,7 @@ async function audit(c, s2, manifestId, runId, field, before, after, createdAt)
|
|
|
271429
272382
|
[manifestId, runId, field, before == null ? null : JSON.stringify(before), after == null ? null : JSON.stringify(after), createdAt]
|
|
271430
272383
|
);
|
|
271431
272384
|
}
|
|
271432
|
-
var import_node_crypto82, BUCKETS, ENDED_SQL, START_EVIDENCE_SQL, CHAT_RUN_SQL, emptyStep, ChatRunLookup;
|
|
272385
|
+
var import_node_crypto82, BUCKETS, ENDED_SQL, START_EVIDENCE_SQL, CHAT_RUN_SQL, emptyStep, fourOf, sameUsage, ChatRunLookup;
|
|
271433
272386
|
var init_usage_ledger_backfill = __esm({
|
|
271434
272387
|
"../storage/src/usage-ledger-backfill.ts"() {
|
|
271435
272388
|
"use strict";
|
|
@@ -271452,6 +272405,13 @@ var init_usage_ledger_backfill = __esm({
|
|
|
271452
272405
|
)`;
|
|
271453
272406
|
CHAT_RUN_SQL = `r.id LIKE 'chat-run:%'`;
|
|
271454
272407
|
emptyStep = () => ({ candidates: 0, changed: 0, samples: [] });
|
|
272408
|
+
fourOf = (u) => ({
|
|
272409
|
+
inputTokens: usageBucket(u["inputTokens"]),
|
|
272410
|
+
outputTokens: usageBucket(u["outputTokens"]),
|
|
272411
|
+
cacheReadTokens: usageBucket(u["cacheReadTokens"]),
|
|
272412
|
+
cacheCreationTokens: usageBucket(u["cacheCreationTokens"])
|
|
272413
|
+
});
|
|
272414
|
+
sameUsage = (a, b2) => BUCKETS.every(([k2]) => usageBucket(a[k2]) === usageBucket(b2[k2])) && reportedCost(a["costUsdMicros"]) === reportedCost(b2["costUsdMicros"]);
|
|
271455
272415
|
ChatRunLookup = class {
|
|
271456
272416
|
constructor(sources) {
|
|
271457
272417
|
this.sources = sources;
|
|
@@ -271603,6 +272563,7 @@ __export(src_exports, {
|
|
|
271603
272563
|
buildTrigger: () => buildTrigger,
|
|
271604
272564
|
buildWorkorderIndex: () => buildWorkorderIndex,
|
|
271605
272565
|
canonicalTypeDefHash: () => canonicalTypeDefHash,
|
|
272566
|
+
claudeResumeNetUsage: () => claudeResumeNetUsage,
|
|
271606
272567
|
companySchemaName: () => companySchemaName,
|
|
271607
272568
|
copyActorMemoriesIdempotent: () => copyActorMemoriesIdempotent,
|
|
271608
272569
|
copyActorsIdempotent: () => copyActorsIdempotent,
|
|
@@ -271640,6 +272601,7 @@ __export(src_exports, {
|
|
|
271640
272601
|
newUsageBackfillManifestId: () => newUsageBackfillManifestId,
|
|
271641
272602
|
openUsageLedgerForBackfill: () => openUsageLedgerForBackfill,
|
|
271642
272603
|
payloadChecksum: () => payloadChecksum,
|
|
272604
|
+
pinChatSessionsToAgentDefault: () => pinChatSessionsToAgentDefault,
|
|
271643
272605
|
planSessionOrd: () => planSessionOrd,
|
|
271644
272606
|
provisionCompanyDataPlaneSchema: () => provisionCompanyDataPlaneSchema,
|
|
271645
272607
|
provisionNewCompanyDataPlane: () => provisionNewCompanyDataPlane,
|
|
@@ -271685,6 +272647,7 @@ var init_src10 = __esm({
|
|
|
271685
272647
|
init_postgres_chat_turns();
|
|
271686
272648
|
init_postgres_chat_items();
|
|
271687
272649
|
init_chat_items_ord_backfill();
|
|
272650
|
+
init_chat_session_runtime_pin_backfill();
|
|
271688
272651
|
init_postgres_delegations();
|
|
271689
272652
|
init_postgres_nodes();
|
|
271690
272653
|
init_postgres_model_prices();
|
|
@@ -273013,11 +273976,13 @@ __export(src_exports2, {
|
|
|
273013
273976
|
chatBroadcastEnabledFromEnv: () => chatBroadcastEnabledFromEnv,
|
|
273014
273977
|
chatDelegationEnabledFromEnv: () => chatDelegationEnabledFromEnv,
|
|
273015
273978
|
chatDispatchScope: () => chatDispatchScope,
|
|
273979
|
+
chatExitModelFields: () => chatExitModelFields,
|
|
273016
273980
|
chatInterruptCauseOf: () => chatInterruptCauseOf,
|
|
273017
273981
|
chatInterruptItemId: () => chatInterruptItemId,
|
|
273018
273982
|
chatItemsDoubleWriteEnabled: () => chatItemsDoubleWriteEnabled,
|
|
273019
273983
|
chatNodeChanged: () => chatNodeChanged,
|
|
273020
273984
|
chatRunLedgerFields: () => chatRunLedgerFields,
|
|
273985
|
+
chatSessionInitialRuntime: () => chatSessionInitialRuntime,
|
|
273021
273986
|
childRoundMessageIds: () => childRoundMessageIds,
|
|
273022
273987
|
clampObservedAt: () => clampObservedAt,
|
|
273023
273988
|
classifyPage: () => classifyPage,
|
|
@@ -273677,7 +274642,23 @@ function parseUsageLedgerBackfillArgs(flags) {
|
|
|
273677
274642
|
if (modes.length !== 1) {
|
|
273678
274643
|
throw new UsageLedgerBackfillArgError("--dry-run / --execute / --verify / --undo \u5FC5\u987B\u4E14\u53EA\u80FD\u9009\u4E00\u4E2A");
|
|
273679
274644
|
}
|
|
273680
|
-
|
|
274645
|
+
const mode = modes[0];
|
|
274646
|
+
let claudeResumeBefore;
|
|
274647
|
+
if (flags.has("claude-resume-before")) {
|
|
274648
|
+
const raw = flags.get("claude-resume-before");
|
|
274649
|
+
if (raw === "" || raw === "true" || Number.isNaN(Date.parse(raw))) {
|
|
274650
|
+
throw new UsageLedgerBackfillArgError("--claude-resume-before \u9700\u8981 ISO \u65F6\u523B\uFF08\u5982 2026-09-23T00:00:00Z\uFF09\uFF1A\u4FEE\u597D\u7684\u8282\u70B9\u5305\u5728\u5168\u90E8\u8282\u70B9\u88C5\u4E0A\u7684\u65F6\u523B");
|
|
274651
|
+
}
|
|
274652
|
+
if (mode.kind !== "dry-run" && mode.kind !== "execute") {
|
|
274653
|
+
throw new UsageLedgerBackfillArgError("--claude-resume-before \u53EA\u80FD\u914D --dry-run \u6216 --execute\uFF08\u64A4\u9500\u7167\u5E38\u7528 --undo\uFF09");
|
|
274654
|
+
}
|
|
274655
|
+
claudeResumeBefore = new Date(raw).toISOString();
|
|
274656
|
+
}
|
|
274657
|
+
return {
|
|
274658
|
+
scope: company !== void 0 ? { companyId: company } : { all: true },
|
|
274659
|
+
mode,
|
|
274660
|
+
...claudeResumeBefore ? { claudeResumeBefore } : {}
|
|
274661
|
+
};
|
|
273681
274662
|
}
|
|
273682
274663
|
async function runUsageLedgerBackfill(flags, io) {
|
|
273683
274664
|
let args;
|
|
@@ -273719,7 +274700,11 @@ ${USAGE_LEDGER_BACKFILL_USAGE}`);
|
|
|
273719
274700
|
const dryRun = args.mode.kind === "dry-run";
|
|
273720
274701
|
const manifestId2 = dryRun ? void 0 : storage.newUsageBackfillManifestId();
|
|
273721
274702
|
for (const l of ledgers) {
|
|
273722
|
-
const r = await storage.backfillUsageLedger(l, {
|
|
274703
|
+
const r = await storage.backfillUsageLedger(l, {
|
|
274704
|
+
dryRun,
|
|
274705
|
+
...manifestId2 ? { manifestId: manifestId2 } : {},
|
|
274706
|
+
...args.claudeResumeBefore ? { claudeResumeBefore: args.claudeResumeBefore } : {}
|
|
274707
|
+
});
|
|
273723
274708
|
const n = (step) => dryRun ? `\u5F85\u6539 ${step.candidates}` : `\u5DF2\u6539 ${step.changed}/${step.candidates}`;
|
|
273724
274709
|
io.out(`\u2014 \u8D26\u672C ${r.label}\uFF08schema=${r.schema}\uFF09`);
|
|
273725
274710
|
io.out(` 1 \u7528\u91CF\u70B9(backfill)\uFF1A${n(r.usagePoints)}${samples(r.usagePoints.samples)}`);
|
|
@@ -273727,6 +274712,12 @@ ${USAGE_LEDGER_BACKFILL_USAGE}`);
|
|
|
273727
274712
|
io.out(
|
|
273728
274713
|
` 3 \u4F1A\u8BDD/\u8F6E\u6B21\uFF1A${n(r.chat)}\uFF08\u5176\u4E2D\u8865\u8F6E\u6B21 ${r.chat.turnFilled}\uFF1B\u67E5\u4E0D\u5230 ${r.chat.notFound}\u3001\u6B67\u4E49 ${r.chat.ambiguous}\uFF0C\u4FDD\u6301 NULL\uFF09` + samples(r.chat.samples)
|
|
273729
274714
|
);
|
|
274715
|
+
if (r.claudeResume) {
|
|
274716
|
+
const c = r.claudeResume;
|
|
274717
|
+
io.out(
|
|
274718
|
+
` 4 Claude \u7EED\u8DD1\u7D2F\u8BA1\u503C\u6263\u56DE\uFF08\u5F00\u8DD1\u65E9\u4E8E ${args.claudeResumeBefore}\uFF0C${c.sessions} \u6761\u4F1A\u8BDD\u7EBF\uFF09\uFF1A${n(c)}\uFF1B\u8FD9\u4E9B run \u7684\u8D39\u7528\u5408\u8BA1 $${(c.costBefore / 1e6).toFixed(2)} \u2192 $${(c.costAfter / 1e6).toFixed(2)}` + samples(c.samples)
|
|
274719
|
+
);
|
|
274720
|
+
}
|
|
273730
274721
|
}
|
|
273731
274722
|
if (dryRun) io.out("[usage-ledger-backfill] dry-run\uFF1A\u4E00\u884C\u672A\u5199\u3002\u4E0B\u4E00\u6B65 --execute\u3002");
|
|
273732
274723
|
else {
|
|
@@ -273774,7 +274765,7 @@ var USAGE_LEDGER_BACKFILL_USAGE, UsageLedgerBackfillArgError, MAX_LISTED;
|
|
|
273774
274765
|
var init_usage_ledger_backfill_command = __esm({
|
|
273775
274766
|
"../cli/src/usage-ledger-backfill-command.ts"() {
|
|
273776
274767
|
"use strict";
|
|
273777
|
-
USAGE_LEDGER_BACKFILL_USAGE = "\u7528\u6CD5\uFF1Aoasis usage-ledger-backfill (--company <id> | --all) (--dry-run | --execute | --verify | --undo <manifestId>)";
|
|
274768
|
+
USAGE_LEDGER_BACKFILL_USAGE = "\u7528\u6CD5\uFF1Aoasis usage-ledger-backfill (--company <id> | --all) (--dry-run | --execute | --verify | --undo <manifestId>) [--claude-resume-before <ISO \u65F6\u523B>]";
|
|
273778
274769
|
UsageLedgerBackfillArgError = class extends Error {
|
|
273779
274770
|
};
|
|
273780
274771
|
MAX_LISTED = 50;
|
|
@@ -273784,7 +274775,7 @@ var init_usage_ledger_backfill_command = __esm({
|
|
|
273784
274775
|
// src/index.ts
|
|
273785
274776
|
var fs48 = __toESM(require("node:fs"));
|
|
273786
274777
|
init_src();
|
|
273787
|
-
var
|
|
274778
|
+
var os15 = __toESM(require("node:os"));
|
|
273788
274779
|
var path43 = __toESM(require("node:path"));
|
|
273789
274780
|
var import_node_child_process24 = require("node:child_process");
|
|
273790
274781
|
var import_node_crypto93 = require("node:crypto");
|
|
@@ -273792,7 +274783,7 @@ var import_node_crypto93 = require("node:crypto");
|
|
|
273792
274783
|
// ../cli/src/cli.ts
|
|
273793
274784
|
init_src();
|
|
273794
274785
|
var fs42 = __toESM(require("node:fs"), 1);
|
|
273795
|
-
var
|
|
274786
|
+
var os13 = __toESM(require("node:os"), 1);
|
|
273796
274787
|
var path37 = __toESM(require("node:path"), 1);
|
|
273797
274788
|
var import_node_crypto91 = require("node:crypto");
|
|
273798
274789
|
|
|
@@ -273802,7 +274793,7 @@ init_chat_cancel_attribution();
|
|
|
273802
274793
|
init_src();
|
|
273803
274794
|
init_src11();
|
|
273804
274795
|
var fs34 = __toESM(require("node:fs"), 1);
|
|
273805
|
-
var
|
|
274796
|
+
var os9 = __toESM(require("node:os"), 1);
|
|
273806
274797
|
var path28 = __toESM(require("node:path"), 1);
|
|
273807
274798
|
var import_node_child_process17 = require("node:child_process");
|
|
273808
274799
|
var import_node_crypto87 = require("node:crypto");
|
|
@@ -275772,132 +276763,7 @@ init_src11();
|
|
|
275772
276763
|
init_src4();
|
|
275773
276764
|
|
|
275774
276765
|
// ../cli/src/chat-exit.ts
|
|
275775
|
-
|
|
275776
|
-
init_src();
|
|
275777
|
-
init_src7();
|
|
275778
|
-
init_chat_cancel_attribution();
|
|
275779
|
-
function transcriptTail(ref2) {
|
|
275780
|
-
try {
|
|
275781
|
-
const stat4 = fs31.statSync(ref2);
|
|
275782
|
-
const size = Math.min(stat4.size, 4e3);
|
|
275783
|
-
const buf = Buffer.alloc(size);
|
|
275784
|
-
const fd = fs31.openSync(ref2, "r");
|
|
275785
|
-
try {
|
|
275786
|
-
fs31.readSync(fd, buf, 0, size, Math.max(0, stat4.size - size));
|
|
275787
|
-
} finally {
|
|
275788
|
-
fs31.closeSync(fd);
|
|
275789
|
-
}
|
|
275790
|
-
return buf.toString("utf8").trim();
|
|
275791
|
-
} catch {
|
|
275792
|
-
return "";
|
|
275793
|
-
}
|
|
275794
|
-
}
|
|
275795
|
-
var SUMMARY_MAX_CHARS = 500;
|
|
275796
|
-
function clipLine(line2) {
|
|
275797
|
-
return line2.length > SUMMARY_MAX_CHARS ? `${line2.slice(0, SUMMARY_MAX_CHARS)}\u2026` : line2;
|
|
275798
|
-
}
|
|
275799
|
-
function providerMessage(line2) {
|
|
275800
|
-
const m2 = /['"]message['"]\s*:\s*(?:'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)")/.exec(line2);
|
|
275801
|
-
const text7 = (m2?.[1] ?? m2?.[2])?.trim();
|
|
275802
|
-
return text7 ? text7 : void 0;
|
|
275803
|
-
}
|
|
275804
|
-
var INTERNAL_PREFIX_RE = /^\[[a-z][a-z0-9_]*\]\s*/;
|
|
275805
|
-
var QUOTA_RE3 = /hit your (?:\w+ )?limit|usage limit|quota|insufficient[_ ](?:balance|credit|funds)|credit balance|billing|\b402\b|额度|余额/i;
|
|
275806
|
-
var RATE_LIMIT_RE = /rate.?limit|too many requests|\b429\b|\b529\b|overloaded|限流/i;
|
|
275807
|
-
var AUTH_RE2 = /\b401\b|\b403\b|unauthori[sz]ed|authenticat|oauth|invalid[_ -]?(?:api[_ -]?key|token|x-api-key)|api[_ -]?key[^\n]{0,40}\b(?:invalid|expired|revoked)|token[^\n]{0,30}\b(?:expired|invalid|revoked)|not logged in|\/login|credential|凭证|登录/i;
|
|
275808
|
-
var MODEL_RE = /\bmodel\b[^\n]{0,120}?\b(?:not found|not exist|does not exist|not available|not supported|unavailable|unknown)\b|\b(?:unknown|invalid|unsupported) model\b|model_not_found/i;
|
|
275809
|
-
var DISK_FULL_RE = /\bENOSPC\b|no space left on device|\bEDQUOT\b|disk quota exceeded|\[Errno 28\]|disk (?:is )?full|磁盘(?:空间)?(?:已满|不足)/i;
|
|
275810
|
-
var UNREACHABLE_RE2 = /不在线|socket 非 OPEN|帧未送达|失联/;
|
|
275811
|
-
function failureKind(reason, line2) {
|
|
275812
|
-
if (line2.startsWith(SESSION_STARTUP_FAILED_PREFIX)) return "startup-failed";
|
|
275813
|
-
switch (reason) {
|
|
275814
|
-
case "auth-error":
|
|
275815
|
-
return "auth";
|
|
275816
|
-
case "server-unreachable":
|
|
275817
|
-
return "node-unreachable";
|
|
275818
|
-
case "timeout":
|
|
275819
|
-
return "timeout";
|
|
275820
|
-
case "output-limit":
|
|
275821
|
-
return "output-limit";
|
|
275822
|
-
case "rate-limit":
|
|
275823
|
-
return QUOTA_RE3.test(line2) ? "quota" : "rate-limit";
|
|
275824
|
-
default:
|
|
275825
|
-
break;
|
|
275826
|
-
}
|
|
275827
|
-
if (!line2) return "unknown";
|
|
275828
|
-
if (DISK_FULL_RE.test(line2)) return "disk-full";
|
|
275829
|
-
if (QUOTA_RE3.test(line2)) return "quota";
|
|
275830
|
-
if (AUTH_RE2.test(line2)) return "auth";
|
|
275831
|
-
if (RATE_LIMIT_RE.test(line2)) return "rate-limit";
|
|
275832
|
-
if (MODEL_RE.test(line2)) return "model";
|
|
275833
|
-
if (UNREACHABLE_RE2.test(line2)) return "node-unreachable";
|
|
275834
|
-
return "unknown";
|
|
275835
|
-
}
|
|
275836
|
-
var chatRebindHint = (what) => `\u5728\u7EC4\u7EC7\u9875\u8FD9\u4F4D Agent \u7684\u300C\u6A21\u578B\u300D\u9875\u7B7E\u91CC${what}`;
|
|
275837
|
-
function resetTime(line2) {
|
|
275838
|
-
return extractResetHint(line2)?.replace(/^(?:resets?|try again at)\s+/i, "").trim() || void 0;
|
|
275839
|
-
}
|
|
275840
|
-
function failureSummary(kind, ctx) {
|
|
275841
|
-
switch (kind) {
|
|
275842
|
-
case "auth":
|
|
275843
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u7684\u767B\u5F55\u5DF2\u8FC7\u671F\u6216\u51ED\u8BC1\u65E0\u6548\uFF0C\u8C03\u7528\u4E0D\u4E86\u6A21\u578B\u3002\u8BF7\u8282\u70B9\u7BA1\u7406\u5458\u5728\u90A3\u53F0\u673A\u5668\u4E0A\u91CD\u65B0\u767B\u5F55\u8FD9\u4E2A\u8FD0\u884C\u65F6\uFF08\u6216\u66F4\u65B0 API Key\uFF09\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u53EF\u7528\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
275844
|
-
case "quota": {
|
|
275845
|
-
const at = resetTime(ctx.line);
|
|
275846
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u989D\u5EA6\u5DF2\u7528\u5B8C${at ? `\uFF0C\u9884\u8BA1 ${at} \u6062\u590D` : ""}\u3002\u8BF7\u7B49\u989D\u5EA6\u6062\u590D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u989D\u5EA6\u5145\u8DB3\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
275847
|
-
}
|
|
275848
|
-
case "rate-limit":
|
|
275849
|
-
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u670D\u52A1\u6682\u65F6\u9650\u6D41\u6216\u7E41\u5FD9\u3002\u8BF7\u7B49\u4E00\u4E24\u5206\u949F\u518D\u53D1\u4E00\u6B21\u3002";
|
|
275850
|
-
case "node-unreachable":
|
|
275851
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u8FD9\u4F4D Agent \u7684\u8282\u70B9\u79BB\u7EBF\u6216\u8FDE\u63A5\u4E2D\u65AD\u3002\u8BF7\u786E\u8BA4\u90A3\u53F0\u673A\u5668\u5F00\u7740\u3001\u8282\u70B9\u7A0B\u5E8F\u5728\u8FD0\u884C\u3001\u7F51\u7EDC\u6B63\u5E38\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u5728\u7EBF\u7684\u8FD0\u884C\u65F6")}\u3002`;
|
|
275852
|
-
case "model":
|
|
275853
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD9\u4E2A\u8FD0\u884C\u65F6\u7528\u4E0D\u4E86\u5F53\u524D\u914D\u7F6E\u7684\u6A21\u578B\u3002\u8BF7${chatRebindHint("\u6362\u4E00\u4E2A\u53EF\u7528\u7684\u6A21\u578B")}\u540E\u518D\u53D1\u4E00\u6B21\u3002`;
|
|
275854
|
-
case "timeout":
|
|
275855
|
-
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD9\u4E00\u8F6E\u8FD0\u884C\u8D85\u8FC7\u4E86\u65F6\u95F4\u4E0A\u9650\uFF0C\u5DF2\u88AB\u7EC8\u6B62\u3002\u53EF\u4EE5\u628A\u4EFB\u52A1\u62C6\u5C0F\u4E00\u4E9B\u518D\u53D1\u3002";
|
|
275856
|
-
case "startup-failed":
|
|
275857
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A${ctx.readable || SESSION_STARTUP_FAILED_PREFIX}\u3002\u8FD9\u4E00\u8F6E\u6CA1\u6709\u5F00\u59CB\u8FD0\u884C\uFF0C\u53EF\u4EE5\u76F4\u63A5\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u591A\u534A\u662F\u90A3\u53F0\u8282\u70B9\u8D1F\u8F7D\u8FC7\u9AD8\uFF0C\u8BF7\u7BA1\u7406\u5458\u7ED9\u5B83\u51CF\u8D1F\u6216${chatRebindHint("\u6362\u4E00\u4E2A\u8FD0\u884C\u65F6")}\u3002`;
|
|
275858
|
-
case "disk-full":
|
|
275859
|
-
return `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u8FD9\u4F4D Agent \u7684\u8282\u70B9\u78C1\u76D8\u7A7A\u95F4\u6EE1\u4E86\uFF0C\u8FD9\u4E00\u8F6E\u5199\u4E0D\u4E86\u6587\u4EF6\u3002\u8BF7\u8282\u70B9\u7BA1\u7406\u5458\u6E05\u7406\u90A3\u53F0\u673A\u5668\u7684\u78C1\u76D8\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u7740\u6025\u7684\u8BDD\u4E5F\u53EF\u4EE5${chatRebindHint("\u6362\u4E00\u4E2A\u8FD0\u884C\u65F6")}\u3002`;
|
|
275860
|
-
case "output-limit":
|
|
275861
|
-
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u6A21\u578B\u8F93\u51FA\u8D85\u51FA\u957F\u5EA6\u4E0A\u9650\uFF0C\u56DE\u590D\u88AB\u622A\u65AD\u4E86\u3002\u53EF\u4EE5\u8BA9\u5B83\u5206\u51E0\u6B21\u8F93\u51FA\uFF0C\u6216\u628A\u4EFB\u52A1\u62C6\u5C0F\u4E00\u4E9B\u518D\u53D1\u3002";
|
|
275862
|
-
case "unknown":
|
|
275863
|
-
if (ctx.line) {
|
|
275864
|
-
return "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u62A5\u9519\u4E86\uFF0C\u6682\u65F6\u6CA1\u8BA4\u51FA\u662F\u4EC0\u4E48\u539F\u56E0\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u70B9\u300C\u5C55\u5F00\u8BE6\u60C5\u300D\u628A\u539F\u59CB\u62A5\u9519\u53D1\u7ED9\u7BA1\u7406\u5458\u3002";
|
|
275865
|
-
}
|
|
275866
|
-
return ctx.hasDetail ? "\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u5F02\u5E38\u9000\u51FA\uFF0C\u6CA1\u6709\u7ED9\u51FA\u62A5\u9519\u539F\u56E0\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u70B9\u300C\u5C55\u5F00\u8BE6\u60C5\u300D\u628A\u539F\u59CB\u8BB0\u5F55\u53D1\u7ED9\u7BA1\u7406\u5458\u3002" : `\u5BF9\u8BDD\u5931\u8D25\uFF1A\u8FD0\u884C\u65F6\u5F02\u5E38\u9000\u51FA\uFF08\u9000\u51FA\u7801 ${ctx.code ?? "\u65E0"}\uFF09\uFF0C\u6CA1\u6709\u7559\u4E0B\u62A5\u9519\u4FE1\u606F\u3002\u53EF\u4EE5\u7A0D\u540E\u518D\u53D1\u4E00\u6B21\uFF1B\u53CD\u590D\u51FA\u73B0\u7684\u8BDD\uFF0C\u8BF7\u7BA1\u7406\u5458\u5230\u300C\u8FD0\u884C\u8F68\u8FF9\u300D\u91CC\u67E5\u8FD9\u4E00\u8F6E\u3002`;
|
|
275867
|
-
}
|
|
275868
|
-
}
|
|
275869
|
-
function buildChatExitError(info) {
|
|
275870
|
-
const genericLine = `runtime exited with code ${info.code ?? "null"}${info.reason ? ` (${info.reason})` : ""}`;
|
|
275871
|
-
let detail = "";
|
|
275872
|
-
if (info.reason !== "cancelled") {
|
|
275873
|
-
detail = info.errorMessage?.trim() ?? "";
|
|
275874
|
-
if (!detail && info.transcriptRef) detail = transcriptTail(info.transcriptRef);
|
|
275875
|
-
}
|
|
275876
|
-
let summary;
|
|
275877
|
-
let cancelledBy;
|
|
275878
|
-
if (info.reason === "cancelled") {
|
|
275879
|
-
cancelledBy = cancelCauseFromExitMessage(info.errorMessage);
|
|
275880
|
-
summary = chatCancelNote(cancelledBy);
|
|
275881
|
-
} else {
|
|
275882
|
-
const firstErrorLine = (info.errorMessage?.split("\n").map((line2) => line2.trim()).find(Boolean) ?? "").replace(INTERNAL_PREFIX_RE, "");
|
|
275883
|
-
const readable = firstErrorLine ? clipLine(providerMessage(firstErrorLine) ?? firstErrorLine) : "";
|
|
275884
|
-
summary = failureSummary(failureKind(info.reason, firstErrorLine), {
|
|
275885
|
-
readable,
|
|
275886
|
-
line: firstErrorLine,
|
|
275887
|
-
hasDetail: Boolean(detail),
|
|
275888
|
-
code: info.code
|
|
275889
|
-
});
|
|
275890
|
-
}
|
|
275891
|
-
const chatExit = {
|
|
275892
|
-
...info.reason ? { reason: info.reason } : {},
|
|
275893
|
-
summary,
|
|
275894
|
-
...cancelledBy ? { cancelledBy } : {},
|
|
275895
|
-
...detail ? { detail: `${genericLine}
|
|
275896
|
-
|
|
275897
|
-
${detail}`.slice(0, 4200) } : {}
|
|
275898
|
-
};
|
|
275899
|
-
return Object.assign(new Error(summary), { chatExit });
|
|
275900
|
-
}
|
|
276766
|
+
init_chat_exit();
|
|
275901
276767
|
|
|
275902
276768
|
// ../cli/src/chat-task-header.ts
|
|
275903
276769
|
init_src11();
|
|
@@ -276690,15 +277556,15 @@ function oasisWrapperScript() {
|
|
|
276690
277556
|
const main = path28.join(repoRoot, "packages/cli/src/main.ts");
|
|
276691
277557
|
const key2 = (0, import_node_crypto87.createHash)("sha256").update(repoRoot).digest("hex").slice(0, 12);
|
|
276692
277558
|
const uid = typeof process.getuid === "function" ? process.getuid() : "na";
|
|
276693
|
-
const stable = path28.join(
|
|
277559
|
+
const stable = path28.join(os9.tmpdir(), `oasis-cli-wrapper-${uid}-${key2}`);
|
|
276694
277560
|
let dir;
|
|
276695
277561
|
try {
|
|
276696
277562
|
fs34.mkdirSync(stable, { recursive: true, mode: 448 });
|
|
276697
277563
|
const st = fs34.lstatSync(stable);
|
|
276698
277564
|
const mine = st.isDirectory() && !st.isSymbolicLink() && (typeof process.getuid !== "function" || st.uid === process.getuid());
|
|
276699
|
-
dir = mine ? stable : fs34.mkdtempSync(path28.join(
|
|
277565
|
+
dir = mine ? stable : fs34.mkdtempSync(path28.join(os9.tmpdir(), "oasis-cli-"));
|
|
276700
277566
|
} catch {
|
|
276701
|
-
dir = fs34.mkdtempSync(path28.join(
|
|
277567
|
+
dir = fs34.mkdtempSync(path28.join(os9.tmpdir(), "oasis-cli-"));
|
|
276702
277568
|
}
|
|
276703
277569
|
const wrapper = path28.join(dir, "oasis");
|
|
276704
277570
|
fs34.writeFileSync(wrapper, `#!/usr/bin/env bash
|
|
@@ -276924,7 +277790,8 @@ async function startServe(opts) {
|
|
|
276924
277790
|
const reloadTimeoutPolicy = () => {
|
|
276925
277791
|
try {
|
|
276926
277792
|
activeTimeoutPolicy = loadPolicyFromFile(resolvePolicyFilePath());
|
|
276927
|
-
|
|
277793
|
+
syncChatWallClockCopy();
|
|
277794
|
+
console.log(`[serve] timeout-policy \u5DF2\u70ED\u8F7D\uFF08version=${activeTimeoutPolicy.version}\uFF0Cchat \u5899\u949F=${wallClockForKind("chat")}ms\uFF09`);
|
|
276928
277795
|
return { ok: true, version: activeTimeoutPolicy.version };
|
|
276929
277796
|
} catch (err) {
|
|
276930
277797
|
console.error(`[serve] timeout-policy \u70ED\u8F7D\u5931\u8D25\uFF0C\u4FDD\u7559\u65E7\u7B56\u7565\uFF1A${err.message}`);
|
|
@@ -276938,6 +277805,8 @@ async function startServe(opts) {
|
|
|
276938
277805
|
return (act.cadence.find((s2) => s2.reassignAfter) ?? act.cadence[act.cadence.length - 1]).atMs;
|
|
276939
277806
|
};
|
|
276940
277807
|
const wallClockForKind = (runtimeKind) => activeTimeoutPolicy.resolve({ executor: "agent", scenario: "wall-clock", runtimeKind }).wallClockMs ?? 120 * 6e4;
|
|
277808
|
+
const syncChatWallClockCopy = () => setChatWallClockMs(wallClockForKind("chat"));
|
|
277809
|
+
syncChatWallClockCopy();
|
|
276941
277810
|
const loadJson = (name) => {
|
|
276942
277811
|
const file = path28.join(opts.dir, name);
|
|
276943
277812
|
return fs34.existsSync(file) ? JSON.parse(fs34.readFileSync(file, "utf8")) : void 0;
|
|
@@ -277059,7 +277928,7 @@ async function startServe(opts) {
|
|
|
277059
277928
|
);
|
|
277060
277929
|
const issuer = createTokenIssuer({ secretFile: path28.join(opts.dir, "session-token-secret") });
|
|
277061
277930
|
const apiActivity = createApiActivityLedger();
|
|
277062
|
-
const operatorActor = `actor:human:${
|
|
277931
|
+
const operatorActor = `actor:human:${os9.userInfo().username}`;
|
|
277063
277932
|
const operatorToken = issuer.issue(operatorActor, { scopes: [OPERATOR_SCOPE] });
|
|
277064
277933
|
fs34.writeFileSync(path28.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
|
|
277065
277934
|
let nodeTokens = createNodeTokenStore(path28.join(opts.dir, "node-tokens.json"));
|
|
@@ -278897,6 +279766,37 @@ async function startServe(opts) {
|
|
|
278897
279766
|
return plan && plan.injectedHistoryCount > 0 ? plan.runtimeMessage : void 0;
|
|
278898
279767
|
};
|
|
278899
279768
|
const resolveCompanyBinding = createCompanyBindingResolver({ actors, defaultCompanyId });
|
|
279769
|
+
if (pgPool) {
|
|
279770
|
+
const pinPool = pgPool;
|
|
279771
|
+
void (async () => {
|
|
279772
|
+
try {
|
|
279773
|
+
const companies2 = await controlPlaneStore.listCompanies();
|
|
279774
|
+
const total = { scanned: 0, pinned: 0, leftUnbound: 0, unresolved: 0 };
|
|
279775
|
+
for (const c of companies2) {
|
|
279776
|
+
const rep = await pinChatSessionsToAgentDefault(pinPool, engineSchemaFor(c.id), {
|
|
279777
|
+
companyId: c.id,
|
|
279778
|
+
// 与派发、与委派回流、与 chat 工作区读口**同一个** resolver 实例——存量钉住的目标必须
|
|
279779
|
+
// 与「不钉时这一轮会派到哪」逐字相同,否则这条迁移本身就改了行为。
|
|
279780
|
+
resolveBinding: async (actorId) => {
|
|
279781
|
+
const b2 = await resolveCompanyBinding(c.id, actorId);
|
|
279782
|
+
return b2 ? { nodeId: b2.nodeId, runtimeKind: b2.runtimeKind } : null;
|
|
279783
|
+
}
|
|
279784
|
+
});
|
|
279785
|
+
total.scanned += rep.scanned;
|
|
279786
|
+
total.pinned += rep.pinned;
|
|
279787
|
+
total.leftUnbound += rep.leftUnbound;
|
|
279788
|
+
total.unresolved += rep.unresolved;
|
|
279789
|
+
}
|
|
279790
|
+
if (total.scanned > 0) {
|
|
279791
|
+
console.log(
|
|
279792
|
+
`[chat-runtime-pin] ADR 0613 \u5B58\u91CF\u4F1A\u8BDD\u9489\u76EE\u6807\uFF1A\u547D\u4E2D ${total.scanned} \u6761\u3001\u5199\u5165 ${total.pinned} \u6761\u3001\u5458\u5DE5\u672A\u7ED1\u5B9A\u7559\u7A7A ${total.leftUnbound} \u6761\u3001binding \u89E3\u6790\u5931\u8D25 ${total.unresolved} \u6761`
|
|
279793
|
+
);
|
|
279794
|
+
}
|
|
279795
|
+
} catch (err) {
|
|
279796
|
+
console.warn(`[chat-runtime-pin] \u5B58\u91CF\u4F1A\u8BDD\u9489\u76EE\u6807\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u542F\u52A8\uFF0C\u4E0B\u6B21\u542F\u52A8\u5E42\u7B49\u91CD\u8BD5\uFF09\uFF1A`, err);
|
|
279797
|
+
}
|
|
279798
|
+
})();
|
|
279799
|
+
}
|
|
278900
279800
|
const delegationWorkdirLocator = buildDelegationWorkdirLocator({
|
|
278901
279801
|
// ⭐ 与派发、与 chat-sessions 域**同一个 resolver 实例**(评审 blocker ① 五修):
|
|
278902
279802
|
// 生产 `resolveCompanyBinding` 在上文构造一次,喂给这里、`dispatchChatImpl`、
|
|
@@ -279328,7 +280228,7 @@ async function startServe(opts) {
|
|
|
279328
280228
|
// 派发台账:动态卡的 runId 与「执行轨迹」抽屉靠它把 work/review 硬关联到 agent_runs.id。
|
|
279329
280229
|
// 与上面 createServer 的 `dispatchesOfWorkorder`(timeline 用)是同一个闭包,别分叉。
|
|
279330
280230
|
dispatchesOfWorkorder: (wid) => fanOutLedger.listByWorkorder(wid),
|
|
279331
|
-
// 任务动态**协调者卡**(F2
|
|
280231
|
+
// 任务动态**协调者卡**(F2)的轨迹入口:协调者不走 dispatcher,台账里没有它,只能从 agent_runs 取。
|
|
279332
280232
|
// 扇出理由同 `dispatchesOfWorkorder`:这个回调拿不到公司,而一张工单只属于一家。
|
|
279333
280233
|
coordinatorRunsOfWorkorder: (wid) => fanOutTrace.listCoordinatorRuns(wid),
|
|
279334
280234
|
// 连败熔断卡面的「末次:{失败原文首句}」:原话只在 `agent_runs.error_message`,快照里只有分类词。
|
|
@@ -279405,6 +280305,13 @@ async function startServe(opts) {
|
|
|
279405
280305
|
// store(`public.actor_bindings`),org-registry cutover 之后它是冻结旧镜像——只留给
|
|
279406
280306
|
// 本域其它老读口,工作区定位一律不许再用它。
|
|
279407
280307
|
resolveBinding: resolveCompanyBinding,
|
|
280308
|
+
/* ADR 0613:建会话 / 「恢复为员工默认运行配置」这两下要读员工详情页配的型号,按**当前公司**读
|
|
280309
|
+
(与 `resolveBinding` 同一条理由:全局 `registry` 对已切 `actor-config` 的公司是冻结旧镜像)。
|
|
280310
|
+
⚠ 只有这两下读它;解析每一轮的模型依旧不读员工配置(ADR 0610 D1)。 */
|
|
280311
|
+
resolveActorModel: async (cid, actorId) => {
|
|
280312
|
+
const ctx = await actors.resolveCtx(cid ?? defaultCompanyId);
|
|
280313
|
+
return (await ctx.service.latestConfig(actorId))?.model ?? null;
|
|
280314
|
+
},
|
|
279408
280315
|
// 按 runId 路由:切换后新会话的事件落在本公司库里,共享 store 会一条都补不出 parts。
|
|
279409
280316
|
// ⚠ `runRoutedTrace` 声明在本行**之后**:包成箭头函数避 TDZ(本域只需要 listEvents)。
|
|
279410
280317
|
trace: { listEvents: (runId, o) => runRoutedTrace.listEvents(runId, o) },
|
|
@@ -279493,7 +280400,7 @@ async function startServe(opts) {
|
|
|
279493
280400
|
liveChat,
|
|
279494
280401
|
// ADR-0587:列表行派生 `unread`,与 collab 域收件箱读同一份按公司的水位(无 PG 时闭包自己回落单实例)。
|
|
279495
280402
|
resolveReadMarkers: readMarkerStoreFor,
|
|
279496
|
-
// ADR
|
|
280403
|
+
// ADR 0610 D4:`GET /api/chat-sessions/:id/usage` 的取数口——**与 collab 域是同一个实例**,
|
|
279497
280404
|
// 按会话取数与组织统计因此永远同一份账本、同一套归属,不会出现两条路各算各的。
|
|
279498
280405
|
usageRead,
|
|
279499
280406
|
defaultCompanyId
|
|
@@ -280044,7 +280951,7 @@ async function startServe(opts) {
|
|
|
280044
280951
|
// ADR-0078 D3:写入围栏的钥匙
|
|
280045
280952
|
...c.artifactId !== void 0 ? { artifactId: c.artifactId } : {},
|
|
280046
280953
|
...c.sessionId !== void 0 ? { sessionId: c.sessionId } : {},
|
|
280047
|
-
// ADR
|
|
280954
|
+
// ADR 0610 D1:签名 scopes 透给域路由,`isOperatorRequest` 据此认出部署级 operator-token。
|
|
280048
280955
|
...c.scopes !== void 0 ? { scopes: c.scopes } : {}
|
|
280049
280956
|
} : null;
|
|
280050
280957
|
},
|
|
@@ -280369,9 +281276,10 @@ async function startServe(opts) {
|
|
|
280369
281276
|
const provision = isolatedKnowledgeTurn ? { env: {}, wrapperPaths: [], requiredTools: [], requiredToolVersions: {}, connectorCreds: [], cleanup: async () => void 0 } : await buildActorProvision(actorService, actorId, chatDispatchScope(priorChatSession));
|
|
280370
281277
|
const actorCtx = await buildActorContext(actorService, actorId).catch(() => null);
|
|
280371
281278
|
const sessionModel = configuredModel(sessionModelOverride);
|
|
280372
|
-
const
|
|
281279
|
+
const actorConfiguredModel = isolatedBackground ? configuredModel(actorCtx?.config?.model) : void 0;
|
|
281280
|
+
const chatResolvedModel = sessionModel ?? actorConfiguredModel;
|
|
280373
281281
|
const chatModel = chatResolvedModel ?? await registryStore.getRuntimeConfig(`runtime:${binding.nodeId}:${binding.runtimeKind}`).then((c) => configuredModel(c?.model)).catch(() => void 0);
|
|
280374
|
-
const chatModelSource = sessionModel ? "session_override" :
|
|
281282
|
+
const chatModelSource = sessionModel ? "session_override" : actorConfiguredModel ? "actor_config" : chatModel ? "runtime_default" : null;
|
|
280375
281283
|
const attachmentFiles = { ...preparedAttachments.files, ...restore ? { "SESSION_FILES.md": restore.index } : {} };
|
|
280376
281284
|
const attachmentBinary = { ...preparedAttachments.binaryFiles };
|
|
280377
281285
|
const attachmentPaths = [...preparedAttachments.paths];
|
|
@@ -280588,8 +281496,7 @@ async function startServe(opts) {
|
|
|
280588
281496
|
startedAt: endedAt
|
|
280589
281497
|
}]);
|
|
280590
281498
|
const usage = info.usage ?? null;
|
|
280591
|
-
const
|
|
280592
|
-
const modelSource = info.model ? "runtime" : chatModelSource;
|
|
281499
|
+
const modelFields = chatExitModelFields(info.model, chatModel, chatModelSource);
|
|
280593
281500
|
let nativeSessionMetadata;
|
|
280594
281501
|
if (info.runtimeSessionId && info.runtimeSessionId !== runtimeSessionId) {
|
|
280595
281502
|
const run = await (await traceStoreFor(runCompanyId)).getRun(traceRunId).catch(() => null);
|
|
@@ -280604,8 +281511,7 @@ async function startServe(opts) {
|
|
|
280604
281511
|
...!isHealthySessionExit(info) && info.reason !== "cancelled" ? { errorCode: info.reason ?? "error", errorMessage: formatExitError(info) } : {},
|
|
280605
281512
|
transcriptRef: info.transcriptRef ?? null,
|
|
280606
281513
|
usage,
|
|
280607
|
-
|
|
280608
|
-
modelSource,
|
|
281514
|
+
...modelFields,
|
|
280609
281515
|
...nativeSessionMetadata ? { metadata: nativeSessionMetadata } : {}
|
|
280610
281516
|
});
|
|
280611
281517
|
if (usage) await settleRunUsage(await traceStoreFor(runCompanyId), traceRunId);
|
|
@@ -280718,7 +281624,11 @@ async function startServe(opts) {
|
|
|
280718
281624
|
info.chatSessionId,
|
|
280719
281625
|
`\u5B50\u4F1A\u8BDD\u8FD9\u4E00\u8F6E\u88AB\u6062\u590D\u5668\u6536\u53E3\u4E3A ${info.status}\uFF08${info.reason}\uFF09`,
|
|
280720
281626
|
info.companyId,
|
|
280721
|
-
{
|
|
281627
|
+
{
|
|
281628
|
+
outcome: info.status === "succeeded" ? "succeeded" : "failed",
|
|
281629
|
+
...info.turnId ? { turnId: info.turnId } : {},
|
|
281630
|
+
...info.exitReason ? { exitReason: info.exitReason } : {}
|
|
281631
|
+
}
|
|
280722
281632
|
);
|
|
280723
281633
|
};
|
|
280724
281634
|
const handshakeThrottleOpts = {};
|
|
@@ -283181,6 +284091,11 @@ ${nodeFault}` : "");
|
|
|
283181
284091
|
const zbCostThresholdMicros = opts.zeroOutputBreaker?.costThresholdMicros ?? (envInt("OASIS_ZERO_OUTPUT_BREAKER_COST_USD") ?? 0) * 1e6;
|
|
283182
284092
|
if (zbEnabled && zbIntervalMs > 0 && (zbThreshold > 0 || zbCostThresholdMicros > 0)) {
|
|
283183
284093
|
const zbActions = /* @__PURE__ */ new Set(["produce", "review"]);
|
|
284094
|
+
const engineWorkIdOf = (metadata) => {
|
|
284095
|
+
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) return null;
|
|
284096
|
+
const v2 = metadata["engineWorkId"];
|
|
284097
|
+
return typeof v2 === "string" && v2.trim() ? v2 : null;
|
|
284098
|
+
};
|
|
283184
284099
|
const listRecentZeroOutputRuns = async (sinceIso) => {
|
|
283185
284100
|
const items = await fanOutTrace.listRunsAcrossWithCompany(
|
|
283186
284101
|
{ status: "no-output", from: sinceIso, limit: 1e3 },
|
|
@@ -283194,7 +284109,10 @@ ${nodeFault}` : "");
|
|
|
283194
284109
|
actorId: r.actorId,
|
|
283195
284110
|
action: r.action,
|
|
283196
284111
|
startedAt: r.startedAt,
|
|
283197
|
-
costUsdMicros: r.usage?.costUsdMicros ?? null
|
|
284112
|
+
costUsdMicros: r.usage?.costUsdMicros ?? null,
|
|
284113
|
+
// ★ 轮次维度(Bug 0211):同一轮里的协议续唤各是一条 run,只数 run 会让上报正文那个数
|
|
284114
|
+
// 比人点开轨迹数到的段数大。**只影响正文措辞,不影响跳闸判据**(阈值仍按 run 数判)。
|
|
284115
|
+
workId: engineWorkIdOf(r.metadata)
|
|
283198
284116
|
}));
|
|
283199
284117
|
};
|
|
283200
284118
|
const latestClosingRemark = async (runId) => {
|
|
@@ -285731,7 +286649,7 @@ async function startNode(opts) {
|
|
|
285731
286649
|
}
|
|
285732
286650
|
|
|
285733
286651
|
// ../cli/src/exec.ts
|
|
285734
|
-
var
|
|
286652
|
+
var os12 = __toESM(require("node:os"), 1);
|
|
285735
286653
|
var UnsafeExecArgvError = class extends Error {
|
|
285736
286654
|
code = "ERR_UNSAFE_EXEC_ARGV";
|
|
285737
286655
|
constructor(message) {
|
|
@@ -285768,7 +286686,7 @@ function planExec(opts) {
|
|
|
285768
286686
|
function computeExitCode(code2, signal) {
|
|
285769
286687
|
if (code2 !== null) return code2;
|
|
285770
286688
|
if (signal) {
|
|
285771
|
-
const num4 =
|
|
286689
|
+
const num4 = os12.constants.signals[signal];
|
|
285772
286690
|
return 128 + (typeof num4 === "number" ? num4 : 1);
|
|
285773
286691
|
}
|
|
285774
286692
|
return 1;
|
|
@@ -286018,7 +286936,7 @@ var COMMAND_DECLS = {
|
|
|
286018
286936
|
},
|
|
286019
286937
|
"usage-ledger-backfill": {
|
|
286020
286938
|
group: "\u57FA\u7840\u8BBE\u65BD",
|
|
286021
|
-
usage: "oasis usage-ledger-backfill (--company <id> | --all) (--dry-run | --execute | --verify | --undo <manifestId>)",
|
|
286939
|
+
usage: "oasis usage-ledger-backfill (--company <id> | --all) (--dry-run | --execute | --verify | --undo <manifestId>) [--claude-resume-before <ISO>]",
|
|
286022
286940
|
description: "\u7528\u91CF\u8D26\u672C\u5386\u53F2\u56DE\u586B\uFF08\u4F7F\u7528\u4E0E\u7EDF\u8BA1\uFF09\uFF1A\u8865\u7EC8\u503C\u7528\u91CF\u70B9\u3001runtime_started_at\u3001chat \u4F1A\u8BDD/\u8F6E\u6B21\uFF1B\u5E42\u7B49\uFF0C\u6539\u52A8\u5199\u5BA1\u8BA1\u8868\uFF0C\u53EF\u6309 manifest \u64A4\u9500\u3002\u4EE5 serve \u7684\u73AF\u5883\u5728\u90E8\u7F72\u673A\u4E0A\u6267\u884C\u3002",
|
|
286023
286941
|
flags: [
|
|
286024
286942
|
{ name: "company", desc: "\u53EA\u5904\u7406\u8FD9\u5BB6\u516C\u53F8\u7684\u8D26\u672C\uFF08\u4ECD\u5728 legacy \u7684\u516C\u53F8 = \u5171\u4EAB\u8D26\u672C + \u672C\u516C\u53F8 chat \u53CD\u67E5\uFF09" },
|
|
@@ -286026,10 +286944,12 @@ var COMMAND_DECLS = {
|
|
|
286026
286944
|
{ name: "dry-run", desc: "\u53EA\u62A5\u6BCF\u4E2A\u8D26\u672C\u5404\u6B65\u5F85\u6539\u6761\u6570\u548C\u6837\u4F8B run id\uFF0C\u4E00\u884C\u4E0D\u5199", boolean: true },
|
|
286027
286945
|
{ name: "execute", desc: "\u5199\u5165\uFF1B\u7ED3\u675F\u65F6\u6253\u5370 manifestId", boolean: true },
|
|
286028
286946
|
{ name: "verify", desc: "\u6838\u5BF9 I6\uFF08\u7EC8\u503C\u70B9 = agent_runs.usage\u3001\u68C0\u67E5\u70B9\u4E0D\u8D85\u7EC8\u503C\uFF09\u4E0E\u542F\u52A8\u8BC1\u636E\uFF1B\u6709\u8FDD\u4F8B\u9000\u51FA\u7801 1", boolean: true },
|
|
286029
|
-
{ name: "undo", desc: "\u6309\u5BA1\u8BA1\u8868\u628A\u67D0\u4E2A manifestId \u7684\u6539\u52A8\u6062\u590D\u539F\u503C" }
|
|
286947
|
+
{ name: "undo", desc: "\u6309\u5BA1\u8BA1\u8868\u628A\u67D0\u4E2A manifestId \u7684\u6539\u52A8\u6062\u590D\u539F\u503C" },
|
|
286948
|
+
{ name: "claude-resume-before", desc: "\u52A0\u8DD1\u7B2C 4 \u6B65\uFF1A\u5F00\u8DD1\u65E9\u4E8E\u8FD9\u4E2A\u65F6\u523B\u7684 claude-code run\uFF0C\u628A\u7EED\u8DD1\u5E26\u8FDB\u6765\u7684\u6574\u6761\u4F1A\u8BDD\u7EBF\u7D2F\u8BA1\u503C\u6263\u56DE\u6210\u672C\u8F6E\u51C0\u503C\uFF08\u53D6\u4FEE\u597D\u7684\u8282\u70B9\u5305\u5728\u5168\u90E8\u8282\u70B9\u88C5\u4E0A\u7684\u65F6\u523B\uFF09" }
|
|
286030
286949
|
],
|
|
286031
286950
|
examples: [
|
|
286032
286951
|
"oasis usage-ledger-backfill --all --dry-run",
|
|
286952
|
+
"oasis usage-ledger-backfill --all --dry-run --claude-resume-before 2026-09-23T00:00:00Z",
|
|
286033
286953
|
"oasis usage-ledger-backfill --all --execute",
|
|
286034
286954
|
"oasis usage-ledger-backfill --all --verify"
|
|
286035
286955
|
]
|
|
@@ -288372,7 +289292,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
288372
289292
|
}
|
|
288373
289293
|
}
|
|
288374
289294
|
}
|
|
288375
|
-
var CLI_VERSION = "2.2.
|
|
289295
|
+
var CLI_VERSION = "2.2.70" ? "2.2.70" : "dev";
|
|
288376
289296
|
function apiHeaders(token, company) {
|
|
288377
289297
|
const headers = {
|
|
288378
289298
|
authorization: `Bearer ${token}`,
|
|
@@ -288607,7 +289527,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
288607
289527
|
const res = await fetch(`${httpBase2}/api/nodes/exchange`, {
|
|
288608
289528
|
method: "POST",
|
|
288609
289529
|
headers: { "content-type": "application/json" },
|
|
288610
|
-
body: JSON.stringify({ enrollToken, nodeId, hostname:
|
|
289530
|
+
body: JSON.stringify({ enrollToken, nodeId, hostname: os13.hostname(), serverUrl, ...companyId ? { companyId } : {} })
|
|
288611
289531
|
});
|
|
288612
289532
|
if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
|
|
288613
289533
|
const body2 = await res.json();
|
|
@@ -288640,7 +289560,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
288640
289560
|
const binPath = path37.join(prefix, "bin", "oasis_test");
|
|
288641
289561
|
const svcArgs = `node --server-ws ${serverUrl} --dir ${dir}${nodeName ? ` --name ${nodeName}` : ""}`;
|
|
288642
289562
|
if (process.platform === "linux") {
|
|
288643
|
-
const svcFile = path37.join(
|
|
289563
|
+
const svcFile = path37.join(os13.homedir(), ".config/systemd/user/oasis-node.service");
|
|
288644
289564
|
fs42.mkdirSync(path37.dirname(svcFile), { recursive: true });
|
|
288645
289565
|
if (spawnSync3("systemctl", ["--user", "is-active", "--quiet", "oasis-node"], {}).status === 0)
|
|
288646
289566
|
spawnSync3("systemctl", ["--user", "stop", "oasis-node"], { stdio: "inherit" });
|
|
@@ -288653,7 +289573,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
288653
289573
|
`ExecStart=${binPath} ${svcArgs}`,
|
|
288654
289574
|
// Carry the install-time PATH so the detached daemon detects CLIs in user dirs
|
|
288655
289575
|
// (~/.npm-global/bin, ~/.local/bin) — systemd --user otherwise gives a minimal PATH.
|
|
288656
|
-
`Environment=PATH=${process.env["PATH"] ?? ""}:${path37.join(
|
|
289576
|
+
`Environment=PATH=${process.env["PATH"] ?? ""}:${path37.join(os13.homedir(), ".npm-global/bin")}:${path37.join(os13.homedir(), ".local/bin")}:/usr/local/bin`,
|
|
288657
289577
|
"Restart=on-failure",
|
|
288658
289578
|
"RestartSec=5",
|
|
288659
289579
|
"StandardOutput=journal",
|
|
@@ -288665,23 +289585,23 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
288665
289585
|
].join("\n"));
|
|
288666
289586
|
spawnSync3("systemctl", ["--user", "daemon-reload"], { stdio: "inherit" });
|
|
288667
289587
|
spawnSync3("systemctl", ["--user", "enable", "--now", "oasis-node"], { stdio: "inherit" });
|
|
288668
|
-
spawnSync3("loginctl", ["enable-linger",
|
|
289588
|
+
spawnSync3("loginctl", ["enable-linger", os13.userInfo().username], { stdio: "ignore" });
|
|
288669
289589
|
println("\u2713 Oasis node service started (systemd --user oasis-node)");
|
|
288670
289590
|
println(" Status : systemctl --user status oasis-node");
|
|
288671
289591
|
println(" Logs : journalctl --user -u oasis-node -f");
|
|
288672
289592
|
println(" Stop : systemctl --user stop oasis-node");
|
|
288673
289593
|
} else if (process.platform === "darwin") {
|
|
288674
|
-
const plist = path37.join(
|
|
289594
|
+
const plist = path37.join(os13.homedir(), "Library/LaunchAgents/com.oasis.node.plist");
|
|
288675
289595
|
fs42.mkdirSync(path37.dirname(plist), { recursive: true });
|
|
288676
289596
|
spawnSync3("launchctl", ["unload", plist], { stdio: "ignore" });
|
|
288677
289597
|
const argXml = [binPath, "node", "--server-ws", serverUrl, "--dir", dir, ...nodeName ? ["--name", nodeName] : []].map((a) => `<string>${a}</string>`).join("");
|
|
288678
|
-
fs42.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>Label</key><string>com.oasis.node</string><key>ProgramArguments</key><array>${argXml}</array><key>RunAtLoad</key><true/><key>KeepAlive</key><true/><key>StandardOutPath</key><string>${
|
|
289598
|
+
fs42.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>Label</key><string>com.oasis.node</string><key>ProgramArguments</key><array>${argXml}</array><key>RunAtLoad</key><true/><key>KeepAlive</key><true/><key>StandardOutPath</key><string>${os13.homedir()}/.oasis-node.log</string><key>StandardErrorPath</key><string>${os13.homedir()}/.oasis-node.err</string></dict></plist>`);
|
|
288679
289599
|
spawnSync3("launchctl", ["load", plist], { stdio: "inherit" });
|
|
288680
289600
|
println("\u2713 Oasis node service started (macOS LaunchAgent com.oasis.node)");
|
|
288681
|
-
println(` Logs : tail -f ${
|
|
289601
|
+
println(` Logs : tail -f ${os13.homedir()}/.oasis-node.log`);
|
|
288682
289602
|
println(` Stop : launchctl unload ${plist}`);
|
|
288683
289603
|
} else {
|
|
288684
|
-
spawnSync3("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path37.join(
|
|
289604
|
+
spawnSync3("sh", ["-c", `nohup ${binPath} ${svcArgs} > ${path37.join(os13.homedir(), ".oasis-node.log")} 2>&1 &`], { stdio: "inherit" });
|
|
288685
289605
|
println(`\u2713 Oasis node started in background (nohup). Logs: ~/.oasis-node.log`);
|
|
288686
289606
|
println(" Note: no automatic restart on reboot in this environment.");
|
|
288687
289607
|
}
|
|
@@ -288790,8 +289710,8 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
288790
289710
|
if (command2 === "serve" && positional[0] === "install") {
|
|
288791
289711
|
const absDir = path37.resolve(dir);
|
|
288792
289712
|
const name = `oasis-serve-${path37.basename(absDir)}`;
|
|
288793
|
-
const unitDir = flags.get("unit-dir") ?? path37.join(
|
|
288794
|
-
const bin = flags.get("bin") ?? path37.join(
|
|
289713
|
+
const unitDir = flags.get("unit-dir") ?? path37.join(os13.homedir(), ".config", "systemd", "user");
|
|
289714
|
+
const bin = flags.get("bin") ?? path37.join(os13.homedir(), ".local", "bin", "oasis");
|
|
288795
289715
|
const port = flags.get("port") ?? "7320";
|
|
288796
289716
|
const extra = (flags.get("dispatch") === "true" ? ` --dispatch true` : "") + (flags.has("model") ? ` --model ${flags.get("model")}` : "");
|
|
288797
289717
|
const unit = [
|
|
@@ -289280,7 +290200,7 @@ Trace: ${run.traceRunId}`);
|
|
|
289280
290200
|
if (plan.inject.mode === "env") {
|
|
289281
290201
|
childEnv[plan.inject.envName] = value2;
|
|
289282
290202
|
} else {
|
|
289283
|
-
tmpDir = await fs42.promises.mkdtemp(path37.join(
|
|
290203
|
+
tmpDir = await fs42.promises.mkdtemp(path37.join(os13.tmpdir(), "oasis-var-exec-"));
|
|
289284
290204
|
const keyfile = path37.join(tmpDir, "value");
|
|
289285
290205
|
await fs42.promises.writeFile(keyfile, value2, { mode: 384 });
|
|
289286
290206
|
childEnv[plan.inject.fileEnv] = keyfile;
|
|
@@ -290166,7 +291086,7 @@ ${res.warning}`);
|
|
|
290166
291086
|
for (const a of st.artifacts) println(` - ${a.path}\uFF08${a.kind ?? "?"}\uFF09status=${a.status ?? "?"}${a.mtime ? ` \xB7 ${new Date(a.mtime).toISOString()}` : ""}`);
|
|
290167
291087
|
if (flags.get("pull") === "true") {
|
|
290168
291088
|
const odPublic2 = (flags.get("od-public-url") ?? process.env["OASIS_OPEN_DESIGN_PUBLIC_URL"] ?? "https://design.open-friday.com").replace(/\/$/, "");
|
|
290169
|
-
const { dir: dir3, entry: entry2 } = await harvestBoard(odBase2, fetch, odPublic2,
|
|
291089
|
+
const { dir: dir3, entry: entry2 } = await harvestBoard(odBase2, fetch, odPublic2, os13.tmpdir(), st.boardKey, st.runs[0]?.runId ?? "status-pull");
|
|
290170
291090
|
println(`[design] \u5DF2\u62C9\u5230\u672C\u5730\uFF1A${dir3}\uFF08\u5165\u53E3 ${entry2}\uFF09`);
|
|
290171
291091
|
println(`[design] \u8BFB\u5B8C\u6EE1\u610F\u5373\u4EA4\u7A3F\uFF1Aoasis propose ${artifactId2} --from-dir ${dir3} --reason "<\u8FD9\u7248\u505A\u4E86\u4EC0\u4E48>"`);
|
|
290172
291092
|
} else {
|
|
@@ -291974,10 +292894,10 @@ function runtimeAssetSourceRoots(input) {
|
|
|
291974
292894
|
|
|
291975
292895
|
// src/paths.ts
|
|
291976
292896
|
var fs46 = __toESM(require("node:fs"));
|
|
291977
|
-
var
|
|
292897
|
+
var os14 = __toESM(require("node:os"));
|
|
291978
292898
|
var path41 = __toESM(require("node:path"));
|
|
291979
292899
|
var DEFAULT_INSTANCE = "default";
|
|
291980
|
-
var home = () =>
|
|
292900
|
+
var home = () => os14.homedir();
|
|
291981
292901
|
var oasisDir = () => path41.join(home(), ".oasis");
|
|
291982
292902
|
var versionsDir = () => path41.join(oasisDir(), "versions");
|
|
291983
292903
|
var versionDir = (label2) => path41.join(versionsDir(), label2);
|
|
@@ -292178,7 +293098,7 @@ function shimScript() {
|
|
|
292178
293098
|
}
|
|
292179
293099
|
|
|
292180
293100
|
// src/index.ts
|
|
292181
|
-
var PKG_VERSION = true ? "2.2.
|
|
293101
|
+
var PKG_VERSION = true ? "2.2.70" : "dev";
|
|
292182
293102
|
var LOCAL_BIN = localBin();
|
|
292183
293103
|
var NPM_PREFIX = npmPrefix();
|
|
292184
293104
|
var INSTANCE = DEFAULT_INSTANCE;
|
|
@@ -292284,7 +293204,7 @@ function installSoftware(label2) {
|
|
|
292284
293204
|
function setupAutostart(name) {
|
|
292285
293205
|
const inst = instancePaths(name);
|
|
292286
293206
|
const cmd = `${process.execPath} "${inst.binFile}" --_daemon --instance ${name}`;
|
|
292287
|
-
const home2 =
|
|
293207
|
+
const home2 = os15.homedir();
|
|
292288
293208
|
const pnpmHome = process.env["PNPM_HOME"] || path43.join(home2, ".local", "share", "pnpm");
|
|
292289
293209
|
const extraBins = [
|
|
292290
293210
|
path43.join(home2, ".npm-global", "bin"),
|
|
@@ -292294,7 +293214,7 @@ function setupAutostart(name) {
|
|
|
292294
293214
|
];
|
|
292295
293215
|
const daemonPath = sanitizeDaemonPath([process.env["PATH"] ?? "", ...extraBins].filter(Boolean).join(":"));
|
|
292296
293216
|
if (process.platform === "linux") {
|
|
292297
|
-
const unitDir = path43.join(
|
|
293217
|
+
const unitDir = path43.join(os15.homedir(), ".config", "systemd", "user");
|
|
292298
293218
|
fs48.mkdirSync(unitDir, { recursive: true });
|
|
292299
293219
|
const unit = systemdUnitName(name);
|
|
292300
293220
|
fs48.mkdirSync(path43.dirname(inst.logFile), { recursive: true });
|
|
@@ -292319,7 +293239,7 @@ function setupAutostart(name) {
|
|
|
292319
293239
|
return false;
|
|
292320
293240
|
} else if (process.platform === "darwin") {
|
|
292321
293241
|
const label2 = launchdLabel(name);
|
|
292322
|
-
const plist = path43.join(
|
|
293242
|
+
const plist = path43.join(os15.homedir(), "Library", "LaunchAgents", `${label2}.plist`);
|
|
292323
293243
|
fs48.mkdirSync(path43.dirname(plist), { recursive: true });
|
|
292324
293244
|
fs48.writeFileSync(plist, `<?xml version="1.0" encoding="UTF-8"?>
|
|
292325
293245
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -292501,7 +293421,7 @@ async function startOneInstance(o) {
|
|
|
292501
293421
|
const res = await fetch(`${httpBase(serverUrl)}/api/nodes/exchange`, {
|
|
292502
293422
|
method: "POST",
|
|
292503
293423
|
headers: { "content-type": "application/json" },
|
|
292504
|
-
body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname:
|
|
293424
|
+
body: JSON.stringify({ enrollToken, nodeId: derivedNodeId, hostname: os15.hostname(), serverUrl, ...companyId ? { companyId } : {} })
|
|
292505
293425
|
});
|
|
292506
293426
|
if (!res.ok) throw new Error(`enroll token exchange failed: HTTP ${res.status}`);
|
|
292507
293427
|
const body2 = await res.json();
|
|
@@ -292566,7 +293486,7 @@ function derivedNodeIdFor(name) {
|
|
|
292566
293486
|
if (name === DEFAULT_INSTANCE) return resolveNodeId();
|
|
292567
293487
|
const user = (() => {
|
|
292568
293488
|
try {
|
|
292569
|
-
return
|
|
293489
|
+
return os15.userInfo().username;
|
|
292570
293490
|
} catch {
|
|
292571
293491
|
return process.env["USER"] ?? process.env["USERNAME"] ?? "unknown";
|
|
292572
293492
|
}
|