oasis_test 0.1.133 → 0.1.135
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 +851 -307
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -971,9 +971,11 @@ var init_telemetry = __esm({
|
|
|
971
971
|
});
|
|
972
972
|
|
|
973
973
|
// ../contract/src/trace.ts
|
|
974
|
+
var DISPLAY_CNY_PER_USD;
|
|
974
975
|
var init_trace = __esm({
|
|
975
976
|
"../contract/src/trace.ts"() {
|
|
976
977
|
"use strict";
|
|
978
|
+
DISPLAY_CNY_PER_USD = 7.2;
|
|
977
979
|
}
|
|
978
980
|
});
|
|
979
981
|
|
|
@@ -1558,7 +1560,7 @@ var init_src2 = __esm({
|
|
|
1558
1560
|
RESOLVED_GAP_AFTER_HEAD_EFFECTS = effects(WAKE, NEUTRAL, VETO, WAKE);
|
|
1559
1561
|
PENDING_REVIEW_EFFECTS = effects(NEUTRAL, NEUTRAL, VETO, NEUTRAL);
|
|
1560
1562
|
GAP_SOLUTION_DELIVERY_SINCE = "2026-09-01T00:00:00.000Z";
|
|
1561
|
-
REPLY_ORIGIN_SINCE = "2026-09-
|
|
1563
|
+
REPLY_ORIGIN_SINCE = "2026-09-05T00:00:00.000Z";
|
|
1562
1564
|
ROUND_LIMIT_MARKER = "\u26A0\uFE0F \u56DE\u5408\u4E0A\u9650";
|
|
1563
1565
|
LETTER_ROUND_LIMIT = 8;
|
|
1564
1566
|
}
|
|
@@ -7210,7 +7212,7 @@ ${supplemental.taskAppend.trim()}
|
|
|
7210
7212
|
...provisioned?.env ?? {},
|
|
7211
7213
|
...spec.part !== void 0 ? { OASIS_PART: spec.part } : {}
|
|
7212
7214
|
};
|
|
7213
|
-
const
|
|
7215
|
+
const resolvedModel2 = this.opts.resolveModel ? await this.opts.resolveModel(dispatchSpec.actor) : void 0;
|
|
7214
7216
|
const resolvedExtraArgs = this.opts.resolveExtraArgs ? await this.opts.resolveExtraArgs(dispatchSpec.actor) : void 0;
|
|
7215
7217
|
this.assertSpawnAttemptCurrent(jobKey, attempt);
|
|
7216
7218
|
const freshWorkdir = workdirKey !== void 0 && !priorConsistent;
|
|
@@ -7227,7 +7229,7 @@ ${supplemental.taskAppend.trim()}
|
|
|
7227
7229
|
server: { url: serverUrl },
|
|
7228
7230
|
limits,
|
|
7229
7231
|
...this.resilienceFields(),
|
|
7230
|
-
...
|
|
7232
|
+
...resolvedModel2 ? { model: resolvedModel2 } : {},
|
|
7231
7233
|
...resolvedExtraArgs && resolvedExtraArgs.length > 0 ? { extraArgs: resolvedExtraArgs } : {},
|
|
7232
7234
|
...binding !== void 0 ? { binding } : {},
|
|
7233
7235
|
...runtimeSessionId !== void 0 ? { runtimeSessionId } : {},
|
|
@@ -154464,6 +154466,45 @@ var init_chat_item_ledger = __esm({
|
|
|
154464
154466
|
}
|
|
154465
154467
|
});
|
|
154466
154468
|
}
|
|
154469
|
+
/**
|
|
154470
|
+
* B4:POST /api/chat 开轮时把 user 的**首条**提交也记进账本——桶按 itemId 索引的合并
|
|
154471
|
+
* 模型这才闭环(否则空闲会话刷新看不到 user 历史,且服务端从不回填 clientSubmitId)。
|
|
154472
|
+
*
|
|
154473
|
+
* - `itemId` 用 `oasis-user-optim:${clientSubmitId}`(与 FE `beginOptimisticUser` 同规则):
|
|
154474
|
+
* 同一次点击的乐观桶位和服务端权威条自然对齐,不需要「双条+去重」的过渡态。
|
|
154475
|
+
* 没给 clientSubmitId 时回落随机 id——旧客户端仍可用,只是 FE 侧没有乐观替换的钩子。
|
|
154476
|
+
* - `payload.clientSubmitId` 也一并写进去——`chat-items-merge` 在 itemId 恰好不同时(跨版本
|
|
154477
|
+
* 混部/异常路径)走 `retractSiblingOptimistic` 兜底,只剩一条 user 气泡。
|
|
154478
|
+
* - `message_id` 绑到本轮建 assistant 行之前的 user 行——但这里没有 messageId 可给,
|
|
154479
|
+
* 落 NULL 由 `bindMessage` 那侧不动它(它只回填 role='assistant' 的行)。
|
|
154480
|
+
*/
|
|
154481
|
+
recordUserSubmission(input) {
|
|
154482
|
+
const payload = {
|
|
154483
|
+
role: "user",
|
|
154484
|
+
text: input.text
|
|
154485
|
+
};
|
|
154486
|
+
if (input.attachments?.length) payload.attachments = input.attachments;
|
|
154487
|
+
if (input.clientSubmitId) payload.clientSubmitId = input.clientSubmitId;
|
|
154488
|
+
const deterministicId = input.clientSubmitId ? `oasis-user-optim:${input.clientSubmitId}` : void 0;
|
|
154489
|
+
return this.insert({
|
|
154490
|
+
kind: "text",
|
|
154491
|
+
role: "user",
|
|
154492
|
+
status: "completed",
|
|
154493
|
+
origin: "server",
|
|
154494
|
+
text: input.text,
|
|
154495
|
+
attrs: {},
|
|
154496
|
+
inContent: false,
|
|
154497
|
+
persist: true,
|
|
154498
|
+
forceNullMessage: true,
|
|
154499
|
+
payload,
|
|
154500
|
+
metadata: {
|
|
154501
|
+
[CHAT_ITEM_META_LEGACY_CONTENT]: false,
|
|
154502
|
+
...input.clientSubmitId ? { clientSubmitId: input.clientSubmitId } : {},
|
|
154503
|
+
...input.attachments?.length ? { attachments: input.attachments } : {}
|
|
154504
|
+
},
|
|
154505
|
+
...deterministicId ? { deterministicId } : {}
|
|
154506
|
+
});
|
|
154507
|
+
}
|
|
154467
154508
|
/** 服务端合成的错误帧(session.done 抛 / exit 判失败)。不入正文,归 control。 */
|
|
154468
154509
|
recordError(text5, extra) {
|
|
154469
154510
|
this.insert({
|
|
@@ -154657,7 +154698,7 @@ var init_chat_item_ledger = __esm({
|
|
|
154657
154698
|
}
|
|
154658
154699
|
}
|
|
154659
154700
|
insert(input) {
|
|
154660
|
-
const id = this.newId();
|
|
154701
|
+
const id = input.deterministicId ?? this.newId();
|
|
154661
154702
|
const row = {
|
|
154662
154703
|
id,
|
|
154663
154704
|
seq: ++this.seqCounter,
|
|
@@ -157933,8 +157974,36 @@ function parseCodexSessionId(lines) {
|
|
|
157933
157974
|
const id = o.payload?.id;
|
|
157934
157975
|
return typeof id === "string" && id ? id : void 0;
|
|
157935
157976
|
}
|
|
157936
|
-
function
|
|
157937
|
-
|
|
157977
|
+
function bucketsOf(usage) {
|
|
157978
|
+
if (!usage) return void 0;
|
|
157979
|
+
return {
|
|
157980
|
+
input: codexNum(usage["input_tokens"]),
|
|
157981
|
+
// cache 字段名跨版本有两种
|
|
157982
|
+
cacheRead: codexNum(usage["cached_input_tokens"]) || codexNum(usage["cache_read_input_tokens"]),
|
|
157983
|
+
cacheWrite: codexNum(usage["cache_write_input_tokens"]),
|
|
157984
|
+
// reasoning 计入 output(对齐 Multica:codex 的 output_tokens 不含 reasoning)。
|
|
157985
|
+
output: codexNum(usage["output_tokens"]) + codexNum(usage["reasoning_output_tokens"])
|
|
157986
|
+
};
|
|
157987
|
+
}
|
|
157988
|
+
function usageFromBuckets(b2) {
|
|
157989
|
+
const inputFresh = Math.max(b2.input - b2.cacheRead, 0);
|
|
157990
|
+
return {
|
|
157991
|
+
inputTokens: inputFresh,
|
|
157992
|
+
outputTokens: b2.output,
|
|
157993
|
+
totalTokens: inputFresh + b2.output,
|
|
157994
|
+
// = input+output(不含 cache,与 claude/OTLP 口径一致)
|
|
157995
|
+
cacheReadTokens: b2.cacheRead,
|
|
157996
|
+
cacheCreationTokens: b2.cacheWrite || null,
|
|
157997
|
+
costUsdMicros: null
|
|
157998
|
+
// codex rollout 无成本(订阅计划)
|
|
157999
|
+
};
|
|
158000
|
+
}
|
|
158001
|
+
function parseCodexTokenUsage(lines, sinceMs) {
|
|
158002
|
+
let lastTotal;
|
|
158003
|
+
let lastTurn;
|
|
158004
|
+
const windowed = { input: 0, cacheRead: 0, cacheWrite: 0, output: 0 };
|
|
158005
|
+
let sawWindowed = false;
|
|
158006
|
+
let sawTimestamp = false;
|
|
157938
158007
|
for (const line of lines) {
|
|
157939
158008
|
if (!line || line.indexOf("token_count") === -1) continue;
|
|
157940
158009
|
let o;
|
|
@@ -157943,25 +158012,29 @@ function parseCodexTokenUsage(lines) {
|
|
|
157943
158012
|
} catch {
|
|
157944
158013
|
continue;
|
|
157945
158014
|
}
|
|
157946
|
-
if (o?.type
|
|
157947
|
-
|
|
157948
|
-
|
|
157949
|
-
|
|
157950
|
-
|
|
157951
|
-
|
|
157952
|
-
|
|
157953
|
-
|
|
157954
|
-
|
|
157955
|
-
|
|
157956
|
-
|
|
157957
|
-
|
|
157958
|
-
|
|
157959
|
-
|
|
157960
|
-
|
|
157961
|
-
|
|
157962
|
-
|
|
157963
|
-
|
|
157964
|
-
|
|
158015
|
+
if (o?.type !== "event_msg" || o.payload?.type !== "token_count") continue;
|
|
158016
|
+
const info = o.payload.info;
|
|
158017
|
+
if (!info) continue;
|
|
158018
|
+
const total = bucketsOf(info.total_token_usage);
|
|
158019
|
+
if (total) lastTotal = total;
|
|
158020
|
+
const turn = bucketsOf(info.last_token_usage);
|
|
158021
|
+
if (turn) lastTurn = turn;
|
|
158022
|
+
if (sinceMs === void 0) continue;
|
|
158023
|
+
const ts3 = typeof o.timestamp === "string" ? Date.parse(o.timestamp) : Number.NaN;
|
|
158024
|
+
if (!Number.isFinite(ts3)) continue;
|
|
158025
|
+
sawTimestamp = true;
|
|
158026
|
+
if (ts3 < sinceMs || !turn) continue;
|
|
158027
|
+
sawWindowed = true;
|
|
158028
|
+
windowed.input += turn.input;
|
|
158029
|
+
windowed.cacheRead += turn.cacheRead;
|
|
158030
|
+
windowed.cacheWrite += turn.cacheWrite;
|
|
158031
|
+
windowed.output += turn.output;
|
|
158032
|
+
}
|
|
158033
|
+
if (sinceMs !== void 0 && sawTimestamp) {
|
|
158034
|
+
return sawWindowed ? usageFromBuckets(windowed) : void 0;
|
|
158035
|
+
}
|
|
158036
|
+
if (sinceMs !== void 0 && lastTurn) return usageFromBuckets(lastTurn);
|
|
158037
|
+
return lastTotal ? usageFromBuckets(lastTotal) : void 0;
|
|
157965
158038
|
}
|
|
157966
158039
|
function parseCodexModel(lines) {
|
|
157967
158040
|
let model;
|
|
@@ -158019,8 +158092,27 @@ function listRecentRollouts(root, sinceMs) {
|
|
|
158019
158092
|
walk(root);
|
|
158020
158093
|
return found.sort((a, b2) => b2.m - a.m).map((x2) => x2.f);
|
|
158021
158094
|
}
|
|
158022
|
-
function
|
|
158023
|
-
const
|
|
158095
|
+
function findRolloutsBySessionId(root, sessionId) {
|
|
158096
|
+
const suffix = `-${sessionId}.jsonl`;
|
|
158097
|
+
const found = [];
|
|
158098
|
+
const walk = (d) => {
|
|
158099
|
+
let ents;
|
|
158100
|
+
try {
|
|
158101
|
+
ents = fs10.readdirSync(d, { withFileTypes: true });
|
|
158102
|
+
} catch {
|
|
158103
|
+
return;
|
|
158104
|
+
}
|
|
158105
|
+
for (const ent of ents) {
|
|
158106
|
+
const p2 = path11.join(d, ent.name);
|
|
158107
|
+
if (ent.isDirectory()) walk(p2);
|
|
158108
|
+
else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(suffix)) found.push(p2);
|
|
158109
|
+
}
|
|
158110
|
+
};
|
|
158111
|
+
walk(root);
|
|
158112
|
+
return found;
|
|
158113
|
+
}
|
|
158114
|
+
function telemetryFromRolloutLines(lines, sinceMs) {
|
|
158115
|
+
const usage = parseCodexTokenUsage(lines, sinceMs);
|
|
158024
158116
|
const model = parseCodexModel(lines);
|
|
158025
158117
|
const sessionId = parseCodexSessionId(lines);
|
|
158026
158118
|
return {
|
|
@@ -158049,7 +158141,7 @@ function scanCodexTelemetry(workdir, sinceMs, sessionsRoot = codexSessionsRoot()
|
|
|
158049
158141
|
continue;
|
|
158050
158142
|
}
|
|
158051
158143
|
if (meta?.type === "session_meta" && meta.payload?.cwd === workdir) {
|
|
158052
|
-
return telemetryFromRolloutLines(lines);
|
|
158144
|
+
return telemetryFromRolloutLines(lines, sinceMs);
|
|
158053
158145
|
}
|
|
158054
158146
|
}
|
|
158055
158147
|
if (preferSessionId) {
|
|
@@ -158060,9 +158152,13 @@ function scanCodexTelemetry(workdir, sinceMs, sessionsRoot = codexSessionsRoot()
|
|
|
158060
158152
|
if (!lines) continue;
|
|
158061
158153
|
const sid = parseCodexSessionId(lines);
|
|
158062
158154
|
if (byName || sid === preferSessionId) {
|
|
158063
|
-
return telemetryFromRolloutLines(lines);
|
|
158155
|
+
return telemetryFromRolloutLines(lines, sinceMs);
|
|
158064
158156
|
}
|
|
158065
158157
|
}
|
|
158158
|
+
for (const f2 of findRolloutsBySessionId(sessionsRoot, preferSessionId)) {
|
|
158159
|
+
const lines = readLines(f2);
|
|
158160
|
+
if (lines) return telemetryFromRolloutLines(lines, sinceMs);
|
|
158161
|
+
}
|
|
158066
158162
|
}
|
|
158067
158163
|
} catch {
|
|
158068
158164
|
}
|
|
@@ -158337,7 +158433,7 @@ var init_codex = __esm({
|
|
|
158337
158433
|
return this.spawnExec(job);
|
|
158338
158434
|
}
|
|
158339
158435
|
async spawnAppServer(job) {
|
|
158340
|
-
const
|
|
158436
|
+
const resolvedModel2 = job.model ?? this.opts.model;
|
|
158341
158437
|
const reasoningSummary = this.opts.reasoningSummary;
|
|
158342
158438
|
const reasoningEffort = this.opts.reasoningEffort;
|
|
158343
158439
|
return runProtocolSession(job, {
|
|
@@ -158356,7 +158452,7 @@ var init_codex = __esm({
|
|
|
158356
158452
|
params: { clientInfo: { name: "oasis-adapter", version: "0.1.0" }, capabilities: {} }
|
|
158357
158453
|
}),
|
|
158358
158454
|
async start(send, currentJob, dir, task, state) {
|
|
158359
|
-
const threadParams = currentJob.resumeRuntimeSession && currentJob.runtimeSessionId ? { threadId: currentJob.runtimeSessionId, cwd: dir, model:
|
|
158455
|
+
const threadParams = currentJob.resumeRuntimeSession && currentJob.runtimeSessionId ? { threadId: currentJob.runtimeSessionId, cwd: dir, model: resolvedModel2 ?? null, approvalPolicy: "never", sandbox: "danger-full-access" } : { cwd: dir, model: resolvedModel2 ?? null, approvalPolicy: "never", sandbox: "danger-full-access" };
|
|
158360
158456
|
let thread;
|
|
158361
158457
|
try {
|
|
158362
158458
|
thread = await send({
|
|
@@ -158366,7 +158462,7 @@ var init_codex = __esm({
|
|
|
158366
158462
|
});
|
|
158367
158463
|
} catch (error2) {
|
|
158368
158464
|
if (!(currentJob.resumeRuntimeSession && currentJob.runtimeSessionId)) throw error2;
|
|
158369
|
-
thread = await send({ jsonrpc: "2.0", method: "thread/start", params: { cwd: dir, model:
|
|
158465
|
+
thread = await send({ jsonrpc: "2.0", method: "thread/start", params: { cwd: dir, model: resolvedModel2 ?? null, approvalPolicy: "never", sandbox: "danger-full-access" } });
|
|
158370
158466
|
}
|
|
158371
158467
|
const threadId = thread.thread?.id ?? thread.id;
|
|
158372
158468
|
if (typeof threadId !== "string" || !threadId) throw new Error("codex app-server returned no thread id");
|
|
@@ -158383,7 +158479,7 @@ ${task}` : task;
|
|
|
158383
158479
|
params: {
|
|
158384
158480
|
threadId,
|
|
158385
158481
|
input: [{ type: "text", text: text5 }],
|
|
158386
|
-
...
|
|
158482
|
+
...resolvedModel2 ? { model: resolvedModel2 } : {},
|
|
158387
158483
|
...reasoningSummary ? { summary: reasoningSummary } : {},
|
|
158388
158484
|
...reasoningEffort ? { effort: reasoningEffort } : {}
|
|
158389
158485
|
}
|
|
@@ -158646,7 +158742,7 @@ ${task}` : task;
|
|
|
158646
158742
|
child.on("exit", (code2) => {
|
|
158647
158743
|
clearTimeout(timer);
|
|
158648
158744
|
const resumeSessionId = job.resumeRuntimeSession ? job.runtimeSessionId : void 0;
|
|
158649
|
-
const telemetry = scanCodexTelemetry(dir, startedAtMs, codexSessionsRoot(),
|
|
158745
|
+
const telemetry = scanCodexTelemetry(dir, startedAtMs, codexSessionsRoot(), job.runtimeSessionId);
|
|
158650
158746
|
const model = telemetry.model ?? job.model ?? this.opts.model;
|
|
158651
158747
|
const runtimeSessionId = telemetry.sessionId ?? resumeSessionId;
|
|
158652
158748
|
const sawStreamError = streamErrorMessages.length > 0;
|
|
@@ -159437,7 +159533,7 @@ ${note}` : note };
|
|
|
159437
159533
|
clientCapabilities: {}
|
|
159438
159534
|
});
|
|
159439
159535
|
const advertisedLoadSession = initRes?.agentCapabilities?.loadSession === true;
|
|
159440
|
-
const
|
|
159536
|
+
const resolvedModel2 = job.model ?? cfg.model;
|
|
159441
159537
|
let sessionId = "";
|
|
159442
159538
|
let ambiguousResume = false;
|
|
159443
159539
|
if (job.resumeRuntimeSession && job.runtimeSessionId && advertisedLoadSession) {
|
|
@@ -159447,10 +159543,10 @@ ${note}` : note };
|
|
|
159447
159543
|
cwd: dir,
|
|
159448
159544
|
sessionId: job.runtimeSessionId,
|
|
159449
159545
|
mcpServers: [],
|
|
159450
|
-
...
|
|
159546
|
+
...resolvedModel2 ? { model: resolvedModel2 } : {}
|
|
159451
159547
|
});
|
|
159452
159548
|
sessionId = extractSessionID(resumeRes);
|
|
159453
|
-
actualModel =
|
|
159549
|
+
actualModel = resolvedModel2 ?? extractCurrentModelID(resumeRes) ?? actualModel;
|
|
159454
159550
|
if (!sessionId) {
|
|
159455
159551
|
sessionId = job.runtimeSessionId;
|
|
159456
159552
|
ambiguousResume = true;
|
|
@@ -159463,22 +159559,22 @@ ${note}` : note };
|
|
|
159463
159559
|
const sessionRes = await client.request("session/new", {
|
|
159464
159560
|
cwd: dir,
|
|
159465
159561
|
mcpServers: [],
|
|
159466
|
-
...
|
|
159562
|
+
...resolvedModel2 ? { model: resolvedModel2 } : {}
|
|
159467
159563
|
});
|
|
159468
159564
|
sessionId = extractSessionID(sessionRes);
|
|
159469
|
-
actualModel =
|
|
159565
|
+
actualModel = resolvedModel2 ?? extractCurrentModelID(sessionRes) ?? actualModel;
|
|
159470
159566
|
if (!sessionId) throw new Error("session/new returned no sessionId");
|
|
159471
159567
|
}
|
|
159472
159568
|
capturedSessionId = sessionId;
|
|
159473
|
-
if (
|
|
159569
|
+
if (resolvedModel2) {
|
|
159474
159570
|
try {
|
|
159475
|
-
await client.request("session/set_model", { sessionId, modelId:
|
|
159571
|
+
await client.request("session/set_model", { sessionId, modelId: resolvedModel2 });
|
|
159476
159572
|
} catch (err) {
|
|
159477
159573
|
throw new Error(
|
|
159478
159574
|
`\u8BE5 ACP \u8FD0\u884C\u65F6\u4E0D\u652F\u6301\u5207\u6362\u6A21\u578B\uFF08session/set_model \u5931\u8D25\uFF09\uFF1A${err instanceof Error ? err.message : String(err)}`
|
|
159479
159575
|
);
|
|
159480
159576
|
}
|
|
159481
|
-
actualModel =
|
|
159577
|
+
actualModel = resolvedModel2;
|
|
159482
159578
|
}
|
|
159483
159579
|
const userText = job.systemPrompt ? `${job.systemPrompt}
|
|
159484
159580
|
|
|
@@ -159514,10 +159610,10 @@ ${task}` : task;
|
|
|
159514
159610
|
const sessionRes = await client.request("session/new", {
|
|
159515
159611
|
cwd: dir,
|
|
159516
159612
|
mcpServers: [],
|
|
159517
|
-
...
|
|
159613
|
+
...resolvedModel2 ? { model: resolvedModel2 } : {}
|
|
159518
159614
|
});
|
|
159519
159615
|
sessionId = extractSessionID(sessionRes);
|
|
159520
|
-
actualModel =
|
|
159616
|
+
actualModel = resolvedModel2 ?? extractCurrentModelID(sessionRes) ?? actualModel;
|
|
159521
159617
|
if (!sessionId) throw new Error("session/new returned no sessionId");
|
|
159522
159618
|
capturedSessionId = sessionId;
|
|
159523
159619
|
promptResult = await sendPrompt(userText);
|
|
@@ -195518,7 +195614,13 @@ function createAppJwt(appId, privateKeyPem, nowMs) {
|
|
|
195518
195614
|
const signer = (0, import_node_crypto33.createSign)("RSA-SHA256");
|
|
195519
195615
|
signer.update(`${header}.${payload}`);
|
|
195520
195616
|
signer.end();
|
|
195521
|
-
|
|
195617
|
+
try {
|
|
195618
|
+
return `${header}.${payload}.${b64url(signer.sign(privateKeyPem))}`;
|
|
195619
|
+
} catch (e) {
|
|
195620
|
+
throw new Error(
|
|
195621
|
+
"github app: \u79C1\u94A5\u89E3\u6790\u5931\u8D25\u2014\u2014\u8FD9\u4E2A .pem \u8BFB\u4E0D\u51FA\u6765\uFF08\u591A\u534A\u662F\u4E0B\u8F7D\u4E0D\u5B8C\u6574\u6216\u88AB\u6539\u8FC7\uFF09\uFF0C\u8BF7\u5728 App \u8BBE\u7F6E\u9875\u91CD\u65B0\u751F\u6210\u4E00\u628A"
|
|
195622
|
+
);
|
|
195623
|
+
}
|
|
195522
195624
|
}
|
|
195523
195625
|
async function mintInstallationToken(args, deps = {}) {
|
|
195524
195626
|
const d = { ...defaultDeps2, ...deps };
|
|
@@ -200290,7 +200392,7 @@ async function startOasisServer(opts) {
|
|
|
200290
200392
|
const discussSessions = opts.discussSessions ?? /* @__PURE__ */ new Map();
|
|
200291
200393
|
const reviewWaiters = /* @__PURE__ */ new Map();
|
|
200292
200394
|
const terminalReviews = /* @__PURE__ */ new Map();
|
|
200293
|
-
const notifyReviewResolved = (draftId, r, resume) => {
|
|
200395
|
+
const notifyReviewResolved = (draftId, r, resume, storeFor) => {
|
|
200294
200396
|
if (terminalReviews.has(draftId)) return;
|
|
200295
200397
|
terminalReviews.set(draftId, r);
|
|
200296
200398
|
if (terminalReviews.size > 512) {
|
|
@@ -200305,7 +200407,7 @@ async function startOasisServer(opts) {
|
|
|
200305
200407
|
}
|
|
200306
200408
|
if (resume?.origin) {
|
|
200307
200409
|
const needsAgentDelivery = resume.kind === "command" && !hadWaiters;
|
|
200308
|
-
void settleAuthorizationStatusLine(resume.origin, r, resume, draftId, needsAgentDelivery);
|
|
200410
|
+
void settleAuthorizationStatusLine(resume.origin, r, resume, draftId, needsAgentDelivery, storeFor);
|
|
200309
200411
|
}
|
|
200310
200412
|
};
|
|
200311
200413
|
const resolveEngine = opts.resolveEngine ?? (async () => ({ kernel: opts.kernel, oplog: opts.oplog, blobs: opts.blobs, ...opts.registry ? { registry: opts.registry } : {} }));
|
|
@@ -200382,8 +200484,13 @@ async function startOasisServer(opts) {
|
|
|
200382
200484
|
}
|
|
200383
200485
|
return void 0;
|
|
200384
200486
|
}
|
|
200385
|
-
const appendNowThroughQueue2 = async (sid, text5, clientKey, attachments) => {
|
|
200386
|
-
|
|
200487
|
+
const appendNowThroughQueue2 = async (sid, text5, clientKey, attachments, perCompanyStore) => {
|
|
200488
|
+
if (perCompanyStore === null) {
|
|
200489
|
+
throw new Error(
|
|
200490
|
+
`appendNowThroughQueue: per-company chat store unresolved (sid=${sid})`
|
|
200491
|
+
);
|
|
200492
|
+
}
|
|
200493
|
+
const store = perCompanyStore ?? opts.chatSession;
|
|
200387
200494
|
if (!store?.enqueuePendingMessage || !store.listPendingMessages || !store.removePendingMessage) {
|
|
200388
200495
|
return liveChat.append(sid, text5);
|
|
200389
200496
|
}
|
|
@@ -200425,8 +200532,8 @@ async function startOasisServer(opts) {
|
|
|
200425
200532
|
const label = ctx.effectLabel || ctx.command || "";
|
|
200426
200533
|
return approved ? `\u547D\u4EE4\u5DF2\u7531 ${by} \u6279\u51C6\u5E76\u4EE5\u5176\u540D\u4E49\u6267\u884C${label ? `\uFF1A${label}` : ""}\u3002` : `\u547D\u4EE4\u5DF2\u88AB ${by} \u9A73\u56DE${reason ? `\uFF1A${reason}` : ""}\u3002`;
|
|
200427
200534
|
};
|
|
200428
|
-
const settleAuthorizationStatusLine = async (origin, resolution, ctx, draftId, needsAgentDelivery) => {
|
|
200429
|
-
const store = opts.chatSession;
|
|
200535
|
+
const settleAuthorizationStatusLine = async (origin, resolution, ctx, draftId, needsAgentDelivery, storeFor) => {
|
|
200536
|
+
const store = storeFor ? await storeFor().catch(() => null) : opts.chatSession;
|
|
200430
200537
|
if (!store) return;
|
|
200431
200538
|
const session = await store.getSession(origin).catch(() => null);
|
|
200432
200539
|
if (!session) {
|
|
@@ -201404,7 +201511,8 @@ async function startOasisServer(opts) {
|
|
|
201404
201511
|
notifyReviewResolved(
|
|
201405
201512
|
draftId,
|
|
201406
201513
|
{ status: "approved", command, effectLabel: review.command.effectLabel, authorizedBy: actor, receipt },
|
|
201407
|
-
{ origin: review.origin, kind: "command", authorizedBy: actor, effectLabel: review.command.effectLabel, command }
|
|
201514
|
+
{ origin: review.origin, kind: "command", authorizedBy: actor, effectLabel: review.command.effectLabel, command },
|
|
201515
|
+
chatStoreNowOrNull
|
|
201408
201516
|
);
|
|
201409
201517
|
res.writeHead(200, { "content-type": "application/json" }).end(
|
|
201410
201518
|
JSON.stringify({ applied: 1, command, artifactId, draftId, draftedBy: review.proposedBy, authorizedBy: actor })
|
|
@@ -201420,7 +201528,8 @@ async function startOasisServer(opts) {
|
|
|
201420
201528
|
// 状态条要的两样也得进 resume 上下文(不能只放在 resolution 里):`effectLabel` 是改图卡的
|
|
201421
201529
|
// 「改动摘要」(= plan.reason,见 diagnosis 口径 1),`authorizedBy` 是「谁批的」。
|
|
201422
201530
|
// kind 仍传下去让三分支自行判定;改图卡到落库那一步就收手,**不**打开 chat 续跑。
|
|
201423
|
-
{ origin: review.origin, kind: review.kind ?? "graph-edit", authorizedBy: actor, effectLabel: review.plan.reason }
|
|
201531
|
+
{ origin: review.origin, kind: review.kind ?? "graph-edit", authorizedBy: actor, effectLabel: review.plan.reason },
|
|
201532
|
+
chatStoreNowOrNull
|
|
201424
201533
|
);
|
|
201425
201534
|
res.writeHead(200, { "content-type": "application/json" }).end(
|
|
201426
201535
|
JSON.stringify({ ...result, draftId, draftedBy: review.proposedBy, authorizedBy: actor })
|
|
@@ -201463,7 +201572,8 @@ async function startOasisServer(opts) {
|
|
|
201463
201572
|
...review.command?.effectLabel || review.plan.reason ? { effectLabel: review.command?.effectLabel || review.plan.reason } : {},
|
|
201464
201573
|
...review.command?.command ? { command: review.command.command } : {},
|
|
201465
201574
|
...reason !== void 0 ? { reason } : {}
|
|
201466
|
-
}
|
|
201575
|
+
},
|
|
201576
|
+
chatStoreNowOrNull
|
|
201467
201577
|
);
|
|
201468
201578
|
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ rejected: true, draftId, annotated: touched.length }));
|
|
201469
201579
|
} catch (err) {
|
|
@@ -202035,7 +202145,8 @@ async function startOasisServer(opts) {
|
|
|
202035
202145
|
}
|
|
202036
202146
|
if (req.method === "POST" && /^\/api\/chat-sessions\/[^/]+\/append$/.test(url.pathname)) {
|
|
202037
202147
|
const sid = decodeURIComponent(url.pathname.split("/")[3] ?? "");
|
|
202038
|
-
const
|
|
202148
|
+
const perCompanyStore = await chatStoreNowOrNull();
|
|
202149
|
+
const cs = await perCompanyStore?.getSession(sid).catch(() => null) ?? null;
|
|
202039
202150
|
if (!cs || cs.humanActorId !== actor) {
|
|
202040
202151
|
res.writeHead(404, { "content-type": "application/json" }).end(JSON.stringify({ error: "CHAT_SESSION_NOT_FOUND" }));
|
|
202041
202152
|
return;
|
|
@@ -202059,13 +202170,14 @@ async function startOasisServer(opts) {
|
|
|
202059
202170
|
res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ error: "EMPTY_TEXT" }));
|
|
202060
202171
|
return;
|
|
202061
202172
|
}
|
|
202062
|
-
const result = await appendNowThroughQueue2(sid, text5, clientKey, insertAttachments);
|
|
202173
|
+
const result = await appendNowThroughQueue2(sid, text5, clientKey, insertAttachments, perCompanyStore);
|
|
202063
202174
|
res.writeHead(result.accepted ? 200 : 409, { "content-type": "application/json" }).end(JSON.stringify(result));
|
|
202064
202175
|
return;
|
|
202065
202176
|
}
|
|
202066
202177
|
if (url.pathname === "/api/chat" && req.method === "POST") {
|
|
202067
202178
|
try {
|
|
202068
202179
|
const body2 = JSON.parse(rawBody);
|
|
202180
|
+
const clientSubmitId = typeof body2.clientSubmitId === "string" && body2.clientSubmitId ? body2.clientSubmitId : void 0;
|
|
202069
202181
|
if (!body2.message) throw new Error("\u7F3A\u5C11 message");
|
|
202070
202182
|
const requestedModel = typeof body2.model === "string" && body2.model.trim() ? body2.model.trim() : null;
|
|
202071
202183
|
if (requestedModel && !body2.chatSessionId) {
|
|
@@ -202286,6 +202398,14 @@ async function startOasisServer(opts) {
|
|
|
202286
202398
|
...assistantMsgId ? { messageId: assistantMsgId } : {},
|
|
202287
202399
|
log: (m2) => console.warn(m2)
|
|
202288
202400
|
});
|
|
202401
|
+
try {
|
|
202402
|
+
itemLedger.recordUserSubmission({
|
|
202403
|
+
text: persistedUserMessage,
|
|
202404
|
+
...clientSubmitId ? { clientSubmitId } : {},
|
|
202405
|
+
...effectiveAttachments.length ? { attachments: effectiveAttachments } : {}
|
|
202406
|
+
});
|
|
202407
|
+
} catch {
|
|
202408
|
+
}
|
|
202289
202409
|
const normalizedSource = typeof session.onNormalizedProviderEvent === "function" ? {
|
|
202290
202410
|
onNormalizedProviderEvent: session.onNormalizedProviderEvent.bind(session),
|
|
202291
202411
|
finishTurn: (signal) => session.finishNormalizedTurn?.(signal)
|
|
@@ -203078,7 +203198,11 @@ async function startOasisServer(opts) {
|
|
|
203078
203198
|
try {
|
|
203079
203199
|
meta = await fetchAppSelfMetadata({ appId, privateKeyPem });
|
|
203080
203200
|
} catch (e) {
|
|
203081
|
-
|
|
203201
|
+
const msg = String(e);
|
|
203202
|
+
bad(
|
|
203203
|
+
400,
|
|
203204
|
+
/HTTP 401/.test(msg) ? "App ID \u4E0E\u79C1\u94A5\u5BF9\u4E0D\u4E0A\u2014\u2014\u786E\u8BA4 App ID \u6284\u81EA\u540C\u4E00\u4E2A App \u7684\u8BBE\u7F6E\u9875" : /私钥解析失败/.test(msg) ? msg.replace(/^Error:\s*/, "").replace(/^github app:\s*/, "") : `GitHub \u62D2\u7EDD\u4E86\u8FD9\u5BF9\u51ED\u636E\uFF1A${msg}`
|
|
203205
|
+
);
|
|
203082
203206
|
return;
|
|
203083
203207
|
}
|
|
203084
203208
|
const excess = excessAppPermissions(meta.permissions);
|
|
@@ -215077,14 +215201,19 @@ function lookupInMap(map, prefixKeys, candidates) {
|
|
|
215077
215201
|
if (!prefix) return null;
|
|
215078
215202
|
return map instanceof Map ? map.get(prefix) ?? null : map[prefix] ?? null;
|
|
215079
215203
|
}
|
|
215204
|
+
function stripBracketTier(model) {
|
|
215205
|
+
return model.replace(/\[[^\]]*\]/g, "").trim();
|
|
215206
|
+
}
|
|
215080
215207
|
function modelCandidates(model) {
|
|
215081
215208
|
const normalized4 = model.trim().toLowerCase();
|
|
215082
215209
|
if (!normalized4) return [];
|
|
215083
|
-
|
|
215210
|
+
const base = [
|
|
215084
215211
|
normalized4,
|
|
215085
215212
|
normalized4.includes(":") ? normalized4.slice(normalized4.lastIndexOf(":") + 1) : "",
|
|
215086
215213
|
normalized4.includes("/") ? normalized4.slice(normalized4.lastIndexOf("/") + 1) : ""
|
|
215087
215214
|
].filter(Boolean);
|
|
215215
|
+
const stripped = base.map(stripBracketTier).filter((m2) => m2 && !base.includes(m2));
|
|
215216
|
+
return [...base, ...new Set(stripped)];
|
|
215088
215217
|
}
|
|
215089
215218
|
function setModelPriceCacheLoader(loader) {
|
|
215090
215219
|
cacheLoader = loader;
|
|
@@ -215154,10 +215283,11 @@ function displayCostUsdMicros(model, usage) {
|
|
|
215154
215283
|
if (estimated.currency === "USD") return estimated.micros;
|
|
215155
215284
|
return Math.round(estimated.micros / DISPLAY_CNY_PER_USD);
|
|
215156
215285
|
}
|
|
215157
|
-
var FOREIGN_MODEL_MARKUP, usd, cny, MODEL_PRICES, STATIC_PREFIX_PRICES, CACHE_TTL_MS2, dbPrices, dbPrefixKeys, cacheLoadedAt, cacheLoader, cacheRefreshInFlight
|
|
215286
|
+
var FOREIGN_MODEL_MARKUP, usd, cny, MODEL_PRICES, STATIC_PREFIX_PRICES, CACHE_TTL_MS2, dbPrices, dbPrefixKeys, cacheLoadedAt, cacheLoader, cacheRefreshInFlight;
|
|
215158
215287
|
var init_model_pricing = __esm({
|
|
215159
215288
|
"../server/src/domains/actors/model-pricing.ts"() {
|
|
215160
215289
|
"use strict";
|
|
215290
|
+
init_src();
|
|
215161
215291
|
FOREIGN_MODEL_MARKUP = 1.08;
|
|
215162
215292
|
usd = (inputPerMillion, outputPerMillion, cachedInputPerMillion) => ({
|
|
215163
215293
|
currency: "USD",
|
|
@@ -215269,7 +215399,80 @@ var init_model_pricing = __esm({
|
|
|
215269
215399
|
cacheLoadedAt = 0;
|
|
215270
215400
|
cacheLoader = null;
|
|
215271
215401
|
cacheRefreshInFlight = null;
|
|
215272
|
-
|
|
215402
|
+
}
|
|
215403
|
+
});
|
|
215404
|
+
|
|
215405
|
+
// ../server/src/domains/usage/accounting.ts
|
|
215406
|
+
function nonNegative(v2) {
|
|
215407
|
+
return Math.max(v2 ?? 0, 0);
|
|
215408
|
+
}
|
|
215409
|
+
function resolvedModel(model) {
|
|
215410
|
+
const trimmed = model?.trim();
|
|
215411
|
+
return trimmed ? trimmed : null;
|
|
215412
|
+
}
|
|
215413
|
+
function splitByWeight(total, w2) {
|
|
215414
|
+
const sum = w2.input + w2.cache + w2.output;
|
|
215415
|
+
if (total === 0) return { input: 0, cache: 0, output: 0 };
|
|
215416
|
+
if (sum <= 0) return { input: 0, cache: 0, output: total };
|
|
215417
|
+
const input = Math.round(total * w2.input / sum);
|
|
215418
|
+
const cache = Math.round(total * w2.cache / sum);
|
|
215419
|
+
return { input, cache, output: total - input - cache };
|
|
215420
|
+
}
|
|
215421
|
+
function toDisplayUsd(currency, micros) {
|
|
215422
|
+
return currency === "USD" ? micros : Math.round(micros / DISPLAY_CNY_PER_USD);
|
|
215423
|
+
}
|
|
215424
|
+
function accountUsage(model, usage) {
|
|
215425
|
+
const resolved = resolvedModel(model);
|
|
215426
|
+
if (!resolved || !usage) return null;
|
|
215427
|
+
const input = nonNegative(usage.inputTokens);
|
|
215428
|
+
const output = nonNegative(usage.outputTokens);
|
|
215429
|
+
const cache = nonNegative(usage.cacheReadTokens) + nonNegative(usage.cacheCreationTokens);
|
|
215430
|
+
const tokens = { input, cache, output, total: input + cache + output };
|
|
215431
|
+
const estimated = estimateUsageCostBreakdown(resolved, usage);
|
|
215432
|
+
const weights = estimated ? { input: estimated.inputMicros, cache: estimated.cacheMicros, output: estimated.outputMicros } : null;
|
|
215433
|
+
const reported = Math.max(usage.costUsdMicros ?? 0, 0);
|
|
215434
|
+
if (reported > 0) {
|
|
215435
|
+
const parts = weights && estimated?.currency === "USD" ? splitByWeight(reported, weights) : { input: 0, cache: 0, output: reported };
|
|
215436
|
+
return {
|
|
215437
|
+
tokens,
|
|
215438
|
+
currency: "USD",
|
|
215439
|
+
amountMicros: reported,
|
|
215440
|
+
parts,
|
|
215441
|
+
displayUsdMicros: reported,
|
|
215442
|
+
displayParts: parts,
|
|
215443
|
+
source: "reported"
|
|
215444
|
+
};
|
|
215445
|
+
}
|
|
215446
|
+
if (estimated && weights) {
|
|
215447
|
+
const amount = weights.input + weights.cache + weights.output;
|
|
215448
|
+
const displayUsdMicros = toDisplayUsd(estimated.currency, amount);
|
|
215449
|
+
return {
|
|
215450
|
+
tokens,
|
|
215451
|
+
currency: estimated.currency,
|
|
215452
|
+
amountMicros: amount,
|
|
215453
|
+
parts: weights,
|
|
215454
|
+
displayUsdMicros,
|
|
215455
|
+
displayParts: estimated.currency === "USD" ? weights : splitByWeight(displayUsdMicros, weights),
|
|
215456
|
+
source: "estimated"
|
|
215457
|
+
};
|
|
215458
|
+
}
|
|
215459
|
+
return {
|
|
215460
|
+
tokens,
|
|
215461
|
+
currency: "USD",
|
|
215462
|
+
amountMicros: 0,
|
|
215463
|
+
parts: { input: 0, cache: 0, output: 0 },
|
|
215464
|
+
displayUsdMicros: 0,
|
|
215465
|
+
displayParts: { input: 0, cache: 0, output: 0 },
|
|
215466
|
+
source: "unpriced"
|
|
215467
|
+
};
|
|
215468
|
+
}
|
|
215469
|
+
function isUnpriced(account) {
|
|
215470
|
+
return account.source === "unpriced" && account.tokens.total > 0;
|
|
215471
|
+
}
|
|
215472
|
+
var init_accounting = __esm({
|
|
215473
|
+
"../server/src/domains/usage/accounting.ts"() {
|
|
215474
|
+
"use strict";
|
|
215475
|
+
init_model_pricing();
|
|
215273
215476
|
}
|
|
215274
215477
|
});
|
|
215275
215478
|
|
|
@@ -215284,55 +215487,44 @@ function emptyCostBreakdown() {
|
|
|
215284
215487
|
outputCnyMicros: 0
|
|
215285
215488
|
};
|
|
215286
215489
|
}
|
|
215287
|
-
function
|
|
215288
|
-
|
|
215289
|
-
|
|
215290
|
-
}
|
|
215291
|
-
|
|
215292
|
-
|
|
215293
|
-
|
|
215294
|
-
|
|
215295
|
-
|
|
215490
|
+
function emptySummary() {
|
|
215491
|
+
return {
|
|
215492
|
+
tokenWeek: 0,
|
|
215493
|
+
tokenWeekBreakdown: { input: 0, cache: 0, output: 0 },
|
|
215494
|
+
costWeekUsdMicros: 0,
|
|
215495
|
+
costWeekCnyMicros: 0,
|
|
215496
|
+
costWeekBreakdown: emptyCostBreakdown(),
|
|
215497
|
+
unpricedModels: []
|
|
215498
|
+
};
|
|
215499
|
+
}
|
|
215500
|
+
function addAccount(target, account) {
|
|
215501
|
+
target.tokenWeekBreakdown.input += account.tokens.input;
|
|
215502
|
+
target.tokenWeekBreakdown.cache += account.tokens.cache;
|
|
215503
|
+
target.tokenWeekBreakdown.output += account.tokens.output;
|
|
215504
|
+
target.tokenWeek += account.tokens.total;
|
|
215505
|
+
if (account.currency === "USD") {
|
|
215506
|
+
target.costWeekUsdMicros += account.amountMicros;
|
|
215507
|
+
target.costWeekBreakdown.inputUsdMicros += account.parts.input;
|
|
215508
|
+
target.costWeekBreakdown.cacheUsdMicros += account.parts.cache;
|
|
215509
|
+
target.costWeekBreakdown.outputUsdMicros += account.parts.output;
|
|
215296
215510
|
} else {
|
|
215297
|
-
target.
|
|
215298
|
-
target.
|
|
215299
|
-
target.
|
|
215300
|
-
|
|
215301
|
-
}
|
|
215302
|
-
function addAlignedCost(target, totals, model, usage) {
|
|
215303
|
-
const storedCost = Math.max(usage.costUsdMicros ?? 0, 0);
|
|
215304
|
-
const estimated = estimateUsageCostBreakdown(model, usage);
|
|
215305
|
-
if (storedCost > 0) {
|
|
215306
|
-
if (estimated && estimated.currency === "USD") {
|
|
215307
|
-
const estTotal = estimated.inputMicros + estimated.cacheMicros + estimated.outputMicros;
|
|
215308
|
-
let inputMicros = 0;
|
|
215309
|
-
let cacheMicros = 0;
|
|
215310
|
-
let outputMicros = storedCost;
|
|
215311
|
-
if (estTotal > 0) {
|
|
215312
|
-
const scale = storedCost / estTotal;
|
|
215313
|
-
inputMicros = Math.round(estimated.inputMicros * scale);
|
|
215314
|
-
cacheMicros = Math.round(estimated.cacheMicros * scale);
|
|
215315
|
-
outputMicros = storedCost - inputMicros - cacheMicros;
|
|
215316
|
-
}
|
|
215317
|
-
addBreakdownParts(target, "USD", { inputMicros, cacheMicros, outputMicros });
|
|
215318
|
-
} else {
|
|
215319
|
-
addBreakdownParts(target, "USD", { inputMicros: 0, cacheMicros: 0, outputMicros: storedCost });
|
|
215320
|
-
}
|
|
215321
|
-
totals.usd += storedCost;
|
|
215322
|
-
return true;
|
|
215511
|
+
target.costWeekCnyMicros += account.amountMicros;
|
|
215512
|
+
target.costWeekBreakdown.inputCnyMicros += account.parts.input;
|
|
215513
|
+
target.costWeekBreakdown.cacheCnyMicros += account.parts.cache;
|
|
215514
|
+
target.costWeekBreakdown.outputCnyMicros += account.parts.output;
|
|
215323
215515
|
}
|
|
215324
|
-
|
|
215325
|
-
|
|
215326
|
-
|
|
215327
|
-
|
|
215328
|
-
|
|
215329
|
-
|
|
215330
|
-
|
|
215331
|
-
|
|
215332
|
-
|
|
215333
|
-
return true;
|
|
215516
|
+
}
|
|
215517
|
+
function summarize2(rows) {
|
|
215518
|
+
const out = emptySummary();
|
|
215519
|
+
const unpriced = /* @__PURE__ */ new Set();
|
|
215520
|
+
for (const row of rows) {
|
|
215521
|
+
const account = accountUsage(row.model, row.usage);
|
|
215522
|
+
if (!account) continue;
|
|
215523
|
+
addAccount(out, account);
|
|
215524
|
+
if (isUnpriced(account)) unpriced.add(resolvedModel(row.model));
|
|
215334
215525
|
}
|
|
215335
|
-
|
|
215526
|
+
out.unpricedModels = [...unpriced].sort();
|
|
215527
|
+
return out;
|
|
215336
215528
|
}
|
|
215337
215529
|
async function actorStats(actorId, opts = {}) {
|
|
215338
215530
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
@@ -215366,118 +215558,43 @@ async function listWeeklyRuns(trace, actorId, from, to) {
|
|
|
215366
215558
|
return out;
|
|
215367
215559
|
}
|
|
215368
215560
|
function summarizeWeeklyRuns(runs) {
|
|
215369
|
-
|
|
215370
|
-
let cache = 0;
|
|
215371
|
-
let output = 0;
|
|
215372
|
-
const totals = { usd: 0, cny: 0 };
|
|
215373
|
-
const costWeekBreakdown = emptyCostBreakdown();
|
|
215374
|
-
const unpriced = /* @__PURE__ */ new Set();
|
|
215375
|
-
for (const run of runs) {
|
|
215376
|
-
const model = resolvedModel(run.effectiveModel);
|
|
215377
|
-
if (!model) continue;
|
|
215378
|
-
const usage = run.usage;
|
|
215379
|
-
if (!usage) continue;
|
|
215380
|
-
const inputTokens = Math.max(usage.inputTokens ?? 0, 0);
|
|
215381
|
-
const outputTokens = Math.max(usage.outputTokens ?? 0, 0);
|
|
215382
|
-
const cacheCreation = Math.max(usage.cacheCreationTokens ?? 0, 0);
|
|
215383
|
-
const cacheRead = Math.max(usage.cacheReadTokens ?? 0, 0);
|
|
215384
|
-
input += inputTokens;
|
|
215385
|
-
cache += cacheCreation + cacheRead;
|
|
215386
|
-
output += outputTokens;
|
|
215387
|
-
const priced = addAlignedCost(costWeekBreakdown, totals, model, usage);
|
|
215388
|
-
if (!priced && inputTokens + outputTokens + cacheCreation + cacheRead > 0) {
|
|
215389
|
-
unpriced.add(model);
|
|
215390
|
-
}
|
|
215391
|
-
}
|
|
215392
|
-
return {
|
|
215393
|
-
tokenWeek: input + cache + output,
|
|
215394
|
-
tokenWeekBreakdown: { input, cache, output },
|
|
215395
|
-
costWeekUsdMicros: totals.usd,
|
|
215396
|
-
costWeekCnyMicros: totals.cny,
|
|
215397
|
-
costWeekBreakdown,
|
|
215398
|
-
unpricedModels: [...unpriced].sort()
|
|
215399
|
-
};
|
|
215561
|
+
return summarize2(runs.map((run) => ({ model: run.effectiveModel, usage: run.usage })));
|
|
215400
215562
|
}
|
|
215401
215563
|
function summarizeWeeklyUsage(rows) {
|
|
215402
|
-
|
|
215403
|
-
let cache = 0;
|
|
215404
|
-
let output = 0;
|
|
215405
|
-
const totals = { usd: 0, cny: 0 };
|
|
215406
|
-
const costWeekBreakdown = emptyCostBreakdown();
|
|
215407
|
-
const unpriced = /* @__PURE__ */ new Set();
|
|
215408
|
-
for (const row of rows) {
|
|
215409
|
-
const model = resolvedModel(row.effectiveModel);
|
|
215410
|
-
if (!model) continue;
|
|
215411
|
-
const inputTokens = Math.max(row.inputTokens, 0);
|
|
215412
|
-
const outputTokens = Math.max(row.outputTokens, 0);
|
|
215413
|
-
const cacheCreation = Math.max(row.cacheCreationTokens, 0);
|
|
215414
|
-
const cacheRead = Math.max(row.cacheReadTokens, 0);
|
|
215415
|
-
input += inputTokens;
|
|
215416
|
-
cache += cacheCreation + cacheRead;
|
|
215417
|
-
output += outputTokens;
|
|
215418
|
-
const priced = addAlignedCost(costWeekBreakdown, totals, model, row);
|
|
215419
|
-
if (!priced && inputTokens + outputTokens + cacheCreation + cacheRead > 0) {
|
|
215420
|
-
unpriced.add(model);
|
|
215421
|
-
}
|
|
215422
|
-
}
|
|
215423
|
-
return {
|
|
215424
|
-
tokenWeek: input + cache + output,
|
|
215425
|
-
tokenWeekBreakdown: { input, cache, output },
|
|
215426
|
-
costWeekUsdMicros: totals.usd,
|
|
215427
|
-
costWeekCnyMicros: totals.cny,
|
|
215428
|
-
costWeekBreakdown,
|
|
215429
|
-
unpricedModels: [...unpriced].sort()
|
|
215430
|
-
};
|
|
215564
|
+
return summarize2(rows.map((row) => ({ model: row.effectiveModel, usage: row })));
|
|
215431
215565
|
}
|
|
215432
215566
|
var init_stats = __esm({
|
|
215433
215567
|
"../server/src/domains/actors/stats.ts"() {
|
|
215434
215568
|
"use strict";
|
|
215435
|
-
|
|
215569
|
+
init_accounting();
|
|
215436
215570
|
}
|
|
215437
215571
|
});
|
|
215438
215572
|
|
|
215439
215573
|
// ../server/src/domains/actors/list-usage.ts
|
|
215440
|
-
function resolvedModel2(model) {
|
|
215441
|
-
const m2 = (model ?? "").trim();
|
|
215442
|
-
return m2 === "" ? null : m2;
|
|
215443
|
-
}
|
|
215444
215574
|
function aggregateUsageByActor(runs) {
|
|
215445
215575
|
const out = /* @__PURE__ */ new Map();
|
|
215446
215576
|
const unpriced = /* @__PURE__ */ new Map();
|
|
215447
215577
|
for (const run of runs) {
|
|
215448
|
-
const
|
|
215449
|
-
if (!
|
|
215450
|
-
const usage = run.usage;
|
|
215451
|
-
if (!usage) continue;
|
|
215452
|
-
const inputTokens = Math.max(usage.inputTokens ?? 0, 0);
|
|
215453
|
-
const outputTokens = Math.max(usage.outputTokens ?? 0, 0);
|
|
215454
|
-
const cacheCreation = Math.max(usage.cacheCreationTokens ?? 0, 0);
|
|
215455
|
-
const cacheRead = Math.max(usage.cacheReadTokens ?? 0, 0);
|
|
215456
|
-
const cacheTokens = cacheCreation + cacheRead;
|
|
215578
|
+
const account = accountUsage(run.effectiveModel, run.usage);
|
|
215579
|
+
if (!account) continue;
|
|
215457
215580
|
let acc = out.get(run.actorId);
|
|
215458
215581
|
if (!acc) {
|
|
215459
215582
|
acc = emptyActorUsageWeek();
|
|
215460
215583
|
out.set(run.actorId, acc);
|
|
215461
215584
|
}
|
|
215462
|
-
acc.tokenWeekBreakdown.input +=
|
|
215463
|
-
acc.tokenWeekBreakdown.cache +=
|
|
215464
|
-
acc.tokenWeekBreakdown.output +=
|
|
215465
|
-
acc.tokenWeek +=
|
|
215466
|
-
|
|
215467
|
-
|
|
215468
|
-
if (
|
|
215469
|
-
acc.costWeekUsdMicros += stored;
|
|
215470
|
-
} else if (estimated) {
|
|
215471
|
-
const total = estimated.inputMicros + estimated.cacheMicros + estimated.outputMicros;
|
|
215472
|
-
if (estimated.currency === "USD") acc.costWeekUsdMicros += total;
|
|
215473
|
-
else acc.costWeekCnyMicros += total;
|
|
215474
|
-
} else if (inputTokens + outputTokens + cacheTokens > 0) {
|
|
215585
|
+
acc.tokenWeekBreakdown.input += account.tokens.input;
|
|
215586
|
+
acc.tokenWeekBreakdown.cache += account.tokens.cache;
|
|
215587
|
+
acc.tokenWeekBreakdown.output += account.tokens.output;
|
|
215588
|
+
acc.tokenWeek += account.tokens.total;
|
|
215589
|
+
if (account.currency === "USD") acc.costWeekUsdMicros += account.amountMicros;
|
|
215590
|
+
else acc.costWeekCnyMicros += account.amountMicros;
|
|
215591
|
+
if (isUnpriced(account)) {
|
|
215475
215592
|
let set = unpriced.get(run.actorId);
|
|
215476
215593
|
if (!set) {
|
|
215477
215594
|
set = /* @__PURE__ */ new Set();
|
|
215478
215595
|
unpriced.set(run.actorId, set);
|
|
215479
215596
|
}
|
|
215480
|
-
set.add(
|
|
215597
|
+
set.add(resolvedModel(run.effectiveModel));
|
|
215481
215598
|
}
|
|
215482
215599
|
}
|
|
215483
215600
|
for (const [actorId, models] of unpriced) {
|
|
@@ -215502,7 +215619,7 @@ var emptyActorUsageWeek;
|
|
|
215502
215619
|
var init_list_usage = __esm({
|
|
215503
215620
|
"../server/src/domains/actors/list-usage.ts"() {
|
|
215504
215621
|
"use strict";
|
|
215505
|
-
|
|
215622
|
+
init_accounting();
|
|
215506
215623
|
emptyActorUsageWeek = () => ({
|
|
215507
215624
|
tokenWeek: 0,
|
|
215508
215625
|
tokenWeekBreakdown: { input: 0, cache: 0, output: 0 },
|
|
@@ -215626,7 +215743,7 @@ function eventToEntry(rec) {
|
|
|
215626
215743
|
...s2
|
|
215627
215744
|
};
|
|
215628
215745
|
}
|
|
215629
|
-
function
|
|
215746
|
+
function summarize3(kind, payload) {
|
|
215630
215747
|
const p2 = payload;
|
|
215631
215748
|
switch (kind) {
|
|
215632
215749
|
case "report_gap":
|
|
@@ -215686,7 +215803,7 @@ async function actorActivity(source, actorId, limit = 50) {
|
|
|
215686
215803
|
for await (const { op } of source.oplog.readAll()) {
|
|
215687
215804
|
if (op.actor !== actorId) continue;
|
|
215688
215805
|
total++;
|
|
215689
|
-
matched.push({ at: op.timestamp, kind: op.kind, target: op.target, ...
|
|
215806
|
+
matched.push({ at: op.timestamp, kind: op.kind, target: op.target, ...summarize3(op.kind, op.payload) });
|
|
215690
215807
|
if (matched.length > capped) matched.shift();
|
|
215691
215808
|
}
|
|
215692
215809
|
} else {
|
|
@@ -222733,26 +222850,15 @@ function emptyUsage() {
|
|
|
222733
222850
|
};
|
|
222734
222851
|
}
|
|
222735
222852
|
function usageOf(run) {
|
|
222736
|
-
|
|
222737
|
-
|
|
222738
|
-
const cache = Math.max(run.usage.cacheReadTokens ?? 0, 0) + Math.max(run.usage.cacheCreationTokens ?? 0, 0);
|
|
222739
|
-
const output = Math.max(run.usage.outputTokens ?? 0, 0);
|
|
222740
|
-
const tokens = input + cache + output;
|
|
222741
|
-
const costUsdMicros = Math.max(run.usage.costUsdMicros ?? 0, 0);
|
|
222742
|
-
const denominator = tokens || 1;
|
|
222743
|
-
const inputCost = Math.round(costUsdMicros * input / denominator);
|
|
222744
|
-
const cacheCost = Math.round(costUsdMicros * cache / denominator);
|
|
222853
|
+
const account = accountUsage(run.effectiveModel, run.usage);
|
|
222854
|
+
if (!account) return null;
|
|
222745
222855
|
return {
|
|
222746
|
-
input,
|
|
222747
|
-
cache,
|
|
222748
|
-
output,
|
|
222749
|
-
tokens,
|
|
222750
|
-
costUsdMicros,
|
|
222751
|
-
costParts: {
|
|
222752
|
-
input: inputCost,
|
|
222753
|
-
cache: cacheCost,
|
|
222754
|
-
output: costUsdMicros - inputCost - cacheCost
|
|
222755
|
-
}
|
|
222856
|
+
input: account.tokens.input,
|
|
222857
|
+
cache: account.tokens.cache,
|
|
222858
|
+
output: account.tokens.output,
|
|
222859
|
+
tokens: account.tokens.total,
|
|
222860
|
+
costUsdMicros: account.displayUsdMicros,
|
|
222861
|
+
costParts: { ...account.displayParts }
|
|
222756
222862
|
};
|
|
222757
222863
|
}
|
|
222758
222864
|
function addUsage(target, addition) {
|
|
@@ -222805,6 +222911,7 @@ function buildOrganizationUsageSummary(input) {
|
|
|
222805
222911
|
const rows = /* @__PURE__ */ new Map();
|
|
222806
222912
|
const total = emptyUsage();
|
|
222807
222913
|
let unpricedRunCount = 0;
|
|
222914
|
+
const unpricedModels = /* @__PURE__ */ new Set();
|
|
222808
222915
|
const orgEmployees = /* @__PURE__ */ new Map();
|
|
222809
222916
|
const orgEmployeeWorkorders = /* @__PURE__ */ new Map();
|
|
222810
222917
|
const runtimeTotals = /* @__PURE__ */ new Map();
|
|
@@ -222820,6 +222927,8 @@ function buildOrganizationUsageSummary(input) {
|
|
|
222820
222927
|
unpricedRunCount += 1;
|
|
222821
222928
|
continue;
|
|
222822
222929
|
}
|
|
222930
|
+
const account = accountUsage(run.effectiveModel, run.usage);
|
|
222931
|
+
if (account && isUnpriced(account)) unpricedModels.add(resolvedModel(run.effectiveModel));
|
|
222823
222932
|
addUsage(total, usage);
|
|
222824
222933
|
const key = bucketKey(formatter, run.startedAt, input.bucketKind);
|
|
222825
222934
|
if (key) {
|
|
@@ -223012,7 +223121,8 @@ function buildOrganizationUsageSummary(input) {
|
|
|
223012
223121
|
workorders: normalizedWorkorderRows,
|
|
223013
223122
|
employees: employeeRows,
|
|
223014
223123
|
runtimes: runtimeRows,
|
|
223015
|
-
unpricedRunCount
|
|
223124
|
+
unpricedRunCount,
|
|
223125
|
+
unpricedModels: [...unpricedModels].sort()
|
|
223016
223126
|
};
|
|
223017
223127
|
}
|
|
223018
223128
|
var UNASSIGNED_ID;
|
|
@@ -223020,6 +223130,7 @@ var init_organization_usage = __esm({
|
|
|
223020
223130
|
"../server/src/domains/collab/organization-usage.ts"() {
|
|
223021
223131
|
"use strict";
|
|
223022
223132
|
init_workorders();
|
|
223133
|
+
init_accounting();
|
|
223023
223134
|
UNASSIGNED_ID = "__unassigned__";
|
|
223024
223135
|
}
|
|
223025
223136
|
});
|
|
@@ -225361,8 +225472,6 @@ function renderCoordinatorView(view, taskBackground) {
|
|
|
225361
225472
|
"unavailable"
|
|
225362
225473
|
];
|
|
225363
225474
|
const attemptStates = [
|
|
225364
|
-
"waiting",
|
|
225365
|
-
"ready",
|
|
225366
225475
|
"running",
|
|
225367
225476
|
"stalled",
|
|
225368
225477
|
"succeeded",
|
|
@@ -225374,7 +225483,12 @@ function renderCoordinatorView(view, taskBackground) {
|
|
|
225374
225483
|
workStates,
|
|
225375
225484
|
(state) => view.nodes.filter((node2) => node2.work.state === state).length
|
|
225376
225485
|
);
|
|
225377
|
-
const
|
|
225486
|
+
const noAttemptCount = view.nodes.filter((node2) => node2.nodeState === null).length;
|
|
225487
|
+
const attemptCounts = visibleCounts(attemptStates, (state) => view.progress[state]);
|
|
225488
|
+
const attemptProgress = [
|
|
225489
|
+
attemptCounts === "none" ? "" : attemptCounts,
|
|
225490
|
+
noAttemptCount > 0 ? `\u65E0 attempt \u8BB0\u5F55 ${noAttemptCount}` : ""
|
|
225491
|
+
].filter(Boolean).join("; ") || "none";
|
|
225378
225492
|
const lines = [
|
|
225379
225493
|
"# Coordinator View",
|
|
225380
225494
|
"",
|
|
@@ -225390,12 +225504,16 @@ function renderCoordinatorView(view, taskBackground) {
|
|
|
225390
225504
|
"## Nodes"
|
|
225391
225505
|
];
|
|
225392
225506
|
for (const node2 of view.nodes) {
|
|
225507
|
+
lines.push(`### ${node2.title} (${node2.nodeId})`);
|
|
225508
|
+
if (node2.sealed) lines.push(`- \u8282\u70B9: sealed(${node2.sealed.reason})`);
|
|
225393
225509
|
lines.push(
|
|
225394
|
-
`### ${node2.title} (${node2.nodeId})`,
|
|
225395
225510
|
`- Work: ${node2.work.state}; Version: ${renderWorkVersion(node2.work)}`,
|
|
225396
|
-
|
|
225511
|
+
// nodeState === null 说的是「账本里没有这条记录」,不是「没在跑」——它和上面那行 Work 状态
|
|
225512
|
+
// 必须并排出现:线上确有 Work running 而执行账本零 attempt 行的工单(ws:wo-9dc06583)。
|
|
225513
|
+
node2.nodeState === null ? "- Attempt: \u6267\u884C\u8D26\u672C\u4E2D\u65E0 attempt \u8BB0\u5F55" : `- Attempt: ${node2.status}; continuity: ${node2.nodeState}; number: ${node2.attemptNo || "none"}`,
|
|
225397
225514
|
`- Actor: ${node2.actorId ?? "unassigned"}; role: ${node2.role ?? "unassigned"}`
|
|
225398
225515
|
);
|
|
225516
|
+
if (node2.dependsOn.length > 0) lines.push(`- Depends on: ${node2.dependsOn.join(", ")}`);
|
|
225399
225517
|
if (node2.conclusion?.trim()) lines.push(`- Conclusion: ${node2.conclusion.trim()}`);
|
|
225400
225518
|
if (node2.recoverySource) {
|
|
225401
225519
|
const source = node2.recoverySource;
|
|
@@ -225413,7 +225531,6 @@ function renderCoordinatorView(view, taskBackground) {
|
|
|
225413
225531
|
}
|
|
225414
225532
|
for (const risk of source.recoveryHandoff?.risks ?? []) lines.push(` - Recovery risk: ${risk}`);
|
|
225415
225533
|
}
|
|
225416
|
-
if (node2.blockedBy.length > 0) lines.push(`- Blocked by: ${node2.blockedBy.join(", ")}`);
|
|
225417
225534
|
if (node2.progress) {
|
|
225418
225535
|
lines.push(`- Latest checkpoint: ${node2.progress.recoverability} at ${node2.progress.lastCheckpointAt}`);
|
|
225419
225536
|
for (const step of node2.progress.pendingSteps) lines.push(` - Pending: ${step}`);
|
|
@@ -225430,7 +225547,12 @@ function renderCoordinatorView(view, taskBackground) {
|
|
|
225430
225547
|
...node2.unresolvedIssues.map((value2) => `[unresolved] ${value2}`),
|
|
225431
225548
|
...node2.risks.map((value2) => `[risk] ${value2}`),
|
|
225432
225549
|
...node2.verificationGaps.map((value2) => `[verification] ${value2}`),
|
|
225433
|
-
|
|
225550
|
+
// [next] 只给 Agent 亲手写的下一步。system_reconstructed 的 nextActions 是系统从
|
|
225551
|
+
// checkpoint.pendingSteps 抄回来的残留:节点已经跑成功了,那几条早就做完,却和 Agent 的计划
|
|
225552
|
+
// 长得一模一样(ws:wo-ecce337b 的 smoke 节点五条「下一步」全是这么来的),协调者会当成还有活干。
|
|
225553
|
+
// 同一道 handoffProducer === "agent" 判断,上面的 Technical notes 本来就有,这里之前漏了。
|
|
225554
|
+
// 真正在跑/卡住的节点不会因此丢信息:那些 pendingSteps 由 node.progress 走 `- Pending:` 出。
|
|
225555
|
+
...node2.handoffProducer === "agent" ? node2.nextActions.map((value2) => `[next] ${value2}`) : []
|
|
225434
225556
|
];
|
|
225435
225557
|
if (openItems.length > 0) {
|
|
225436
225558
|
lines.push("- Open items:");
|
|
@@ -225438,10 +225560,7 @@ function renderCoordinatorView(view, taskBackground) {
|
|
|
225438
225560
|
}
|
|
225439
225561
|
lines.push("");
|
|
225440
225562
|
}
|
|
225441
|
-
lines.push("##
|
|
225442
|
-
if (view.dependencyBlocks.length === 0) lines.push("- None");
|
|
225443
|
-
for (const block of view.dependencyBlocks) lines.push(`- ${block.nodeId} blocks: ${block.blocks.join(", ")}`);
|
|
225444
|
-
lines.push("", "## Attention items");
|
|
225563
|
+
lines.push("## Attention items");
|
|
225445
225564
|
const unavailableWorkCount = view.nodes.filter((node2) => node2.work.state === "unavailable").length;
|
|
225446
225565
|
const workAttention = view.nodes.filter((node2) => node2.work.state === "failed" || node2.work.state === "dead" || node2.work.state === "retry");
|
|
225447
225566
|
if (unavailableWorkCount > 0) {
|
|
@@ -225452,8 +225571,7 @@ function renderCoordinatorView(view, taskBackground) {
|
|
|
225452
225571
|
`- Work ${node2.nodeId} [${node2.work.state}]: current head ${node2.work.currentWorkId ?? "none"}; delivered ${node2.work.acceptedWorkId ?? "none"}.`
|
|
225453
225572
|
);
|
|
225454
225573
|
}
|
|
225455
|
-
if (unavailableWorkCount === 0 && workAttention.length === 0
|
|
225456
|
-
for (const item of view.todo) lines.push(`- Attempt P${item.priority} ${item.nodeId} [${item.nodeState}]: ${item.action}`);
|
|
225574
|
+
if (unavailableWorkCount === 0 && workAttention.length === 0) lines.push("- None");
|
|
225457
225575
|
return `${lines.join("\n")}
|
|
225458
225576
|
`;
|
|
225459
225577
|
}
|
|
@@ -225541,50 +225659,18 @@ function stateFromAttempt(attempt, handoff, checkpoint, now, stalledAfterMs, ope
|
|
|
225541
225659
|
if (attempt.status === "no-output") return handoff?.unresolvedIssues.length ? "blocked" : "no_change";
|
|
225542
225660
|
return "failed";
|
|
225543
225661
|
}
|
|
225544
|
-
|
|
225545
|
-
const out = /* @__PURE__ */ new Map();
|
|
225546
|
-
for (const node2 of nodes) for (const upstream of node2.dependsOn) out.set(upstream, [...out.get(upstream) ?? [], node2.nodeId]);
|
|
225547
|
-
return out;
|
|
225548
|
-
}
|
|
225549
|
-
function waitingDescendants(source, reverse, states) {
|
|
225550
|
-
const found = /* @__PURE__ */ new Set();
|
|
225551
|
-
const queue = [...reverse.get(source) ?? []];
|
|
225552
|
-
while (queue.length) {
|
|
225553
|
-
const nodeId = queue.shift();
|
|
225554
|
-
if (found.has(nodeId) || states.get(nodeId) !== "waiting") continue;
|
|
225555
|
-
found.add(nodeId);
|
|
225556
|
-
queue.push(...reverse.get(nodeId) ?? []);
|
|
225557
|
-
}
|
|
225558
|
-
return [...found].sort();
|
|
225559
|
-
}
|
|
225560
|
-
function todoAction(node2) {
|
|
225561
|
-
if (node2.handoffProducer === "agent" && node2.nextActions[0]) return `Agent Handoff: ${node2.nextActions[0]}`;
|
|
225562
|
-
if (node2.nodeState === "ready") return "\u8282\u70B9 ready\uFF0C\u7B49\u5F85\u8C03\u5EA6";
|
|
225563
|
-
if (node2.nodeState === "blocked" && node2.unresolvedIssues[0]) return `\u8282\u70B9 blocked\uFF1A${node2.unresolvedIssues[0]}`;
|
|
225564
|
-
if (!node2.progress) return `\u8282\u70B9 ${node2.nodeState}\uFF0C\u65E0 checkpoint`;
|
|
225565
|
-
if (node2.progress.recoverability === "full") return `\u8282\u70B9 ${node2.nodeState}\uFF0Ccheckpoint \u5B8C\u6574\u53EF\u6062\u590D`;
|
|
225566
|
-
if (node2.progress.recoverability === "partial") return `\u8282\u70B9 ${node2.nodeState}\uFF0Ccheckpoint \u90E8\u5206\u53EF\u6062\u590D\uFF0C\u9700\u5173\u6CE8\u5DF2\u6709\u4EA7\u51FA`;
|
|
225567
|
-
return `\u8282\u70B9 ${node2.nodeState}\uFF0Ccheckpoint \u4E0D\u53EF\u6062\u590D`;
|
|
225568
|
-
}
|
|
225569
|
-
var import_node_crypto56, DONE_STATES, BLOCKING_STATES, HANDOFF_OUTCOMES2, RESUME_EXTERNAL_EFFECT_LIMIT, RESUME_SNAPSHOT_PREFIX, RESUME_SNAPSHOT_SUFFIX, TODO_RANK, ExecutionContinuityService;
|
|
225662
|
+
var import_node_crypto56, BLOCKING_STATES, HANDOFF_OUTCOMES2, RESUME_EXTERNAL_EFFECT_LIMIT, RESUME_SNAPSHOT_PREFIX, RESUME_SNAPSHOT_SUFFIX, ExecutionContinuityService;
|
|
225570
225663
|
var init_service8 = __esm({
|
|
225571
225664
|
"../server/src/domains/execution-continuity/service.ts"() {
|
|
225572
225665
|
"use strict";
|
|
225573
225666
|
init_src();
|
|
225574
225667
|
import_node_crypto56 = require("node:crypto");
|
|
225575
225668
|
init_src5();
|
|
225576
|
-
DONE_STATES = /* @__PURE__ */ new Set(["succeeded", "no_change"]);
|
|
225577
225669
|
BLOCKING_STATES = /* @__PURE__ */ new Set(["stalled", "failed", "blocked"]);
|
|
225578
225670
|
HANDOFF_OUTCOMES2 = /* @__PURE__ */ new Set(["succeeded", "no-output", "failed", "cancelled", "timeout", "orphaned"]);
|
|
225579
225671
|
RESUME_EXTERNAL_EFFECT_LIMIT = 20;
|
|
225580
225672
|
RESUME_SNAPSHOT_PREFIX = "<!-- oasis-resume-pack-snapshot:v1:";
|
|
225581
225673
|
RESUME_SNAPSHOT_SUFFIX = " -->";
|
|
225582
|
-
TODO_RANK = {
|
|
225583
|
-
stalled: 0,
|
|
225584
|
-
failed: 1,
|
|
225585
|
-
blocked: 2,
|
|
225586
|
-
ready: 3
|
|
225587
|
-
};
|
|
225588
225674
|
ExecutionContinuityService = class {
|
|
225589
225675
|
mode;
|
|
225590
225676
|
store;
|
|
@@ -225857,10 +225943,6 @@ var init_service8 = __esm({
|
|
|
225857
225943
|
const attempt = latest.get(node2.nodeId);
|
|
225858
225944
|
if (attempt) stateByNode.set(node2.nodeId, stateFromAttempt(attempt, handoffs.get(attempt.id) ?? null, checkpoints.get(attempt.id) ?? null, this.now(), this.stalledAfterMs));
|
|
225859
225945
|
}
|
|
225860
|
-
for (const node2 of graph) {
|
|
225861
|
-
if (stateByNode.has(node2.nodeId)) continue;
|
|
225862
|
-
stateByNode.set(node2.nodeId, node2.dependsOn.every((id) => DONE_STATES.has(stateByNode.get(id) ?? "waiting")) ? "ready" : "waiting");
|
|
225863
|
-
}
|
|
225864
225946
|
const nodes = graph.map((node2) => {
|
|
225865
225947
|
const attempt = latest.get(node2.nodeId) ?? null;
|
|
225866
225948
|
const handoff = attempt ? handoffs.get(attempt.id) ?? null : null;
|
|
@@ -225873,10 +225955,10 @@ var init_service8 = __esm({
|
|
|
225873
225955
|
recoveryCheckpoint: recoverySnapshot.latestCheckpoint,
|
|
225874
225956
|
recoveryHandoff: recoverySnapshot.previousHandoff
|
|
225875
225957
|
} : null;
|
|
225876
|
-
const nodeState = stateByNode.get(node2.nodeId);
|
|
225958
|
+
const nodeState = stateByNode.get(node2.nodeId) ?? null;
|
|
225877
225959
|
const wasRecovered = recoverySource !== null;
|
|
225878
|
-
const executionState = wasRecovered && nodeState === "failed" ? "recovery_failed" : BLOCKING_STATES.has(nodeState) ? "awaiting_coordinator" : wasRecovered ? "recovered" : nodeState === "running" ? "running" : null;
|
|
225879
|
-
const includeProgress = checkpoint && ["running", "stalled", "blocked", "failed"].includes(nodeState);
|
|
225960
|
+
const executionState = wasRecovered && nodeState === "failed" ? "recovery_failed" : nodeState !== null && BLOCKING_STATES.has(nodeState) ? "awaiting_coordinator" : wasRecovered ? "recovered" : nodeState === "running" ? "running" : null;
|
|
225961
|
+
const includeProgress = checkpoint && nodeState !== null && ["running", "stalled", "blocked", "failed"].includes(nodeState);
|
|
225880
225962
|
return {
|
|
225881
225963
|
nodeId: node2.nodeId,
|
|
225882
225964
|
title: node2.title,
|
|
@@ -225903,18 +225985,15 @@ var init_service8 = __esm({
|
|
|
225903
225985
|
recoverability: checkpoint.recoverability,
|
|
225904
225986
|
lastCheckpointAt: checkpoint.createdAt
|
|
225905
225987
|
} } : {},
|
|
225906
|
-
|
|
225988
|
+
sealed: facts?.sealed ?? null,
|
|
225989
|
+
// 纯透传的图事实,零派生:不看 attempt、不判断谁在等谁。见 CoordinatorNodeView.dependsOn。
|
|
225990
|
+
dependsOn: node2.dependsOn,
|
|
225907
225991
|
// 纯透传(展示层事实,见 CoordinatorNodeView.work/conclusion)。不参与本方法里任何
|
|
225908
|
-
// Attempt nodeState
|
|
225992
|
+
// Attempt nodeState 的派生。
|
|
225909
225993
|
...facts?.conclusion?.trim() ? { conclusion: facts.conclusion.trim() } : {}
|
|
225910
225994
|
};
|
|
225911
225995
|
});
|
|
225912
|
-
const reverse = reverseEdges(graph);
|
|
225913
|
-
const dependencyBlocks = nodes.filter((node2) => BLOCKING_STATES.has(node2.nodeState)).map((node2) => ({ nodeId: node2.nodeId, blocks: waitingDescendants(node2.nodeId, reverse, stateByNode) })).filter((item) => item.blocks.length > 0).sort((a, b2) => b2.blocks.length - a.blocks.length || a.nodeId.localeCompare(b2.nodeId));
|
|
225914
|
-
const todos = nodes.filter((node2) => node2.nodeState === "stalled" || node2.nodeState === "failed" || node2.nodeState === "blocked" || node2.nodeState === "ready").sort((a, b2) => TODO_RANK[a.nodeState] - TODO_RANK[b2.nodeState] || a.nodeId.localeCompare(b2.nodeId)).map((node2, index2) => ({ priority: index2 + 1, nodeId: node2.nodeId, nodeState: node2.nodeState, action: todoAction(node2) }));
|
|
225915
225996
|
const progress = Object.fromEntries([
|
|
225916
|
-
"waiting",
|
|
225917
|
-
"ready",
|
|
225918
225997
|
"running",
|
|
225919
225998
|
"stalled",
|
|
225920
225999
|
"succeeded",
|
|
@@ -225922,8 +226001,7 @@ var init_service8 = __esm({
|
|
|
225922
226001
|
"blocked",
|
|
225923
226002
|
"failed"
|
|
225924
226003
|
].map((state) => [state, nodes.filter((node2) => node2.nodeState === state).length]));
|
|
225925
|
-
|
|
225926
|
-
return { workOrderId, mode: this.mode, collaborationStatus, progress, nodes, dependencyBlocks, todo: todos };
|
|
226004
|
+
return { workOrderId, mode: this.mode, progress, nodes };
|
|
225927
226005
|
}
|
|
225928
226006
|
};
|
|
225929
226007
|
}
|
|
@@ -226242,9 +226320,11 @@ function nodeCoordinatorFactsFromSnapshot(snapshot) {
|
|
|
226242
226320
|
};
|
|
226243
226321
|
const accepted = node2.latestAcceptId ? workById.get(node2.latestAcceptId) : void 0;
|
|
226244
226322
|
const conclusion = accepted?.conclusion?.trim() || snapshot.works.filter((work2) => work2.nodeId === node2.id && work2.status === "success" && work2.conclusion?.trim()).sort((a, b2) => a.createdAt.localeCompare(b2.createdAt)).at(-1)?.conclusion?.trim();
|
|
226323
|
+
const sealed = node2.cancelledAt ? { reason: node2.sealReason ?? "cancelled", at: node2.cancelledAt } : null;
|
|
226245
226324
|
out[node2.id] = {
|
|
226246
226325
|
work,
|
|
226247
|
-
...conclusion ? { conclusion } : {}
|
|
226326
|
+
...conclusion ? { conclusion } : {},
|
|
226327
|
+
sealed
|
|
226248
226328
|
};
|
|
226249
226329
|
}
|
|
226250
226330
|
return out;
|
|
@@ -226660,6 +226740,33 @@ function mapChatItemToSnapshotEntry(row) {
|
|
|
226660
226740
|
payload: row.payload
|
|
226661
226741
|
};
|
|
226662
226742
|
}
|
|
226743
|
+
function synthesizeMessageItem(msg, seq) {
|
|
226744
|
+
const attachments = Array.isArray(msg.attachments) ? msg.attachments.map((a) => ({
|
|
226745
|
+
name: a.name,
|
|
226746
|
+
...a.blobRef !== void 0 ? { blobRef: a.blobRef } : {},
|
|
226747
|
+
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
226748
|
+
})) : void 0;
|
|
226749
|
+
const clientSubmitId = typeof msg.clientSubmitId === "string" ? msg.clientSubmitId : void 0;
|
|
226750
|
+
const role = msg.role === "user" || msg.role === "system" ? msg.role : "assistant";
|
|
226751
|
+
const status = msg.status === "running" ? "streaming" : msg.status === "error" ? "failed" : "completed";
|
|
226752
|
+
return {
|
|
226753
|
+
itemId: `chat-message:${msg.id}`,
|
|
226754
|
+
turnId: msg.runId ?? `chat-message-turn:${msg.id}`,
|
|
226755
|
+
itemType: "message",
|
|
226756
|
+
role,
|
|
226757
|
+
status,
|
|
226758
|
+
itemVersion: 0,
|
|
226759
|
+
seq,
|
|
226760
|
+
messageId: msg.id,
|
|
226761
|
+
updatedAt: msg.completedAt ?? msg.createdAt,
|
|
226762
|
+
payload: {
|
|
226763
|
+
role,
|
|
226764
|
+
text: msg.content ?? "",
|
|
226765
|
+
...attachments?.length ? { attachments } : {},
|
|
226766
|
+
...clientSubmitId ? { clientSubmitId } : {}
|
|
226767
|
+
}
|
|
226768
|
+
};
|
|
226769
|
+
}
|
|
226663
226770
|
function throwWorkdirError(code2) {
|
|
226664
226771
|
switch (code2) {
|
|
226665
226772
|
case "PATH_ESCAPE":
|
|
@@ -226929,6 +227036,24 @@ function createChatSessionsDomain(opts) {
|
|
|
226929
227036
|
}
|
|
226930
227037
|
const snapshotEntries = [];
|
|
226931
227038
|
let nextSinceVersion = sinceVersion;
|
|
227039
|
+
const HISTORY_TURNS = 12;
|
|
227040
|
+
const historicalEntries = [];
|
|
227041
|
+
if (sinceVersion === 0) {
|
|
227042
|
+
const listRecentTurns2 = store2.listRecentTurns;
|
|
227043
|
+
const messages = listRecentTurns2 ? (await listRecentTurns2.call(store2, chatSessionId, HISTORY_TURNS).catch(() => ({ messages: [], hasMoreBefore: false }))).messages : windowMessagesByTurns(await store2.listMessages(chatSessionId).catch(() => []), HISTORY_TURNS).messages;
|
|
227044
|
+
const coveredMessageIds = /* @__PURE__ */ new Set();
|
|
227045
|
+
for (const msg of messages) {
|
|
227046
|
+
if (!msg.id) continue;
|
|
227047
|
+
const rows = await items.listItemsByMessage(msg.id).catch(() => []);
|
|
227048
|
+
if (rows.length > 0) coveredMessageIds.add(msg.id);
|
|
227049
|
+
}
|
|
227050
|
+
let syntheticSeq = 0;
|
|
227051
|
+
for (const msg of messages) {
|
|
227052
|
+
if (!msg.id || coveredMessageIds.has(msg.id)) continue;
|
|
227053
|
+
syntheticSeq += 1;
|
|
227054
|
+
historicalEntries.push(synthesizeMessageItem(msg, syntheticSeq));
|
|
227055
|
+
}
|
|
227056
|
+
}
|
|
226932
227057
|
if (turnId) {
|
|
226933
227058
|
const rows = await items.listItemsByTurn(chatSessionId, turnId, { sinceTurnVersion: sinceVersion }).catch(() => []);
|
|
226934
227059
|
for (const row of rows) {
|
|
@@ -226939,7 +227064,8 @@ function createChatSessionsDomain(opts) {
|
|
|
226939
227064
|
const body2 = {
|
|
226940
227065
|
chatSessionId,
|
|
226941
227066
|
turnId,
|
|
226942
|
-
|
|
227067
|
+
// 历史合成条在前,active turn 的 chat_items 在后——顺序即桶排序,桶按 seq 单调排列。
|
|
227068
|
+
items: [...historicalEntries, ...snapshotEntries],
|
|
226943
227069
|
nextSinceVersion,
|
|
226944
227070
|
frameCursor: cursor ? { epoch: cursor.epoch, seq: cursor.seq } : { epoch: 0, seq: 0 },
|
|
226945
227071
|
canAppend: cursor?.canAppend ?? false
|
|
@@ -227047,7 +227173,11 @@ function createChatSessionsDomain(opts) {
|
|
|
227047
227173
|
};
|
|
227048
227174
|
const wkKernel = opts.kernel;
|
|
227049
227175
|
const allSummaries = buildWorkorderSummaries(wkKernel.model, resolver2, (wo) => byWo.get(wo) ?? null, (wo) => held.has(wo), void 0, void 0, (role) => wkKernel.actorForRole(role));
|
|
227050
|
-
const
|
|
227176
|
+
const summaryById = new Map(allSummaries.map((s2) => [s2.id, s2]));
|
|
227177
|
+
const items = [...workOrderIds].reverse().flatMap((id) => {
|
|
227178
|
+
const s2 = summaryById.get(id);
|
|
227179
|
+
return s2 ? [s2] : [];
|
|
227180
|
+
});
|
|
227051
227181
|
return { status: 200, body: { items } };
|
|
227052
227182
|
});
|
|
227053
227183
|
router.get("/api/chat-broadcasts/pending", async (req) => {
|
|
@@ -230065,7 +230195,7 @@ function automationsDomain(opts) {
|
|
|
230065
230195
|
}
|
|
230066
230196
|
return out;
|
|
230067
230197
|
};
|
|
230068
|
-
const
|
|
230198
|
+
const summarize4 = async (automation, req) => {
|
|
230069
230199
|
const [triggers, recent, canWrite] = await Promise.all([
|
|
230070
230200
|
service.listTriggers(automation.id),
|
|
230071
230201
|
service.listRuns(automation.id, { limit: RECENT_LIMIT2 }),
|
|
@@ -230158,13 +230288,13 @@ function automationsDomain(opts) {
|
|
|
230158
230288
|
router.get("/api/automations", async (req) => {
|
|
230159
230289
|
const includeArchived = req.query.get("includeArchived") === "1";
|
|
230160
230290
|
const automations = await service.listAutomations(companyOf(req), { includeArchived });
|
|
230161
|
-
const items = await Promise.all(automations.map((a) =>
|
|
230291
|
+
const items = await Promise.all(automations.map((a) => summarize4(a, req)));
|
|
230162
230292
|
const body2 = { items };
|
|
230163
230293
|
return { status: 200, body: body2 };
|
|
230164
230294
|
});
|
|
230165
230295
|
router.get("/api/automations/:id", async (req) => {
|
|
230166
230296
|
const automation = await mustGet(req);
|
|
230167
|
-
return { status: 200, body: await
|
|
230297
|
+
return { status: 200, body: await summarize4(automation, req) };
|
|
230168
230298
|
});
|
|
230169
230299
|
router.get("/api/automations/:id/runs", async (req) => {
|
|
230170
230300
|
const automation = await mustGet(req);
|
|
@@ -230244,7 +230374,7 @@ function automationsDomain(opts) {
|
|
|
230244
230374
|
...triggers !== void 0 ? { triggers } : {}
|
|
230245
230375
|
});
|
|
230246
230376
|
const withTarget = createTargetSession ? await service.createChatTargetSession(created, req.auth.actor) : created;
|
|
230247
|
-
return { status: 201, body: await
|
|
230377
|
+
return { status: 201, body: await summarize4(withTarget, req) };
|
|
230248
230378
|
});
|
|
230249
230379
|
router.patch("/api/automations/:id", async (req) => {
|
|
230250
230380
|
const automation = await mustGet(req);
|
|
@@ -230291,7 +230421,7 @@ function automationsDomain(opts) {
|
|
|
230291
230421
|
},
|
|
230292
230422
|
req.auth.actor
|
|
230293
230423
|
);
|
|
230294
|
-
return { status: 200, body: await
|
|
230424
|
+
return { status: 200, body: await summarize4(updated, req) };
|
|
230295
230425
|
});
|
|
230296
230426
|
router.post("/api/automations/:id/chat-target-session", async (req) => {
|
|
230297
230427
|
const automation = await mustGet(req);
|
|
@@ -230305,7 +230435,7 @@ function automationsDomain(opts) {
|
|
|
230305
230435
|
if (!owner) throw new ApiError(400, "CHAT_TARGET_NO_OWNER", "\u89E3\u6790\u4E0D\u5230\u4EBA\u7C7B\u5F52\u5C5E\u8005\uFF0C\u65E0\u6CD5\u5EFA\u957F\u671F\u76EE\u6807\u4F1A\u8BDD");
|
|
230306
230436
|
const withOwner = automation.ownerHumanActorId ? automation : await service.updateAutomation(automation.id, { ownerHumanActorId: owner }, req.auth.actor);
|
|
230307
230437
|
const updated = await service.createChatTargetSession(withOwner, req.auth.actor);
|
|
230308
|
-
return { status: 201, body: await
|
|
230438
|
+
return { status: 201, body: await summarize4(updated, req) };
|
|
230309
230439
|
});
|
|
230310
230440
|
router.post("/api/automations/:id/enabled", async (req) => {
|
|
230311
230441
|
const automation = await mustGet(req);
|
|
@@ -230313,7 +230443,7 @@ function automationsDomain(opts) {
|
|
|
230313
230443
|
const b2 = req.body ?? {};
|
|
230314
230444
|
if (typeof b2.enabled !== "boolean") throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 enabled\uFF08boolean\uFF09");
|
|
230315
230445
|
const updated = await service.setEnabled(automation.id, b2.enabled, req.auth.actor);
|
|
230316
|
-
return { status: 200, body: await
|
|
230446
|
+
return { status: 200, body: await summarize4(updated, req) };
|
|
230317
230447
|
});
|
|
230318
230448
|
router.post("/api/automations/:id/run-now", async (req) => {
|
|
230319
230449
|
const automation = await mustGet(req);
|
|
@@ -232609,10 +232739,11 @@ ${ctx.nodeFault}
|
|
|
232609
232739
|
``,
|
|
232610
232740
|
`## \u5B8C\u6574\u5DE5\u5355\u4E0A\u4E0B\u6587\u4E0E\u5168\u5C40\u6267\u884C\u72B6\u6001\uFF08\u5148\u8BFB \`execution/COORDINATOR_VIEW.md\`\uFF09`,
|
|
232611
232741
|
`\u90A3\u4EFD\u6587\u4EF6\u5148\u7ED9\u51FA\u6743\u5A01\u4EFB\u52A1\u80CC\u666F\uFF08\u5B8C\u6574 brief \u6B63\u6587\u3001\u76EE\u6807\u3001\u9A8C\u6536\u6807\u51C6\u3001\u8303\u56F4/\u8303\u56F4\u5916\u4E8B\u9879\u3001\u7EA6\u675F\u548C\u7248\u672C\u6765\u6E90\uFF09\uFF0C`,
|
|
232612
|
-
`\u518D\u7ED9\u51FA\u672C\u5DE5\u5355**\u6240\u6709\u8282\u70B9**\u7684\u4E00\u6B21\u6027\u5FEB\u7167\uFF1A\
|
|
232613
|
-
`\
|
|
232742
|
+
`\u518D\u7ED9\u51FA\u672C\u5DE5\u5355**\u6240\u6709\u8282\u70B9**\u7684\u4E00\u6B21\u6027\u4E8B\u5B9E\u5FEB\u7167\uFF1A\u6BCF\u4E2A\u8282\u70B9\u7684 Work \u72B6\u6001\u4E0E\u4EA4\u4ED8\u7248\u672C\u3001\u6700\u8FD1\u4E00\u8D9F Attempt`,
|
|
232743
|
+
`\u8DD1\u6210\u4EC0\u4E48\u6837\u3001\u8282\u70B9\u662F\u5426\u5DF2\u79BB\u573A\uFF08sealed\uFF09\u3001\u5DF2\u4EA4\u4ED8\u7684\u8282\u70B9\u4EA4\u4E86\u4EC0\u4E48\uFF08Conclusion = \u5DF2\u4EA4\u4ED8\u7248\u672C\u7684\u4E1A\u52A1`,
|
|
232744
|
+
`\u5B8C\u6210\u6458\u8981\uFF09\u3001\u52A8\u4E86\u54EA\u4E9B\u4EA7\u7269\u4E0E\u7248\u672C\uFF0C\u4EE5\u53CA\u5F00\u653E\u9879\u3002`,
|
|
232614
232745
|
`\u82E5\u6587\u4EF6\u660E\u786E\u5199\u7740\u67D0\u9879\u672A\u63D0\u4F9B\u6216\u6B63\u6587\u4E0D\u53EF\u8BFB\uFF0C\u4E0D\u8981\u81EA\u884C\u8865\u9020\uFF1B\u7248\u672C\u4E0D\u4E00\u81F4\u65F6\u4FDD\u7559\u5DEE\u5F02\u5E76\u5411\u4EBA\u8BF4\u660E\u3002`,
|
|
232615
|
-
`\
|
|
232746
|
+
`\u5B83\u53EA\u9648\u8FF0\u4E8B\u5B9E\uFF0C\u4E0D\u542B\u7CFB\u7EDF\u7ED9\u51FA\u7684\u4F18\u5148\u7EA7\u3001\u5F85\u529E\u6216\u5904\u7F6E\u5EFA\u8BAE\u2014\u2014\u600E\u4E48\u5904\u7F6E\u7531\u4F60\u5224\u65AD\u3002`,
|
|
232616
232747
|
`Technical notes \u53EA\u8865\u5145 Agent \u7684\u6280\u672F\u4EA4\u63A5\uFF1BExecution diagnostic \u53EA\u8BF4\u660E\u4F1A\u8BDD\u600E\u4E48\u7ED3\u675F\uFF0C\u4E8C\u8005\u90FD\u4E0D\u66FF\u4EE3 Conclusion\u3002`,
|
|
232617
232748
|
``
|
|
232618
232749
|
].join("\n") : task;
|
|
@@ -243954,6 +244085,9 @@ var init_company_owned_registry_store = __esm({
|
|
|
243954
244085
|
});
|
|
243955
244086
|
|
|
243956
244087
|
// ../storage/src/tenant-cutover.ts
|
|
244088
|
+
function maxGate(a, b2) {
|
|
244089
|
+
return GATE_RANK[a] >= GATE_RANK[b2] ? a : b2;
|
|
244090
|
+
}
|
|
243957
244091
|
function rowToCutover(row) {
|
|
243958
244092
|
return {
|
|
243959
244093
|
companyId: row.company_id,
|
|
@@ -243966,7 +244100,7 @@ function rowToCutover(row) {
|
|
|
243966
244100
|
updatedAt: new Date(row.updated_at).toISOString()
|
|
243967
244101
|
};
|
|
243968
244102
|
}
|
|
243969
|
-
var COMPANY_DATA_BUNDLES, LEGAL, CutoverIllegalTransitionError, CutoverGateOpenRollbackError, TenantCutoverStore;
|
|
244103
|
+
var COMPANY_DATA_BUNDLES, LEGAL, GATE_RANK, CutoverIllegalTransitionError, CutoverGateOpenRollbackError, TenantCutoverStore;
|
|
243970
244104
|
var init_tenant_cutover = __esm({
|
|
243971
244105
|
"../storage/src/tenant-cutover.ts"() {
|
|
243972
244106
|
"use strict";
|
|
@@ -243989,6 +244123,12 @@ var init_tenant_cutover = __esm({
|
|
|
243989
244123
|
frozen: ["company-primary", "legacy"],
|
|
243990
244124
|
"company-primary": ["legacy"]
|
|
243991
244125
|
};
|
|
244126
|
+
GATE_RANK = {
|
|
244127
|
+
"gate-closed": 0,
|
|
244128
|
+
"gate-open": 1,
|
|
244129
|
+
"contract-ready": 2,
|
|
244130
|
+
contracted: 3
|
|
244131
|
+
};
|
|
243992
244132
|
CutoverIllegalTransitionError = class extends Error {
|
|
243993
244133
|
constructor(from, to) {
|
|
243994
244134
|
super(`\u975E\u6CD5\u5207\u6362 ${from} \u2192 ${to}`);
|
|
@@ -244090,19 +244230,37 @@ var init_tenant_cutover = __esm({
|
|
|
244090
244230
|
}
|
|
244091
244231
|
return rowToCutover(r.rows[0]);
|
|
244092
244232
|
}
|
|
244233
|
+
/**
|
|
244234
|
+
* 该 bundle 的 **bundle-global** gate(ADR §7.1):取这个 bundle 所有公司行里到过的最高档。
|
|
244235
|
+
*
|
|
244236
|
+
* 为什么不能只看单行:`markBundlePrimary` 给新公司插的行硬编 `gate-closed`,于是
|
|
244237
|
+
* 「gate 已经全局打开、之后新建的公司」那一行是 gate-closed —— 拿它判回滚,就会
|
|
244238
|
+
* **放行一次本该被永久禁止的回滚**(2026-09-04 生产实测:21 家 09-03 之后建的公司
|
|
244239
|
+
* 在 skills 已 gate-open 的情况下,行上仍是 gate-closed)。
|
|
244240
|
+
*/
|
|
244241
|
+
async bundleGate(bundle) {
|
|
244242
|
+
const r = await this.pool.query(
|
|
244243
|
+
`SELECT DISTINCT gate FROM ${this.s}.tenant_storage_cutover WHERE bundle=$1`,
|
|
244244
|
+
[bundle]
|
|
244245
|
+
);
|
|
244246
|
+
let g2 = "gate-closed";
|
|
244247
|
+
for (const row of r.rows) g2 = maxGate(g2, row.gate);
|
|
244248
|
+
return g2;
|
|
244249
|
+
}
|
|
244093
244250
|
async casTransition(companyId, bundle, expectedEpoch, to, opts) {
|
|
244094
244251
|
const cur = await this.get(companyId, bundle);
|
|
244095
244252
|
if (cur.epoch !== expectedEpoch) {
|
|
244096
244253
|
throw new Error(`cutover epoch \u4E0D\u5339\u914D\uFF1A\u671F\u671B ${expectedEpoch} \u5B9E\u9645 ${cur.epoch}`);
|
|
244097
244254
|
}
|
|
244098
|
-
|
|
244255
|
+
const globalGate = maxGate(cur.gate, await this.bundleGate(bundle));
|
|
244256
|
+
if (to === "legacy" && globalGate !== "gate-closed") {
|
|
244099
244257
|
throw new CutoverGateOpenRollbackError();
|
|
244100
244258
|
}
|
|
244101
244259
|
if (cur.state !== to && !LEGAL[cur.state].includes(to)) {
|
|
244102
244260
|
throw new CutoverIllegalTransitionError(cur.state, to);
|
|
244103
244261
|
}
|
|
244104
244262
|
const nextEpoch = cur.epoch + 1;
|
|
244105
|
-
const gate = opts.gate ?? cur.gate;
|
|
244263
|
+
const gate = maxGate(opts.gate ?? cur.gate, globalGate);
|
|
244106
244264
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
244107
244265
|
const updated = await this.pool.query(
|
|
244108
244266
|
`INSERT INTO ${this.s}.tenant_storage_cutover
|
|
@@ -244125,28 +244283,44 @@ var init_tenant_cutover = __esm({
|
|
|
244125
244283
|
* 与 markNewCompanyPrimary 的区别:那个是整包切,只对全新空公司成立;这个按 bundle 逐个来。
|
|
244126
244284
|
*/
|
|
244127
244285
|
async markBundlePrimary(companyId, bundle, operator) {
|
|
244286
|
+
const gate = await this.bundleGate(bundle);
|
|
244128
244287
|
const r = await this.pool.query(
|
|
244129
244288
|
`INSERT INTO ${this.s}.tenant_storage_cutover
|
|
244130
244289
|
(company_id, bundle, state, epoch, gate, manifest_generation, journal_hwm, updated_at)
|
|
244131
|
-
VALUES ($1,$2,'company-primary',1,
|
|
244290
|
+
VALUES ($1,$2,'company-primary',1,$4,0,0,$3)
|
|
244132
244291
|
ON CONFLICT (company_id, bundle) DO NOTHING`,
|
|
244133
|
-
[companyId, bundle, (/* @__PURE__ */ new Date()).toISOString()]
|
|
244292
|
+
[companyId, bundle, (/* @__PURE__ */ new Date()).toISOString(), gate]
|
|
244134
244293
|
);
|
|
244135
244294
|
return (r.rowCount ?? 0) > 0;
|
|
244136
244295
|
}
|
|
244137
|
-
/** 新公司:所有 4c bundle 直接 company-primary
|
|
244296
|
+
/** 新公司:所有 4c bundle 直接 company-primary(各自继承该 bundle 的全局 gate)。 */
|
|
244138
244297
|
async markNewCompanyPrimary(companyId, operator) {
|
|
244139
244298
|
for (const bundle of COMPANY_DATA_BUNDLES) {
|
|
244140
244299
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
244300
|
+
const gate = await this.bundleGate(bundle);
|
|
244141
244301
|
await this.pool.query(
|
|
244142
244302
|
`INSERT INTO ${this.s}.tenant_storage_cutover
|
|
244143
244303
|
(company_id, bundle, state, epoch, gate, manifest_generation, journal_hwm, updated_at)
|
|
244144
|
-
VALUES ($1,$2,'company-primary',1,
|
|
244304
|
+
VALUES ($1,$2,'company-primary',1,$4,0,0,$3)
|
|
244145
244305
|
ON CONFLICT (company_id, bundle) DO NOTHING`,
|
|
244146
|
-
[companyId, bundle, now]
|
|
244306
|
+
[companyId, bundle, now, gate]
|
|
244147
244307
|
);
|
|
244148
244308
|
}
|
|
244149
244309
|
}
|
|
244310
|
+
/**
|
|
244311
|
+
* 把该 bundle 里落后于全局档的 gate 列一次性归一(修存量的 gate-closed 残行)。
|
|
244312
|
+
* 只推进、绝不回退;返回被改的行数。
|
|
244313
|
+
*/
|
|
244314
|
+
async normalizeBundleGate(bundle) {
|
|
244315
|
+
const gate = await this.bundleGate(bundle);
|
|
244316
|
+
if (gate === "gate-closed") return 0;
|
|
244317
|
+
const r = await this.pool.query(
|
|
244318
|
+
`UPDATE ${this.s}.tenant_storage_cutover SET gate=$2, updated_at=$3
|
|
244319
|
+
WHERE bundle=$1 AND gate <> $2`,
|
|
244320
|
+
[bundle, gate, (/* @__PURE__ */ new Date()).toISOString()]
|
|
244321
|
+
);
|
|
244322
|
+
return r.rowCount ?? 0;
|
|
244323
|
+
}
|
|
244150
244324
|
readsCompanySchema(row) {
|
|
244151
244325
|
return row.state === "company-primary";
|
|
244152
244326
|
}
|
|
@@ -245147,6 +245321,350 @@ var init_tenant_migration_operator = __esm({
|
|
|
245147
245321
|
}
|
|
245148
245322
|
});
|
|
245149
245323
|
|
|
245324
|
+
// ../storage/src/tenant-new-company-provision.ts
|
|
245325
|
+
async function provisionNewCompanyDataPlane(input) {
|
|
245326
|
+
const legacySchema = input.legacySchema ?? "public";
|
|
245327
|
+
const controlSchema = input.controlSchema ?? "public";
|
|
245328
|
+
const operator = input.operator ?? "serve-provision";
|
|
245329
|
+
const { pool, companyId, cutover } = input;
|
|
245330
|
+
const loc = await input.locations.provision(companyId);
|
|
245331
|
+
await provisionCompanyDataPlaneSchema(pool, loc.schemaName);
|
|
245332
|
+
const report = {
|
|
245333
|
+
companyId,
|
|
245334
|
+
schemaName: loc.schemaName,
|
|
245335
|
+
provisioned: [],
|
|
245336
|
+
alreadyPrimary: [],
|
|
245337
|
+
skipped: []
|
|
245338
|
+
};
|
|
245339
|
+
const eligible = async (b2) => {
|
|
245340
|
+
const row = await cutover.get(companyId, b2);
|
|
245341
|
+
if (row.state === "company-primary") {
|
|
245342
|
+
report.alreadyPrimary.push(b2);
|
|
245343
|
+
return false;
|
|
245344
|
+
}
|
|
245345
|
+
if (row.epoch !== 0) {
|
|
245346
|
+
report.skipped.push({ bundle: b2, reason: `epoch=${row.epoch}\uFF08\u6709\u4EBA\u663E\u5F0F\u52A8\u8FC7\uFF0C\u81EA\u52A8\u8DEF\u5F84\u4E0D\u63A5\u7BA1\uFF09` });
|
|
245347
|
+
return false;
|
|
245348
|
+
}
|
|
245349
|
+
return true;
|
|
245350
|
+
};
|
|
245351
|
+
const identityTodo = [];
|
|
245352
|
+
for (const b2 of IDENTITY_BUNDLES) if (await eligible(b2)) identityTodo.push(b2);
|
|
245353
|
+
if (identityTodo.length > 0) {
|
|
245354
|
+
const owned = await CompanyOwnedRegistryStore.open(pool, loc.schemaName, companyId);
|
|
245355
|
+
await runIdentityMigration({
|
|
245356
|
+
pool,
|
|
245357
|
+
target: owned,
|
|
245358
|
+
roster: await input.roster(),
|
|
245359
|
+
manifestId: `provision-i-${companyId}-${Date.now()}`,
|
|
245360
|
+
legacySchema,
|
|
245361
|
+
controlSchema
|
|
245362
|
+
});
|
|
245363
|
+
for (const b2 of identityTodo) {
|
|
245364
|
+
await advanceCutover(cutover, companyId, b2, "company-primary", operator);
|
|
245365
|
+
report.provisioned.push(b2);
|
|
245366
|
+
}
|
|
245367
|
+
}
|
|
245368
|
+
if (await eligible("types")) {
|
|
245369
|
+
await copyArtifactTypesIdempotent(
|
|
245370
|
+
pool,
|
|
245371
|
+
companyId,
|
|
245372
|
+
loc.schemaName,
|
|
245373
|
+
`provision-t-${companyId}-${Date.now()}`,
|
|
245374
|
+
legacySchema,
|
|
245375
|
+
controlSchema
|
|
245376
|
+
);
|
|
245377
|
+
await advanceCutover(
|
|
245378
|
+
cutover,
|
|
245379
|
+
companyId,
|
|
245380
|
+
"types",
|
|
245381
|
+
"company-primary",
|
|
245382
|
+
operator,
|
|
245383
|
+
{ pool, companySchema: loc.schemaName, legacySchema }
|
|
245384
|
+
);
|
|
245385
|
+
report.provisioned.push("types");
|
|
245386
|
+
}
|
|
245387
|
+
if (await eligible("org-registry")) {
|
|
245388
|
+
await copyOrgRegistryIdempotent(
|
|
245389
|
+
pool,
|
|
245390
|
+
companyId,
|
|
245391
|
+
loc.schemaName,
|
|
245392
|
+
`provision-o-${companyId}-${Date.now()}`,
|
|
245393
|
+
{ takeLegacyRows: false, legacySchema, controlSchema }
|
|
245394
|
+
);
|
|
245395
|
+
await advanceCutover(cutover, companyId, "org-registry", "company-primary", operator);
|
|
245396
|
+
report.provisioned.push("org-registry");
|
|
245397
|
+
}
|
|
245398
|
+
if (await eligible("skills")) {
|
|
245399
|
+
const n = await input.legacySkillCount();
|
|
245400
|
+
if (n > 0) {
|
|
245401
|
+
report.skipped.push({ bundle: "skills", reason: `legacy \u4FA7\u6709 ${n} \u6761\u6280\u80FD\u5B58\u91CF\uFF0C\u9700\u8D70 operator \u5168\u94FE` });
|
|
245402
|
+
} else {
|
|
245403
|
+
const marked = await cutover.markBundlePrimary(companyId, "skills", operator);
|
|
245404
|
+
if (!marked) await advanceCutover(cutover, companyId, "skills", "company-primary", operator);
|
|
245405
|
+
report.provisioned.push("skills");
|
|
245406
|
+
}
|
|
245407
|
+
}
|
|
245408
|
+
const known = /* @__PURE__ */ new Set([
|
|
245409
|
+
...report.provisioned,
|
|
245410
|
+
...report.alreadyPrimary,
|
|
245411
|
+
...report.skipped.map((s2) => s2.bundle)
|
|
245412
|
+
]);
|
|
245413
|
+
for (const b2 of COMPANY_DATA_BUNDLES) {
|
|
245414
|
+
if (!known.has(b2)) report.skipped.push({ bundle: b2, reason: "\u672A\u88AB provisioning \u8986\u76D6\uFF08\u65B0\u589E bundle \u5FD8\u4E86\u63A5\u7EBF\uFF1F\uFF09" });
|
|
245415
|
+
}
|
|
245416
|
+
return report;
|
|
245417
|
+
}
|
|
245418
|
+
var IDENTITY_BUNDLES;
|
|
245419
|
+
var init_tenant_new_company_provision = __esm({
|
|
245420
|
+
"../storage/src/tenant-new-company-provision.ts"() {
|
|
245421
|
+
"use strict";
|
|
245422
|
+
init_esm();
|
|
245423
|
+
init_company_owned_registry_store();
|
|
245424
|
+
init_company_data_plane_schema();
|
|
245425
|
+
init_tenant_schema_mapping();
|
|
245426
|
+
init_tenant_cutover();
|
|
245427
|
+
init_tenant_migration_operator();
|
|
245428
|
+
IDENTITY_BUNDLES = ["actors", "actor-config", "assistant"];
|
|
245429
|
+
}
|
|
245430
|
+
});
|
|
245431
|
+
|
|
245432
|
+
// ../storage/src/tenancy-attribution.ts
|
|
245433
|
+
function realCompanyId(v2) {
|
|
245434
|
+
return typeof v2 === "string" && v2.trim().length > 0 ? v2 : null;
|
|
245435
|
+
}
|
|
245436
|
+
async function buildActorRosterIndex(pool, controlSchema = "public") {
|
|
245437
|
+
const schemas = await pool.query(`
|
|
245438
|
+
SELECT n.nspname FROM pg_namespace n JOIN pg_class c ON c.relnamespace = n.oid
|
|
245439
|
+
WHERE n.nspname LIKE 'c\\_%' AND c.relname = 'actors' AND c.relkind = 'r'`);
|
|
245440
|
+
const seen = /* @__PURE__ */ new Map();
|
|
245441
|
+
const schemaToCompany = /* @__PURE__ */ new Map();
|
|
245442
|
+
for (const r of (await pool.query(
|
|
245443
|
+
`SELECT company_id, schema_name FROM ${quoteIdent2(controlSchema)}.tenant_storage_locations`
|
|
245444
|
+
)).rows) {
|
|
245445
|
+
schemaToCompany.set(r.schema_name, r.company_id);
|
|
245446
|
+
}
|
|
245447
|
+
for (const row of schemas.rows) {
|
|
245448
|
+
const ns = row.nspname;
|
|
245449
|
+
const company = schemaToCompany.get(ns);
|
|
245450
|
+
if (!company) continue;
|
|
245451
|
+
const hasRoster = await pool.query(
|
|
245452
|
+
`SELECT 1 FROM information_schema.columns
|
|
245453
|
+
WHERE table_schema=$1 AND table_name='actors' AND column_name='roster'`,
|
|
245454
|
+
[ns]
|
|
245455
|
+
);
|
|
245456
|
+
const q = hasRoster.rowCount ? `SELECT id FROM ${quoteIdent2(ns)}.actors WHERE roster IS TRUE` : `SELECT id FROM ${quoteIdent2(ns)}.actors`;
|
|
245457
|
+
for (const a of (await pool.query(q)).rows) {
|
|
245458
|
+
const id = a.id;
|
|
245459
|
+
if (!seen.has(id)) seen.set(id, /* @__PURE__ */ new Set());
|
|
245460
|
+
seen.get(id).add(company);
|
|
245461
|
+
}
|
|
245462
|
+
}
|
|
245463
|
+
const out = /* @__PURE__ */ new Map();
|
|
245464
|
+
for (const [id, set] of seen) out.set(id, set.size === 1 ? [...set][0] : null);
|
|
245465
|
+
return out;
|
|
245466
|
+
}
|
|
245467
|
+
function tally(rows, table) {
|
|
245468
|
+
const byRung = {};
|
|
245469
|
+
const byCompany = {};
|
|
245470
|
+
for (const r of rows) {
|
|
245471
|
+
byRung[r.rung] = (byRung[r.rung] ?? 0) + 1;
|
|
245472
|
+
byCompany[r.companyId] = (byCompany[r.companyId] ?? 0) + 1;
|
|
245473
|
+
}
|
|
245474
|
+
return {
|
|
245475
|
+
table,
|
|
245476
|
+
total: rows.length,
|
|
245477
|
+
byRung,
|
|
245478
|
+
byCompany,
|
|
245479
|
+
fallback: byRung["fallback-default"] ?? 0,
|
|
245480
|
+
conflicts: rows.filter((r) => r.conflict).length
|
|
245481
|
+
};
|
|
245482
|
+
}
|
|
245483
|
+
async function attributeAgentRuns(o) {
|
|
245484
|
+
const ls = quoteIdent2(o.legacySchema ?? "public");
|
|
245485
|
+
const roster = await buildActorRosterIndex(o.pool, o.legacySchema ?? "public");
|
|
245486
|
+
const rows = await o.pool.query(`
|
|
245487
|
+
SELECT r.id, r.actor_id, w.company_id AS wo_company, (w.id IS NOT NULL) AS wo_in_legacy
|
|
245488
|
+
FROM ${ls}.agent_runs r
|
|
245489
|
+
LEFT JOIN ${ls}.workorders w ON w.id = r.work_order_id`);
|
|
245490
|
+
const out = [];
|
|
245491
|
+
for (const r of rows.rows) {
|
|
245492
|
+
const key = `agent_runs:${r.id}`;
|
|
245493
|
+
const wo = realCompanyId(r.wo_company);
|
|
245494
|
+
const byActor2 = roster.get(r.actor_id) ?? null;
|
|
245495
|
+
const conflict = wo !== null && byActor2 !== null && wo !== byActor2 ? { rung: "actor-roster", companyId: byActor2 } : void 0;
|
|
245496
|
+
if (wo !== null) {
|
|
245497
|
+
out.push({ key, companyId: wo, rung: "workorder", ...conflict ? { conflict } : {} });
|
|
245498
|
+
continue;
|
|
245499
|
+
}
|
|
245500
|
+
if (byActor2 !== null) {
|
|
245501
|
+
out.push({ key, companyId: byActor2, rung: "actor-roster" });
|
|
245502
|
+
continue;
|
|
245503
|
+
}
|
|
245504
|
+
if (r.wo_in_legacy) {
|
|
245505
|
+
out.push({ key, companyId: o.defaultCompanyId, rung: "schema-identity" });
|
|
245506
|
+
continue;
|
|
245507
|
+
}
|
|
245508
|
+
out.push({ key, companyId: o.defaultCompanyId, rung: "fallback-default" });
|
|
245509
|
+
}
|
|
245510
|
+
return out;
|
|
245511
|
+
}
|
|
245512
|
+
async function attributeByRun(o, table, joinColumn, keyColumns) {
|
|
245513
|
+
const ls = quoteIdent2(o.legacySchema ?? "public");
|
|
245514
|
+
const runs = /* @__PURE__ */ new Map();
|
|
245515
|
+
for (const r of await attributeAgentRuns(o)) runs.set(r.key.slice("agent_runs:".length), r.companyId);
|
|
245516
|
+
const keyExpr = keyColumns.map((c) => `COALESCE(${quoteIdent2(c)}::text,'\u2205')`).join(` || ':' || `);
|
|
245517
|
+
const rows = await o.pool.query(
|
|
245518
|
+
`SELECT ${keyExpr} AS k, ${quoteIdent2(joinColumn)}::text AS run FROM ${ls}.${quoteIdent2(table)}`
|
|
245519
|
+
);
|
|
245520
|
+
return rows.rows.map((r) => {
|
|
245521
|
+
const c = runs.get(r.run);
|
|
245522
|
+
return c ? { key: `${table}:${r.k}`, companyId: c, rung: "run" } : { key: `${table}:${r.k}`, companyId: o.defaultCompanyId, rung: "fallback-default" };
|
|
245523
|
+
});
|
|
245524
|
+
}
|
|
245525
|
+
async function attributeDispatches(o) {
|
|
245526
|
+
const ls = quoteIdent2(o.legacySchema ?? "public");
|
|
245527
|
+
const roster = await buildActorRosterIndex(o.pool, o.legacySchema ?? "public");
|
|
245528
|
+
const rows = await o.pool.query(`
|
|
245529
|
+
SELECT d.id, d.actor_id, w.company_id AS wo_company, (w.id IS NOT NULL) AS wo_in_legacy
|
|
245530
|
+
FROM ${ls}.dispatches d LEFT JOIN ${ls}.workorders w ON w.id = d.workorder_id`);
|
|
245531
|
+
return rows.rows.map((r) => {
|
|
245532
|
+
const key = `dispatches:${r.id}`;
|
|
245533
|
+
const wo = realCompanyId(r.wo_company);
|
|
245534
|
+
const a = roster.get(r.actor_id) ?? null;
|
|
245535
|
+
const conflict = wo !== null && a !== null && wo !== a ? { rung: "actor-roster", companyId: a } : void 0;
|
|
245536
|
+
if (wo !== null) return { key, companyId: wo, rung: "workorder", ...conflict ? { conflict } : {} };
|
|
245537
|
+
if (a !== null) return { key, companyId: a, rung: "actor-roster" };
|
|
245538
|
+
if (r.wo_in_legacy) return { key, companyId: o.defaultCompanyId, rung: "schema-identity" };
|
|
245539
|
+
return { key, companyId: o.defaultCompanyId, rung: "fallback-default" };
|
|
245540
|
+
});
|
|
245541
|
+
}
|
|
245542
|
+
async function attributeWorkorderDrafts(o) {
|
|
245543
|
+
const ls = quoteIdent2(o.legacySchema ?? "public");
|
|
245544
|
+
const rows = await o.pool.query(`
|
|
245545
|
+
SELECT d.id, w.company_id, (w.id IS NOT NULL) AS wo_in_legacy FROM ${ls}.workorder_drafts d
|
|
245546
|
+
LEFT JOIN ${ls}.workorders w ON w.id = d.workspace`);
|
|
245547
|
+
return rows.rows.map((r) => {
|
|
245548
|
+
const key = `workorder_drafts:${r.id}`;
|
|
245549
|
+
const wo = realCompanyId(r.company_id);
|
|
245550
|
+
if (wo !== null) return { key, companyId: wo, rung: "workorder" };
|
|
245551
|
+
if (r.wo_in_legacy) return { key, companyId: o.defaultCompanyId, rung: "schema-identity" };
|
|
245552
|
+
return { key, companyId: o.defaultCompanyId, rung: "fallback-default" };
|
|
245553
|
+
});
|
|
245554
|
+
}
|
|
245555
|
+
async function attributeInboxReadMarkers(o) {
|
|
245556
|
+
const ls = quoteIdent2(o.legacySchema ?? "public");
|
|
245557
|
+
const roster = await buildActorRosterIndex(o.pool, o.legacySchema ?? "public");
|
|
245558
|
+
const rows = await o.pool.query(`
|
|
245559
|
+
SELECT i.actor_id, i.scope, s.company_id AS chat_company
|
|
245560
|
+
FROM ${ls}.inbox_read_markers i
|
|
245561
|
+
LEFT JOIN ${ls}.chat_sessions s
|
|
245562
|
+
ON i.scope LIKE 'chat:%' AND s.id = substring(i.scope from 6)`);
|
|
245563
|
+
return rows.rows.map((r) => {
|
|
245564
|
+
const key = `inbox_read_markers:${r.actor_id}:${r.scope}`;
|
|
245565
|
+
const chat = realCompanyId(r.chat_company);
|
|
245566
|
+
if (chat !== null) return { key, companyId: chat, rung: "chat-session" };
|
|
245567
|
+
const m2 = /(?:^|:)(company:[^:]+)$/.exec(String(r.scope));
|
|
245568
|
+
if (m2) return { key, companyId: m2[1], rung: "scope-literal" };
|
|
245569
|
+
const a = roster.get(r.actor_id);
|
|
245570
|
+
if (a) return { key, companyId: a, rung: "actor-roster" };
|
|
245571
|
+
return { key, companyId: o.defaultCompanyId, rung: "fallback-default" };
|
|
245572
|
+
});
|
|
245573
|
+
}
|
|
245574
|
+
async function attributeActorMemories(o) {
|
|
245575
|
+
const ls = quoteIdent2(o.legacySchema ?? "public");
|
|
245576
|
+
const roster = await buildActorRosterIndex(o.pool, o.legacySchema ?? "public");
|
|
245577
|
+
const rows = await o.pool.query(`SELECT mem_id, actor_id FROM ${ls}.actor_memories`);
|
|
245578
|
+
return rows.rows.map((r) => {
|
|
245579
|
+
const a = roster.get(r.actor_id);
|
|
245580
|
+
return a ? { key: `actor_memories:${r.mem_id}`, companyId: a, rung: "actor-roster" } : { key: `actor_memories:${r.mem_id}`, companyId: o.defaultCompanyId, rung: "fallback-default" };
|
|
245581
|
+
});
|
|
245582
|
+
}
|
|
245583
|
+
async function attributeBlobs(o) {
|
|
245584
|
+
const ls = quoteIdent2(o.legacySchema ?? "public");
|
|
245585
|
+
const refs = /* @__PURE__ */ new Map();
|
|
245586
|
+
const add = (hash2, company) => {
|
|
245587
|
+
if (!refs.has(hash2)) refs.set(hash2, /* @__PURE__ */ new Set());
|
|
245588
|
+
refs.get(hash2).add(company);
|
|
245589
|
+
};
|
|
245590
|
+
const schemas = await o.pool.query(`
|
|
245591
|
+
SELECT n.nspname FROM pg_namespace n JOIN pg_class c ON c.relnamespace = n.oid
|
|
245592
|
+
WHERE n.nspname LIKE 'c\\_%' AND c.relname = 'skill_files' AND c.relkind='r'`);
|
|
245593
|
+
const schemaToCompany = /* @__PURE__ */ new Map();
|
|
245594
|
+
for (const r of (await o.pool.query(
|
|
245595
|
+
`SELECT company_id, schema_name FROM ${ls}.tenant_storage_locations`
|
|
245596
|
+
)).rows) {
|
|
245597
|
+
schemaToCompany.set(r.schema_name, r.company_id);
|
|
245598
|
+
}
|
|
245599
|
+
for (const s2 of schemas.rows) {
|
|
245600
|
+
const company = schemaToCompany.get(s2.nspname);
|
|
245601
|
+
if (!company) continue;
|
|
245602
|
+
for (const f2 of (await o.pool.query(
|
|
245603
|
+
`SELECT DISTINCT blob_hash FROM ${quoteIdent2(s2.nspname)}.skill_files WHERE blob_hash IS NOT NULL`
|
|
245604
|
+
)).rows) {
|
|
245605
|
+
add(f2.blob_hash, company);
|
|
245606
|
+
}
|
|
245607
|
+
}
|
|
245608
|
+
const legacyRefs = [
|
|
245609
|
+
{ sql: `SELECT f.blob_id AS h, w.company_id AS c FROM ${ls}.work_order_files f
|
|
245610
|
+
JOIN ${ls}.workorders w ON w.id = f.work_order_id WHERE f.blob_id IS NOT NULL` },
|
|
245611
|
+
{ sql: `SELECT e.blob_ref AS h, w.company_id AS c FROM ${ls}.agent_run_events e
|
|
245612
|
+
JOIN ${ls}.agent_runs r ON r.id = e.run_id
|
|
245613
|
+
JOIN ${ls}.workorders w ON w.id = r.work_order_id WHERE e.blob_ref IS NOT NULL` }
|
|
245614
|
+
];
|
|
245615
|
+
for (const q of legacyRefs) {
|
|
245616
|
+
let res;
|
|
245617
|
+
try {
|
|
245618
|
+
res = await o.pool.query(q.sql);
|
|
245619
|
+
} catch {
|
|
245620
|
+
continue;
|
|
245621
|
+
}
|
|
245622
|
+
for (const r of res.rows) if (r.h && r.c) add(r.h, r.c);
|
|
245623
|
+
}
|
|
245624
|
+
const all2 = await o.pool.query(`SELECT hash FROM ${ls}.blobs`);
|
|
245625
|
+
const out = [];
|
|
245626
|
+
for (const b2 of all2.rows) {
|
|
245627
|
+
const hash2 = b2.hash;
|
|
245628
|
+
const owners = refs.get(hash2);
|
|
245629
|
+
if (!owners || owners.size === 0) {
|
|
245630
|
+
out.push({ key: `blobs:${hash2}`, companyId: o.defaultCompanyId, rung: "fallback-default" });
|
|
245631
|
+
continue;
|
|
245632
|
+
}
|
|
245633
|
+
for (const c of owners) out.push({ key: `blobs:${hash2}@${c}`, companyId: c, rung: "referrer" });
|
|
245634
|
+
}
|
|
245635
|
+
return out;
|
|
245636
|
+
}
|
|
245637
|
+
async function inventoryZeroTenantTables(o) {
|
|
245638
|
+
const reports = [];
|
|
245639
|
+
reports.push(tally(await attributeAgentRuns(o), "agent_runs"));
|
|
245640
|
+
const traceFollowers = [
|
|
245641
|
+
["agent_run_events", "run_id", ["run_id", "seq"]],
|
|
245642
|
+
["agent_tool_calls", "run_id", ["id"]],
|
|
245643
|
+
["agent_run_links", "run_id", ["run_id", "ref_type", "ref_id", "relation"]]
|
|
245644
|
+
];
|
|
245645
|
+
for (const [t, j, k2] of traceFollowers) reports.push(tally(await attributeByRun(o, t, j, k2), t));
|
|
245646
|
+
for (const [t, j, k2] of [
|
|
245647
|
+
["execution_checkpoints", "attempt_id", ["checkpoint_id"]],
|
|
245648
|
+
["node_handoffs", "attempt_id", ["handoff_id"]],
|
|
245649
|
+
["external_effects", "attempt_id", ["node_id", "attempt_id", "kind", "idempotency_key"]]
|
|
245650
|
+
]) {
|
|
245651
|
+
reports.push(tally(await attributeByRun(o, t, j, k2), t));
|
|
245652
|
+
}
|
|
245653
|
+
reports.push(tally(await attributeDispatches(o), "dispatches"));
|
|
245654
|
+
reports.push(tally(await attributeWorkorderDrafts(o), "workorder_drafts"));
|
|
245655
|
+
reports.push(tally(await attributeInboxReadMarkers(o), "inbox_read_markers"));
|
|
245656
|
+
reports.push(tally(await attributeActorMemories(o), "actor_memories"));
|
|
245657
|
+
reports.push(tally(await attributeBlobs(o), "blobs"));
|
|
245658
|
+
return reports;
|
|
245659
|
+
}
|
|
245660
|
+
var init_tenancy_attribution = __esm({
|
|
245661
|
+
"../storage/src/tenancy-attribution.ts"() {
|
|
245662
|
+
"use strict";
|
|
245663
|
+
init_esm();
|
|
245664
|
+
init_pg_ident();
|
|
245665
|
+
}
|
|
245666
|
+
});
|
|
245667
|
+
|
|
245150
245668
|
// ../storage/src/knowledge-snapshot-crypto.ts
|
|
245151
245669
|
function sealSnapshot(snapshot, key) {
|
|
245152
245670
|
if (snapshot.content.startsWith(PREFIX3)) return structuredClone(snapshot);
|
|
@@ -245812,8 +246330,16 @@ __export(src_exports, {
|
|
|
245812
246330
|
advanceCutover: () => advanceCutover,
|
|
245813
246331
|
assertInstallersPresent: () => assertInstallersPresent,
|
|
245814
246332
|
assertTypeCatalogCovered: () => assertTypeCatalogCovered,
|
|
246333
|
+
attributeActorMemories: () => attributeActorMemories,
|
|
246334
|
+
attributeAgentRuns: () => attributeAgentRuns,
|
|
246335
|
+
attributeBlobs: () => attributeBlobs,
|
|
246336
|
+
attributeByRun: () => attributeByRun,
|
|
246337
|
+
attributeDispatches: () => attributeDispatches,
|
|
246338
|
+
attributeInboxReadMarkers: () => attributeInboxReadMarkers,
|
|
246339
|
+
attributeWorkorderDrafts: () => attributeWorkorderDrafts,
|
|
245815
246340
|
backfillTenancyColumns: () => backfillTenancyColumns,
|
|
245816
246341
|
backfillTypeRegistryFromFile: () => backfillTypeRegistryFromFile,
|
|
246342
|
+
buildActorRosterIndex: () => buildActorRosterIndex,
|
|
245817
246343
|
buildTrigger: () => buildTrigger,
|
|
245818
246344
|
canonicalTypeDefHash: () => canonicalTypeDefHash,
|
|
245819
246345
|
companySchemaName: () => companySchemaName,
|
|
@@ -245833,12 +246359,15 @@ __export(src_exports, {
|
|
|
245833
246359
|
inventoryActorsByIds: () => inventoryActorsByIds,
|
|
245834
246360
|
inventoryPublicSkills: () => inventoryPublicSkills,
|
|
245835
246361
|
inventoryTenancy: () => inventoryTenancy,
|
|
246362
|
+
inventoryZeroTenantTables: () => inventoryZeroTenantTables,
|
|
245836
246363
|
isUniqueViolation: () => isUniqueViolation2,
|
|
245837
246364
|
listTenancyCompanies: () => listTenancyCompanies,
|
|
246365
|
+
maxGate: () => maxGate,
|
|
245838
246366
|
missingTypeNames: () => missingTypeNames,
|
|
245839
246367
|
moveTenancyRows: () => moveTenancyRows,
|
|
245840
246368
|
payloadChecksum: () => payloadChecksum,
|
|
245841
246369
|
provisionCompanyDataPlaneSchema: () => provisionCompanyDataPlaneSchema,
|
|
246370
|
+
provisionNewCompanyDataPlane: () => provisionNewCompanyDataPlane,
|
|
245842
246371
|
quoteIdent: () => quoteIdent2,
|
|
245843
246372
|
renderTenancyInventoryMarkdown: () => renderTenancyInventoryMarkdown,
|
|
245844
246373
|
renderTenancyMoveReport: () => renderTenancyMoveReport,
|
|
@@ -245883,6 +246412,8 @@ var init_src11 = __esm({
|
|
|
245883
246412
|
init_cutover_aware_registry();
|
|
245884
246413
|
init_tenant_cutover();
|
|
245885
246414
|
init_tenant_migration_operator();
|
|
246415
|
+
init_tenant_new_company_provision();
|
|
246416
|
+
init_tenancy_attribution();
|
|
245886
246417
|
init_postgres_knowledge();
|
|
245887
246418
|
}
|
|
245888
246419
|
});
|
|
@@ -248199,12 +248730,25 @@ async function startServe(opts) {
|
|
|
248199
248730
|
companyId,
|
|
248200
248731
|
ownedOrgRegistry
|
|
248201
248732
|
});
|
|
248202
|
-
|
|
248203
|
-
|
|
248204
|
-
|
|
248205
|
-
|
|
248206
|
-
|
|
248207
|
-
|
|
248733
|
+
if (companyId !== defaultCompanyId) {
|
|
248734
|
+
try {
|
|
248735
|
+
const scoped = scopedRegistryFor(companyId);
|
|
248736
|
+
const rep = await provisionNewCompanyDataPlane({
|
|
248737
|
+
pool: pgPool,
|
|
248738
|
+
companyId,
|
|
248739
|
+
cutover: cutoverStore,
|
|
248740
|
+
locations: locationStore,
|
|
248741
|
+
roster: () => scoped.listActors(),
|
|
248742
|
+
legacySkillCount: async () => (await scoped.listInstalledSkills()).length,
|
|
248743
|
+
legacySchema: pgSchema,
|
|
248744
|
+
controlSchema: pgSchema,
|
|
248745
|
+
operator: "serve-provision"
|
|
248746
|
+
});
|
|
248747
|
+
if (rep.provisioned.length > 0) {
|
|
248748
|
+
console.log(`[tenancy] ${companyId} provisioning\uFF1A\u5DF2\u7F6E company-primary=${rep.provisioned.join(",")}` + (rep.skipped.length > 0 ? ` \u8DF3\u8FC7=${rep.skipped.map((x2) => `${x2.bundle}(${x2.reason})`).join("; ")}` : ""));
|
|
248749
|
+
}
|
|
248750
|
+
} catch (e) {
|
|
248751
|
+
console.error(`[tenancy] ${companyId} provisioning \u5931\u8D25\uFF0C\u672C\u6B21\u9000\u56DE legacy \u8DEF\u5F84\uFF1A${e.message}`);
|
|
248208
248752
|
}
|
|
248209
248753
|
}
|
|
248210
248754
|
const plane = { overlay, types: types2, assistants, humanPrefs };
|
|
@@ -258728,7 +259272,7 @@ function shimScript() {
|
|
|
258728
259272
|
}
|
|
258729
259273
|
|
|
258730
259274
|
// src/index.ts
|
|
258731
|
-
var PKG_VERSION = true ? "0.1.
|
|
259275
|
+
var PKG_VERSION = true ? "0.1.135" : "dev";
|
|
258732
259276
|
var LOCAL_BIN = localBin();
|
|
258733
259277
|
var NPM_PREFIX = npmPrefix();
|
|
258734
259278
|
var INSTANCE = DEFAULT_INSTANCE;
|