oasis_test_v2 2.2.30 → 2.2.32
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 +1016 -357
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1295,11 +1295,12 @@ var init_chat_session = __esm({
|
|
|
1295
1295
|
});
|
|
1296
1296
|
|
|
1297
1297
|
// ../contract/src/live-protocol.ts
|
|
1298
|
-
var NORMALIZED_PROVIDER_EVENT_VERSION;
|
|
1298
|
+
var NORMALIZED_PROVIDER_EVENT_VERSION, SUBAGENT_TASK_CODE;
|
|
1299
1299
|
var init_live_protocol = __esm({
|
|
1300
1300
|
"../contract/src/live-protocol.ts"() {
|
|
1301
1301
|
"use strict";
|
|
1302
1302
|
NORMALIZED_PROVIDER_EVENT_VERSION = 1;
|
|
1303
|
+
SUBAGENT_TASK_CODE = "subagent_task";
|
|
1303
1304
|
}
|
|
1304
1305
|
});
|
|
1305
1306
|
|
|
@@ -23127,14 +23128,132 @@ var init_filter_extra_args = __esm({
|
|
|
23127
23128
|
});
|
|
23128
23129
|
|
|
23129
23130
|
// ../adapters/src/claude-code/index.ts
|
|
23130
|
-
function createClaudeLiveParserState(streamId) {
|
|
23131
|
+
function createClaudeLiveParserState(streamId, opts = {}) {
|
|
23131
23132
|
return {
|
|
23132
23133
|
streamId,
|
|
23133
23134
|
turnNumber: 0,
|
|
23134
23135
|
turnId: `claude-turn:${streamId}:0`,
|
|
23135
|
-
blockIds: /* @__PURE__ */ new Map()
|
|
23136
|
+
blockIds: /* @__PURE__ */ new Map(),
|
|
23137
|
+
agentTasks: /* @__PURE__ */ new Map(),
|
|
23138
|
+
subagentCalls: /* @__PURE__ */ new Map(),
|
|
23139
|
+
...opts.readSubagentUsage ? { readSubagentUsage: opts.readSubagentUsage } : {}
|
|
23136
23140
|
};
|
|
23137
23141
|
}
|
|
23142
|
+
function numberOf(value2) {
|
|
23143
|
+
return typeof value2 === "number" && Number.isFinite(value2) ? value2 : void 0;
|
|
23144
|
+
}
|
|
23145
|
+
function subagentCallOf(message) {
|
|
23146
|
+
const id = stringOf(message?.id);
|
|
23147
|
+
const usage = parseResultUsage(message?.usage);
|
|
23148
|
+
if (!id || !usage) return void 0;
|
|
23149
|
+
return {
|
|
23150
|
+
id,
|
|
23151
|
+
call: {
|
|
23152
|
+
model: stringOf(message?.model) ?? "unknown",
|
|
23153
|
+
tokens: {
|
|
23154
|
+
inputTokens: usage.input ?? 0,
|
|
23155
|
+
outputTokens: usage.output ?? 0,
|
|
23156
|
+
cacheReadTokens: usage.cacheRead ?? 0,
|
|
23157
|
+
cacheCreationTokens: usage.cacheCreation ?? 0
|
|
23158
|
+
}
|
|
23159
|
+
}
|
|
23160
|
+
};
|
|
23161
|
+
}
|
|
23162
|
+
function recordSubagentCall(calls, id, call) {
|
|
23163
|
+
const prev = calls.get(id);
|
|
23164
|
+
calls.set(id, prev ? {
|
|
23165
|
+
model: call.model,
|
|
23166
|
+
tokens: {
|
|
23167
|
+
inputTokens: Math.max(prev.tokens.inputTokens, call.tokens.inputTokens),
|
|
23168
|
+
outputTokens: Math.max(prev.tokens.outputTokens, call.tokens.outputTokens),
|
|
23169
|
+
cacheReadTokens: Math.max(prev.tokens.cacheReadTokens, call.tokens.cacheReadTokens),
|
|
23170
|
+
cacheCreationTokens: Math.max(prev.tokens.cacheCreationTokens, call.tokens.cacheCreationTokens)
|
|
23171
|
+
}
|
|
23172
|
+
} : call);
|
|
23173
|
+
}
|
|
23174
|
+
function byModelOf(calls) {
|
|
23175
|
+
const out = {};
|
|
23176
|
+
for (const { model, tokens } of calls.values()) {
|
|
23177
|
+
const acc = out[model] ?? (out[model] = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheCreationTokens: 0 });
|
|
23178
|
+
acc.inputTokens += tokens.inputTokens;
|
|
23179
|
+
acc.outputTokens += tokens.outputTokens;
|
|
23180
|
+
acc.cacheReadTokens += tokens.cacheReadTokens;
|
|
23181
|
+
acc.cacheCreationTokens += tokens.cacheCreationTokens;
|
|
23182
|
+
}
|
|
23183
|
+
return out;
|
|
23184
|
+
}
|
|
23185
|
+
function readSubagentTranscriptUsage(outputFile) {
|
|
23186
|
+
try {
|
|
23187
|
+
const stat3 = fs7.statSync(outputFile);
|
|
23188
|
+
if (!stat3.isFile() || stat3.size > SUBAGENT_TRANSCRIPT_MAX_BYTES) return void 0;
|
|
23189
|
+
const calls = /* @__PURE__ */ new Map();
|
|
23190
|
+
for (const line of fs7.readFileSync(outputFile, "utf8").split("\n")) {
|
|
23191
|
+
if (!line.includes('"assistant"') || !line.includes('"usage"')) continue;
|
|
23192
|
+
let parsed;
|
|
23193
|
+
try {
|
|
23194
|
+
parsed = JSON.parse(line);
|
|
23195
|
+
} catch {
|
|
23196
|
+
continue;
|
|
23197
|
+
}
|
|
23198
|
+
if (parsed.type !== "assistant") continue;
|
|
23199
|
+
const hit = subagentCallOf(objectOf(parsed.message));
|
|
23200
|
+
if (hit) recordSubagentCall(calls, hit.id, hit.call);
|
|
23201
|
+
}
|
|
23202
|
+
return calls.size > 0 ? byModelOf(calls) : void 0;
|
|
23203
|
+
} catch {
|
|
23204
|
+
return void 0;
|
|
23205
|
+
}
|
|
23206
|
+
}
|
|
23207
|
+
function subagentTaskEvents(parsed, state) {
|
|
23208
|
+
const taskId = stringOf(parsed.task_id);
|
|
23209
|
+
if (!taskId) return [];
|
|
23210
|
+
const emit = (toolUseId, task) => [
|
|
23211
|
+
liveEvent(state, `${SUBAGENT_TASK_CODE}:${toolUseId}:${task.status}`, "control", "completed", {
|
|
23212
|
+
code: SUBAGENT_TASK_CODE,
|
|
23213
|
+
toolCallId: toolUseId,
|
|
23214
|
+
task: jsonOf(task)
|
|
23215
|
+
})
|
|
23216
|
+
];
|
|
23217
|
+
if (parsed.subtype === "task_started") {
|
|
23218
|
+
const toolUseId = stringOf(parsed.tool_use_id);
|
|
23219
|
+
if (parsed.task_type !== "local_agent" || !toolUseId) return [];
|
|
23220
|
+
const description = stringOf(parsed.description);
|
|
23221
|
+
const subagentType = stringOf(parsed.subagent_type);
|
|
23222
|
+
const info = {
|
|
23223
|
+
...description ? { description } : {},
|
|
23224
|
+
...subagentType ? { subagentType } : {},
|
|
23225
|
+
background: parsed.is_backgrounded === true
|
|
23226
|
+
};
|
|
23227
|
+
state.agentTasks.set(taskId, { toolUseId, ...info });
|
|
23228
|
+
return emit(toolUseId, { status: "running", ...info });
|
|
23229
|
+
}
|
|
23230
|
+
if (parsed.subtype === "task_notification") {
|
|
23231
|
+
const known = state.agentTasks.get(taskId);
|
|
23232
|
+
if (!known) return [];
|
|
23233
|
+
state.agentTasks.delete(taskId);
|
|
23234
|
+
const { toolUseId, ...info } = known;
|
|
23235
|
+
const usage = objectOf(parsed.usage);
|
|
23236
|
+
const summary = stringOf(parsed.summary);
|
|
23237
|
+
const totalTokens = numberOf(usage?.total_tokens);
|
|
23238
|
+
const toolUses = numberOf(usage?.tool_uses);
|
|
23239
|
+
const durationMs3 = numberOf(usage?.duration_ms);
|
|
23240
|
+
const outputFile = stringOf(parsed.output_file);
|
|
23241
|
+
const fromTranscript = outputFile ? state.readSubagentUsage?.(outputFile) : void 0;
|
|
23242
|
+
const streamCalls = state.subagentCalls.get(toolUseId);
|
|
23243
|
+
state.subagentCalls.delete(toolUseId);
|
|
23244
|
+
const tokenUsage = fromTranscript && Object.keys(fromTranscript).length > 0 ? { byModel: fromTranscript, source: "transcript" } : streamCalls?.size ? { byModel: byModelOf(streamCalls), source: "stream" } : void 0;
|
|
23245
|
+
return emit(toolUseId, {
|
|
23246
|
+
...info,
|
|
23247
|
+
status: SUBAGENT_TERMINAL[stringOf(parsed.status) ?? ""] ?? "completed",
|
|
23248
|
+
...summary ? { summary } : {},
|
|
23249
|
+
...totalTokens !== void 0 ? { totalTokens } : {},
|
|
23250
|
+
...toolUses !== void 0 ? { toolUses } : {},
|
|
23251
|
+
...durationMs3 !== void 0 ? { durationMs: durationMs3 } : {},
|
|
23252
|
+
...tokenUsage ? { usage: tokenUsage } : {}
|
|
23253
|
+
});
|
|
23254
|
+
}
|
|
23255
|
+
return [];
|
|
23256
|
+
}
|
|
23138
23257
|
function objectOf(value2) {
|
|
23139
23258
|
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2) ? value2 : void 0;
|
|
23140
23259
|
}
|
|
@@ -23167,6 +23286,18 @@ function normalizeClaudeLiveLine(line, state) {
|
|
|
23167
23286
|
const failed = parsed.is_error === true || parsed.subtype === "error";
|
|
23168
23287
|
return [liveEvent(state, itemId, "control", failed ? "turn_failed" : "turn_completed", jsonOf(parsed))];
|
|
23169
23288
|
}
|
|
23289
|
+
if (parsed.type === "system") return subagentTaskEvents(parsed, state);
|
|
23290
|
+
if (parsed.type === "assistant") {
|
|
23291
|
+
const parent = stringOf(parsed.parent_tool_use_id);
|
|
23292
|
+
const hit = parent ? subagentCallOf(objectOf(parsed.message)) : void 0;
|
|
23293
|
+
if (parent && hit) {
|
|
23294
|
+
const calls = state.subagentCalls.get(parent) ?? /* @__PURE__ */ new Map();
|
|
23295
|
+
recordSubagentCall(calls, hit.id, hit.call);
|
|
23296
|
+
state.subagentCalls.set(parent, calls);
|
|
23297
|
+
}
|
|
23298
|
+
return [];
|
|
23299
|
+
}
|
|
23300
|
+
if ((parsed.type === "user" || parsed.type === "stream_event") && stringOf(parsed.parent_tool_use_id)) return [];
|
|
23170
23301
|
if (parsed.type === "user") {
|
|
23171
23302
|
const content3 = Array.isArray(objectOf(parsed.message)?.content) ? objectOf(parsed.message).content : [];
|
|
23172
23303
|
return content3.flatMap((block) => {
|
|
@@ -23237,19 +23368,21 @@ function normalizeClaudeStreamLine(line) {
|
|
|
23237
23368
|
const message = parsed["message"];
|
|
23238
23369
|
const content3 = Array.isArray(message?.content) ? message.content : [];
|
|
23239
23370
|
const out = [];
|
|
23371
|
+
const parentToolCallId = stringOf(parsed["parent_tool_use_id"]);
|
|
23372
|
+
const sub = parentToolCallId ? { parentToolCallId } : {};
|
|
23240
23373
|
for (const block of content3) {
|
|
23241
23374
|
switch (block["type"]) {
|
|
23242
23375
|
case "text":
|
|
23243
|
-
if (type === "assistant") out.push({ kind: "message", payload: { text: block["text"] } });
|
|
23376
|
+
if (type === "assistant") out.push({ kind: "message", payload: { text: block["text"], ...sub } });
|
|
23244
23377
|
break;
|
|
23245
23378
|
case "thinking":
|
|
23246
|
-
out.push({ kind: "thought", payload: { text: block["thinking"] } });
|
|
23379
|
+
out.push({ kind: "thought", payload: { text: block["thinking"], ...sub } });
|
|
23247
23380
|
break;
|
|
23248
23381
|
case "tool_use":
|
|
23249
|
-
out.push({ kind: "tool_use", payload: { id: block["id"], name: block["name"], input: block["input"] } });
|
|
23382
|
+
out.push({ kind: "tool_use", payload: { id: block["id"], name: block["name"], input: block["input"], ...sub } });
|
|
23250
23383
|
break;
|
|
23251
23384
|
case "tool_result":
|
|
23252
|
-
out.push({ kind: "tool_result", payload: { tool_use_id: block["tool_use_id"], content: block["content"], is_error: block["is_error"] ?? false } });
|
|
23385
|
+
out.push({ kind: "tool_result", payload: { tool_use_id: block["tool_use_id"], content: block["content"], is_error: block["is_error"] ?? false, ...sub } });
|
|
23253
23386
|
break;
|
|
23254
23387
|
default:
|
|
23255
23388
|
break;
|
|
@@ -23350,7 +23483,7 @@ function accumulateClaudeUsage(acc, p2) {
|
|
|
23350
23483
|
acc.saw = true;
|
|
23351
23484
|
}
|
|
23352
23485
|
} else if (type === "result") {
|
|
23353
|
-
acc.finalUsage = mergeFinalUsage(
|
|
23486
|
+
acc.finalUsage = mergeFinalUsage(parseModelUsage(p2["modelUsage"]), parseResultUsage(p2["usage"]));
|
|
23354
23487
|
const c = p2["total_cost_usd"];
|
|
23355
23488
|
if (typeof c === "number" && Number.isFinite(c)) {
|
|
23356
23489
|
acc.costUsd = c;
|
|
@@ -23400,7 +23533,7 @@ function classifyExit(result) {
|
|
|
23400
23533
|
if (status === 429 || status === 529) return "rate-limit";
|
|
23401
23534
|
return "error";
|
|
23402
23535
|
}
|
|
23403
|
-
var import_node_child_process3, import_node_crypto8, fs7, path7, readline, CLAUDE_BLOCKED_FLAGS, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
23536
|
+
var import_node_child_process3, import_node_crypto8, fs7, path7, readline, CLAUDE_BLOCKED_FLAGS, SUBAGENT_TRANSCRIPT_MAX_BYTES, SUBAGENT_TERMINAL, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
23404
23537
|
var init_claude_code = __esm({
|
|
23405
23538
|
"../adapters/src/claude-code/index.ts"() {
|
|
23406
23539
|
"use strict";
|
|
@@ -23415,6 +23548,7 @@ var init_claude_code = __esm({
|
|
|
23415
23548
|
init_resume_classify();
|
|
23416
23549
|
init_root_bypass();
|
|
23417
23550
|
init_session_paths();
|
|
23551
|
+
init_src();
|
|
23418
23552
|
init_transcript();
|
|
23419
23553
|
init_filter_extra_args();
|
|
23420
23554
|
CLAUDE_BLOCKED_FLAGS = /* @__PURE__ */ new Map([
|
|
@@ -23445,6 +23579,13 @@ var init_claude_code = __esm({
|
|
|
23445
23579
|
["--include-partial-messages", "boolean"]
|
|
23446
23580
|
// 同上
|
|
23447
23581
|
]);
|
|
23582
|
+
SUBAGENT_TRANSCRIPT_MAX_BYTES = 32 * 1024 * 1024;
|
|
23583
|
+
SUBAGENT_TERMINAL = {
|
|
23584
|
+
completed: "completed",
|
|
23585
|
+
failed: "failed",
|
|
23586
|
+
killed: "stopped",
|
|
23587
|
+
stopped: "stopped"
|
|
23588
|
+
};
|
|
23448
23589
|
ONE_SHOT_UNSAFE_TOOLS = ["ScheduleWakeup", "CronCreate", "CronDelete", "CronList"];
|
|
23449
23590
|
ClaudeCodeAdapter = class {
|
|
23450
23591
|
constructor(opts = {}) {
|
|
@@ -23670,7 +23811,7 @@ var init_claude_code = __esm({
|
|
|
23670
23811
|
const usageAcc = newClaudeUsageAcc();
|
|
23671
23812
|
let sessionModel;
|
|
23672
23813
|
const outputCbs = [];
|
|
23673
|
-
const liveParser = createClaudeLiveParserState(`claude-live:${id}
|
|
23814
|
+
const liveParser = createClaudeLiveParserState(`claude-live:${id}`, { readSubagentUsage: readSubagentTranscriptUsage });
|
|
23674
23815
|
if (this.opts.streamJson) {
|
|
23675
23816
|
const rl = readline.createInterface({ input: child.stdout });
|
|
23676
23817
|
rl.on("line", (line) => {
|
|
@@ -28919,6 +29060,14 @@ var init_keys = __esm({
|
|
|
28919
29060
|
});
|
|
28920
29061
|
|
|
28921
29062
|
// ../adapters/src/_core/normalizer/normalizer.ts
|
|
29063
|
+
function parentToolCallIdOf(payload) {
|
|
29064
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return void 0;
|
|
29065
|
+
const id = payload.parentToolCallId;
|
|
29066
|
+
return typeof id === "string" && id !== "" ? id : void 0;
|
|
29067
|
+
}
|
|
29068
|
+
function textBlocksOf(blocks) {
|
|
29069
|
+
return blocks.map((b2) => b2 && typeof b2 === "object" && typeof b2.text === "string" ? b2.text : "").filter(Boolean).join("\n");
|
|
29070
|
+
}
|
|
28922
29071
|
var ProviderStreamNormalizer;
|
|
28923
29072
|
var init_normalizer = __esm({
|
|
28924
29073
|
"../adapters/src/_core/normalizer/normalizer.ts"() {
|
|
@@ -28955,6 +29104,8 @@ var init_normalizer = __esm({
|
|
|
28955
29104
|
producedAny = false;
|
|
28956
29105
|
/** Receipts wait for a whole output block; they never split its bytes. */
|
|
28957
29106
|
pendingInputs = /* @__PURE__ */ new Map();
|
|
29107
|
+
/** 子代理正文/思考块的序号(它们没有 provider id)。严格递增、turn 收尾清零。 */
|
|
29108
|
+
subagentBlocks = 0;
|
|
28958
29109
|
constructor(opts) {
|
|
28959
29110
|
this.providerName = opts.providerName;
|
|
28960
29111
|
this.hasLiveProtocol = opts.hasLiveProtocol === true;
|
|
@@ -28975,6 +29126,11 @@ var init_normalizer = __esm({
|
|
|
28975
29126
|
}
|
|
28976
29127
|
/** 遥测事件。 */
|
|
28977
29128
|
onTelemetry(event) {
|
|
29129
|
+
const parentToolCallId = parentToolCallIdOf(event.payload);
|
|
29130
|
+
if (parentToolCallId) {
|
|
29131
|
+
this.subagentItem(event, parentToolCallId);
|
|
29132
|
+
return;
|
|
29133
|
+
}
|
|
28978
29134
|
if (this.hasLiveProtocol && event.kind !== "tool_use") return;
|
|
28979
29135
|
if (event.kind === "message" && this.sawTextOutput) return;
|
|
28980
29136
|
const part = chatPartFromTrajectoryEvent(event);
|
|
@@ -29008,6 +29164,17 @@ var init_normalizer = __esm({
|
|
|
29008
29164
|
this.closeOpen("completed");
|
|
29009
29165
|
return;
|
|
29010
29166
|
}
|
|
29167
|
+
if (event.itemType === "control" && payload.code === SUBAGENT_TASK_CODE && typeof payload.toolCallId === "string" && payload.task && typeof payload.task === "object") {
|
|
29168
|
+
this.emitItem({
|
|
29169
|
+
key: providerItemKey(this.providerName, event.itemId),
|
|
29170
|
+
kind: "control",
|
|
29171
|
+
role: "assistant",
|
|
29172
|
+
origin: "live",
|
|
29173
|
+
opShape: { op: "set_status", status: "completed" },
|
|
29174
|
+
attrs: { code: SUBAGENT_TASK_CODE, toolCallId: payload.toolCallId, task: payload.task }
|
|
29175
|
+
});
|
|
29176
|
+
return;
|
|
29177
|
+
}
|
|
29011
29178
|
this.turnId = event.turnId || this.turnId;
|
|
29012
29179
|
if (event.operation === "turn_completed" || event.operation === "turn_failed") {
|
|
29013
29180
|
this.turnFinished(event.operation === "turn_failed" ? "failed" : "completed");
|
|
@@ -29041,11 +29208,52 @@ var init_normalizer = __esm({
|
|
|
29041
29208
|
}
|
|
29042
29209
|
if (event.operation === "completed" && event.itemType === "tool" && event.payload !== void 0) {
|
|
29043
29210
|
const id = typeof payload.tool_use_id === "string" ? payload.tool_use_id : event.itemId;
|
|
29044
|
-
const output = typeof payload.content === "string" ? payload.content : typeof payload.output === "string" ? payload.output : "";
|
|
29211
|
+
const output = typeof payload.content === "string" ? payload.content : Array.isArray(payload.content) ? textBlocksOf(payload.content) : typeof payload.output === "string" ? payload.output : "";
|
|
29045
29212
|
this.toolResult("live", id, void 0, output, payload.is_error === true);
|
|
29046
29213
|
return;
|
|
29047
29214
|
}
|
|
29048
29215
|
}
|
|
29216
|
+
/**
|
|
29217
|
+
* 子代理内部的一块(带 parentToolCallId 的 telemetry)。子代理没有 partial stream,每块到达时
|
|
29218
|
+
* 就是完整的,所以不走散文的「开一段 → 续写」,也不过认领闸、不关主线程开着的那段——后台子代理
|
|
29219
|
+
* 与主线程并发时,主线程正文不能被它切成几截。
|
|
29220
|
+
*/
|
|
29221
|
+
subagentItem(event, parentToolCallId) {
|
|
29222
|
+
const part = chatPartFromTrajectoryEvent(event);
|
|
29223
|
+
if (!part) return;
|
|
29224
|
+
const sub = { parentToolCallId };
|
|
29225
|
+
if (part.type === "text" || part.type === "thinking") {
|
|
29226
|
+
const kind = part.type;
|
|
29227
|
+
const key = providerItemKey(this.providerName, `sub:${parentToolCallId}:${kind}`, this.subagentBlocks++);
|
|
29228
|
+
this.emitItem({ key, kind, role: "assistant", origin: "telemetry", opShape: { op: "set_text", text: part.text ?? "" }, attrs: sub });
|
|
29229
|
+
this.emitItem({ key, kind, role: "assistant", origin: "telemetry", opShape: { op: "set_status", status: "completed" }, attrs: sub });
|
|
29230
|
+
return;
|
|
29231
|
+
}
|
|
29232
|
+
if (part.type === "tool_use") {
|
|
29233
|
+
const id = part.toolCallId;
|
|
29234
|
+
this.emitItem({
|
|
29235
|
+
key: id ? providerItemKey(this.providerName, `tool_use:${id}`) : this.nextFallbackKey("tool_call"),
|
|
29236
|
+
kind: "tool_call",
|
|
29237
|
+
role: "assistant",
|
|
29238
|
+
origin: "telemetry",
|
|
29239
|
+
opShape: { op: "patch_input", input: part.input ?? null },
|
|
29240
|
+
attrs: { toolName: part.toolName ?? "tool", ...id ? { toolCallId: id } : {}, ...sub }
|
|
29241
|
+
});
|
|
29242
|
+
return;
|
|
29243
|
+
}
|
|
29244
|
+
if (part.type === "tool_result") {
|
|
29245
|
+
const id = part.toolCallId;
|
|
29246
|
+
const output = part.output ?? "";
|
|
29247
|
+
this.emitItem({
|
|
29248
|
+
key: id ? providerItemKey(this.providerName, `tool_result:${id}`) : this.nextFallbackKey("tool_result"),
|
|
29249
|
+
kind: "tool_result",
|
|
29250
|
+
role: "assistant",
|
|
29251
|
+
origin: "telemetry",
|
|
29252
|
+
opShape: { op: "set_text", text: output },
|
|
29253
|
+
attrs: { output, isError: part.isError === true, ...id ? { toolCallId: id } : {}, ...sub }
|
|
29254
|
+
});
|
|
29255
|
+
}
|
|
29256
|
+
}
|
|
29049
29257
|
// ── turn 生命周期 ──────────────────────────────────────────────────────────
|
|
29050
29258
|
/** turn 收尾:关掉开着的散文、清兜底 index、报一条 turn 信号(服务端据此清 itemKeyMap)。 */
|
|
29051
29259
|
turnFinished(signal) {
|
|
@@ -29057,6 +29265,7 @@ var init_normalizer = __esm({
|
|
|
29057
29265
|
this.closedKeys.clear();
|
|
29058
29266
|
this.sawTextOutput = false;
|
|
29059
29267
|
this.producedAny = false;
|
|
29268
|
+
this.subagentBlocks = 0;
|
|
29060
29269
|
if (!produced) return;
|
|
29061
29270
|
this.emit({ normalizedVersion: NORMALIZED_PROVIDER_EVENT_VERSION, type: "turn", turnId: this.turnId, signal });
|
|
29062
29271
|
}
|
|
@@ -29282,6 +29491,341 @@ var init_src6 = __esm({
|
|
|
29282
29491
|
}
|
|
29283
29492
|
});
|
|
29284
29493
|
|
|
29494
|
+
// ../server/src/domains/actors/model-pricing.ts
|
|
29495
|
+
function lookupInMap(map, prefixKeys, candidates) {
|
|
29496
|
+
for (const candidate of candidates) {
|
|
29497
|
+
const exact = map instanceof Map ? map.get(candidate) : map[candidate];
|
|
29498
|
+
if (exact) return exact;
|
|
29499
|
+
}
|
|
29500
|
+
const prefix = prefixKeys.find((p2) => candidates.some((candidate) => candidate.startsWith(`${p2}-`) || candidate.startsWith(`${p2}:`)));
|
|
29501
|
+
if (!prefix) return null;
|
|
29502
|
+
return map instanceof Map ? map.get(prefix) ?? null : map[prefix] ?? null;
|
|
29503
|
+
}
|
|
29504
|
+
function stripBracketTier(model) {
|
|
29505
|
+
return model.replace(/\[[^\]]*\]/g, "").trim();
|
|
29506
|
+
}
|
|
29507
|
+
function modelCandidates(model) {
|
|
29508
|
+
const normalized4 = model.trim().toLowerCase();
|
|
29509
|
+
if (!normalized4) return [];
|
|
29510
|
+
const base = [
|
|
29511
|
+
normalized4,
|
|
29512
|
+
normalized4.includes(":") ? normalized4.slice(normalized4.lastIndexOf(":") + 1) : "",
|
|
29513
|
+
normalized4.includes("/") ? normalized4.slice(normalized4.lastIndexOf("/") + 1) : ""
|
|
29514
|
+
].filter(Boolean);
|
|
29515
|
+
const stripped = base.map(stripBracketTier).filter((m2) => m2 && !base.includes(m2));
|
|
29516
|
+
return [...base, ...new Set(stripped)];
|
|
29517
|
+
}
|
|
29518
|
+
function setModelPriceCacheLoader(loader) {
|
|
29519
|
+
cacheLoader = loader;
|
|
29520
|
+
}
|
|
29521
|
+
async function warmModelPriceCache() {
|
|
29522
|
+
if (!cacheLoader) return 0;
|
|
29523
|
+
try {
|
|
29524
|
+
const next = await cacheLoader();
|
|
29525
|
+
dbPrices = next;
|
|
29526
|
+
dbPrefixKeys = [...next.keys()].sort((a, b2) => b2.length - a.length);
|
|
29527
|
+
cacheLoadedAt = Date.now();
|
|
29528
|
+
return next.size;
|
|
29529
|
+
} catch (err) {
|
|
29530
|
+
console.warn(`[model-pricing] \u9884\u70ED\u4EF7\u683C\u7F13\u5B58\u5931\u8D25\uFF0C\u6CBF\u7528\u9759\u6001\u5FEB\u7167\uFF1A${String(err)}`);
|
|
29531
|
+
return 0;
|
|
29532
|
+
}
|
|
29533
|
+
}
|
|
29534
|
+
function maybeRefreshCache() {
|
|
29535
|
+
if (!cacheLoader) return;
|
|
29536
|
+
if (dbPrices && Date.now() - cacheLoadedAt < CACHE_TTL_MS2) return;
|
|
29537
|
+
if (cacheRefreshInFlight) return;
|
|
29538
|
+
cacheRefreshInFlight = warmModelPriceCache().catch(() => 0).then(() => {
|
|
29539
|
+
cacheRefreshInFlight = null;
|
|
29540
|
+
});
|
|
29541
|
+
}
|
|
29542
|
+
function priceForModel(model) {
|
|
29543
|
+
if (!model) return null;
|
|
29544
|
+
const candidates = modelCandidates(model);
|
|
29545
|
+
if (candidates.length === 0) return null;
|
|
29546
|
+
maybeRefreshCache();
|
|
29547
|
+
if (dbPrices && dbPrices.size > 0) {
|
|
29548
|
+
const fromDb = lookupInMap(dbPrices, dbPrefixKeys, candidates);
|
|
29549
|
+
if (fromDb) return fromDb;
|
|
29550
|
+
}
|
|
29551
|
+
return lookupInMap(MODEL_PRICES, STATIC_PREFIX_PRICES, candidates);
|
|
29552
|
+
}
|
|
29553
|
+
function estimateUsageCostBreakdown(model, usage) {
|
|
29554
|
+
const price = priceForModel(model);
|
|
29555
|
+
if (!price) return null;
|
|
29556
|
+
const inputTokens = Math.max(usage.inputTokens ?? 0, 0);
|
|
29557
|
+
const outputTokens = Math.max(usage.outputTokens ?? 0, 0);
|
|
29558
|
+
const cacheReadTokens = Math.max(usage.cacheReadTokens ?? 0, 0);
|
|
29559
|
+
const cacheCreationTokens = Math.max(usage.cacheCreationTokens ?? 0, 0);
|
|
29560
|
+
const cacheReadPrice = price.cachedInputPerMillion ?? price.inputPerMillion * 0.1;
|
|
29561
|
+
return {
|
|
29562
|
+
currency: price.currency,
|
|
29563
|
+
inputMicros: Math.round(inputTokens * price.inputPerMillion / 1e6 * 1e6),
|
|
29564
|
+
cacheMicros: Math.round(
|
|
29565
|
+
(cacheCreationTokens * price.inputPerMillion + cacheReadTokens * cacheReadPrice) / 1e6 * 1e6
|
|
29566
|
+
),
|
|
29567
|
+
outputMicros: Math.round(outputTokens * price.outputPerMillion / 1e6 * 1e6)
|
|
29568
|
+
};
|
|
29569
|
+
}
|
|
29570
|
+
function estimateUsageCost(model, usage) {
|
|
29571
|
+
const breakdown = estimateUsageCostBreakdown(model, usage);
|
|
29572
|
+
if (!breakdown) return null;
|
|
29573
|
+
return {
|
|
29574
|
+
currency: breakdown.currency,
|
|
29575
|
+
micros: breakdown.inputMicros + breakdown.cacheMicros + breakdown.outputMicros
|
|
29576
|
+
};
|
|
29577
|
+
}
|
|
29578
|
+
function displayCostUsdMicros(model, usage) {
|
|
29579
|
+
const stored = Math.max(usage.costUsdMicros ?? 0, 0);
|
|
29580
|
+
if (stored > 0) return stored;
|
|
29581
|
+
const estimated = estimateUsageCost(model, usage);
|
|
29582
|
+
if (!estimated || estimated.micros <= 0) return 0;
|
|
29583
|
+
if (estimated.currency === "USD") return estimated.micros;
|
|
29584
|
+
return Math.round(estimated.micros / DISPLAY_CNY_PER_USD);
|
|
29585
|
+
}
|
|
29586
|
+
var FOREIGN_MODEL_MARKUP, usd, cny, MODEL_PRICES, STATIC_PREFIX_PRICES, CACHE_TTL_MS2, dbPrices, dbPrefixKeys, cacheLoadedAt, cacheLoader, cacheRefreshInFlight;
|
|
29587
|
+
var init_model_pricing = __esm({
|
|
29588
|
+
"../server/src/domains/actors/model-pricing.ts"() {
|
|
29589
|
+
"use strict";
|
|
29590
|
+
init_src();
|
|
29591
|
+
FOREIGN_MODEL_MARKUP = 1.08;
|
|
29592
|
+
usd = (inputPerMillion, outputPerMillion, cachedInputPerMillion) => ({
|
|
29593
|
+
currency: "USD",
|
|
29594
|
+
inputPerMillion: inputPerMillion * FOREIGN_MODEL_MARKUP,
|
|
29595
|
+
outputPerMillion: outputPerMillion * FOREIGN_MODEL_MARKUP,
|
|
29596
|
+
...cachedInputPerMillion !== void 0 ? { cachedInputPerMillion: cachedInputPerMillion * FOREIGN_MODEL_MARKUP } : {}
|
|
29597
|
+
});
|
|
29598
|
+
cny = (inputPerMillion, outputPerMillion, cachedInputPerMillion) => ({
|
|
29599
|
+
currency: "CNY",
|
|
29600
|
+
inputPerMillion,
|
|
29601
|
+
outputPerMillion,
|
|
29602
|
+
...cachedInputPerMillion !== void 0 ? { cachedInputPerMillion } : {}
|
|
29603
|
+
});
|
|
29604
|
+
MODEL_PRICES = {
|
|
29605
|
+
"gpt-5.5": usd(5, 30, 0.5),
|
|
29606
|
+
"gpt-5.5-pro": usd(30, 180),
|
|
29607
|
+
"chat-latest": usd(5, 30, 0.5),
|
|
29608
|
+
"gpt-5.4-mini": usd(0.75, 4.5, 0.075),
|
|
29609
|
+
"gpt-5.4-nano": usd(0.2, 1.25, 0.02),
|
|
29610
|
+
"gpt-5.4": usd(2.5, 15, 0.25),
|
|
29611
|
+
"gpt-5.4-pro": usd(30, 180),
|
|
29612
|
+
"gpt-5.3-codex": usd(1.75, 14, 0.175),
|
|
29613
|
+
"gpt-5.2": usd(1.75, 14, 0.175),
|
|
29614
|
+
"gpt-5.2-chat-latest": usd(1.75, 14, 0.175),
|
|
29615
|
+
"gpt-5.2-pro": usd(21, 168),
|
|
29616
|
+
"gpt-5.2-codex": usd(1.75, 14, 0.175),
|
|
29617
|
+
"gpt-5.1": usd(1.25, 10, 0.125),
|
|
29618
|
+
"gpt-5.1-chat-latest": usd(1.25, 10, 0.125),
|
|
29619
|
+
"gpt-5.1-codex": usd(1.25, 10, 0.125),
|
|
29620
|
+
"gpt-5.1-codex-max": usd(1.25, 10, 0.125),
|
|
29621
|
+
"gpt-5.1-codex-mini": usd(0.25, 2, 0.025),
|
|
29622
|
+
"gpt-5-pro": usd(15, 120),
|
|
29623
|
+
"gpt-5-codex": usd(1.25, 10, 0.125),
|
|
29624
|
+
"gpt-5-search-api": usd(1.25, 10, 0.125),
|
|
29625
|
+
"gpt-5": usd(1.25, 10, 0.125),
|
|
29626
|
+
"gpt-5-mini": usd(0.25, 2, 0.025),
|
|
29627
|
+
"gpt-5-nano": usd(0.05, 0.4, 5e-3),
|
|
29628
|
+
"gpt-5-chat-latest": usd(1.25, 10, 0.125),
|
|
29629
|
+
"gpt-4.1": usd(2, 8, 0.5),
|
|
29630
|
+
"gpt-4.1-2025-04-14": usd(2, 8, 0.5),
|
|
29631
|
+
"gpt-4.1-mini": usd(0.4, 1.6, 0.1),
|
|
29632
|
+
"gpt-4.1-mini-2025-04-14": usd(0.4, 1.6, 0.1),
|
|
29633
|
+
"gpt-4.1-nano": usd(0.1, 0.4, 0.025),
|
|
29634
|
+
"gpt-4.1-nano-2025-04-14": usd(0.1, 0.4, 0.025),
|
|
29635
|
+
"o4-mini": usd(1.1, 4.4, 0.275),
|
|
29636
|
+
// o3 / o3-mini 在 codex 静态目录里可选,却一直不在价目快照里(费用记 0)。
|
|
29637
|
+
// 这两行按 OpenAI 公开价填,不是智增增快照里的行;供应商价目表同步到时以 DB 为准。
|
|
29638
|
+
"o3": usd(2, 8),
|
|
29639
|
+
"o3-mini": usd(1.1, 4.4),
|
|
29640
|
+
"claude-fable-5-1": usd(10, 50),
|
|
29641
|
+
"claude-fable-5": usd(10, 50),
|
|
29642
|
+
"claude-mythos-5-1": usd(10, 50),
|
|
29643
|
+
"claude-mythos-5": usd(10, 50),
|
|
29644
|
+
// claude-opus-5 是 Claude Code 当代默认款,却一直不在这张快照里:查不到价 → 费用记 0
|
|
29645
|
+
// (与 2026-09-04 那次 `claude-opus-5[1m]` 记 0 同一类坑)。按 Opus 档 $5/$25 补上。
|
|
29646
|
+
"claude-opus-5": usd(5, 25),
|
|
29647
|
+
"claude-opus-4-8": usd(5, 25),
|
|
29648
|
+
"claude-opus-4-7": usd(5, 25),
|
|
29649
|
+
"claude-sonnet-5": usd(2, 10),
|
|
29650
|
+
"claude-sonnet-4-6": usd(3, 15),
|
|
29651
|
+
"claude-opus-4-6": usd(5, 25),
|
|
29652
|
+
"claude-opus-4-5-20251101": usd(5, 25),
|
|
29653
|
+
"claude-opus-4-5": usd(5, 25),
|
|
29654
|
+
"claude-sonnet-4-5-20250929": usd(3, 15),
|
|
29655
|
+
// 短名同样要有:前缀比对是「表里的键是模型名的前缀」,带日期的那行匹配不上不带日期的短名。
|
|
29656
|
+
// claude-sonnet-4-5 从 2026-07-04 起就在目录里可选,却一直查不到价(费用记 0),本次一并补。
|
|
29657
|
+
"claude-sonnet-4-5": usd(3, 15),
|
|
29658
|
+
"claude-opus-4-1-20250805": usd(15, 75),
|
|
29659
|
+
"claude-opus-4-20250514": usd(15, 75),
|
|
29660
|
+
"claude-sonnet-4-20250514": usd(3, 15),
|
|
29661
|
+
"claude-3-7-sonnet-20250219": usd(3, 15),
|
|
29662
|
+
"claude-3-5-sonnet-20241022": usd(3, 15),
|
|
29663
|
+
"claude-3-5-sonnet-20240620": usd(3, 15),
|
|
29664
|
+
"claude-3-sonnet-20240229": usd(3, 15),
|
|
29665
|
+
"claude-haiku-4-5-20251001": usd(1, 5),
|
|
29666
|
+
// codebuddy 目录用点号写法(claude-sonnet-4.6),与上面的连字符写法是同一批模型,
|
|
29667
|
+
// 但字符串对不上就查不到价 → 记 0。同价另起别名行。
|
|
29668
|
+
"claude-sonnet-4.6": usd(3, 15),
|
|
29669
|
+
"claude-opus-4.7": usd(5, 25),
|
|
29670
|
+
"gemini-3.1-pro": usd(2, 12),
|
|
29671
|
+
"gemini-3-pro-preview": usd(2, 12),
|
|
29672
|
+
// Claude Code 回报的可能是不带日期的短名,短名匹配不上带日期的那行(前缀比对是「表里的键是模型名的前缀」)。
|
|
29673
|
+
"claude-haiku-4-5": usd(1, 5),
|
|
29674
|
+
"gemini-3.5-flash": usd(1.5, 9),
|
|
29675
|
+
"gemini-3.1-pro-preview": usd(2, 12),
|
|
29676
|
+
"gemini-3.1-pro-preview-customtools": usd(2, 12),
|
|
29677
|
+
"gemini-3.1-flash-lite-preview": usd(0.25, 1.5),
|
|
29678
|
+
"gemini-3-flash-preview": usd(0.5, 3),
|
|
29679
|
+
"gemini-2.5-pro": usd(1.25, 10),
|
|
29680
|
+
"gemini-2.5-flash": usd(0.3, 2.5),
|
|
29681
|
+
"gemini-2.5-flash-lite": usd(0.1, 0.4),
|
|
29682
|
+
"gemini-2.5-flash-preview-09-2025": usd(0.3, 2.5),
|
|
29683
|
+
"gemini-2.0-flash": usd(0.1, 0.4),
|
|
29684
|
+
"deepseek-v4-flash": cny(1, 2, 0.02),
|
|
29685
|
+
"deepseek-v4-pro": cny(3, 6, 0.025),
|
|
29686
|
+
"deepseek-chat": cny(2, 3),
|
|
29687
|
+
"deepseek-reasoner": cny(2, 3),
|
|
29688
|
+
"deepseek-v3.2": cny(2, 3),
|
|
29689
|
+
"deepseek-coder": cny(2, 3),
|
|
29690
|
+
"deepseek-r1": cny(4, 16),
|
|
29691
|
+
"deepseek-r1-0528": cny(4, 16),
|
|
29692
|
+
"deepseek-v3": cny(2, 8),
|
|
29693
|
+
"deepseek-v3-0324": cny(2, 8),
|
|
29694
|
+
"deepseek-v3.1": cny(4, 12),
|
|
29695
|
+
"qwen3-max": cny(6, 24),
|
|
29696
|
+
"qwen3-max-preview": cny(6, 24),
|
|
29697
|
+
"qwen3-coder-plus": cny(4, 16),
|
|
29698
|
+
"qwen3-235b-a22b": cny(4, 40),
|
|
29699
|
+
"qwen3-32b": cny(2, 20),
|
|
29700
|
+
"qwen3-30b-a3b": cny(1.5, 15),
|
|
29701
|
+
"qwen3-14b": cny(1, 10),
|
|
29702
|
+
"qwen3-8b": cny(0.5, 5),
|
|
29703
|
+
"qwen3-4b": cny(0.3, 3),
|
|
29704
|
+
"qwen3-1.7b": cny(0.3, 3),
|
|
29705
|
+
"qwen3-0.6b": cny(0.3, 3),
|
|
29706
|
+
"qwq-plus": cny(1.6, 4),
|
|
29707
|
+
"qwq-plus-latest": cny(1.6, 4),
|
|
29708
|
+
"qwq-plus-2025-03-05": cny(1.6, 4),
|
|
29709
|
+
"kimi-k2.7-code": cny(6.5, 27),
|
|
29710
|
+
"kimi-k2.6": cny(6.5, 27),
|
|
29711
|
+
"kimi-k2.5": cny(4, 21),
|
|
29712
|
+
"kimi-k2-0905-preview": cny(4, 16),
|
|
29713
|
+
"kimi-k2-0711-preview": cny(4, 16),
|
|
29714
|
+
"kimi-k2-turbo-preview": cny(8, 58)
|
|
29715
|
+
};
|
|
29716
|
+
STATIC_PREFIX_PRICES = Object.keys(MODEL_PRICES).sort((a, b2) => b2.length - a.length);
|
|
29717
|
+
CACHE_TTL_MS2 = 5 * 6e4;
|
|
29718
|
+
dbPrices = null;
|
|
29719
|
+
dbPrefixKeys = [];
|
|
29720
|
+
cacheLoadedAt = 0;
|
|
29721
|
+
cacheLoader = null;
|
|
29722
|
+
cacheRefreshInFlight = null;
|
|
29723
|
+
}
|
|
29724
|
+
});
|
|
29725
|
+
|
|
29726
|
+
// ../server/src/domains/usage/accounting.ts
|
|
29727
|
+
function nonNegative(v2) {
|
|
29728
|
+
return Math.max(v2 ?? 0, 0);
|
|
29729
|
+
}
|
|
29730
|
+
function resolvedModel(model) {
|
|
29731
|
+
const trimmed = model?.trim();
|
|
29732
|
+
return trimmed ? trimmed : null;
|
|
29733
|
+
}
|
|
29734
|
+
function splitByWeight(total, w2) {
|
|
29735
|
+
const sum = w2.input + w2.cache + w2.output;
|
|
29736
|
+
if (total === 0) return { input: 0, cache: 0, output: 0 };
|
|
29737
|
+
if (sum <= 0) return { input: 0, cache: 0, output: total };
|
|
29738
|
+
const input = Math.round(total * w2.input / sum);
|
|
29739
|
+
const cache = Math.round(total * w2.cache / sum);
|
|
29740
|
+
return { input, cache, output: total - input - cache };
|
|
29741
|
+
}
|
|
29742
|
+
function toDisplayUsd(currency, micros) {
|
|
29743
|
+
return currency === "USD" ? micros : Math.round(micros / DISPLAY_CNY_PER_USD);
|
|
29744
|
+
}
|
|
29745
|
+
function accountUsage(model, usage) {
|
|
29746
|
+
const resolved = resolvedModel(model);
|
|
29747
|
+
if (!resolved || !usage) return null;
|
|
29748
|
+
const input = nonNegative(usage.inputTokens);
|
|
29749
|
+
const output = nonNegative(usage.outputTokens);
|
|
29750
|
+
const cache = nonNegative(usage.cacheReadTokens) + nonNegative(usage.cacheCreationTokens);
|
|
29751
|
+
const tokens = { input, cache, output, total: input + cache + output };
|
|
29752
|
+
const estimated = estimateUsageCostBreakdown(resolved, usage);
|
|
29753
|
+
const weights = estimated ? { input: estimated.inputMicros, cache: estimated.cacheMicros, output: estimated.outputMicros } : null;
|
|
29754
|
+
const reported = Math.max(usage.costUsdMicros ?? 0, 0);
|
|
29755
|
+
if (reported > 0) {
|
|
29756
|
+
const parts = weights && estimated?.currency === "USD" ? splitByWeight(reported, weights) : { input: 0, cache: 0, output: reported };
|
|
29757
|
+
return {
|
|
29758
|
+
tokens,
|
|
29759
|
+
currency: "USD",
|
|
29760
|
+
amountMicros: reported,
|
|
29761
|
+
parts,
|
|
29762
|
+
displayUsdMicros: reported,
|
|
29763
|
+
displayParts: parts,
|
|
29764
|
+
source: "reported"
|
|
29765
|
+
};
|
|
29766
|
+
}
|
|
29767
|
+
if (estimated && weights) {
|
|
29768
|
+
const amount = weights.input + weights.cache + weights.output;
|
|
29769
|
+
const displayUsdMicros = toDisplayUsd(estimated.currency, amount);
|
|
29770
|
+
return {
|
|
29771
|
+
tokens,
|
|
29772
|
+
currency: estimated.currency,
|
|
29773
|
+
amountMicros: amount,
|
|
29774
|
+
parts: weights,
|
|
29775
|
+
displayUsdMicros,
|
|
29776
|
+
displayParts: estimated.currency === "USD" ? weights : splitByWeight(displayUsdMicros, weights),
|
|
29777
|
+
source: "estimated"
|
|
29778
|
+
};
|
|
29779
|
+
}
|
|
29780
|
+
return {
|
|
29781
|
+
tokens,
|
|
29782
|
+
currency: "USD",
|
|
29783
|
+
amountMicros: 0,
|
|
29784
|
+
parts: { input: 0, cache: 0, output: 0 },
|
|
29785
|
+
displayUsdMicros: 0,
|
|
29786
|
+
displayParts: { input: 0, cache: 0, output: 0 },
|
|
29787
|
+
source: "unpriced"
|
|
29788
|
+
};
|
|
29789
|
+
}
|
|
29790
|
+
function isUnpriced(account) {
|
|
29791
|
+
return account.source === "unpriced" && account.tokens.total > 0;
|
|
29792
|
+
}
|
|
29793
|
+
var init_accounting = __esm({
|
|
29794
|
+
"../server/src/domains/usage/accounting.ts"() {
|
|
29795
|
+
"use strict";
|
|
29796
|
+
init_model_pricing();
|
|
29797
|
+
}
|
|
29798
|
+
});
|
|
29799
|
+
|
|
29800
|
+
// ../server/src/subagent-cost.ts
|
|
29801
|
+
function estimateSubagentCostUsdMicros(usage) {
|
|
29802
|
+
if (!usage) return void 0;
|
|
29803
|
+
const models = Object.entries(usage.byModel);
|
|
29804
|
+
if (models.length === 0) return void 0;
|
|
29805
|
+
let total = 0;
|
|
29806
|
+
for (const [model, tokens] of models) {
|
|
29807
|
+
const account = accountUsage(model, { ...tokens, costUsdMicros: null });
|
|
29808
|
+
if (!account || account.source !== "estimated") return void 0;
|
|
29809
|
+
total += account.displayUsdMicros;
|
|
29810
|
+
}
|
|
29811
|
+
return total;
|
|
29812
|
+
}
|
|
29813
|
+
function withSubagentCostEstimate(event) {
|
|
29814
|
+
if (event.type !== "item" || event.attrs?.code !== SUBAGENT_TASK_CODE) return event;
|
|
29815
|
+
const task = event.attrs.task;
|
|
29816
|
+
if (!task?.usage || task.estimatedCostUsdMicros !== void 0) return event;
|
|
29817
|
+
const estimatedCostUsdMicros = estimateSubagentCostUsdMicros(task.usage);
|
|
29818
|
+
if (estimatedCostUsdMicros === void 0) return event;
|
|
29819
|
+
return { ...event, attrs: { ...event.attrs, task: { ...task, estimatedCostUsdMicros } } };
|
|
29820
|
+
}
|
|
29821
|
+
var init_subagent_cost = __esm({
|
|
29822
|
+
"../server/src/subagent-cost.ts"() {
|
|
29823
|
+
"use strict";
|
|
29824
|
+
init_src();
|
|
29825
|
+
init_accounting();
|
|
29826
|
+
}
|
|
29827
|
+
});
|
|
29828
|
+
|
|
29285
29829
|
// ../contract/src/chat-item.ts
|
|
29286
29830
|
var CHAT_ITEM_TERMINAL_STATUSES, isTerminalChatItemStatus, CHAT_ITEM_META_LEGACY_CONTENT;
|
|
29287
29831
|
var init_chat_item = __esm({
|
|
@@ -29305,8 +29849,9 @@ async function resolveChatItemsTurnId(items, messageId, fallback) {
|
|
|
29305
29849
|
const existing = await items.listItemsByMessage(messageId).catch(() => []);
|
|
29306
29850
|
return existing.length ? existing[existing.length - 1].turnId : fallback;
|
|
29307
29851
|
}
|
|
29308
|
-
function projectsIntoContent(kind, role, origin, telemetryTextInContent) {
|
|
29852
|
+
function projectsIntoContent(kind, role, origin, telemetryTextInContent, attrs = {}) {
|
|
29309
29853
|
if (kind !== "text" || role !== "assistant") return false;
|
|
29854
|
+
if (attrs.parentToolCallId) return false;
|
|
29310
29855
|
switch (origin) {
|
|
29311
29856
|
case "stdout":
|
|
29312
29857
|
case "live":
|
|
@@ -29322,6 +29867,7 @@ var init_chat_item_ledger = __esm({
|
|
|
29322
29867
|
"../server/src/chat-item-ledger.ts"() {
|
|
29323
29868
|
"use strict";
|
|
29324
29869
|
init_src();
|
|
29870
|
+
init_subagent_cost();
|
|
29325
29871
|
init_chat_item();
|
|
29326
29872
|
import_node_crypto15 = require("node:crypto");
|
|
29327
29873
|
CHAT_ITEMS_DOUBLE_WRITE_ENV = "OASIS_CHAT_ITEMS_DOUBLE_WRITE";
|
|
@@ -29422,7 +29968,8 @@ var init_chat_item_ledger = __esm({
|
|
|
29422
29968
|
* 应用一条归一层事件。**这是 provider 正文进入系统的唯一入口**(ADR D4(b))——
|
|
29423
29969
|
* `LiveChatRegistry.applyNormalizedEvent` 与两条恢复路都经它,别再开第二个口子。
|
|
29424
29970
|
*/
|
|
29425
|
-
apply(
|
|
29971
|
+
apply(raw) {
|
|
29972
|
+
const event = withSubagentCostEstimate(raw);
|
|
29426
29973
|
if (event.type === "turn") {
|
|
29427
29974
|
this.itemKeyMap.clear();
|
|
29428
29975
|
this.lastTurnId = null;
|
|
@@ -29661,7 +30208,7 @@ var init_chat_item_ledger = __esm({
|
|
|
29661
30208
|
// ── 内部:建行与应用 op ────────────────────────────────────────────────────
|
|
29662
30209
|
createFrom(event) {
|
|
29663
30210
|
const attrs = event.attrs ?? {};
|
|
29664
|
-
const inContent = projectsIntoContent(event.kind, event.role, event.origin, this.telemetryTextInContent);
|
|
30211
|
+
const inContent = projectsIntoContent(event.kind, event.role, event.origin, this.telemetryTextInContent, attrs);
|
|
29665
30212
|
const text5 = event.opShape.op === "append_text" || event.opShape.op === "set_text" ? event.opShape.text : "";
|
|
29666
30213
|
const status = event.kind === "text" || event.kind === "thinking" ? "streaming" : "completed";
|
|
29667
30214
|
const id = this.insert({
|
|
@@ -29733,25 +30280,33 @@ var init_chat_item_ledger = __esm({
|
|
|
29733
30280
|
}
|
|
29734
30281
|
/** 按 kind 折出落库 payload。**唯一一处** payload 形状定义,别在别处再拼一遍。 */
|
|
29735
30282
|
payloadOf(row) {
|
|
30283
|
+
const parent = row.attrs.parentToolCallId ? { parentToolCallId: row.attrs.parentToolCallId } : {};
|
|
29736
30284
|
switch (row.kind) {
|
|
29737
30285
|
case "text":
|
|
29738
30286
|
case "thinking":
|
|
29739
|
-
return { text: row.text };
|
|
30287
|
+
return { text: row.text, ...parent };
|
|
29740
30288
|
case "tool_call":
|
|
29741
30289
|
return {
|
|
29742
30290
|
toolName: row.attrs.toolName ?? "tool",
|
|
29743
30291
|
...row.attrs.toolCallId ? { toolCallId: row.attrs.toolCallId } : {},
|
|
29744
|
-
input: row.attrs.input ?? null
|
|
30292
|
+
input: row.attrs.input ?? null,
|
|
30293
|
+
...parent
|
|
29745
30294
|
};
|
|
29746
30295
|
case "tool_result":
|
|
29747
30296
|
return {
|
|
29748
30297
|
...row.attrs.toolCallId ? { toolCallId: row.attrs.toolCallId } : {},
|
|
29749
30298
|
...row.attrs.toolName ? { toolName: row.attrs.toolName } : {},
|
|
29750
30299
|
output: row.attrs.output ?? row.text,
|
|
29751
|
-
...row.attrs.isError === true ? { isError: true } : {}
|
|
30300
|
+
...row.attrs.isError === true ? { isError: true } : {},
|
|
30301
|
+
...parent
|
|
29752
30302
|
};
|
|
29753
30303
|
case "control":
|
|
29754
|
-
return {
|
|
30304
|
+
return {
|
|
30305
|
+
code: row.attrs.code ?? "control",
|
|
30306
|
+
...row.attrs.note ? { note: row.attrs.note } : {},
|
|
30307
|
+
...row.attrs.code === SUBAGENT_TASK_CODE && row.attrs.toolCallId ? { toolCallId: row.attrs.toolCallId } : {},
|
|
30308
|
+
...row.attrs.code === SUBAGENT_TASK_CODE && row.attrs.task ? { task: row.attrs.task } : {}
|
|
30309
|
+
};
|
|
29755
30310
|
}
|
|
29756
30311
|
}
|
|
29757
30312
|
insert(input) {
|
|
@@ -160517,6 +161072,35 @@ var init_infra_error = __esm({
|
|
|
160517
161072
|
}
|
|
160518
161073
|
});
|
|
160519
161074
|
|
|
161075
|
+
// ../server/src/keyed-mutex.ts
|
|
161076
|
+
function createKeyedMutex() {
|
|
161077
|
+
const tails = /* @__PURE__ */ new Map();
|
|
161078
|
+
return {
|
|
161079
|
+
async acquire(key) {
|
|
161080
|
+
const previous3 = tails.get(key) ?? Promise.resolve();
|
|
161081
|
+
let release;
|
|
161082
|
+
const mine = new Promise((resolve10) => {
|
|
161083
|
+
release = resolve10;
|
|
161084
|
+
});
|
|
161085
|
+
const tail = previous3.then(() => mine);
|
|
161086
|
+
tails.set(key, tail);
|
|
161087
|
+
await previous3;
|
|
161088
|
+
let released = false;
|
|
161089
|
+
return () => {
|
|
161090
|
+
if (released) return;
|
|
161091
|
+
released = true;
|
|
161092
|
+
release();
|
|
161093
|
+
if (tails.get(key) === tail) tails.delete(key);
|
|
161094
|
+
};
|
|
161095
|
+
}
|
|
161096
|
+
};
|
|
161097
|
+
}
|
|
161098
|
+
var init_keyed_mutex = __esm({
|
|
161099
|
+
"../server/src/keyed-mutex.ts"() {
|
|
161100
|
+
"use strict";
|
|
161101
|
+
}
|
|
161102
|
+
});
|
|
161103
|
+
|
|
160520
161104
|
// ../server/src/live-chat.ts
|
|
160521
161105
|
function normalizedKindToItemType(kind) {
|
|
160522
161106
|
if (kind === "text") return "message";
|
|
@@ -160540,7 +161124,9 @@ function v3StartedPayload(role, attrs, itemType, kind) {
|
|
|
160540
161124
|
if (attrs?.input !== void 0) base.input = attrs.input;
|
|
160541
161125
|
if (attrs?.output !== void 0) base.output = attrs.output;
|
|
160542
161126
|
if (attrs?.isError !== void 0) base.isError = attrs.isError;
|
|
161127
|
+
if (attrs?.parentToolCallId) base.parentToolCallId = attrs.parentToolCallId;
|
|
160543
161128
|
if (itemType === "control" && kind === "control" && attrs?.code) base.code = attrs.code;
|
|
161129
|
+
if (itemType === "control" && attrs?.task) base.task = attrs.task;
|
|
160544
161130
|
return base;
|
|
160545
161131
|
}
|
|
160546
161132
|
var DEFAULT_BUFFER_MAX, DEFAULT_GRACE_MS, DEFAULT_LIVE_COALESCE_MS, DEFAULT_LIVE_COALESCE_MAX_CHUNKS, DEFAULT_LIVE_COALESCE_MAX_CHARS, LiveChatRegistry;
|
|
@@ -160548,6 +161134,7 @@ var init_live_chat = __esm({
|
|
|
160548
161134
|
"../server/src/live-chat.ts"() {
|
|
160549
161135
|
"use strict";
|
|
160550
161136
|
init_chat_item_ledger();
|
|
161137
|
+
init_subagent_cost();
|
|
160551
161138
|
DEFAULT_BUFFER_MAX = 4e3;
|
|
160552
161139
|
DEFAULT_GRACE_MS = 6e4;
|
|
160553
161140
|
DEFAULT_LIVE_COALESCE_MS = 24;
|
|
@@ -160715,7 +161302,8 @@ var init_live_chat = __esm({
|
|
|
160715
161302
|
*
|
|
160716
161303
|
* 账本坏掉不影响对话;v3 emit 抛异常也不影响 v2 通路与账本落盘——两条独立通路。
|
|
160717
161304
|
*/
|
|
160718
|
-
applyNormalizedEvent(turn,
|
|
161305
|
+
applyNormalizedEvent(turn, raw) {
|
|
161306
|
+
const event = withSubagentCostEstimate(raw);
|
|
160719
161307
|
if (event.type === "item" && event.kind === "control" && event.attrs?.code === "input_consumed") {
|
|
160720
161308
|
const key = event.attrs.clientMessageKey;
|
|
160721
161309
|
if (key) turn.inputReceipts.get(key)?.consume();
|
|
@@ -203113,6 +203701,15 @@ function toApiError(err) {
|
|
|
203113
203701
|
if (isInfrastructureError(err)) return new ApiError(INFRA_ERROR_STATUS, INFRA_ERROR_CODE, message);
|
|
203114
203702
|
return new ApiError(400, "BAD_REQUEST", message);
|
|
203115
203703
|
}
|
|
203704
|
+
function workorderApplyTarget(rawBody) {
|
|
203705
|
+
try {
|
|
203706
|
+
const body2 = JSON.parse(rawBody);
|
|
203707
|
+
const briefSpawn = body2.plan?.ops?.find((op) => op.action === "spawn" && op.id === body2.briefArtifactId && op.workspace);
|
|
203708
|
+
return briefSpawn?.workspace ?? body2.plan?.workspace ?? "";
|
|
203709
|
+
} catch {
|
|
203710
|
+
return "";
|
|
203711
|
+
}
|
|
203712
|
+
}
|
|
203116
203713
|
async function loadWorkorderSnapshot(kernel, workorderId) {
|
|
203117
203714
|
if (!workorderId) return null;
|
|
203118
203715
|
const store = kernel.getStore?.();
|
|
@@ -204616,6 +205213,7 @@ async function startOasisServer(opts) {
|
|
|
204616
205213
|
const stagingWorkspace = /* @__PURE__ */ new Map();
|
|
204617
205214
|
const discussSessions = opts.discussSessions ?? /* @__PURE__ */ new Map();
|
|
204618
205215
|
const openingDiscussions = /* @__PURE__ */ new Map();
|
|
205216
|
+
const workorderApplyLocks = createKeyedMutex();
|
|
204619
205217
|
const reviewWaiters = /* @__PURE__ */ new Map();
|
|
204620
205218
|
const leftWaiterIds = /* @__PURE__ */ new Map();
|
|
204621
205219
|
const LEFT_WAITER_IDS_MAX_DRAFTS = 512;
|
|
@@ -205908,6 +206506,7 @@ async function startOasisServer(opts) {
|
|
|
205908
206506
|
}
|
|
205909
206507
|
}
|
|
205910
206508
|
if (url.pathname === "/api/workorder/apply" && req.method === "POST") {
|
|
206509
|
+
const releaseApplyLock = await workorderApplyLocks.acquire(`${currentCompanyId ?? ""}\0${workorderApplyTarget(rawBody)}`);
|
|
205911
206510
|
try {
|
|
205912
206511
|
const body2 = JSON.parse(rawBody);
|
|
205913
206512
|
let targetWs = body2.plan.workspace;
|
|
@@ -206066,6 +206665,8 @@ async function startOasisServer(opts) {
|
|
|
206066
206665
|
res.writeHead(status, { "content-type": "application/json" }).end(
|
|
206067
206666
|
JSON.stringify({ error: code2, message: err instanceof Error ? err.message : String(err) })
|
|
206068
206667
|
);
|
|
206668
|
+
} finally {
|
|
206669
|
+
releaseApplyLock();
|
|
206069
206670
|
}
|
|
206070
206671
|
return;
|
|
206071
206672
|
}
|
|
@@ -207495,6 +208096,7 @@ ${composed}`;
|
|
|
207495
208096
|
session.onTelemetry?.((event) => {
|
|
207496
208097
|
if (hasLiveProtocol && event.kind !== "tool_use") return;
|
|
207497
208098
|
if (event.kind === "message" && sawTextOutput) return;
|
|
208099
|
+
if (typeof event.payload?.parentToolCallId === "string") return;
|
|
207498
208100
|
if (liveProtocol && live && !hasLiveProtocol) {
|
|
207499
208101
|
const payload = event.payload && typeof event.payload === "object" && !Array.isArray(event.payload) ? event.payload : {};
|
|
207500
208102
|
const itemId = event.kind === "tool_use" ? typeof payload.id === "string" ? payload.id : `${liveTurnId}:tool` : event.kind === "tool_result" ? typeof payload.tool_use_id === "string" ? payload.tool_use_id : `${liveTurnId}:tool` : event.kind === "thought" ? `${liveTurnId}:thinking` : `${liveTurnId}:message`;
|
|
@@ -208787,6 +209389,7 @@ var init_server3 = __esm({
|
|
|
208787
209389
|
init_company_data_store_router();
|
|
208788
209390
|
init_router();
|
|
208789
209391
|
init_infra_error();
|
|
209392
|
+
init_keyed_mutex();
|
|
208790
209393
|
init_live_chat();
|
|
208791
209394
|
init_chat_turn_wait();
|
|
208792
209395
|
init_append_now();
|
|
@@ -211943,312 +212546,6 @@ var init_uncategorized_project = __esm({
|
|
|
211943
212546
|
}
|
|
211944
212547
|
});
|
|
211945
212548
|
|
|
211946
|
-
// ../server/src/domains/actors/model-pricing.ts
|
|
211947
|
-
function lookupInMap(map, prefixKeys, candidates) {
|
|
211948
|
-
for (const candidate of candidates) {
|
|
211949
|
-
const exact = map instanceof Map ? map.get(candidate) : map[candidate];
|
|
211950
|
-
if (exact) return exact;
|
|
211951
|
-
}
|
|
211952
|
-
const prefix = prefixKeys.find((p2) => candidates.some((candidate) => candidate.startsWith(`${p2}-`) || candidate.startsWith(`${p2}:`)));
|
|
211953
|
-
if (!prefix) return null;
|
|
211954
|
-
return map instanceof Map ? map.get(prefix) ?? null : map[prefix] ?? null;
|
|
211955
|
-
}
|
|
211956
|
-
function stripBracketTier(model) {
|
|
211957
|
-
return model.replace(/\[[^\]]*\]/g, "").trim();
|
|
211958
|
-
}
|
|
211959
|
-
function modelCandidates(model) {
|
|
211960
|
-
const normalized4 = model.trim().toLowerCase();
|
|
211961
|
-
if (!normalized4) return [];
|
|
211962
|
-
const base = [
|
|
211963
|
-
normalized4,
|
|
211964
|
-
normalized4.includes(":") ? normalized4.slice(normalized4.lastIndexOf(":") + 1) : "",
|
|
211965
|
-
normalized4.includes("/") ? normalized4.slice(normalized4.lastIndexOf("/") + 1) : ""
|
|
211966
|
-
].filter(Boolean);
|
|
211967
|
-
const stripped = base.map(stripBracketTier).filter((m2) => m2 && !base.includes(m2));
|
|
211968
|
-
return [...base, ...new Set(stripped)];
|
|
211969
|
-
}
|
|
211970
|
-
function setModelPriceCacheLoader(loader) {
|
|
211971
|
-
cacheLoader = loader;
|
|
211972
|
-
}
|
|
211973
|
-
async function warmModelPriceCache() {
|
|
211974
|
-
if (!cacheLoader) return 0;
|
|
211975
|
-
try {
|
|
211976
|
-
const next = await cacheLoader();
|
|
211977
|
-
dbPrices = next;
|
|
211978
|
-
dbPrefixKeys = [...next.keys()].sort((a, b2) => b2.length - a.length);
|
|
211979
|
-
cacheLoadedAt = Date.now();
|
|
211980
|
-
return next.size;
|
|
211981
|
-
} catch (err) {
|
|
211982
|
-
console.warn(`[model-pricing] \u9884\u70ED\u4EF7\u683C\u7F13\u5B58\u5931\u8D25\uFF0C\u6CBF\u7528\u9759\u6001\u5FEB\u7167\uFF1A${String(err)}`);
|
|
211983
|
-
return 0;
|
|
211984
|
-
}
|
|
211985
|
-
}
|
|
211986
|
-
function maybeRefreshCache() {
|
|
211987
|
-
if (!cacheLoader) return;
|
|
211988
|
-
if (dbPrices && Date.now() - cacheLoadedAt < CACHE_TTL_MS2) return;
|
|
211989
|
-
if (cacheRefreshInFlight) return;
|
|
211990
|
-
cacheRefreshInFlight = warmModelPriceCache().catch(() => 0).then(() => {
|
|
211991
|
-
cacheRefreshInFlight = null;
|
|
211992
|
-
});
|
|
211993
|
-
}
|
|
211994
|
-
function priceForModel(model) {
|
|
211995
|
-
if (!model) return null;
|
|
211996
|
-
const candidates = modelCandidates(model);
|
|
211997
|
-
if (candidates.length === 0) return null;
|
|
211998
|
-
maybeRefreshCache();
|
|
211999
|
-
if (dbPrices && dbPrices.size > 0) {
|
|
212000
|
-
const fromDb = lookupInMap(dbPrices, dbPrefixKeys, candidates);
|
|
212001
|
-
if (fromDb) return fromDb;
|
|
212002
|
-
}
|
|
212003
|
-
return lookupInMap(MODEL_PRICES, STATIC_PREFIX_PRICES, candidates);
|
|
212004
|
-
}
|
|
212005
|
-
function estimateUsageCostBreakdown(model, usage) {
|
|
212006
|
-
const price = priceForModel(model);
|
|
212007
|
-
if (!price) return null;
|
|
212008
|
-
const inputTokens = Math.max(usage.inputTokens ?? 0, 0);
|
|
212009
|
-
const outputTokens = Math.max(usage.outputTokens ?? 0, 0);
|
|
212010
|
-
const cacheReadTokens = Math.max(usage.cacheReadTokens ?? 0, 0);
|
|
212011
|
-
const cacheCreationTokens = Math.max(usage.cacheCreationTokens ?? 0, 0);
|
|
212012
|
-
const cacheReadPrice = price.cachedInputPerMillion ?? price.inputPerMillion * 0.1;
|
|
212013
|
-
return {
|
|
212014
|
-
currency: price.currency,
|
|
212015
|
-
inputMicros: Math.round(inputTokens * price.inputPerMillion / 1e6 * 1e6),
|
|
212016
|
-
cacheMicros: Math.round(
|
|
212017
|
-
(cacheCreationTokens * price.inputPerMillion + cacheReadTokens * cacheReadPrice) / 1e6 * 1e6
|
|
212018
|
-
),
|
|
212019
|
-
outputMicros: Math.round(outputTokens * price.outputPerMillion / 1e6 * 1e6)
|
|
212020
|
-
};
|
|
212021
|
-
}
|
|
212022
|
-
function estimateUsageCost(model, usage) {
|
|
212023
|
-
const breakdown = estimateUsageCostBreakdown(model, usage);
|
|
212024
|
-
if (!breakdown) return null;
|
|
212025
|
-
return {
|
|
212026
|
-
currency: breakdown.currency,
|
|
212027
|
-
micros: breakdown.inputMicros + breakdown.cacheMicros + breakdown.outputMicros
|
|
212028
|
-
};
|
|
212029
|
-
}
|
|
212030
|
-
function displayCostUsdMicros(model, usage) {
|
|
212031
|
-
const stored = Math.max(usage.costUsdMicros ?? 0, 0);
|
|
212032
|
-
if (stored > 0) return stored;
|
|
212033
|
-
const estimated = estimateUsageCost(model, usage);
|
|
212034
|
-
if (!estimated || estimated.micros <= 0) return 0;
|
|
212035
|
-
if (estimated.currency === "USD") return estimated.micros;
|
|
212036
|
-
return Math.round(estimated.micros / DISPLAY_CNY_PER_USD);
|
|
212037
|
-
}
|
|
212038
|
-
var FOREIGN_MODEL_MARKUP, usd, cny, MODEL_PRICES, STATIC_PREFIX_PRICES, CACHE_TTL_MS2, dbPrices, dbPrefixKeys, cacheLoadedAt, cacheLoader, cacheRefreshInFlight;
|
|
212039
|
-
var init_model_pricing = __esm({
|
|
212040
|
-
"../server/src/domains/actors/model-pricing.ts"() {
|
|
212041
|
-
"use strict";
|
|
212042
|
-
init_src();
|
|
212043
|
-
FOREIGN_MODEL_MARKUP = 1.08;
|
|
212044
|
-
usd = (inputPerMillion, outputPerMillion, cachedInputPerMillion) => ({
|
|
212045
|
-
currency: "USD",
|
|
212046
|
-
inputPerMillion: inputPerMillion * FOREIGN_MODEL_MARKUP,
|
|
212047
|
-
outputPerMillion: outputPerMillion * FOREIGN_MODEL_MARKUP,
|
|
212048
|
-
...cachedInputPerMillion !== void 0 ? { cachedInputPerMillion: cachedInputPerMillion * FOREIGN_MODEL_MARKUP } : {}
|
|
212049
|
-
});
|
|
212050
|
-
cny = (inputPerMillion, outputPerMillion, cachedInputPerMillion) => ({
|
|
212051
|
-
currency: "CNY",
|
|
212052
|
-
inputPerMillion,
|
|
212053
|
-
outputPerMillion,
|
|
212054
|
-
...cachedInputPerMillion !== void 0 ? { cachedInputPerMillion } : {}
|
|
212055
|
-
});
|
|
212056
|
-
MODEL_PRICES = {
|
|
212057
|
-
"gpt-5.5": usd(5, 30, 0.5),
|
|
212058
|
-
"gpt-5.5-pro": usd(30, 180),
|
|
212059
|
-
"chat-latest": usd(5, 30, 0.5),
|
|
212060
|
-
"gpt-5.4-mini": usd(0.75, 4.5, 0.075),
|
|
212061
|
-
"gpt-5.4-nano": usd(0.2, 1.25, 0.02),
|
|
212062
|
-
"gpt-5.4": usd(2.5, 15, 0.25),
|
|
212063
|
-
"gpt-5.4-pro": usd(30, 180),
|
|
212064
|
-
"gpt-5.3-codex": usd(1.75, 14, 0.175),
|
|
212065
|
-
"gpt-5.2": usd(1.75, 14, 0.175),
|
|
212066
|
-
"gpt-5.2-chat-latest": usd(1.75, 14, 0.175),
|
|
212067
|
-
"gpt-5.2-pro": usd(21, 168),
|
|
212068
|
-
"gpt-5.2-codex": usd(1.75, 14, 0.175),
|
|
212069
|
-
"gpt-5.1": usd(1.25, 10, 0.125),
|
|
212070
|
-
"gpt-5.1-chat-latest": usd(1.25, 10, 0.125),
|
|
212071
|
-
"gpt-5.1-codex": usd(1.25, 10, 0.125),
|
|
212072
|
-
"gpt-5.1-codex-max": usd(1.25, 10, 0.125),
|
|
212073
|
-
"gpt-5.1-codex-mini": usd(0.25, 2, 0.025),
|
|
212074
|
-
"gpt-5-pro": usd(15, 120),
|
|
212075
|
-
"gpt-5-codex": usd(1.25, 10, 0.125),
|
|
212076
|
-
"gpt-5-search-api": usd(1.25, 10, 0.125),
|
|
212077
|
-
"gpt-5": usd(1.25, 10, 0.125),
|
|
212078
|
-
"gpt-5-mini": usd(0.25, 2, 0.025),
|
|
212079
|
-
"gpt-5-nano": usd(0.05, 0.4, 5e-3),
|
|
212080
|
-
"gpt-5-chat-latest": usd(1.25, 10, 0.125),
|
|
212081
|
-
"gpt-4.1": usd(2, 8, 0.5),
|
|
212082
|
-
"gpt-4.1-2025-04-14": usd(2, 8, 0.5),
|
|
212083
|
-
"gpt-4.1-mini": usd(0.4, 1.6, 0.1),
|
|
212084
|
-
"gpt-4.1-mini-2025-04-14": usd(0.4, 1.6, 0.1),
|
|
212085
|
-
"gpt-4.1-nano": usd(0.1, 0.4, 0.025),
|
|
212086
|
-
"gpt-4.1-nano-2025-04-14": usd(0.1, 0.4, 0.025),
|
|
212087
|
-
"o4-mini": usd(1.1, 4.4, 0.275),
|
|
212088
|
-
// o3 / o3-mini 在 codex 静态目录里可选,却一直不在价目快照里(费用记 0)。
|
|
212089
|
-
// 这两行按 OpenAI 公开价填,不是智增增快照里的行;供应商价目表同步到时以 DB 为准。
|
|
212090
|
-
"o3": usd(2, 8),
|
|
212091
|
-
"o3-mini": usd(1.1, 4.4),
|
|
212092
|
-
"claude-fable-5-1": usd(10, 50),
|
|
212093
|
-
"claude-fable-5": usd(10, 50),
|
|
212094
|
-
"claude-mythos-5-1": usd(10, 50),
|
|
212095
|
-
"claude-mythos-5": usd(10, 50),
|
|
212096
|
-
// claude-opus-5 是 Claude Code 当代默认款,却一直不在这张快照里:查不到价 → 费用记 0
|
|
212097
|
-
// (与 2026-09-04 那次 `claude-opus-5[1m]` 记 0 同一类坑)。按 Opus 档 $5/$25 补上。
|
|
212098
|
-
"claude-opus-5": usd(5, 25),
|
|
212099
|
-
"claude-opus-4-8": usd(5, 25),
|
|
212100
|
-
"claude-opus-4-7": usd(5, 25),
|
|
212101
|
-
"claude-sonnet-5": usd(2, 10),
|
|
212102
|
-
"claude-sonnet-4-6": usd(3, 15),
|
|
212103
|
-
"claude-opus-4-6": usd(5, 25),
|
|
212104
|
-
"claude-opus-4-5-20251101": usd(5, 25),
|
|
212105
|
-
"claude-opus-4-5": usd(5, 25),
|
|
212106
|
-
"claude-sonnet-4-5-20250929": usd(3, 15),
|
|
212107
|
-
// 短名同样要有:前缀比对是「表里的键是模型名的前缀」,带日期的那行匹配不上不带日期的短名。
|
|
212108
|
-
// claude-sonnet-4-5 从 2026-07-04 起就在目录里可选,却一直查不到价(费用记 0),本次一并补。
|
|
212109
|
-
"claude-sonnet-4-5": usd(3, 15),
|
|
212110
|
-
"claude-opus-4-1-20250805": usd(15, 75),
|
|
212111
|
-
"claude-opus-4-20250514": usd(15, 75),
|
|
212112
|
-
"claude-sonnet-4-20250514": usd(3, 15),
|
|
212113
|
-
"claude-3-7-sonnet-20250219": usd(3, 15),
|
|
212114
|
-
"claude-3-5-sonnet-20241022": usd(3, 15),
|
|
212115
|
-
"claude-3-5-sonnet-20240620": usd(3, 15),
|
|
212116
|
-
"claude-3-sonnet-20240229": usd(3, 15),
|
|
212117
|
-
"claude-haiku-4-5-20251001": usd(1, 5),
|
|
212118
|
-
// codebuddy 目录用点号写法(claude-sonnet-4.6),与上面的连字符写法是同一批模型,
|
|
212119
|
-
// 但字符串对不上就查不到价 → 记 0。同价另起别名行。
|
|
212120
|
-
"claude-sonnet-4.6": usd(3, 15),
|
|
212121
|
-
"claude-opus-4.7": usd(5, 25),
|
|
212122
|
-
"gemini-3.1-pro": usd(2, 12),
|
|
212123
|
-
"gemini-3-pro-preview": usd(2, 12),
|
|
212124
|
-
// Claude Code 回报的可能是不带日期的短名,短名匹配不上带日期的那行(前缀比对是「表里的键是模型名的前缀」)。
|
|
212125
|
-
"claude-haiku-4-5": usd(1, 5),
|
|
212126
|
-
"gemini-3.5-flash": usd(1.5, 9),
|
|
212127
|
-
"gemini-3.1-pro-preview": usd(2, 12),
|
|
212128
|
-
"gemini-3.1-pro-preview-customtools": usd(2, 12),
|
|
212129
|
-
"gemini-3.1-flash-lite-preview": usd(0.25, 1.5),
|
|
212130
|
-
"gemini-3-flash-preview": usd(0.5, 3),
|
|
212131
|
-
"gemini-2.5-pro": usd(1.25, 10),
|
|
212132
|
-
"gemini-2.5-flash": usd(0.3, 2.5),
|
|
212133
|
-
"gemini-2.5-flash-lite": usd(0.1, 0.4),
|
|
212134
|
-
"gemini-2.5-flash-preview-09-2025": usd(0.3, 2.5),
|
|
212135
|
-
"gemini-2.0-flash": usd(0.1, 0.4),
|
|
212136
|
-
"deepseek-v4-flash": cny(1, 2, 0.02),
|
|
212137
|
-
"deepseek-v4-pro": cny(3, 6, 0.025),
|
|
212138
|
-
"deepseek-chat": cny(2, 3),
|
|
212139
|
-
"deepseek-reasoner": cny(2, 3),
|
|
212140
|
-
"deepseek-v3.2": cny(2, 3),
|
|
212141
|
-
"deepseek-coder": cny(2, 3),
|
|
212142
|
-
"deepseek-r1": cny(4, 16),
|
|
212143
|
-
"deepseek-r1-0528": cny(4, 16),
|
|
212144
|
-
"deepseek-v3": cny(2, 8),
|
|
212145
|
-
"deepseek-v3-0324": cny(2, 8),
|
|
212146
|
-
"deepseek-v3.1": cny(4, 12),
|
|
212147
|
-
"qwen3-max": cny(6, 24),
|
|
212148
|
-
"qwen3-max-preview": cny(6, 24),
|
|
212149
|
-
"qwen3-coder-plus": cny(4, 16),
|
|
212150
|
-
"qwen3-235b-a22b": cny(4, 40),
|
|
212151
|
-
"qwen3-32b": cny(2, 20),
|
|
212152
|
-
"qwen3-30b-a3b": cny(1.5, 15),
|
|
212153
|
-
"qwen3-14b": cny(1, 10),
|
|
212154
|
-
"qwen3-8b": cny(0.5, 5),
|
|
212155
|
-
"qwen3-4b": cny(0.3, 3),
|
|
212156
|
-
"qwen3-1.7b": cny(0.3, 3),
|
|
212157
|
-
"qwen3-0.6b": cny(0.3, 3),
|
|
212158
|
-
"qwq-plus": cny(1.6, 4),
|
|
212159
|
-
"qwq-plus-latest": cny(1.6, 4),
|
|
212160
|
-
"qwq-plus-2025-03-05": cny(1.6, 4),
|
|
212161
|
-
"kimi-k2.7-code": cny(6.5, 27),
|
|
212162
|
-
"kimi-k2.6": cny(6.5, 27),
|
|
212163
|
-
"kimi-k2.5": cny(4, 21),
|
|
212164
|
-
"kimi-k2-0905-preview": cny(4, 16),
|
|
212165
|
-
"kimi-k2-0711-preview": cny(4, 16),
|
|
212166
|
-
"kimi-k2-turbo-preview": cny(8, 58)
|
|
212167
|
-
};
|
|
212168
|
-
STATIC_PREFIX_PRICES = Object.keys(MODEL_PRICES).sort((a, b2) => b2.length - a.length);
|
|
212169
|
-
CACHE_TTL_MS2 = 5 * 6e4;
|
|
212170
|
-
dbPrices = null;
|
|
212171
|
-
dbPrefixKeys = [];
|
|
212172
|
-
cacheLoadedAt = 0;
|
|
212173
|
-
cacheLoader = null;
|
|
212174
|
-
cacheRefreshInFlight = null;
|
|
212175
|
-
}
|
|
212176
|
-
});
|
|
212177
|
-
|
|
212178
|
-
// ../server/src/domains/usage/accounting.ts
|
|
212179
|
-
function nonNegative(v2) {
|
|
212180
|
-
return Math.max(v2 ?? 0, 0);
|
|
212181
|
-
}
|
|
212182
|
-
function resolvedModel(model) {
|
|
212183
|
-
const trimmed = model?.trim();
|
|
212184
|
-
return trimmed ? trimmed : null;
|
|
212185
|
-
}
|
|
212186
|
-
function splitByWeight(total, w2) {
|
|
212187
|
-
const sum = w2.input + w2.cache + w2.output;
|
|
212188
|
-
if (total === 0) return { input: 0, cache: 0, output: 0 };
|
|
212189
|
-
if (sum <= 0) return { input: 0, cache: 0, output: total };
|
|
212190
|
-
const input = Math.round(total * w2.input / sum);
|
|
212191
|
-
const cache = Math.round(total * w2.cache / sum);
|
|
212192
|
-
return { input, cache, output: total - input - cache };
|
|
212193
|
-
}
|
|
212194
|
-
function toDisplayUsd(currency, micros) {
|
|
212195
|
-
return currency === "USD" ? micros : Math.round(micros / DISPLAY_CNY_PER_USD);
|
|
212196
|
-
}
|
|
212197
|
-
function accountUsage(model, usage) {
|
|
212198
|
-
const resolved = resolvedModel(model);
|
|
212199
|
-
if (!resolved || !usage) return null;
|
|
212200
|
-
const input = nonNegative(usage.inputTokens);
|
|
212201
|
-
const output = nonNegative(usage.outputTokens);
|
|
212202
|
-
const cache = nonNegative(usage.cacheReadTokens) + nonNegative(usage.cacheCreationTokens);
|
|
212203
|
-
const tokens = { input, cache, output, total: input + cache + output };
|
|
212204
|
-
const estimated = estimateUsageCostBreakdown(resolved, usage);
|
|
212205
|
-
const weights = estimated ? { input: estimated.inputMicros, cache: estimated.cacheMicros, output: estimated.outputMicros } : null;
|
|
212206
|
-
const reported = Math.max(usage.costUsdMicros ?? 0, 0);
|
|
212207
|
-
if (reported > 0) {
|
|
212208
|
-
const parts = weights && estimated?.currency === "USD" ? splitByWeight(reported, weights) : { input: 0, cache: 0, output: reported };
|
|
212209
|
-
return {
|
|
212210
|
-
tokens,
|
|
212211
|
-
currency: "USD",
|
|
212212
|
-
amountMicros: reported,
|
|
212213
|
-
parts,
|
|
212214
|
-
displayUsdMicros: reported,
|
|
212215
|
-
displayParts: parts,
|
|
212216
|
-
source: "reported"
|
|
212217
|
-
};
|
|
212218
|
-
}
|
|
212219
|
-
if (estimated && weights) {
|
|
212220
|
-
const amount = weights.input + weights.cache + weights.output;
|
|
212221
|
-
const displayUsdMicros = toDisplayUsd(estimated.currency, amount);
|
|
212222
|
-
return {
|
|
212223
|
-
tokens,
|
|
212224
|
-
currency: estimated.currency,
|
|
212225
|
-
amountMicros: amount,
|
|
212226
|
-
parts: weights,
|
|
212227
|
-
displayUsdMicros,
|
|
212228
|
-
displayParts: estimated.currency === "USD" ? weights : splitByWeight(displayUsdMicros, weights),
|
|
212229
|
-
source: "estimated"
|
|
212230
|
-
};
|
|
212231
|
-
}
|
|
212232
|
-
return {
|
|
212233
|
-
tokens,
|
|
212234
|
-
currency: "USD",
|
|
212235
|
-
amountMicros: 0,
|
|
212236
|
-
parts: { input: 0, cache: 0, output: 0 },
|
|
212237
|
-
displayUsdMicros: 0,
|
|
212238
|
-
displayParts: { input: 0, cache: 0, output: 0 },
|
|
212239
|
-
source: "unpriced"
|
|
212240
|
-
};
|
|
212241
|
-
}
|
|
212242
|
-
function isUnpriced(account) {
|
|
212243
|
-
return account.source === "unpriced" && account.tokens.total > 0;
|
|
212244
|
-
}
|
|
212245
|
-
var init_accounting = __esm({
|
|
212246
|
-
"../server/src/domains/usage/accounting.ts"() {
|
|
212247
|
-
"use strict";
|
|
212248
|
-
init_model_pricing();
|
|
212249
|
-
}
|
|
212250
|
-
});
|
|
212251
|
-
|
|
212252
212549
|
// ../server/src/domains/actors/stats.ts
|
|
212253
212550
|
function emptyCostBreakdown() {
|
|
212254
212551
|
return {
|
|
@@ -212404,6 +212701,66 @@ function foldSingleNodeTasks(items) {
|
|
|
212404
212701
|
}
|
|
212405
212702
|
return folded;
|
|
212406
212703
|
}
|
|
212704
|
+
function basenameOfPath(name) {
|
|
212705
|
+
const i = name.lastIndexOf("/");
|
|
212706
|
+
return i >= 0 ? name.slice(i + 1) : name;
|
|
212707
|
+
}
|
|
212708
|
+
function creatorKindOf(actorId) {
|
|
212709
|
+
if (!actorId) return null;
|
|
212710
|
+
return actorId.startsWith("actor:human:") ? "human" : "agent";
|
|
212711
|
+
}
|
|
212712
|
+
function emitChatFolders(items, chatFiles, resolveName) {
|
|
212713
|
+
const groups = /* @__PURE__ */ new Map();
|
|
212714
|
+
for (const file of chatFiles) {
|
|
212715
|
+
const list2 = groups.get(file.chatSessionId) ?? [];
|
|
212716
|
+
list2.push(file);
|
|
212717
|
+
groups.set(file.chatSessionId, list2);
|
|
212718
|
+
}
|
|
212719
|
+
for (const [sessionId, group] of groups) {
|
|
212720
|
+
const head = group[0];
|
|
212721
|
+
const folderPath = `chat:${sessionId}`;
|
|
212722
|
+
const latest = group.reduce((acc, file) => file.uploadedAt > acc ? file.uploadedAt : acc, group[0].uploadedAt);
|
|
212723
|
+
items.push({
|
|
212724
|
+
kind: "folder",
|
|
212725
|
+
id: `folder:${folderPath}`,
|
|
212726
|
+
name: head.chatTitle,
|
|
212727
|
+
path: folderPath,
|
|
212728
|
+
filePath: null,
|
|
212729
|
+
depth: 0,
|
|
212730
|
+
type: "folder",
|
|
212731
|
+
size: null,
|
|
212732
|
+
taskId: null,
|
|
212733
|
+
taskTitle: CHAT_FOLDER_TASK_LABEL,
|
|
212734
|
+
creatorKind: creatorKindOf(head.chatOwnerId),
|
|
212735
|
+
creatorId: head.chatOwnerId,
|
|
212736
|
+
creatorName: resolveName(head.chatOwnerId),
|
|
212737
|
+
updatedAt: latest,
|
|
212738
|
+
folderKind: "chat",
|
|
212739
|
+
chatSessionId: sessionId
|
|
212740
|
+
});
|
|
212741
|
+
for (const file of group) {
|
|
212742
|
+
items.push({
|
|
212743
|
+
kind: "file",
|
|
212744
|
+
id: file.fileId,
|
|
212745
|
+
name: file.name,
|
|
212746
|
+
path: `${folderPath}/${file.name}`,
|
|
212747
|
+
filePath: null,
|
|
212748
|
+
depth: 1,
|
|
212749
|
+
type: file.contentType ?? inferTypeFromName(basenameOfPath(file.name)),
|
|
212750
|
+
blobRef: file.blobId,
|
|
212751
|
+
contentType: file.contentType ?? null,
|
|
212752
|
+
size: file.size,
|
|
212753
|
+
taskId: null,
|
|
212754
|
+
taskTitle: CHAT_FOLDER_TASK_LABEL,
|
|
212755
|
+
creatorKind: creatorKindOf(file.uploadedBy),
|
|
212756
|
+
creatorId: file.uploadedBy ?? null,
|
|
212757
|
+
creatorName: file.uploadedBy ? resolveName(file.uploadedBy) : null,
|
|
212758
|
+
updatedAt: file.uploadedAt,
|
|
212759
|
+
chatSessionId: sessionId
|
|
212760
|
+
});
|
|
212761
|
+
}
|
|
212762
|
+
}
|
|
212763
|
+
}
|
|
212407
212764
|
function fillFolderSizes(items) {
|
|
212408
212765
|
const folders = items.filter((i) => i.kind === "folder" && i.path);
|
|
212409
212766
|
if (folders.length === 0) return;
|
|
@@ -212623,7 +212980,7 @@ function laterOf(a, b2) {
|
|
|
212623
212980
|
if (!b2) return a;
|
|
212624
212981
|
return b2 > a ? b2 : a;
|
|
212625
212982
|
}
|
|
212626
|
-
var DEFAULT_AGENT_ACTOR, MemoryProjectStateStore, MemoryArtifactStateStore, ProjectsService;
|
|
212983
|
+
var DEFAULT_AGENT_ACTOR, CHAT_FOLDER_TASK_LABEL, MemoryProjectStateStore, MemoryArtifactStateStore, ProjectsService;
|
|
212627
212984
|
var init_service4 = __esm({
|
|
212628
212985
|
"../server/src/domains/projects/service.ts"() {
|
|
212629
212986
|
"use strict";
|
|
@@ -212635,6 +212992,7 @@ var init_service4 = __esm({
|
|
|
212635
212992
|
init_stats();
|
|
212636
212993
|
init_node_state();
|
|
212637
212994
|
DEFAULT_AGENT_ACTOR = "actor:agent:system";
|
|
212995
|
+
CHAT_FOLDER_TASK_LABEL = "\u5BF9\u8BDD";
|
|
212638
212996
|
MemoryProjectStateStore = class {
|
|
212639
212997
|
projects = /* @__PURE__ */ new Map();
|
|
212640
212998
|
members = /* @__PURE__ */ new Map();
|
|
@@ -213410,12 +213768,12 @@ var init_service4 = __esm({
|
|
|
213410
213768
|
...items.filter((item) => item.blobRef).map((item) => `${item.name}\0${item.blobRef}`),
|
|
213411
213769
|
...files.map((file) => `${file.name}\0${file.blobId}`)
|
|
213412
213770
|
]);
|
|
213413
|
-
|
|
213771
|
+
const chatFiles = [];
|
|
213772
|
+
if (this.listChatFiles) {
|
|
213414
213773
|
for (const file of await this.listChatFiles(projectId2)) {
|
|
213415
|
-
const key = `${file.name}\0${file.blobId}`;
|
|
213774
|
+
const key = `${basenameOfPath(file.name)}\0${file.blobId}`;
|
|
213416
213775
|
if (existingFiles.has(key)) continue;
|
|
213417
|
-
|
|
213418
|
-
files.push(file);
|
|
213776
|
+
chatFiles.push(file);
|
|
213419
213777
|
}
|
|
213420
213778
|
}
|
|
213421
213779
|
for (const file of files) {
|
|
@@ -213441,8 +213799,18 @@ var init_service4 = __esm({
|
|
|
213441
213799
|
updatedAt: file.uploadedAt
|
|
213442
213800
|
});
|
|
213443
213801
|
}
|
|
213802
|
+
emitChatFolders(items, chatFiles, (actorId) => this.resolveActorName(actorId));
|
|
213444
213803
|
fillFolderSizes(items);
|
|
213804
|
+
const chatFolderTime = new Map(items.filter((item) => item.folderKind === "chat" && item.chatSessionId).map((item) => [item.chatSessionId, item.updatedAt]));
|
|
213445
213805
|
items.sort((a, b2) => {
|
|
213806
|
+
const chatA = a.chatSessionId ? 1 : 0;
|
|
213807
|
+
const chatB = b2.chatSessionId ? 1 : 0;
|
|
213808
|
+
if (chatA !== chatB) return chatA - chatB;
|
|
213809
|
+
if (a.chatSessionId && b2.chatSessionId && a.chatSessionId !== b2.chatSessionId) {
|
|
213810
|
+
const timeA = chatFolderTime.get(a.chatSessionId) ?? "";
|
|
213811
|
+
const timeB = chatFolderTime.get(b2.chatSessionId) ?? "";
|
|
213812
|
+
return timeB.localeCompare(timeA) || a.chatSessionId.localeCompare(b2.chatSessionId);
|
|
213813
|
+
}
|
|
213446
213814
|
const pathA = a.path ?? "";
|
|
213447
213815
|
const pathB = b2.path ?? "";
|
|
213448
213816
|
if (pathA !== pathB) return pathA.localeCompare(pathB);
|
|
@@ -214767,6 +215135,8 @@ var init_dev_store = __esm({
|
|
|
214767
215135
|
sessionWorkOrderKinds = /* @__PURE__ */ new Map();
|
|
214768
215136
|
/** ADR-0166 D6 待发队列(每会话一条,按 seq 升序 = 入队序)。 */
|
|
214769
215137
|
pending = /* @__PURE__ */ new Map();
|
|
215138
|
+
/** `outputs/` 产出文件的服务端副本表(2026-09-14):sessionId → 路径 → 副本。 */
|
|
215139
|
+
outputCopies = /* @__PURE__ */ new Map();
|
|
214770
215140
|
pendingSeq = 0;
|
|
214771
215141
|
async claimPendingInsert(m2) {
|
|
214772
215142
|
const list2 = this.pending.get(m2.chatSessionId) ?? [];
|
|
@@ -214950,6 +215320,7 @@ var init_dev_store = __esm({
|
|
|
214950
215320
|
this.messages.delete(id);
|
|
214951
215321
|
this.sessionWorkOrders.delete(id);
|
|
214952
215322
|
this.sessionWorkOrderKinds.delete(id);
|
|
215323
|
+
this.outputCopies.delete(id);
|
|
214953
215324
|
}
|
|
214954
215325
|
async appendMessage(m2) {
|
|
214955
215326
|
return (await this.appendMessageOnce(m2)).message;
|
|
@@ -215078,6 +215449,27 @@ var init_dev_store = __esm({
|
|
|
215078
215449
|
}
|
|
215079
215450
|
return rows.sort((left, right) => left.createdAt.localeCompare(right.createdAt) || left.messageId.localeCompare(right.messageId));
|
|
215080
215451
|
}
|
|
215452
|
+
async readOutputCopies(sessionId) {
|
|
215453
|
+
const hit = this.outputCopies.get(sessionId);
|
|
215454
|
+
return hit ? { ...hit } : null;
|
|
215455
|
+
}
|
|
215456
|
+
async mergeOutputCopies(sessionId, copies) {
|
|
215457
|
+
if (copies.length === 0 || !this.sessions.has(sessionId)) return;
|
|
215458
|
+
const next = { ...this.outputCopies.get(sessionId) ?? {} };
|
|
215459
|
+
for (const copy of copies) next[copy.path] = { ...copy };
|
|
215460
|
+
this.outputCopies.set(sessionId, next);
|
|
215461
|
+
}
|
|
215462
|
+
async listOutputCopies(projectId2) {
|
|
215463
|
+
const rows = [];
|
|
215464
|
+
for (const session of this.sessions.values()) {
|
|
215465
|
+
if (session.visibility === "internal") continue;
|
|
215466
|
+
if ((session.projectId ?? null) !== projectId2) continue;
|
|
215467
|
+
const copies = this.outputCopies.get(session.id);
|
|
215468
|
+
if (!copies || Object.keys(copies).length === 0) continue;
|
|
215469
|
+
rows.push({ sessionId: session.id, ...session.projectId ? { projectId: session.projectId } : {}, copies: { ...copies } });
|
|
215470
|
+
}
|
|
215471
|
+
return rows.sort((left, right) => left.sessionId.localeCompare(right.sessionId));
|
|
215472
|
+
}
|
|
215081
215473
|
async listRunningAssistantMessages() {
|
|
215082
215474
|
const out = [];
|
|
215083
215475
|
for (const list2 of this.messages.values()) {
|
|
@@ -216103,6 +216495,148 @@ var init_outputs_scan = __esm({
|
|
|
216103
216495
|
}
|
|
216104
216496
|
});
|
|
216105
216497
|
|
|
216498
|
+
// ../server/src/domains/chat-sessions/outputs-copy.ts
|
|
216499
|
+
function isOutputPath(path41) {
|
|
216500
|
+
return path41.startsWith(`${SESSION_OUTPUTS_DIR}/`);
|
|
216501
|
+
}
|
|
216502
|
+
function basenameOf2(path41) {
|
|
216503
|
+
const i = path41.lastIndexOf("/");
|
|
216504
|
+
return i >= 0 ? path41.slice(i + 1) : path41;
|
|
216505
|
+
}
|
|
216506
|
+
function planOutputCopies(fingerprints, copies, limits = OUTPUT_COPY_LIMITS) {
|
|
216507
|
+
const have = copies ?? {};
|
|
216508
|
+
const plan = { toCopy: [], skipped: [] };
|
|
216509
|
+
let totalBytes = 0;
|
|
216510
|
+
for (const path41 of Object.keys(fingerprints).sort((a, b2) => a.localeCompare(b2))) {
|
|
216511
|
+
if (!isOutputPath(path41)) continue;
|
|
216512
|
+
const fp = fingerprints[path41];
|
|
216513
|
+
if (typeof fp.size !== "number" || !Number.isFinite(fp.size) || typeof fp.mtime !== "string" || fp.mtime === "") continue;
|
|
216514
|
+
const copy = have[path41];
|
|
216515
|
+
if (copy && copy.size === fp.size && copy.mtime === fp.mtime) continue;
|
|
216516
|
+
if (fp.size > limits.maxFileBytes) {
|
|
216517
|
+
plan.skipped.push({ path: path41, code: "TOO_LARGE" });
|
|
216518
|
+
continue;
|
|
216519
|
+
}
|
|
216520
|
+
if (plan.toCopy.length >= limits.maxFiles || totalBytes + fp.size > limits.maxTotalBytes) {
|
|
216521
|
+
plan.skipped.push({ path: path41, code: "BUDGET" });
|
|
216522
|
+
continue;
|
|
216523
|
+
}
|
|
216524
|
+
totalBytes += fp.size;
|
|
216525
|
+
plan.toCopy.push({ path: path41, size: fp.size, mtime: fp.mtime });
|
|
216526
|
+
}
|
|
216527
|
+
return plan;
|
|
216528
|
+
}
|
|
216529
|
+
async function copySessionOutputs(deps) {
|
|
216530
|
+
const now = deps.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
216531
|
+
const limits = deps.limits ?? OUTPUT_COPY_LIMITS;
|
|
216532
|
+
const result = { copied: [], skipped: [] };
|
|
216533
|
+
let existing;
|
|
216534
|
+
try {
|
|
216535
|
+
existing = await deps.readCopies(deps.sessionId);
|
|
216536
|
+
} catch {
|
|
216537
|
+
return result;
|
|
216538
|
+
}
|
|
216539
|
+
const plan = planOutputCopies(deps.fingerprints, existing, limits);
|
|
216540
|
+
result.skipped.push(...plan.skipped);
|
|
216541
|
+
for (const file of plan.toCopy) {
|
|
216542
|
+
let read;
|
|
216543
|
+
try {
|
|
216544
|
+
read = await deps.bridge.read(
|
|
216545
|
+
deps.loc.nodeId,
|
|
216546
|
+
{ workdirKey: deps.loc.workdirKey, runtimeKind: deps.loc.runtimeKind, rtId: deps.loc.rtId, path: file.path },
|
|
216547
|
+
limits.maxFileBytes
|
|
216548
|
+
);
|
|
216549
|
+
} catch {
|
|
216550
|
+
result.skipped.push({ path: file.path, code: "READ_FAILED" });
|
|
216551
|
+
continue;
|
|
216552
|
+
}
|
|
216553
|
+
if (!read.ok) {
|
|
216554
|
+
result.skipped.push({ path: file.path, code: read.code === "TOO_LARGE" ? "TOO_LARGE" : "READ_FAILED" });
|
|
216555
|
+
continue;
|
|
216556
|
+
}
|
|
216557
|
+
const bytes2 = Buffer.from(read.contentBase64, "base64");
|
|
216558
|
+
let blobRef;
|
|
216559
|
+
try {
|
|
216560
|
+
blobRef = await deps.putBlob(new Uint8Array(bytes2));
|
|
216561
|
+
} catch {
|
|
216562
|
+
result.skipped.push({ path: file.path, code: "STORE_FAILED" });
|
|
216563
|
+
continue;
|
|
216564
|
+
}
|
|
216565
|
+
result.copied.push({
|
|
216566
|
+
path: file.path,
|
|
216567
|
+
name: basenameOf2(file.path),
|
|
216568
|
+
blobRef,
|
|
216569
|
+
contentType: read.contentType ? read.contentType : null,
|
|
216570
|
+
size: bytes2.length,
|
|
216571
|
+
// 记**扫描时**的 mtime(不是读的那一刻):下一轮拿同一把节点时钟的指纹来比,相等才算复制过。
|
|
216572
|
+
mtime: file.mtime,
|
|
216573
|
+
copiedAt: now()
|
|
216574
|
+
});
|
|
216575
|
+
}
|
|
216576
|
+
if (result.copied.length > 0) {
|
|
216577
|
+
try {
|
|
216578
|
+
await deps.mergeCopies(deps.sessionId, result.copied);
|
|
216579
|
+
} catch {
|
|
216580
|
+
result.skipped.push(...result.copied.map((copy) => ({ path: copy.path, code: "STORE_FAILED" })));
|
|
216581
|
+
result.copied = [];
|
|
216582
|
+
}
|
|
216583
|
+
}
|
|
216584
|
+
return result;
|
|
216585
|
+
}
|
|
216586
|
+
function createOutputCopyScheduler(deps) {
|
|
216587
|
+
const inFlight = /* @__PURE__ */ new Set();
|
|
216588
|
+
return {
|
|
216589
|
+
schedule(args) {
|
|
216590
|
+
const { store, chatSessionId, companyId } = args;
|
|
216591
|
+
const readCopies = store.readOutputCopies?.bind(store);
|
|
216592
|
+
const mergeCopies = store.mergeOutputCopies?.bind(store);
|
|
216593
|
+
if (!readCopies || !mergeCopies) return Promise.resolve(null);
|
|
216594
|
+
const key = `${companyId ?? ""}|${chatSessionId}`;
|
|
216595
|
+
if (inFlight.has(key)) return Promise.resolve(null);
|
|
216596
|
+
inFlight.add(key);
|
|
216597
|
+
return (async () => {
|
|
216598
|
+
try {
|
|
216599
|
+
const session = await store.getSession(chatSessionId);
|
|
216600
|
+
if (!session || session.visibility === "internal" || session.analyzedRunId) return null;
|
|
216601
|
+
if (deps.isDelegationChild && await deps.isDelegationChild(companyId, chatSessionId).catch(() => false)) return null;
|
|
216602
|
+
const result = await copySessionOutputs({
|
|
216603
|
+
bridge: args.bridge,
|
|
216604
|
+
loc: args.loc,
|
|
216605
|
+
sessionId: chatSessionId,
|
|
216606
|
+
fingerprints: args.fingerprints,
|
|
216607
|
+
readCopies,
|
|
216608
|
+
mergeCopies,
|
|
216609
|
+
putBlob: deps.putBlob,
|
|
216610
|
+
...deps.limits ? { limits: deps.limits } : {}
|
|
216611
|
+
});
|
|
216612
|
+
if (result.skipped.length > 0) {
|
|
216613
|
+
const head = result.skipped.slice(0, 5).map((s2) => `${s2.path}:${s2.code}`).join(", ");
|
|
216614
|
+
deps.log?.(`[outputs-copy] ${chatSessionId}: \u590D\u5236 ${result.copied.length} \u4E2A\uFF0C\u8DF3\u8FC7 ${result.skipped.length} \u4E2A\uFF08${head}${result.skipped.length > 5 ? " \u2026" : ""}\uFF09`);
|
|
216615
|
+
}
|
|
216616
|
+
return result;
|
|
216617
|
+
} catch (err) {
|
|
216618
|
+
deps.log?.(`[outputs-copy] ${chatSessionId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
216619
|
+
return null;
|
|
216620
|
+
} finally {
|
|
216621
|
+
inFlight.delete(key);
|
|
216622
|
+
}
|
|
216623
|
+
})();
|
|
216624
|
+
}
|
|
216625
|
+
};
|
|
216626
|
+
}
|
|
216627
|
+
var OUTPUT_COPY_LIMITS;
|
|
216628
|
+
var init_outputs_copy = __esm({
|
|
216629
|
+
"../server/src/domains/chat-sessions/outputs-copy.ts"() {
|
|
216630
|
+
"use strict";
|
|
216631
|
+
init_src();
|
|
216632
|
+
OUTPUT_COPY_LIMITS = {
|
|
216633
|
+
maxFileBytes: 2 * 1024 * 1024,
|
|
216634
|
+
maxFiles: 50,
|
|
216635
|
+
maxTotalBytes: 50 * 1024 * 1024
|
|
216636
|
+
};
|
|
216637
|
+
}
|
|
216638
|
+
});
|
|
216639
|
+
|
|
216106
216640
|
// ../server/src/org-model-backfill.ts
|
|
216107
216641
|
function resolveDisplayName(existing, humanActor, accountName) {
|
|
216108
216642
|
const pick3 = existing?.trim() || humanActor?.name?.trim() || accountName?.trim();
|
|
@@ -225139,7 +225673,11 @@ function toApiProjectFilesView(view) {
|
|
|
225139
225673
|
creator_kind: item.creatorKind,
|
|
225140
225674
|
creator_id: item.creatorId,
|
|
225141
225675
|
creator_name: item.creatorName,
|
|
225142
|
-
updated_at: item.updatedAt
|
|
225676
|
+
updated_at: item.updatedAt,
|
|
225677
|
+
// 对话文件夹(`"chat"`):前端据此换带对话气泡的文件夹图标。其余文件夹与文件行为 null。
|
|
225678
|
+
folder_kind: item.folderKind ?? null,
|
|
225679
|
+
// 对话文件夹及其子文件所属的对话;前端「所属任务」列的「对话」筛选档靠它。其余行为 null。
|
|
225680
|
+
chat_session_id: item.chatSessionId ?? null
|
|
225143
225681
|
}))
|
|
225144
225682
|
};
|
|
225145
225683
|
}
|
|
@@ -229589,37 +230127,93 @@ var init_files_view = __esm({
|
|
|
229589
230127
|
});
|
|
229590
230128
|
|
|
229591
230129
|
// ../server/src/domains/projects/chat-files.ts
|
|
229592
|
-
|
|
229593
|
-
|
|
229594
|
-
|
|
229595
|
-
|
|
229596
|
-
|
|
229597
|
-
|
|
229598
|
-
|
|
229599
|
-
|
|
229600
|
-
const
|
|
229601
|
-
const
|
|
229602
|
-
|
|
229603
|
-
|
|
229604
|
-
|
|
229605
|
-
|
|
229606
|
-
|
|
229607
|
-
|
|
229608
|
-
|
|
229609
|
-
|
|
229610
|
-
|
|
229611
|
-
|
|
229612
|
-
|
|
229613
|
-
|
|
229614
|
-
|
|
229615
|
-
|
|
229616
|
-
|
|
230130
|
+
function chatFolderTitle(session) {
|
|
230131
|
+
const title = session.title?.trim();
|
|
230132
|
+
return title ? title : "\u672A\u547D\u540D\u5BF9\u8BDD";
|
|
230133
|
+
}
|
|
230134
|
+
function outputDisplayName(path41) {
|
|
230135
|
+
return path41.startsWith("outputs/") ? path41.slice("outputs/".length) : path41;
|
|
230136
|
+
}
|
|
230137
|
+
async function collectProjectChatFiles(chat, projectId2, meta, options = {}) {
|
|
230138
|
+
const scope = isUncategorizedProjectId(projectId2) ? null : projectId2;
|
|
230139
|
+
const [attachmentMessages, outputSessions] = await Promise.all([
|
|
230140
|
+
chat.listAttachmentMessages ? chat.listAttachmentMessages(scope) : Promise.resolve([]),
|
|
230141
|
+
chat.listOutputCopies ? chat.listOutputCopies(scope) : Promise.resolve([])
|
|
230142
|
+
]);
|
|
230143
|
+
const sessionIds = [.../* @__PURE__ */ new Set([
|
|
230144
|
+
...attachmentMessages.map((m2) => m2.sessionId),
|
|
230145
|
+
...outputSessions.map((s2) => s2.sessionId)
|
|
230146
|
+
])];
|
|
230147
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
230148
|
+
await Promise.all(sessionIds.map(async (id) => {
|
|
230149
|
+
const session = await chat.getSession(id);
|
|
230150
|
+
if (!session) return;
|
|
230151
|
+
if ((session.projectId ?? null) !== scope) return;
|
|
230152
|
+
if (session.visibility === "internal" || session.analyzedRunId) return;
|
|
230153
|
+
if (options.isDelegationChild && await options.isDelegationChild(id).catch(() => false)) return;
|
|
230154
|
+
sessions.set(id, session);
|
|
230155
|
+
}));
|
|
230156
|
+
const out = [];
|
|
230157
|
+
const base = (session) => ({
|
|
230158
|
+
projectId: projectId2,
|
|
230159
|
+
chatSessionId: session.id,
|
|
230160
|
+
chatTitle: chatFolderTitle(session),
|
|
230161
|
+
chatOwnerId: session.humanActorId
|
|
229617
230162
|
});
|
|
230163
|
+
const bySession = /* @__PURE__ */ new Map();
|
|
230164
|
+
for (const message of attachmentMessages) {
|
|
230165
|
+
if (!sessions.has(message.sessionId)) continue;
|
|
230166
|
+
const list2 = bySession.get(message.sessionId) ?? [];
|
|
230167
|
+
list2.push(message);
|
|
230168
|
+
bySession.set(message.sessionId, list2);
|
|
230169
|
+
}
|
|
230170
|
+
for (const [sessionId, messages] of bySession) {
|
|
230171
|
+
const session = sessions.get(sessionId);
|
|
230172
|
+
const rows = await collectMessageFiles(messages.map((m2) => ({ ...m2, id: m2.messageId })), { meta });
|
|
230173
|
+
for (const row of mergeChatSessionFiles(rows, [])) {
|
|
230174
|
+
if (row.blob_ref === null) continue;
|
|
230175
|
+
out.push({
|
|
230176
|
+
...base(session),
|
|
230177
|
+
fileId: `chat:${sessionId}:${row.id}`,
|
|
230178
|
+
name: row.name,
|
|
230179
|
+
blobId: row.blob_ref,
|
|
230180
|
+
...row.content_type ? { contentType: row.content_type } : {},
|
|
230181
|
+
size: row.size,
|
|
230182
|
+
uploadedBy: session.humanActorId,
|
|
230183
|
+
uploadedAt: row.updated_at,
|
|
230184
|
+
chatSource: "attachment"
|
|
230185
|
+
});
|
|
230186
|
+
}
|
|
230187
|
+
}
|
|
230188
|
+
for (const record8 of outputSessions) {
|
|
230189
|
+
const session = sessions.get(record8.sessionId);
|
|
230190
|
+
if (!session) continue;
|
|
230191
|
+
const seen = new Set(out.filter((file) => file.chatSessionId === session.id).map((file) => `${file.name}\0${file.blobId}`));
|
|
230192
|
+
const copies = record8.copies ?? {};
|
|
230193
|
+
for (const path41 of Object.keys(copies).sort((a, b2) => a.localeCompare(b2))) {
|
|
230194
|
+
const copy = copies[path41];
|
|
230195
|
+
if (!copy?.blobRef) continue;
|
|
230196
|
+
if (seen.has(`${copy.name}\0${copy.blobRef}`)) continue;
|
|
230197
|
+
out.push({
|
|
230198
|
+
...base(session),
|
|
230199
|
+
fileId: `chat:${session.id}:out:${copy.path}`,
|
|
230200
|
+
name: outputDisplayName(copy.path),
|
|
230201
|
+
blobId: copy.blobRef,
|
|
230202
|
+
...copy.contentType ? { contentType: copy.contentType } : {},
|
|
230203
|
+
size: copy.size,
|
|
230204
|
+
uploadedBy: session.aiActorId,
|
|
230205
|
+
uploadedAt: Number.isNaN(Date.parse(copy.mtime)) ? copy.copiedAt : new Date(copy.mtime).toISOString(),
|
|
230206
|
+
chatSource: "output"
|
|
230207
|
+
});
|
|
230208
|
+
}
|
|
230209
|
+
}
|
|
230210
|
+
return out;
|
|
229618
230211
|
}
|
|
229619
230212
|
var init_chat_files2 = __esm({
|
|
229620
230213
|
"../server/src/domains/projects/chat-files.ts"() {
|
|
229621
230214
|
"use strict";
|
|
229622
230215
|
init_files_view();
|
|
230216
|
+
init_uncategorized_project();
|
|
229623
230217
|
}
|
|
229624
230218
|
});
|
|
229625
230219
|
|
|
@@ -248817,6 +249411,7 @@ var init_postgres_chat_sessions = __esm({
|
|
|
248817
249411
|
await pool.query(`ALTER TABLE ${q2}.chat_sessions ADD COLUMN IF NOT EXISTS model text`);
|
|
248818
249412
|
await pool.query(`ALTER TABLE ${q2}.chat_sessions ADD COLUMN IF NOT EXISTS visibility text`);
|
|
248819
249413
|
await pool.query(`ALTER TABLE ${q2}.chat_sessions ADD COLUMN IF NOT EXISTS outputs_fingerprints jsonb`);
|
|
249414
|
+
await pool.query(`ALTER TABLE ${q2}.chat_sessions ADD COLUMN IF NOT EXISTS outputs_copies jsonb`);
|
|
248820
249415
|
await pool.query(`
|
|
248821
249416
|
WITH ranked AS (
|
|
248822
249417
|
SELECT id, row_number() OVER (PARTITION BY session_id ORDER BY seq, created_at, id) AS rn
|
|
@@ -249064,6 +249659,53 @@ var init_postgres_chat_sessions = __esm({
|
|
|
249064
249659
|
[JSON.stringify(fingerprints), sessionId, this.companyId]
|
|
249065
249660
|
);
|
|
249066
249661
|
}
|
|
249662
|
+
/**
|
|
249663
|
+
* `outputs/` 产出文件的服务端副本表(2026-09-14)。读:没有副本 → null。
|
|
249664
|
+
*/
|
|
249665
|
+
async readOutputCopies(sessionId) {
|
|
249666
|
+
const r = await this.pool.query(
|
|
249667
|
+
`SELECT outputs_copies FROM ${this.s}.chat_sessions WHERE id = $1 AND company_id = $2`,
|
|
249668
|
+
[sessionId, this.companyId]
|
|
249669
|
+
);
|
|
249670
|
+
return r.rows[0]?.outputs_copies ?? null;
|
|
249671
|
+
}
|
|
249672
|
+
/**
|
|
249673
|
+
* 按路径**合并**写入:同一路径新副本覆盖旧副本,其余路径保留。合并在一条 UPDATE 里用 jsonb `||` 完成,
|
|
249674
|
+
* 不是读出来改完再整份写回——两次收尾的复制前后脚落库时,后写的不会把先写的吞掉。
|
|
249675
|
+
*/
|
|
249676
|
+
async mergeOutputCopies(sessionId, copies) {
|
|
249677
|
+
if (copies.length === 0) return;
|
|
249678
|
+
const patch = {};
|
|
249679
|
+
for (const copy of copies) patch[copy.path] = copy;
|
|
249680
|
+
await this.pool.query(
|
|
249681
|
+
`UPDATE ${this.s}.chat_sessions
|
|
249682
|
+
SET outputs_copies = COALESCE(outputs_copies, '{}'::jsonb) || $1::jsonb
|
|
249683
|
+
WHERE id = $2 AND company_id = $3`,
|
|
249684
|
+
[JSON.stringify(patch), sessionId, this.companyId]
|
|
249685
|
+
);
|
|
249686
|
+
}
|
|
249687
|
+
/**
|
|
249688
|
+
* 某个范围内有副本的会话。口径同 {@link listAttachmentMessages}:排除内部会话、按公司收口、
|
|
249689
|
+
* `project_id IS NOT DISTINCT FROM $1`(null = 没绑项目的会话)。只取三列,不碰会话其余字段。
|
|
249690
|
+
*/
|
|
249691
|
+
async listOutputCopies(projectId2) {
|
|
249692
|
+
const r = await this.pool.query(
|
|
249693
|
+
`SELECT id, project_id, outputs_copies
|
|
249694
|
+
FROM ${this.s}.chat_sessions
|
|
249695
|
+
WHERE outputs_copies IS NOT NULL
|
|
249696
|
+
AND outputs_copies <> '{}'::jsonb
|
|
249697
|
+
AND visibility IS DISTINCT FROM 'internal'
|
|
249698
|
+
AND project_id IS NOT DISTINCT FROM $1
|
|
249699
|
+
AND company_id = $2
|
|
249700
|
+
ORDER BY id`,
|
|
249701
|
+
[projectId2, this.companyId]
|
|
249702
|
+
);
|
|
249703
|
+
return r.rows.map((row) => ({
|
|
249704
|
+
sessionId: row.id,
|
|
249705
|
+
...row.project_id ? { projectId: row.project_id } : {},
|
|
249706
|
+
copies: row.outputs_copies ?? {}
|
|
249707
|
+
}));
|
|
249708
|
+
}
|
|
249067
249709
|
/** 删项目时把本公司里绑到它的会话回落成「不指定项目」。会话一条都不删,只清 project_id。 */
|
|
249068
249710
|
async clearProjectBinding(projectId2) {
|
|
249069
249711
|
if (!projectId2) return 0;
|
|
@@ -259242,6 +259884,7 @@ var init_src11 = __esm({
|
|
|
259242
259884
|
init_company_scoped_registry();
|
|
259243
259885
|
init_session_workdir();
|
|
259244
259886
|
init_outputs_scan();
|
|
259887
|
+
init_outputs_copy();
|
|
259245
259888
|
init_org_model_backfill();
|
|
259246
259889
|
init_types_admin();
|
|
259247
259890
|
init_roles_admin();
|
|
@@ -261050,6 +261693,13 @@ async function startServe(opts) {
|
|
|
261050
261693
|
}
|
|
261051
261694
|
}
|
|
261052
261695
|
return null;
|
|
261696
|
+
}, {
|
|
261697
|
+
// 委派子会话不进项目(ADR 0555:它的 outputs/ 是交给协调者的)。闭包在请求时才读
|
|
261698
|
+
// `delegationStoreFor`,避开它在下方声明的 TDZ。
|
|
261699
|
+
isDelegationChild: async (sessionId) => {
|
|
261700
|
+
const ledger = await delegationStoreFor(companyId).catch(() => null);
|
|
261701
|
+
return Boolean(ledger && await ledger.getByChildSession(sessionId).catch(() => null));
|
|
261702
|
+
}
|
|
261053
261703
|
});
|
|
261054
261704
|
},
|
|
261055
261705
|
projects: projectStateStore,
|
|
@@ -262212,6 +262862,14 @@ async function startServe(opts) {
|
|
|
262212
262862
|
delegationStores.set(id, store);
|
|
262213
262863
|
return store;
|
|
262214
262864
|
};
|
|
262865
|
+
const outputCopyScheduler = createOutputCopyScheduler({
|
|
262866
|
+
putBlob: (bytes2) => assets.put(bytes2),
|
|
262867
|
+
isDelegationChild: async (companyId, sessionId) => {
|
|
262868
|
+
const ledger = await delegationStoreFor(companyId).catch(() => null);
|
|
262869
|
+
return Boolean(ledger && await ledger.getByChildSession(sessionId).catch(() => null));
|
|
262870
|
+
},
|
|
262871
|
+
log: (message) => console.warn(message)
|
|
262872
|
+
});
|
|
262215
262873
|
const chatBroadcastMarkers = /* @__PURE__ */ new Map([
|
|
262216
262874
|
[defaultCompanyId, chatBroadcastMarker]
|
|
262217
262875
|
]);
|
|
@@ -262943,6 +263601,7 @@ async function startServe(opts) {
|
|
|
262943
263601
|
readFingerprints: read,
|
|
262944
263602
|
writeFingerprints: write
|
|
262945
263603
|
}).catch(() => null);
|
|
263604
|
+
if (diff && store) void outputCopyScheduler.schedule({ store, bridge, loc: located.loc, chatSessionId, companyId, fingerprints: diff.fingerprints });
|
|
262946
263605
|
return diff?.changed ?? null;
|
|
262947
263606
|
},
|
|
262948
263607
|
delegationWorkdir: createDelegationWorkdirPort({
|
|
@@ -273778,7 +274437,7 @@ function shimScript() {
|
|
|
273778
274437
|
}
|
|
273779
274438
|
|
|
273780
274439
|
// src/index.ts
|
|
273781
|
-
var PKG_VERSION = true ? "2.2.
|
|
274440
|
+
var PKG_VERSION = true ? "2.2.32" : "dev";
|
|
273782
274441
|
var LOCAL_BIN = localBin();
|
|
273783
274442
|
var NPM_PREFIX = npmPrefix();
|
|
273784
274443
|
var INSTANCE = DEFAULT_INSTANCE;
|