oasis_test 0.1.121 → 0.1.122
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 +1696 -375
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2877,11 +2877,18 @@ var init_execution_continuity = __esm({
|
|
|
2877
2877
|
});
|
|
2878
2878
|
|
|
2879
2879
|
// ../contract/src/automation.ts
|
|
2880
|
-
|
|
2880
|
+
function normalizeChatTarget(raw) {
|
|
2881
|
+
if (raw?.mode === "existing_session" && typeof raw.sessionId === "string" && raw.sessionId) {
|
|
2882
|
+
return { mode: "existing_session", sessionId: raw.sessionId };
|
|
2883
|
+
}
|
|
2884
|
+
return DEFAULT_CHAT_TARGET;
|
|
2885
|
+
}
|
|
2886
|
+
var AUTOMATION_EVENT_NAMES, DEFAULT_CHAT_TARGET;
|
|
2881
2887
|
var init_automation = __esm({
|
|
2882
2888
|
"../contract/src/automation.ts"() {
|
|
2883
2889
|
"use strict";
|
|
2884
2890
|
AUTOMATION_EVENT_NAMES = ["workorder.completed"];
|
|
2891
|
+
DEFAULT_CHAT_TARGET = { mode: "new_session" };
|
|
2885
2892
|
}
|
|
2886
2893
|
});
|
|
2887
2894
|
|
|
@@ -2899,6 +2906,19 @@ var init_chat = __esm({
|
|
|
2899
2906
|
}
|
|
2900
2907
|
});
|
|
2901
2908
|
|
|
2909
|
+
// ../contract/src/chat-turn.ts
|
|
2910
|
+
function automationTurnSourceRunId(automationRunId) {
|
|
2911
|
+
return `automation:${automationRunId}`;
|
|
2912
|
+
}
|
|
2913
|
+
function automationTurnMessageKey(automationRunId) {
|
|
2914
|
+
return `automation-message:${automationRunId}`;
|
|
2915
|
+
}
|
|
2916
|
+
var init_chat_turn = __esm({
|
|
2917
|
+
"../contract/src/chat-turn.ts"() {
|
|
2918
|
+
"use strict";
|
|
2919
|
+
}
|
|
2920
|
+
});
|
|
2921
|
+
|
|
2902
2922
|
// ../contract/src/knowledge.ts
|
|
2903
2923
|
var init_knowledge = __esm({
|
|
2904
2924
|
"../contract/src/knowledge.ts"() {
|
|
@@ -2952,6 +2972,7 @@ var init_src2 = __esm({
|
|
|
2952
2972
|
init_automation();
|
|
2953
2973
|
init_playbook();
|
|
2954
2974
|
init_chat();
|
|
2975
|
+
init_chat_turn();
|
|
2955
2976
|
init_knowledge();
|
|
2956
2977
|
init_http_api();
|
|
2957
2978
|
}
|
|
@@ -18615,6 +18636,111 @@ var init_command_policy = __esm({
|
|
|
18615
18636
|
}
|
|
18616
18637
|
});
|
|
18617
18638
|
|
|
18639
|
+
// ../server/src/chat-turn-gate.ts
|
|
18640
|
+
function localTurnSourceRunId(source, turnId) {
|
|
18641
|
+
return `${source}:${turnId}`;
|
|
18642
|
+
}
|
|
18643
|
+
function localTurnMessageKey(source, turnId) {
|
|
18644
|
+
return `${source}-message:${turnId}`;
|
|
18645
|
+
}
|
|
18646
|
+
async function openChatTurn(args) {
|
|
18647
|
+
const turns = args.turns;
|
|
18648
|
+
if (!turns) return { ok: true, turn: null };
|
|
18649
|
+
const nowIso = args.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
18650
|
+
const turnId = (args.newId ?? import_node_crypto4.randomUUID)();
|
|
18651
|
+
const messageKey = localTurnMessageKey(args.source, turnId);
|
|
18652
|
+
const claim = await turns.claimTurn({
|
|
18653
|
+
turnId,
|
|
18654
|
+
chatSessionId: args.chatSessionId,
|
|
18655
|
+
source: args.source,
|
|
18656
|
+
sourceRunId: localTurnSourceRunId(args.source, turnId),
|
|
18657
|
+
messageKey,
|
|
18658
|
+
reservedAt: nowIso()
|
|
18659
|
+
});
|
|
18660
|
+
if (claim.outcome === "busy") return { ok: false, activeTurn: claim.activeTurn };
|
|
18661
|
+
const id = claim.turn.id;
|
|
18662
|
+
let settled = false;
|
|
18663
|
+
return {
|
|
18664
|
+
ok: true,
|
|
18665
|
+
turn: {
|
|
18666
|
+
id,
|
|
18667
|
+
messageKey: claim.turn.messageKey,
|
|
18668
|
+
async start(handles) {
|
|
18669
|
+
await turns.settleTurn(id, {
|
|
18670
|
+
status: "running",
|
|
18671
|
+
startedAt: nowIso(),
|
|
18672
|
+
...handles.assistantRunId ? { assistantRunId: handles.assistantRunId } : {},
|
|
18673
|
+
...handles.dispatchId ? { dispatchId: handles.dispatchId } : {}
|
|
18674
|
+
}).catch((e) => args.log?.(`[chat-turn] \u8F6E\u6B21\u8F6C running \u5931\u8D25 ${id}: ${String(e)}`));
|
|
18675
|
+
},
|
|
18676
|
+
async settle(patch) {
|
|
18677
|
+
if (settled) return;
|
|
18678
|
+
settled = true;
|
|
18679
|
+
await turns.settleTurn(id, patch).catch((e) => args.log?.(`[chat-turn] \u8F6E\u6B21\u6536\u53E3\u5931\u8D25 ${id}: ${String(e)}`));
|
|
18680
|
+
}
|
|
18681
|
+
}
|
|
18682
|
+
};
|
|
18683
|
+
}
|
|
18684
|
+
async function reconcileChatTurn(turn, deps) {
|
|
18685
|
+
if (deps.isOwned?.(turn)) return { settled: false, turnId: turn.id, reason: "owned" };
|
|
18686
|
+
const grace = deps.noRunGraceMs ?? 10 * 6e4;
|
|
18687
|
+
const age = deps.now - Date.parse(turn.reservedAt);
|
|
18688
|
+
const runId = turn.assistantRunId ?? turn.dispatchId;
|
|
18689
|
+
if (!runId) {
|
|
18690
|
+
if (age < grace) return { settled: false, turnId: turn.id, reason: "in_grace" };
|
|
18691
|
+
await deps.turns.settleTurn(turn.id, {
|
|
18692
|
+
status: "orphaned",
|
|
18693
|
+
completedAt: new Date(deps.now).toISOString(),
|
|
18694
|
+
lastError: "\u5360\u4F4D\u540E\u672A\u63D0\u4EA4 runtime\uFF08\u8FDB\u7A0B\u4E2D\u65AD\uFF09\uFF0C\u8D85\u5BBD\u9650\u5224\u5B64\u513F\u5E76\u91CA\u653E\u4F1A\u8BDD\u69FD"
|
|
18695
|
+
});
|
|
18696
|
+
return { settled: true, turnId: turn.id, status: "orphaned", reason: "\u5360\u4F4D\u540E\u672A\u63D0\u4EA4 runtime" };
|
|
18697
|
+
}
|
|
18698
|
+
const run = await deps.getRun(runId).catch(() => null);
|
|
18699
|
+
if (run && (run.status === "running" || run.status === "queued")) {
|
|
18700
|
+
return { settled: false, turnId: turn.id, reason: "still_running" };
|
|
18701
|
+
}
|
|
18702
|
+
if (!run) {
|
|
18703
|
+
if (age < grace) return { settled: false, turnId: turn.id, reason: "in_grace" };
|
|
18704
|
+
await deps.turns.settleTurn(turn.id, {
|
|
18705
|
+
status: "orphaned",
|
|
18706
|
+
completedAt: new Date(deps.now).toISOString(),
|
|
18707
|
+
lastError: `\u8D26\u672C\u67E5\u65E0 run ${runId}\uFF0C\u8D85\u5BBD\u9650\u5224\u5B64\u513F\u5E76\u91CA\u653E\u4F1A\u8BDD\u69FD`
|
|
18708
|
+
});
|
|
18709
|
+
return { settled: true, turnId: turn.id, status: "orphaned", reason: `\u8D26\u672C\u67E5\u65E0 run ${runId}` };
|
|
18710
|
+
}
|
|
18711
|
+
const status = run.status === "succeeded" ? "succeeded" : run.status === "cancelled" ? "cancelled" : "failed";
|
|
18712
|
+
await deps.turns.settleTurn(turn.id, {
|
|
18713
|
+
status,
|
|
18714
|
+
completedAt: run.endedAt ?? new Date(deps.now).toISOString(),
|
|
18715
|
+
...status === "succeeded" ? {} : { lastError: `run ${runId} \u7EC8\u6001 ${run.status}\uFF08\u7531\u6062\u590D\u5668\u6536\u53E3\uFF09` }
|
|
18716
|
+
});
|
|
18717
|
+
return { settled: true, turnId: turn.id, status, reason: `run \u7EC8\u6001 ${run.status}` };
|
|
18718
|
+
}
|
|
18719
|
+
async function sweepStaleChatTurns(deps) {
|
|
18720
|
+
const before = new Date(deps.now - (deps.staleAfterMs ?? 2 * 6e4)).toISOString();
|
|
18721
|
+
const stale = await deps.turns.listStaleActiveTurns(before, deps.limit ?? 50);
|
|
18722
|
+
const settled = [];
|
|
18723
|
+
for (const turn of stale) {
|
|
18724
|
+
const outcome = await reconcileChatTurn(turn, deps).catch((e) => {
|
|
18725
|
+
deps.log?.(`[chat-turn-sweep] \u6838\u5B9E\u8F6E\u6B21 ${turn.id} \u5931\u8D25: ${String(e)}`);
|
|
18726
|
+
return null;
|
|
18727
|
+
});
|
|
18728
|
+
if (!outcome?.settled) continue;
|
|
18729
|
+
settled.push(outcome);
|
|
18730
|
+
deps.log?.(
|
|
18731
|
+
`[chat-turn-sweep] \u8F6E\u6B21 ${turn.id}\uFF08\u4F1A\u8BDD ${turn.chatSessionId}\uFF09\u6536\u53E3\u4E3A ${outcome.status}\uFF08${outcome.reason}\uFF09\uFF0C\u4F1A\u8BDD\u69FD\u5DF2\u91CA\u653E`
|
|
18732
|
+
);
|
|
18733
|
+
}
|
|
18734
|
+
return settled;
|
|
18735
|
+
}
|
|
18736
|
+
var import_node_crypto4;
|
|
18737
|
+
var init_chat_turn_gate = __esm({
|
|
18738
|
+
"../server/src/chat-turn-gate.ts"() {
|
|
18739
|
+
"use strict";
|
|
18740
|
+
import_node_crypto4 = require("node:crypto");
|
|
18741
|
+
}
|
|
18742
|
+
});
|
|
18743
|
+
|
|
18618
18744
|
// ../channels/src/memory-store.ts
|
|
18619
18745
|
var init_memory_store = __esm({
|
|
18620
18746
|
"../channels/src/memory-store.ts"() {
|
|
@@ -18800,11 +18926,11 @@ var init_parse = __esm({
|
|
|
18800
18926
|
|
|
18801
18927
|
// ../channels/src/feishu/crypto.ts
|
|
18802
18928
|
function decryptFeishu(encrypt, encryptKey) {
|
|
18803
|
-
const key = (0,
|
|
18929
|
+
const key = (0, import_node_crypto5.createHash)("sha256").update(encryptKey).digest();
|
|
18804
18930
|
const data = Buffer.from(encrypt, "base64");
|
|
18805
18931
|
const iv = data.subarray(0, 16);
|
|
18806
18932
|
const ciphertext = data.subarray(16);
|
|
18807
|
-
const decipher = (0,
|
|
18933
|
+
const decipher = (0, import_node_crypto5.createDecipheriv)("aes-256-cbc", key, iv);
|
|
18808
18934
|
decipher.setAutoPadding(true);
|
|
18809
18935
|
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
18810
18936
|
}
|
|
@@ -18838,11 +18964,11 @@ function verifyToken(decoded, expected) {
|
|
|
18838
18964
|
const token = headerToken ?? decoded["token"];
|
|
18839
18965
|
return token === expected;
|
|
18840
18966
|
}
|
|
18841
|
-
var
|
|
18967
|
+
var import_node_crypto5;
|
|
18842
18968
|
var init_crypto = __esm({
|
|
18843
18969
|
"../channels/src/feishu/crypto.ts"() {
|
|
18844
18970
|
"use strict";
|
|
18845
|
-
|
|
18971
|
+
import_node_crypto5 = require("node:crypto");
|
|
18846
18972
|
}
|
|
18847
18973
|
});
|
|
18848
18974
|
|
|
@@ -18978,11 +19104,12 @@ var init_src6 = __esm({
|
|
|
18978
19104
|
function errMsg(e) {
|
|
18979
19105
|
return e instanceof Error ? e.message : String(e);
|
|
18980
19106
|
}
|
|
18981
|
-
var
|
|
19107
|
+
var import_node_crypto6, FEISHU, ChannelService, CardStreamer;
|
|
18982
19108
|
var init_service = __esm({
|
|
18983
19109
|
"../server/src/channels/service.ts"() {
|
|
18984
19110
|
"use strict";
|
|
18985
|
-
|
|
19111
|
+
import_node_crypto6 = require("node:crypto");
|
|
19112
|
+
init_chat_turn_gate();
|
|
18986
19113
|
init_src6();
|
|
18987
19114
|
FEISHU = "feishu";
|
|
18988
19115
|
ChannelService = class {
|
|
@@ -19062,7 +19189,7 @@ var init_service = __esm({
|
|
|
19062
19189
|
return existing.chatSessionId;
|
|
19063
19190
|
}
|
|
19064
19191
|
}
|
|
19065
|
-
const id = (0,
|
|
19192
|
+
const id = (0, import_node_crypto6.randomUUID)();
|
|
19066
19193
|
const now = this.now();
|
|
19067
19194
|
if (cs) {
|
|
19068
19195
|
const rt = await this.deps.resolveRuntime?.(a.aiActorId).catch(() => null);
|
|
@@ -19098,8 +19225,20 @@ var init_service = __esm({
|
|
|
19098
19225
|
if (cs) {
|
|
19099
19226
|
const sess = await cs.getSession(intent.chatSessionId).catch(() => null);
|
|
19100
19227
|
resumeRt = sess?.runtimeSessionId ?? void 0;
|
|
19101
|
-
await cs.appendMessage({ id: (0,
|
|
19228
|
+
await cs.appendMessage({ id: (0, import_node_crypto6.randomUUID)(), sessionId: intent.chatSessionId, role: "user", content: intent.message, createdAt: this.now() }).catch(() => void 0);
|
|
19102
19229
|
}
|
|
19230
|
+
const opened = await openChatTurn({
|
|
19231
|
+
turns: this.deps.chatTurns,
|
|
19232
|
+
chatSessionId: intent.chatSessionId,
|
|
19233
|
+
source: "channel",
|
|
19234
|
+
now: () => this.now(),
|
|
19235
|
+
log: (m2) => this.log(m2)
|
|
19236
|
+
});
|
|
19237
|
+
if (!opened.ok) {
|
|
19238
|
+
await client.sendText(intent.chatId, "\u23F3 \u4E0A\u4E00\u6761\u8FD8\u5728\u5904\u7406\u4E2D\uFF0C\u7B49\u5B83\u8DD1\u5B8C\u518D\u53D1\u8FD9\u6761\u5427\uFF08\u8FD9\u6B21\u6CA1\u6709\u6392\u961F\uFF09\u3002").catch(() => void 0);
|
|
19239
|
+
return;
|
|
19240
|
+
}
|
|
19241
|
+
const held = opened.turn;
|
|
19103
19242
|
let session;
|
|
19104
19243
|
try {
|
|
19105
19244
|
session = await this.deps.dispatchChat({
|
|
@@ -19109,18 +19248,21 @@ var init_service = __esm({
|
|
|
19109
19248
|
...resumeRt ? { sessionId: resumeRt } : {}
|
|
19110
19249
|
});
|
|
19111
19250
|
} catch (err) {
|
|
19251
|
+
await held?.settle({ status: "failed", completedAt: this.now(), lastError: errMsg(err) });
|
|
19112
19252
|
await client.sendText(intent.chatId, `\u26A0\uFE0F \u6682\u65F6\u65E0\u6CD5\u5904\u7406\uFF1A${errMsg(err)}`).catch(() => void 0);
|
|
19113
19253
|
return;
|
|
19114
19254
|
}
|
|
19255
|
+
await held?.start({ assistantRunId: session.runId ?? null, dispatchId: session.runId ?? null });
|
|
19115
19256
|
const streamer = new CardStreamer(client, intent.chatId, this.cardIntervalMs, this.log);
|
|
19116
19257
|
session.onOutput((chunk) => streamer.push(chunk));
|
|
19117
19258
|
void session.done.then(async () => {
|
|
19259
|
+
await held?.settle({ status: "succeeded", completedAt: this.now() });
|
|
19118
19260
|
await streamer.finalize();
|
|
19119
19261
|
if (cs) {
|
|
19120
19262
|
const reply = streamer.text();
|
|
19121
19263
|
if (reply || session.runId) {
|
|
19122
19264
|
await cs.appendMessage({
|
|
19123
|
-
id: (0,
|
|
19265
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
19124
19266
|
sessionId: intent.chatSessionId,
|
|
19125
19267
|
role: "assistant",
|
|
19126
19268
|
content: reply,
|
|
@@ -19137,6 +19279,7 @@ var init_service = __esm({
|
|
|
19137
19279
|
}).catch(() => void 0);
|
|
19138
19280
|
}
|
|
19139
19281
|
}).catch(async (err) => {
|
|
19282
|
+
await held?.settle({ status: "failed", completedAt: this.now(), lastError: errMsg(err) });
|
|
19140
19283
|
await streamer.error(errMsg(err));
|
|
19141
19284
|
});
|
|
19142
19285
|
}
|
|
@@ -40197,7 +40340,7 @@ var require_websocket = __commonJS({
|
|
|
40197
40340
|
var http2 = require("http");
|
|
40198
40341
|
var net = require("net");
|
|
40199
40342
|
var tls = require("tls");
|
|
40200
|
-
var { randomBytes: randomBytes9, createHash:
|
|
40343
|
+
var { randomBytes: randomBytes9, createHash: createHash22 } = require("crypto");
|
|
40201
40344
|
var { Duplex, Readable } = require("stream");
|
|
40202
40345
|
var { URL: URL2 } = require("url");
|
|
40203
40346
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -40865,7 +41008,7 @@ var require_websocket = __commonJS({
|
|
|
40865
41008
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
40866
41009
|
return;
|
|
40867
41010
|
}
|
|
40868
|
-
const digest =
|
|
41011
|
+
const digest = createHash22("sha1").update(key + GUID).digest("base64");
|
|
40869
41012
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
40870
41013
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
40871
41014
|
return;
|
|
@@ -41234,7 +41377,7 @@ var require_websocket_server = __commonJS({
|
|
|
41234
41377
|
var EventEmitter = require("events");
|
|
41235
41378
|
var http2 = require("http");
|
|
41236
41379
|
var { Duplex } = require("stream");
|
|
41237
|
-
var { createHash:
|
|
41380
|
+
var { createHash: createHash22 } = require("crypto");
|
|
41238
41381
|
var extension2 = require_extension();
|
|
41239
41382
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
41240
41383
|
var subprotocol2 = require_subprotocol();
|
|
@@ -41541,7 +41684,7 @@ var require_websocket_server = __commonJS({
|
|
|
41541
41684
|
);
|
|
41542
41685
|
}
|
|
41543
41686
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
41544
|
-
const digest =
|
|
41687
|
+
const digest = createHash22("sha1").update(key + GUID).digest("base64");
|
|
41545
41688
|
const headers = [
|
|
41546
41689
|
"HTTP/1.1 101 Switching Protocols",
|
|
41547
41690
|
"Upgrade: websocket",
|
|
@@ -149144,7 +149287,7 @@ function slug4(name) {
|
|
|
149144
149287
|
return s2 || "user";
|
|
149145
149288
|
}
|
|
149146
149289
|
function short6() {
|
|
149147
|
-
return (0,
|
|
149290
|
+
return (0, import_node_crypto7.randomBytes)(4).toString("hex").slice(0, 6);
|
|
149148
149291
|
}
|
|
149149
149292
|
async function assertBindingWritePermission(caller, targetHumanId, deps) {
|
|
149150
149293
|
if (caller === targetHumanId) return true;
|
|
@@ -149209,11 +149352,11 @@ async function resolveWorkorderPrincipals(caller, cliOverrides, deps) {
|
|
|
149209
149352
|
}
|
|
149210
149353
|
return { error: "UNBOUND_AGENT_NO_OWNER", message: `owner \u65E0\u6CD5\u89E3\u6790\uFF1A\u8C03\u7528\u65B9 ${caller} \u65E2\u975E\u5728\u5C97\u771F\u4EBA\u4E5F\u975E\u5DF2\u7ED1\u52A9\u7406` };
|
|
149211
149354
|
}
|
|
149212
|
-
var
|
|
149355
|
+
var import_node_crypto7, DEFAULT_ASSISTANT_PROMPT, DEFAULT_ASSISTANT_SKILLS, DEFAULT_ASSISTANT_RUNTIME_KIND, ASSISTANT_ARCHIVED_CODE, AssistantLazyCreateError, AssistantsService;
|
|
149213
149356
|
var init_assistants = __esm({
|
|
149214
149357
|
"../server/src/domains/actors/assistants.ts"() {
|
|
149215
149358
|
"use strict";
|
|
149216
|
-
|
|
149359
|
+
import_node_crypto7 = require("node:crypto");
|
|
149217
149360
|
init_src2();
|
|
149218
149361
|
DEFAULT_ASSISTANT_PROMPT = "\u4F60\u662F\u8FD9\u540D\u771F\u4EBA\u5458\u5DE5\u7684\u4E13\u5C5E\u4E2A\u4EBA\u52A9\u7406\u3002\u4F60\u4EE5\u5176\u300C\u5DE5\u5355\u7BA1\u7406\u8005\u300D\u8EAB\u4EFD\u4EE3\u8DD1\uFF0C\u9075\u5FAA\u4E09\u6863\u6743\u9650\u6A21\u578B\uFF1A\u6863 A\uFF08\u52A0\u8FB9\u3001\u65B0\u5EFA\u8282\u70B9\u3001\u6539\u6807\u9898\u4E0E brief\u3001\u5E38\u89C4\u8BC4\u8BBA\u7B54\u7591\u3001\u63A8\u8FDB\u81EA\u5DF1\u63A5\u7684\u6D3B\uFF09\u53EF\u9006\u6539\u52A8\u76F4\u63A5\u751F\u6548\uFF1B\u6863 B\uFF08\u65AD\u8FB9\u3001\u5E9F\u8282\u70B9\u3001\u6539\u6D3E\u3001\u64A4\u90E8\u4EF6\uFF09\u9500\u6BC1\u6027\u6539\u52A8\u81EA\u52A8\u6253\u5305\u6210\u5F85\u786E\u8BA4\u63D0\u6848\uFF0C\u4EA4\u7531\u672C\u4EBA\u786E\u8BA4\u540E\u751F\u6548\uFF1B\u6863 C\uFF08force-conclude\u3001promote \u7B49\u6CBB\u7406\u547D\u4EE4\uFF09\u8D70\u4EBA\u5DE5\u6388\u6743\u5361\u3002\u4F60\u4E0D\u627F\u62C5\u4E1A\u52A1\u4E13\u4E1A\u5C97\u4F4D\u804C\u8D23\uFF0C\u53EA\u5728\u5176\u6388\u6743\u8303\u56F4\u5185\u534F\u52A9\u5EFA\u5355\u3001\u8DDF\u8FDB\u4E0E\u6C9F\u901A\u3002";
|
|
149219
149362
|
DEFAULT_ASSISTANT_SKILLS = [];
|
|
@@ -151488,6 +151631,59 @@ var init_injected_context = __esm({
|
|
|
151488
151631
|
}
|
|
151489
151632
|
});
|
|
151490
151633
|
|
|
151634
|
+
// ../server/src/domains/chat-sessions/continuation.ts
|
|
151635
|
+
function chatNodeChanged(recorded, current) {
|
|
151636
|
+
const nodeChanged = Boolean(recorded?.nodeId && current?.nodeId && recorded.nodeId !== current.nodeId);
|
|
151637
|
+
const kindChanged = Boolean(recorded?.runtimeKind && current?.runtimeKind && recorded.runtimeKind !== current.runtimeKind);
|
|
151638
|
+
return nodeChanged || kindChanged;
|
|
151639
|
+
}
|
|
151640
|
+
function toHistory(messages, excludeMessageKey) {
|
|
151641
|
+
return messages.filter((m2) => m2.role !== "system" && !(m2.role === "assistant" && m2.status === "running")).filter((m2) => !excludeMessageKey || m2.messageKey !== excludeMessageKey).map((m2) => ({
|
|
151642
|
+
role: m2.role,
|
|
151643
|
+
content: m2.role === "user" ? stripInjectedChatContext(m2.content) : m2.content
|
|
151644
|
+
}));
|
|
151645
|
+
}
|
|
151646
|
+
async function planChatContinuation(input) {
|
|
151647
|
+
const { session } = input;
|
|
151648
|
+
const currentRuntimeId = input.currentRuntime?.nodeId ?? null;
|
|
151649
|
+
const currentRuntimeKind = input.currentRuntime?.runtimeKind ?? null;
|
|
151650
|
+
const runtimeChanged = chatNodeChanged(
|
|
151651
|
+
{ nodeId: session.runtimeId, runtimeKind: session.runtimeKind },
|
|
151652
|
+
{ nodeId: currentRuntimeId, runtimeKind: currentRuntimeKind }
|
|
151653
|
+
);
|
|
151654
|
+
const limit = input.historyLimit ?? 20;
|
|
151655
|
+
const effectiveSessionId = runtimeChanged ? void 0 : session.runtimeSessionId ?? void 0;
|
|
151656
|
+
const needsHistoryInjection = runtimeChanged || !session.runtimeSessionId;
|
|
151657
|
+
const readHistory = async () => toHistory(await input.listMessages(session.id, limit), input.excludeMessageKey);
|
|
151658
|
+
const history = needsHistoryInjection ? await readHistory() : [];
|
|
151659
|
+
const runtimeMessage = buildRuntimeChatPrompt({
|
|
151660
|
+
userMessage: input.userMessage,
|
|
151661
|
+
...history.length ? { history } : {},
|
|
151662
|
+
...input.draftWorkspace ? { draftWorkspace: input.draftWorkspace } : {}
|
|
151663
|
+
});
|
|
151664
|
+
const fallbackHistory = effectiveSessionId ? await readHistory() : [];
|
|
151665
|
+
const fallbackMessage = fallbackHistory.length ? buildRuntimeChatPrompt({
|
|
151666
|
+
userMessage: input.userMessage,
|
|
151667
|
+
history: fallbackHistory,
|
|
151668
|
+
...input.draftWorkspace ? { draftWorkspace: input.draftWorkspace } : {}
|
|
151669
|
+
}) : void 0;
|
|
151670
|
+
return {
|
|
151671
|
+
runtimeMessage,
|
|
151672
|
+
...fallbackMessage ? { fallbackMessage } : {},
|
|
151673
|
+
...effectiveSessionId ? { effectiveSessionId } : {},
|
|
151674
|
+
runtimeChanged,
|
|
151675
|
+
currentRuntimeId,
|
|
151676
|
+
currentRuntimeKind,
|
|
151677
|
+
injectedHistoryCount: history.length
|
|
151678
|
+
};
|
|
151679
|
+
}
|
|
151680
|
+
var init_continuation = __esm({
|
|
151681
|
+
"../server/src/domains/chat-sessions/continuation.ts"() {
|
|
151682
|
+
"use strict";
|
|
151683
|
+
init_injected_context();
|
|
151684
|
+
}
|
|
151685
|
+
});
|
|
151686
|
+
|
|
151491
151687
|
// ../server/src/domains/knowledge/config-store.ts
|
|
151492
151688
|
function normalizedHttpUrl(value, field, allowEmpty = false) {
|
|
151493
151689
|
if (allowEmpty && (value === void 0 || value === null || value === "")) return "";
|
|
@@ -151637,11 +151833,11 @@ var init_config_store = __esm({
|
|
|
151637
151833
|
function clone2(value) {
|
|
151638
151834
|
return structuredClone(value);
|
|
151639
151835
|
}
|
|
151640
|
-
var
|
|
151836
|
+
var import_node_crypto8, import_promises2, import_node_path2, MemoryKnowledgeRunStore, FileKnowledgeRunStore;
|
|
151641
151837
|
var init_run_store = __esm({
|
|
151642
151838
|
"../server/src/domains/knowledge/run-store.ts"() {
|
|
151643
151839
|
"use strict";
|
|
151644
|
-
|
|
151840
|
+
import_node_crypto8 = require("node:crypto");
|
|
151645
151841
|
import_promises2 = require("node:fs/promises");
|
|
151646
151842
|
import_node_path2 = require("node:path");
|
|
151647
151843
|
MemoryKnowledgeRunStore = class {
|
|
@@ -151758,7 +151954,7 @@ var init_run_store = __esm({
|
|
|
151758
151954
|
}
|
|
151759
151955
|
async persist(runs) {
|
|
151760
151956
|
const shape = { version: 1, runs };
|
|
151761
|
-
const temp = `${this.file}.${process.pid}.${(0,
|
|
151957
|
+
const temp = `${this.file}.${process.pid}.${(0, import_node_crypto8.randomUUID)()}.tmp`;
|
|
151762
151958
|
try {
|
|
151763
151959
|
await (0, import_promises2.writeFile)(temp, `${JSON.stringify(shape, null, 2)}
|
|
151764
151960
|
`, { mode: 384 });
|
|
@@ -152301,11 +152497,11 @@ function retryableKnowledgeRun(record8) {
|
|
|
152301
152497
|
const latestAnswerAttempt = [...record8.attempts ?? []].reverse().find((attempt) => attempt.kind !== "fast");
|
|
152302
152498
|
return record8.status === "succeeded" && record8.request.action === "ask" && record8.executionHealth === "degraded" && latestAnswerAttempt?.status === "failed";
|
|
152303
152499
|
}
|
|
152304
|
-
var
|
|
152500
|
+
var import_node_crypto9, ACTION_LABEL, STATUS_MARKER, FINAL_ANSWER_MARKER, ACTIVE_STATUSES, RETRYABLE_STATUSES, HEARTBEAT_INTERVAL_MS, LEASE_MS, MAX_CONCURRENT_READS, ACTION_FLOW, KnowledgeService;
|
|
152305
152501
|
var init_service2 = __esm({
|
|
152306
152502
|
"../server/src/domains/knowledge/service.ts"() {
|
|
152307
152503
|
"use strict";
|
|
152308
|
-
|
|
152504
|
+
import_node_crypto9 = require("node:crypto");
|
|
152309
152505
|
init_src5();
|
|
152310
152506
|
init_config_store();
|
|
152311
152507
|
init_run_store();
|
|
@@ -152347,7 +152543,7 @@ var init_service2 = __esm({
|
|
|
152347
152543
|
constructor(options) {
|
|
152348
152544
|
this.options = options;
|
|
152349
152545
|
this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
152350
|
-
this.id = options.id ??
|
|
152546
|
+
this.id = options.id ?? import_node_crypto9.randomUUID;
|
|
152351
152547
|
this.runStore = options.runStore ?? new MemoryKnowledgeRunStore();
|
|
152352
152548
|
this.heartbeatIntervalMs = options.heartbeatIntervalMs ?? HEARTBEAT_INTERVAL_MS;
|
|
152353
152549
|
this.leaseMs = options.leaseMs ?? LEASE_MS;
|
|
@@ -153612,7 +153808,7 @@ function trustedKnowledgeInvocationId(body, turn) {
|
|
|
153612
153808
|
if (body.action !== "ask") return void 0;
|
|
153613
153809
|
const scope = turn?.artifactId ?? turn?.dispatchId;
|
|
153614
153810
|
if (!scope) return void 0;
|
|
153615
|
-
const fingerprint = (0,
|
|
153811
|
+
const fingerprint = (0, import_node_crypto10.createHash)("sha256").update(JSON.stringify({
|
|
153616
153812
|
action: body.action,
|
|
153617
153813
|
message: body.message?.trim() ?? "",
|
|
153618
153814
|
queryMode: body.queryMode === "deep" ? "deep" : "fast"
|
|
@@ -153711,11 +153907,11 @@ function knowledgeRoutes(service) {
|
|
|
153711
153907
|
});
|
|
153712
153908
|
};
|
|
153713
153909
|
}
|
|
153714
|
-
var
|
|
153910
|
+
var import_node_crypto10;
|
|
153715
153911
|
var init_routes = __esm({
|
|
153716
153912
|
"../server/src/domains/knowledge/routes.ts"() {
|
|
153717
153913
|
"use strict";
|
|
153718
|
-
|
|
153914
|
+
import_node_crypto10 = require("node:crypto");
|
|
153719
153915
|
init_src5();
|
|
153720
153916
|
init_router();
|
|
153721
153917
|
}
|
|
@@ -154920,7 +155116,7 @@ function createAppJwt(appId, privateKeyPem, nowMs) {
|
|
|
154920
155116
|
exp: nowSec + JWT_TTL_SEC,
|
|
154921
155117
|
iss: appId
|
|
154922
155118
|
}));
|
|
154923
|
-
const signer = (0,
|
|
155119
|
+
const signer = (0, import_node_crypto11.createSign)("RSA-SHA256");
|
|
154924
155120
|
signer.update(`${header}.${payload}`);
|
|
154925
155121
|
signer.end();
|
|
154926
155122
|
return `${header}.${payload}.${b64url(signer.sign(privateKeyPem))}`;
|
|
@@ -155024,11 +155220,11 @@ async function exchangeManifestCode(code, deps = {}) {
|
|
|
155024
155220
|
...typeof body["webhook_secret"] === "string" ? { webhookSecret: body["webhook_secret"] } : {}
|
|
155025
155221
|
};
|
|
155026
155222
|
}
|
|
155027
|
-
var
|
|
155223
|
+
var import_node_crypto11, GITHUB_API, JWT_TTL_SEC, JWT_IAT_SKEW_SEC, defaultDeps2;
|
|
155028
155224
|
var init_app_auth = __esm({
|
|
155029
155225
|
"../connectors/src/github/app-auth.ts"() {
|
|
155030
155226
|
"use strict";
|
|
155031
|
-
|
|
155227
|
+
import_node_crypto11 = require("node:crypto");
|
|
155032
155228
|
GITHUB_API = "https://api.github.com";
|
|
155033
155229
|
JWT_TTL_SEC = 9 * 60;
|
|
155034
155230
|
JWT_IAT_SKEW_SEC = 60;
|
|
@@ -157288,7 +157484,7 @@ var init_readiness = __esm({
|
|
|
157288
157484
|
function deriveBoardKey(artifactId) {
|
|
157289
157485
|
const tail = artifactId.split(":").pop() ?? artifactId;
|
|
157290
157486
|
const ascii = tail.replace(/[^a-zA-Z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 24);
|
|
157291
|
-
const sha8 = (0,
|
|
157487
|
+
const sha8 = (0, import_node_crypto12.createHash)("sha256").update(artifactId).digest("hex").slice(0, 8);
|
|
157292
157488
|
return ascii ? `od-${ascii}-${sha8}` : `od-${sha8}`;
|
|
157293
157489
|
}
|
|
157294
157490
|
async function odApi(base, fetchImpl, method, p2, body) {
|
|
@@ -157331,7 +157527,7 @@ function materializeContext(resolvedDir, files) {
|
|
|
157331
157527
|
}
|
|
157332
157528
|
}
|
|
157333
157529
|
async function putVisibleUserTurn(base, fetchImpl, args) {
|
|
157334
|
-
const messageId = (0,
|
|
157530
|
+
const messageId = (0, import_node_crypto12.randomUUID)();
|
|
157335
157531
|
await odApi(
|
|
157336
157532
|
base,
|
|
157337
157533
|
fetchImpl,
|
|
@@ -157346,8 +157542,8 @@ async function startDesignRun(base, fetchImpl, args) {
|
|
|
157346
157542
|
agentId: args.agentId,
|
|
157347
157543
|
projectId: args.boardKey,
|
|
157348
157544
|
conversationId: args.conversationId,
|
|
157349
|
-
assistantMessageId: (0,
|
|
157350
|
-
clientRequestId: (0,
|
|
157545
|
+
assistantMessageId: (0, import_node_crypto12.randomUUID)(),
|
|
157546
|
+
clientRequestId: (0, import_node_crypto12.randomUUID)(),
|
|
157351
157547
|
message: args.message,
|
|
157352
157548
|
// 提案 design-conversational-driving 坑②:systemPrompt 从写死改为可选——缺省用引擎侧默认,
|
|
157353
157549
|
// 让设计意图由驱动方每轮的话(message)表达,而非焊死一句。
|
|
@@ -157528,11 +157724,11 @@ async function runDesignChatTurn(opts) {
|
|
|
157528
157724
|
const { artifacts, fileCount } = await fetchResultPackage(opts.base, fetchImpl, runId);
|
|
157529
157725
|
return { boardKey, conversationId, runId, userMessageId, artifacts, fileCount };
|
|
157530
157726
|
}
|
|
157531
|
-
var
|
|
157727
|
+
var import_node_crypto12, fs4, os, path3;
|
|
157532
157728
|
var init_driver = __esm({
|
|
157533
157729
|
"../adapters/src/open-design/driver.ts"() {
|
|
157534
157730
|
"use strict";
|
|
157535
|
-
|
|
157731
|
+
import_node_crypto12 = require("node:crypto");
|
|
157536
157732
|
fs4 = __toESM(require("node:fs"), 1);
|
|
157537
157733
|
os = __toESM(require("node:os"), 1);
|
|
157538
157734
|
path3 = __toESM(require("node:path"), 1);
|
|
@@ -157625,7 +157821,7 @@ function resolveWorkRoots(workRoot) {
|
|
|
157625
157821
|
}
|
|
157626
157822
|
function workdirSlug(workdirKey) {
|
|
157627
157823
|
const safe = workdirKey.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 48);
|
|
157628
|
-
const h = (0,
|
|
157824
|
+
const h = (0, import_node_crypto13.createHash)("sha256").update(workdirKey).digest("hex").slice(0, 8);
|
|
157629
157825
|
return `${safe}-${h}`;
|
|
157630
157826
|
}
|
|
157631
157827
|
function sessionDirFor(workRoot, runtimeKind, workdirKey) {
|
|
@@ -157757,11 +157953,11 @@ function prepareWorkdir(args) {
|
|
|
157757
157953
|
function legacyChatSessionDir(workRoot, rtId) {
|
|
157758
157954
|
return import_node_path13.default.join(resolveLegacyWorkRoot(workRoot), "oasis-chat-sessions", rtId.replace(/[^a-zA-Z0-9_-]+/g, "_"));
|
|
157759
157955
|
}
|
|
157760
|
-
var
|
|
157956
|
+
var import_node_crypto13, import_node_fs9, import_node_os6, import_node_path13, META_FILE, LOCK_FILE, NEW_WORK_ROOT, slug5, LEGACY_ROOTS, LEGACY_ONESHOT_PREFIX;
|
|
157761
157957
|
var init_session_paths = __esm({
|
|
157762
157958
|
"../adapters/src/_core/session-paths.ts"() {
|
|
157763
157959
|
"use strict";
|
|
157764
|
-
|
|
157960
|
+
import_node_crypto13 = require("node:crypto");
|
|
157765
157961
|
import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
157766
157962
|
import_node_os6 = __toESM(require("node:os"), 1);
|
|
157767
157963
|
import_node_path13 = __toESM(require("node:path"), 1);
|
|
@@ -157789,7 +157985,7 @@ function executionEnvHash(p2) {
|
|
|
157789
157985
|
binPkg: p2.binPackageDir ?? null,
|
|
157790
157986
|
extraRo: [...p2.extraRoBindDirs ?? []].sort()
|
|
157791
157987
|
});
|
|
157792
|
-
return (0,
|
|
157988
|
+
return (0, import_node_crypto14.createHash)("sha256").update(material).digest("hex").slice(0, 16);
|
|
157793
157989
|
}
|
|
157794
157990
|
function persistContainerName(workdirKey) {
|
|
157795
157991
|
return `oasis-wd-${workdirSlug(workdirKey)}`;
|
|
@@ -157909,11 +158105,11 @@ function wrapForContainer(p2) {
|
|
|
157909
158105
|
function killContainerArgs(containerName) {
|
|
157910
158106
|
return ["kill", containerName];
|
|
157911
158107
|
}
|
|
157912
|
-
var
|
|
158108
|
+
var import_node_crypto14, path6, CONTAINER_DEFAULT_PATH, CONTAINER_HOME, EE_HASH_LABEL;
|
|
157913
158109
|
var init_container_wrap = __esm({
|
|
157914
158110
|
"../adapters/src/_core/container-wrap.ts"() {
|
|
157915
158111
|
"use strict";
|
|
157916
|
-
|
|
158112
|
+
import_node_crypto14 = require("node:crypto");
|
|
157917
158113
|
path6 = __toESM(require("node:path"), 1);
|
|
157918
158114
|
init_session_paths();
|
|
157919
158115
|
CONTAINER_DEFAULT_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
|
|
@@ -158380,12 +158576,12 @@ function classifyExit(result) {
|
|
|
158380
158576
|
if (status === 429 || status === 529) return "rate-limit";
|
|
158381
158577
|
return "error";
|
|
158382
158578
|
}
|
|
158383
|
-
var import_node_child_process7,
|
|
158579
|
+
var import_node_child_process7, import_node_crypto15, fs9, path8, readline, CLAUDE_BLOCKED_FLAGS, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
|
|
158384
158580
|
var init_claude_code = __esm({
|
|
158385
158581
|
"../adapters/src/claude-code/index.ts"() {
|
|
158386
158582
|
"use strict";
|
|
158387
158583
|
import_node_child_process7 = require("node:child_process");
|
|
158388
|
-
|
|
158584
|
+
import_node_crypto15 = require("node:crypto");
|
|
158389
158585
|
fs9 = __toESM(require("node:fs"), 1);
|
|
158390
158586
|
path8 = __toESM(require("node:path"), 1);
|
|
158391
158587
|
readline = __toESM(require("node:readline"), 1);
|
|
@@ -158455,7 +158651,7 @@ var init_claude_code = __esm({
|
|
|
158455
158651
|
}
|
|
158456
158652
|
async spawn(job) {
|
|
158457
158653
|
const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
|
|
158458
|
-
const id = `claude-${slug6}-${(0,
|
|
158654
|
+
const id = `claude-${slug6}-${(0, import_node_crypto15.randomUUID)().slice(0, 8)}`;
|
|
158459
158655
|
const dir = job.workdirKey ? prepareWorkdir({
|
|
158460
158656
|
workRoot: this.opts.workRoot,
|
|
158461
158657
|
runtimeKind: "claude",
|
|
@@ -159934,13 +160130,13 @@ function normalizeCodexConsoleLine(line, state = createCodexNormalizeState()) {
|
|
|
159934
160130
|
tool.output.push(line);
|
|
159935
160131
|
return [];
|
|
159936
160132
|
}
|
|
159937
|
-
var import_node_child_process9,
|
|
160133
|
+
var import_node_child_process9, import_node_crypto16, fs10, os5, path10, readline2, CODEX_BLOCKED_FLAGS, CODEX_ARGV_PROMPT_MAX_BYTES, CodexAdapter;
|
|
159938
160134
|
var init_codex = __esm({
|
|
159939
160135
|
"../adapters/src/codex/index.ts"() {
|
|
159940
160136
|
"use strict";
|
|
159941
160137
|
import_node_child_process9 = require("node:child_process");
|
|
159942
160138
|
init_container_runtime();
|
|
159943
|
-
|
|
160139
|
+
import_node_crypto16 = require("node:crypto");
|
|
159944
160140
|
fs10 = __toESM(require("node:fs"), 1);
|
|
159945
160141
|
os5 = __toESM(require("node:os"), 1);
|
|
159946
160142
|
path10 = __toESM(require("node:path"), 1);
|
|
@@ -159986,7 +160182,7 @@ var init_codex = __esm({
|
|
|
159986
160182
|
capabilities = { appendInput: false };
|
|
159987
160183
|
async spawn(job) {
|
|
159988
160184
|
const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
|
|
159989
|
-
const id = `codex-${slug6}-${(0,
|
|
160185
|
+
const id = `codex-${slug6}-${(0, import_node_crypto16.randomUUID)().slice(0, 8)}`;
|
|
159990
160186
|
const startedAtMs = Date.now();
|
|
159991
160187
|
const dir = job.workdirKey ? prepareWorkdir({
|
|
159992
160188
|
workRoot: this.opts.workRoot,
|
|
@@ -160775,7 +160971,7 @@ async function runACPSession(job, cfg) {
|
|
|
160775
160971
|
}
|
|
160776
160972
|
const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
|
|
160777
160973
|
const binTag = path11.basename(cfg.bin).replace(/[^a-zA-Z0-9]/g, "").slice(0, 12) || "acp";
|
|
160778
|
-
const id = `${binTag}-${slug6}-${(0,
|
|
160974
|
+
const id = `${binTag}-${slug6}-${(0, import_node_crypto17.randomUUID)().slice(0, 8)}`;
|
|
160779
160975
|
const dir = job.workdirKey ? prepareWorkdir({
|
|
160780
160976
|
workRoot: cfg.workRoot,
|
|
160781
160977
|
runtimeKind: cfg.runtimeKind ?? "subprocess",
|
|
@@ -161085,12 +161281,12 @@ ${task}` : task;
|
|
|
161085
161281
|
}
|
|
161086
161282
|
};
|
|
161087
161283
|
}
|
|
161088
|
-
var import_node_child_process10,
|
|
161284
|
+
var import_node_child_process10, import_node_crypto17, fs11, path11, readline3, ACPClient, LEGACY_APPROVE_OPTION_ID;
|
|
161089
161285
|
var init_acp = __esm({
|
|
161090
161286
|
"../adapters/src/_core/acp.ts"() {
|
|
161091
161287
|
"use strict";
|
|
161092
161288
|
import_node_child_process10 = require("node:child_process");
|
|
161093
|
-
|
|
161289
|
+
import_node_crypto17 = require("node:crypto");
|
|
161094
161290
|
fs11 = __toESM(require("node:fs"), 1);
|
|
161095
161291
|
path11 = __toESM(require("node:path"), 1);
|
|
161096
161292
|
readline3 = __toESM(require("node:readline"), 1);
|
|
@@ -161588,7 +161784,7 @@ var init_reasonix = __esm({
|
|
|
161588
161784
|
// ../adapters/src/_core/subprocess.ts
|
|
161589
161785
|
async function materialize(job, cfg) {
|
|
161590
161786
|
const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
|
|
161591
|
-
const id = `${slug6}-${(0,
|
|
161787
|
+
const id = `${slug6}-${(0, import_node_crypto18.randomUUID)().slice(0, 8)}`;
|
|
161592
161788
|
const dir = job.workdirKey ? prepareWorkdir({
|
|
161593
161789
|
workRoot: cfg.workRoot,
|
|
161594
161790
|
runtimeKind: cfg.runtimeKind ?? "subprocess",
|
|
@@ -161860,12 +162056,12 @@ async function runOneShotText(job, cfg) {
|
|
|
161860
162056
|
}
|
|
161861
162057
|
});
|
|
161862
162058
|
}
|
|
161863
|
-
var import_node_child_process11,
|
|
162059
|
+
var import_node_child_process11, import_node_crypto18, fs12, path12, readline4;
|
|
161864
162060
|
var init_subprocess = __esm({
|
|
161865
162061
|
"../adapters/src/_core/subprocess.ts"() {
|
|
161866
162062
|
"use strict";
|
|
161867
162063
|
import_node_child_process11 = require("node:child_process");
|
|
161868
|
-
|
|
162064
|
+
import_node_crypto18 = require("node:crypto");
|
|
161869
162065
|
fs12 = __toESM(require("node:fs"), 1);
|
|
161870
162066
|
path12 = __toESM(require("node:path"), 1);
|
|
161871
162067
|
readline4 = __toESM(require("node:readline"), 1);
|
|
@@ -162312,11 +162508,11 @@ function normalizeOpenClaw(line) {
|
|
|
162312
162508
|
}
|
|
162313
162509
|
return [];
|
|
162314
162510
|
}
|
|
162315
|
-
var
|
|
162511
|
+
var import_node_crypto19, OpenClawAdapter;
|
|
162316
162512
|
var init_openclaw = __esm({
|
|
162317
162513
|
"../adapters/src/openclaw/index.ts"() {
|
|
162318
162514
|
"use strict";
|
|
162319
|
-
|
|
162515
|
+
import_node_crypto19 = require("node:crypto");
|
|
162320
162516
|
init_subprocess();
|
|
162321
162517
|
OpenClawAdapter = class {
|
|
162322
162518
|
constructor(opts = {}) {
|
|
@@ -162334,7 +162530,7 @@ var init_openclaw = __esm({
|
|
|
162334
162530
|
---
|
|
162335
162531
|
|
|
162336
162532
|
${task}` : task;
|
|
162337
|
-
const sessionId = job2.runtimeSessionId ?? `oasis-${(0,
|
|
162533
|
+
const sessionId = job2.runtimeSessionId ?? `oasis-${(0, import_node_crypto19.randomUUID)().slice(0, 8)}`;
|
|
162338
162534
|
return [
|
|
162339
162535
|
"agent",
|
|
162340
162536
|
...opts.mode !== "gateway" ? ["--local"] : [],
|
|
@@ -162818,11 +163014,6 @@ function resolveCallbackBase(supplied, requestHost) {
|
|
|
162818
163014
|
}
|
|
162819
163015
|
return `${parsed.origin}${parsed.pathname.replace(/\/+$/, "")}`;
|
|
162820
163016
|
}
|
|
162821
|
-
function chatNodeChanged(recorded, current) {
|
|
162822
|
-
const nodeChanged = Boolean(recorded?.nodeId && current?.nodeId && recorded.nodeId !== current.nodeId);
|
|
162823
|
-
const kindChanged = Boolean(recorded?.runtimeKind && current?.runtimeKind && recorded.runtimeKind !== current.runtimeKind);
|
|
162824
|
-
return nodeChanged || kindChanged;
|
|
162825
|
-
}
|
|
162826
163017
|
function wantsChatParts(req) {
|
|
162827
163018
|
const accept = req.headers.accept;
|
|
162828
163019
|
return typeof accept === "string" && accept.includes("application/x-ndjson");
|
|
@@ -164266,12 +164457,12 @@ async function startOasisServer(opts) {
|
|
|
164266
164457
|
if (!store || !dispatch) return;
|
|
164267
164458
|
const session = await store.getSession(origin).catch(() => null);
|
|
164268
164459
|
if (!session) return;
|
|
164269
|
-
const { randomUUID:
|
|
164460
|
+
const { randomUUID: randomUUID31 } = await import("node:crypto");
|
|
164270
164461
|
const approved = resolution.status === "approved";
|
|
164271
164462
|
const by = ctx.authorizedBy ?? "\u7BA1\u7406\u8005";
|
|
164272
164463
|
const label = ctx.effectLabel || ctx.command || "";
|
|
164273
164464
|
const statusText = 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${ctx.reason ? `\uFF1A${ctx.reason}` : ""}\u3002`;
|
|
164274
|
-
await store.appendMessage({ id:
|
|
164465
|
+
await store.appendMessage({ id: randomUUID31(), sessionId: origin, role: "system", content: statusText, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
|
|
164275
164466
|
if (liveChat.isRunning(origin)) return;
|
|
164276
164467
|
const prompt = approved ? `\u4E0A\u4E00\u6761\u5F85\u6388\u6743\u547D\u4EE4\u5DF2\u88AB ${by} \u6279\u51C6\u5E76\u4EE5\u5176\u540D\u4E49\u6267\u884C\uFF08\u547D\u4EE4\uFF1A${label}\uFF09\u3002\u8BF7\u7EE7\u7EED\u539F\u4EFB\u52A1\u3002` : `\u4E0A\u4E00\u6761\u5F85\u6388\u6743\u547D\u4EE4\u5DF2\u88AB ${by} \u9A73\u56DE${ctx.reason ? `\uFF08\u7406\u7531\uFF1A${ctx.reason}\uFF09` : ""}\u3002\u522B\u91CD\u8BD5\u540C\u4E00\u6761\u2014\u2014\u8BF7\u6539\u65B9\u6848\u6216\u5148\u5411\u53D1\u8D77\u4EBA\u95EE\u6E05\u695A\u3002`;
|
|
164277
164468
|
let dispatched;
|
|
@@ -164292,7 +164483,7 @@ async function startOasisServer(opts) {
|
|
|
164292
164483
|
void dispatched.done.then(async () => {
|
|
164293
164484
|
if (text || dispatched.runId) {
|
|
164294
164485
|
await store.appendMessage({
|
|
164295
|
-
id:
|
|
164486
|
+
id: randomUUID31(),
|
|
164296
164487
|
sessionId: origin,
|
|
164297
164488
|
role: "assistant",
|
|
164298
164489
|
content: text,
|
|
@@ -164307,6 +164498,7 @@ async function startOasisServer(opts) {
|
|
|
164307
164498
|
store: opts.channels.store,
|
|
164308
164499
|
dispatchChat: (req) => opts.dispatchChat(req),
|
|
164309
164500
|
chatSession: opts.chatSession,
|
|
164501
|
+
chatTurns: opts.chatTurns,
|
|
164310
164502
|
revealVar: (key, actorId) => opts.actors.service.revealResolvedVariable(key, actorId),
|
|
164311
164503
|
// 决策 0080 第一期:探活成功时把 bot 的 app_name 落到连接器记录(account)供显示——
|
|
164312
164504
|
// 此前名称在 botInfo 后被丢弃,前端身份位只能显示 App ID(cli_xxx)。
|
|
@@ -165097,11 +165289,11 @@ async function startOasisServer(opts) {
|
|
|
165097
165289
|
const itemKey = `${baseItemKey}:${ctx.ownerId}`;
|
|
165098
165290
|
let chatSessionId;
|
|
165099
165291
|
if (chatStore) {
|
|
165100
|
-
const { randomUUID:
|
|
165292
|
+
const { randomUUID: randomUUID31 } = await import("node:crypto");
|
|
165101
165293
|
const known = discussSessions.get(itemKey);
|
|
165102
165294
|
if (known && await chatStore.getSession(known).catch(() => null)) chatSessionId = known;
|
|
165103
165295
|
if (!chatSessionId) {
|
|
165104
|
-
chatSessionId =
|
|
165296
|
+
chatSessionId = randomUUID31();
|
|
165105
165297
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
165106
165298
|
const title = `\u89E3\u51B3\uFF1A${ctx.seed.slice(ctx.seed.indexOf("\uFF1A") + 1, ctx.seed.indexOf("\uFF1A") + 25) || "\u5DE5\u5355\u5361\u70B9"}`;
|
|
165107
165299
|
const reg0 = (await resolveEngine(currentCompanyId).catch(() => null))?.registry ?? opts.registry;
|
|
@@ -165555,38 +165747,62 @@ async function startOasisServer(opts) {
|
|
|
165555
165747
|
}
|
|
165556
165748
|
const registry2 = engine.registry ?? opts.registry;
|
|
165557
165749
|
const currentBinding = persistTarget && registry2 ? await registry2.getBinding(persistTarget.aiActorId).catch(() => null) : null;
|
|
165558
|
-
const currentRuntimeId = currentBinding?.status === "active" ? currentBinding.nodeId : null;
|
|
165559
|
-
const currentRuntimeKind = currentBinding?.status === "active" ? currentBinding.runtimeKind : null;
|
|
165560
|
-
const runtimeChanged = chatNodeChanged(
|
|
165561
|
-
{ nodeId: persistTarget?.runtimeId, runtimeKind: persistTarget?.runtimeKind },
|
|
165562
|
-
{ nodeId: currentRuntimeId, runtimeKind: currentRuntimeKind }
|
|
165563
|
-
);
|
|
165564
165750
|
const persistedUserMessage = persistTarget ? stripInjectedChatContext(body.message) : body.message;
|
|
165565
|
-
const needsHistoryInjection = Boolean(persistTarget && (runtimeChanged || !persistTarget.runtimeSessionId));
|
|
165566
|
-
const history = needsHistoryInjection && chatStore && persistTarget ? (await chatStore.listMessages(persistTarget.id, 20)).filter((message) => message.role !== "system" && !(message.role === "assistant" && message.status === "running")).map((message) => ({
|
|
165567
|
-
role: message.role,
|
|
165568
|
-
content: message.role === "user" ? stripInjectedChatContext(message.content) : message.content
|
|
165569
|
-
})) : [];
|
|
165570
165751
|
const draft = persistTarget && opts.workorderDrafts ? await opts.workorderDrafts.forSession(persistTarget.id) : void 0;
|
|
165571
165752
|
const draftWorkspace = draft && ![...engine.kernel.model.artifacts.values()].some((artifact) => artifact.workspace === draft.workspace) ? draft.workspace : void 0;
|
|
165572
|
-
const
|
|
165753
|
+
const plan = persistTarget && chatStore ? await planChatContinuation({
|
|
165754
|
+
session: persistTarget,
|
|
165755
|
+
userMessage: persistedUserMessage,
|
|
165756
|
+
listMessages: (sid, limit) => chatStore.listMessages(sid, limit),
|
|
165757
|
+
currentRuntime: currentBinding?.status === "active" ? { nodeId: currentBinding.nodeId, runtimeKind: currentBinding.runtimeKind } : null,
|
|
165758
|
+
...draftWorkspace ? { draftWorkspace } : {}
|
|
165759
|
+
}) : null;
|
|
165760
|
+
const currentRuntimeId = plan?.currentRuntimeId ?? null;
|
|
165761
|
+
const currentRuntimeKind = plan?.currentRuntimeKind ?? null;
|
|
165762
|
+
const runtimeMessage = plan ? plan.runtimeMessage : buildRuntimeChatPrompt({
|
|
165573
165763
|
userMessage: persistedUserMessage,
|
|
165574
|
-
...history.length ? { history } : {},
|
|
165575
165764
|
...draftWorkspace ? { draftWorkspace } : {}
|
|
165576
165765
|
});
|
|
165577
|
-
const effectiveSessionId =
|
|
165578
|
-
const
|
|
165579
|
-
|
|
165580
|
-
|
|
165581
|
-
|
|
165582
|
-
|
|
165583
|
-
|
|
165584
|
-
|
|
165585
|
-
|
|
165586
|
-
|
|
165587
|
-
|
|
165588
|
-
|
|
165589
|
-
|
|
165766
|
+
const effectiveSessionId = plan ? plan.effectiveSessionId : body.sessionId || void 0;
|
|
165767
|
+
const fallbackMessage = plan?.fallbackMessage;
|
|
165768
|
+
let heldTurn = null;
|
|
165769
|
+
if (persistTarget) {
|
|
165770
|
+
const opened = await openChatTurn({
|
|
165771
|
+
turns: opts.chatTurns,
|
|
165772
|
+
chatSessionId: persistTarget.id,
|
|
165773
|
+
source: "human",
|
|
165774
|
+
log: (m2) => console.warn(m2)
|
|
165775
|
+
});
|
|
165776
|
+
if (!opened.ok) {
|
|
165777
|
+
throw new ApiError(
|
|
165778
|
+
409,
|
|
165779
|
+
"CHAT_SESSION_BUSY",
|
|
165780
|
+
`\u8FD9\u4E2A\u4F1A\u8BDD\u6B63\u5728\u8DD1\u4E00\u8F6E\uFF0C\u8FD9\u53E5\u8BDD\u6CA1\u6709\u53D1\u51FA\u2014\u2014\u4E0D\u6392\u961F\u3001\u4E5F\u4E0D\u63D2\u8BDD\u3002\u7B49\u8FD9\u4E00\u8F6E\u8DD1\u5B8C\u518D\u53D1\uFF0C\u6216\u8005\u7528\u300C\u63D2\u5165\u300D\u628A\u5B83\u9001\u8FDB\u6B63\u5728\u8DD1\u7684\u90A3\u4E00\u8F6E\u3002\uFF08\u5360\u7740\u7684\u8F6E\u6B21 ${opened.activeTurn.id}\uFF0C\u6765\u6E90 ${opened.activeTurn.source}\uFF09`
|
|
165781
|
+
);
|
|
165782
|
+
}
|
|
165783
|
+
heldTurn = opened.turn;
|
|
165784
|
+
}
|
|
165785
|
+
let session;
|
|
165786
|
+
try {
|
|
165787
|
+
session = await opts.dispatchChat({
|
|
165788
|
+
actorId: body.actorId,
|
|
165789
|
+
message: runtimeMessage,
|
|
165790
|
+
...effectiveSessionId ? { sessionId: effectiveSessionId } : {},
|
|
165791
|
+
...fallbackMessage ? { fallbackMessage } : {},
|
|
165792
|
+
...body.chatSessionId ? { chatSessionId: body.chatSessionId } : {},
|
|
165793
|
+
...body.workspace ? { workspace: body.workspace } : {},
|
|
165794
|
+
...currentCompanyId !== void 0 ? { companyId: currentCompanyId } : {},
|
|
165795
|
+
...attachments.length ? { attachments } : {}
|
|
165796
|
+
});
|
|
165797
|
+
} catch (err) {
|
|
165798
|
+
await heldTurn?.settle({
|
|
165799
|
+
status: "failed",
|
|
165800
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
165801
|
+
lastError: err instanceof Error ? err.message : String(err)
|
|
165802
|
+
});
|
|
165803
|
+
throw err;
|
|
165804
|
+
}
|
|
165805
|
+
await heldTurn?.start({ assistantRunId: session.runId ?? null, dispatchId: session.runId ?? null });
|
|
165590
165806
|
if (chatStore && persistTarget) {
|
|
165591
165807
|
if (currentRuntimeId) {
|
|
165592
165808
|
await chatStore.updateSession(persistTarget.id, {
|
|
@@ -165596,14 +165812,14 @@ async function startOasisServer(opts) {
|
|
|
165596
165812
|
runtimeSessionId: session.nativeSessionId ?? session.id
|
|
165597
165813
|
}).catch(() => void 0);
|
|
165598
165814
|
}
|
|
165599
|
-
const { randomUUID:
|
|
165815
|
+
const { randomUUID: randomUUID32 } = await import("node:crypto");
|
|
165600
165816
|
const persistAttachments = attachments.map((a) => ({
|
|
165601
165817
|
name: a.name,
|
|
165602
165818
|
...a.blobRef !== void 0 ? { blobRef: a.blobRef } : {},
|
|
165603
165819
|
...a.contentType !== void 0 ? { contentType: a.contentType } : {}
|
|
165604
165820
|
}));
|
|
165605
165821
|
await chatStore.appendMessage({
|
|
165606
|
-
id:
|
|
165822
|
+
id: randomUUID32(),
|
|
165607
165823
|
sessionId: persistTarget.id,
|
|
165608
165824
|
role: "user",
|
|
165609
165825
|
content: persistedUserMessage,
|
|
@@ -165613,8 +165829,8 @@ async function startOasisServer(opts) {
|
|
|
165613
165829
|
}
|
|
165614
165830
|
let assistantMsgId;
|
|
165615
165831
|
if (chatStore && persistTarget) {
|
|
165616
|
-
const { randomUUID:
|
|
165617
|
-
const id =
|
|
165832
|
+
const { randomUUID: randomUUID32 } = await import("node:crypto");
|
|
165833
|
+
const id = randomUUID32();
|
|
165618
165834
|
await chatStore.appendMessage({
|
|
165619
165835
|
id,
|
|
165620
165836
|
sessionId: persistTarget.id,
|
|
@@ -165650,9 +165866,9 @@ async function startOasisServer(opts) {
|
|
|
165650
165866
|
}).catch(() => void 0);
|
|
165651
165867
|
} else {
|
|
165652
165868
|
if (!assistantText && !session.runId && parts.length === 0) return;
|
|
165653
|
-
const { randomUUID:
|
|
165869
|
+
const { randomUUID: randomUUID32 } = await import("node:crypto");
|
|
165654
165870
|
await chatStore.appendMessage({
|
|
165655
|
-
id:
|
|
165871
|
+
id: randomUUID32(),
|
|
165656
165872
|
sessionId: persistTarget.id,
|
|
165657
165873
|
role: "assistant",
|
|
165658
165874
|
content: assistantText,
|
|
@@ -165663,6 +165879,12 @@ async function startOasisServer(opts) {
|
|
|
165663
165879
|
...parts.length ? { parts } : {}
|
|
165664
165880
|
}).catch(() => void 0);
|
|
165665
165881
|
}
|
|
165882
|
+
await heldTurn?.settle({
|
|
165883
|
+
status: status === "done" ? "succeeded" : "failed",
|
|
165884
|
+
completedAt: finishedAt,
|
|
165885
|
+
...session.runId ? { assistantRunId: session.runId, dispatchId: session.runId } : {},
|
|
165886
|
+
...status === "done" ? {} : { lastError: "\u8FD9\u4E00\u8F6E\u4EE5 error \u6536\u5C3E" }
|
|
165887
|
+
});
|
|
165666
165888
|
await chatStore.updateSession(persistTarget.id, {
|
|
165667
165889
|
...currentRuntimeId ? { runtimeId: currentRuntimeId } : {},
|
|
165668
165890
|
...currentRuntimeKind ? { runtimeKind: currentRuntimeKind } : {},
|
|
@@ -165885,8 +166107,8 @@ async function startOasisServer(opts) {
|
|
|
165885
166107
|
}
|
|
165886
166108
|
}
|
|
165887
166109
|
const { spawn: spawn9 } = await import("node:child_process");
|
|
165888
|
-
const { randomUUID:
|
|
165889
|
-
const sessionId = body.sessionId ??
|
|
166110
|
+
const { randomUUID: randomUUID31 } = await import("node:crypto");
|
|
166111
|
+
const sessionId = body.sessionId ?? randomUUID31();
|
|
165890
166112
|
const args = [
|
|
165891
166113
|
"-p",
|
|
165892
166114
|
body.message,
|
|
@@ -166111,8 +166333,8 @@ async function startOasisServer(opts) {
|
|
|
166111
166333
|
res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ error: `\u56DE\u8C03\u5730\u5740\u4E0D\u53EF\u7528\uFF0C\u5DF2\u4E2D\u6B62\uFF08\u907F\u514D\u5728 GitHub \u4E0A\u7559\u4E0B\u5B64\u513F App\uFF09\uFF1A${e.message}` }));
|
|
166112
166334
|
return;
|
|
166113
166335
|
}
|
|
166114
|
-
const { randomUUID:
|
|
166115
|
-
const state =
|
|
166336
|
+
const { randomUUID: randomUUID31 } = await import("node:crypto");
|
|
166337
|
+
const state = randomUUID31();
|
|
166116
166338
|
const nameSlug = (actorName || actorId?.split(":").pop() || owner?.login || "bot").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "bot";
|
|
166117
166339
|
const manifest = buildAppManifest({
|
|
166118
166340
|
employeeSlug: nameSlug,
|
|
@@ -166563,8 +166785,11 @@ var init_server3 = __esm({
|
|
|
166563
166785
|
init_planner();
|
|
166564
166786
|
init_chat_parts();
|
|
166565
166787
|
init_injected_context();
|
|
166788
|
+
init_continuation();
|
|
166789
|
+
init_chat_turn_gate();
|
|
166566
166790
|
init_knowledge2();
|
|
166567
166791
|
init_src8();
|
|
166792
|
+
init_continuation();
|
|
166568
166793
|
githubAppPending = new PendingAppCreations();
|
|
166569
166794
|
defaultResolveActor = (token) => token.startsWith("token:") ? token.slice("token:".length) : null;
|
|
166570
166795
|
enc = (s2) => new TextEncoder().encode(s2);
|
|
@@ -166662,7 +166887,7 @@ function createNodeTokenStore(file) {
|
|
|
166662
166887
|
return {
|
|
166663
166888
|
issue(nodeId) {
|
|
166664
166889
|
const table = read();
|
|
166665
|
-
const token = `ont_${(0,
|
|
166890
|
+
const token = `ont_${(0, import_node_crypto20.randomBytes)(24).toString("base64url")}`;
|
|
166666
166891
|
table[token] = nodeId;
|
|
166667
166892
|
write(table);
|
|
166668
166893
|
return token;
|
|
@@ -166704,7 +166929,7 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
|
|
|
166704
166929
|
return {
|
|
166705
166930
|
issue(name, ttlMs = defaultTtlMs) {
|
|
166706
166931
|
const m2 = prune();
|
|
166707
|
-
const token = `ent_${(0,
|
|
166932
|
+
const token = `ent_${(0, import_node_crypto20.randomBytes)(24).toString("base64url")}`;
|
|
166708
166933
|
const expiresAt2 = Date.now() + ttlMs;
|
|
166709
166934
|
m2.set(token, { name, expiresAt: expiresAt2 });
|
|
166710
166935
|
write(m2);
|
|
@@ -166734,33 +166959,33 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
|
|
|
166734
166959
|
}
|
|
166735
166960
|
};
|
|
166736
166961
|
}
|
|
166737
|
-
var
|
|
166962
|
+
var import_node_crypto20, fs15, path15, SESSION_TOKEN_PREFIX, b64url2, fromB64url, readOrCreateSecret, sign, signatureMatches, isTokenClaims;
|
|
166738
166963
|
var init_tokens = __esm({
|
|
166739
166964
|
"../server/src/tokens.ts"() {
|
|
166740
166965
|
"use strict";
|
|
166741
|
-
|
|
166966
|
+
import_node_crypto20 = require("node:crypto");
|
|
166742
166967
|
fs15 = __toESM(require("node:fs"), 1);
|
|
166743
166968
|
path15 = __toESM(require("node:path"), 1);
|
|
166744
166969
|
SESSION_TOKEN_PREFIX = "oat_v2_";
|
|
166745
166970
|
b64url2 = (value) => Buffer.from(value).toString("base64url");
|
|
166746
166971
|
fromB64url = (value) => Buffer.from(value, "base64url").toString("utf8");
|
|
166747
166972
|
readOrCreateSecret = (file) => {
|
|
166748
|
-
if (!file) return (0,
|
|
166973
|
+
if (!file) return (0, import_node_crypto20.randomBytes)(32);
|
|
166749
166974
|
try {
|
|
166750
166975
|
const raw = fs15.readFileSync(file, "utf8").trim();
|
|
166751
166976
|
if (raw) return Buffer.from(raw, "base64url");
|
|
166752
166977
|
} catch {
|
|
166753
166978
|
}
|
|
166754
|
-
const secret = (0,
|
|
166979
|
+
const secret = (0, import_node_crypto20.randomBytes)(32);
|
|
166755
166980
|
fs15.mkdirSync(path15.dirname(file), { recursive: true });
|
|
166756
166981
|
fs15.writeFileSync(file, secret.toString("base64url"), { mode: 384 });
|
|
166757
166982
|
return secret;
|
|
166758
166983
|
};
|
|
166759
|
-
sign = (secret, payload) => (0,
|
|
166984
|
+
sign = (secret, payload) => (0, import_node_crypto20.createHmac)("sha256", secret).update(payload).digest("base64url");
|
|
166760
166985
|
signatureMatches = (actual, expected) => {
|
|
166761
166986
|
const a = Buffer.from(actual);
|
|
166762
166987
|
const b2 = Buffer.from(expected);
|
|
166763
|
-
return a.length === b2.length && (0,
|
|
166988
|
+
return a.length === b2.length && (0, import_node_crypto20.timingSafeEqual)(a, b2);
|
|
166764
166989
|
};
|
|
166765
166990
|
isTokenClaims = (value) => {
|
|
166766
166991
|
if (value === null || typeof value !== "object") return false;
|
|
@@ -166807,31 +167032,31 @@ function createDataplaneTokenIssuer(opts = {}) {
|
|
|
166807
167032
|
}
|
|
166808
167033
|
};
|
|
166809
167034
|
}
|
|
166810
|
-
var
|
|
167035
|
+
var import_node_crypto21, fs16, path16, PREFIX, b64url3, fromB64url2, sign2, sigMatches, readOrCreateSecret2, isClaims;
|
|
166811
167036
|
var init_session_dataplane_token = __esm({
|
|
166812
167037
|
"../server/src/session-dataplane-token.ts"() {
|
|
166813
167038
|
"use strict";
|
|
166814
|
-
|
|
167039
|
+
import_node_crypto21 = require("node:crypto");
|
|
166815
167040
|
fs16 = __toESM(require("node:fs"), 1);
|
|
166816
167041
|
path16 = __toESM(require("node:path"), 1);
|
|
166817
167042
|
init_src2();
|
|
166818
167043
|
PREFIX = "osd_";
|
|
166819
167044
|
b64url3 = (v2) => Buffer.from(v2, "utf8").toString("base64url");
|
|
166820
167045
|
fromB64url2 = (v2) => Buffer.from(v2, "base64url").toString("utf8");
|
|
166821
|
-
sign2 = (secret, payload) => (0,
|
|
167046
|
+
sign2 = (secret, payload) => (0, import_node_crypto21.createHmac)("sha256", secret).update(payload).digest("base64url");
|
|
166822
167047
|
sigMatches = (actual, expected) => {
|
|
166823
167048
|
const a = Buffer.from(actual);
|
|
166824
167049
|
const b2 = Buffer.from(expected);
|
|
166825
|
-
return a.length === b2.length && (0,
|
|
167050
|
+
return a.length === b2.length && (0, import_node_crypto21.timingSafeEqual)(a, b2);
|
|
166826
167051
|
};
|
|
166827
167052
|
readOrCreateSecret2 = (file) => {
|
|
166828
|
-
if (!file) return (0,
|
|
167053
|
+
if (!file) return (0, import_node_crypto21.randomBytes)(32);
|
|
166829
167054
|
try {
|
|
166830
167055
|
const raw = fs16.readFileSync(file, "utf8").trim();
|
|
166831
167056
|
if (raw) return Buffer.from(raw, "base64url");
|
|
166832
167057
|
} catch {
|
|
166833
167058
|
}
|
|
166834
|
-
const secret = (0,
|
|
167059
|
+
const secret = (0, import_node_crypto21.randomBytes)(32);
|
|
166835
167060
|
fs16.mkdirSync(path16.dirname(file), { recursive: true });
|
|
166836
167061
|
fs16.writeFileSync(file, secret.toString("base64url"), { mode: 384 });
|
|
166837
167062
|
return secret;
|
|
@@ -168195,7 +168420,9 @@ var init_memory_automation_store = __esm({
|
|
|
168195
168420
|
collaborators: [],
|
|
168196
168421
|
createdBy: input.createdBy ?? null,
|
|
168197
168422
|
createdAt: now,
|
|
168198
|
-
updatedAt: now
|
|
168423
|
+
updatedAt: now,
|
|
168424
|
+
chatTarget: input.chatTarget ?? null,
|
|
168425
|
+
ownerHumanActorId: input.ownerHumanActorId ?? null
|
|
168199
168426
|
};
|
|
168200
168427
|
this.automations.set(id, structuredClone(a));
|
|
168201
168428
|
if (input.triggers?.length) await this.replaceTriggers(id, input.triggers);
|
|
@@ -168678,11 +168905,11 @@ function onlyHits(pool, q) {
|
|
|
168678
168905
|
if (!q.requireMatch || q.keywords.length === 0) return [...pool];
|
|
168679
168906
|
return pool.filter((r) => memoryMatchScore(r, q.keywords) > 0);
|
|
168680
168907
|
}
|
|
168681
|
-
var
|
|
168908
|
+
var import_node_crypto22, MemoryActorMemoryStore, toIndexEntry;
|
|
168682
168909
|
var init_memory_actor_memory_store = __esm({
|
|
168683
168910
|
"../testkit/src/memory-actor-memory-store.ts"() {
|
|
168684
168911
|
"use strict";
|
|
168685
|
-
|
|
168912
|
+
import_node_crypto22 = require("node:crypto");
|
|
168686
168913
|
init_src2();
|
|
168687
168914
|
MemoryActorMemoryStore = class {
|
|
168688
168915
|
rows = /* @__PURE__ */ new Map();
|
|
@@ -168736,7 +168963,7 @@ var init_memory_actor_memory_store = __esm({
|
|
|
168736
168963
|
async write(input, now) {
|
|
168737
168964
|
if (input.memId === void 0) {
|
|
168738
168965
|
const rec = {
|
|
168739
|
-
memId: `mem:${(0,
|
|
168966
|
+
memId: `mem:${(0, import_node_crypto22.randomUUID)()}`,
|
|
168740
168967
|
actorId: input.actorId,
|
|
168741
168968
|
projectId: input.projectId,
|
|
168742
168969
|
keywords: [...input.keywords],
|
|
@@ -170628,11 +170855,11 @@ var init_service3 = __esm({
|
|
|
170628
170855
|
});
|
|
170629
170856
|
|
|
170630
170857
|
// ../server/src/dev-store.ts
|
|
170631
|
-
var
|
|
170858
|
+
var import_node_crypto23, fs17, path17, NdjsonOplogStore, DirBlobStore, MUTATORS, FileTypeRegistryStore, FileRoleRegistryStore, FileRegistryStore, FileAssistantBindStore, FileHumanPrefsStore, FileProjectStateStore, FileProjectDocumentStore, FileArtifactStateStore, FileTraceStore, MemoryChatSessionStore, FileChatSessionStore, MemoryChatTurnStore, FileChatTurnStore, MemoryReadMarkerStore, FileReadMarkerStore;
|
|
170632
170859
|
var init_dev_store = __esm({
|
|
170633
170860
|
"../server/src/dev-store.ts"() {
|
|
170634
170861
|
"use strict";
|
|
170635
|
-
|
|
170862
|
+
import_node_crypto23 = require("node:crypto");
|
|
170636
170863
|
fs17 = __toESM(require("node:fs"), 1);
|
|
170637
170864
|
path17 = __toESM(require("node:path"), 1);
|
|
170638
170865
|
init_src2();
|
|
@@ -170686,7 +170913,7 @@ var init_dev_store = __esm({
|
|
|
170686
170913
|
return path17.join(this.dir, hash);
|
|
170687
170914
|
}
|
|
170688
170915
|
async put(bytes) {
|
|
170689
|
-
const hash = (0,
|
|
170916
|
+
const hash = (0, import_node_crypto23.createHash)("sha256").update(bytes).digest("hex");
|
|
170690
170917
|
const file = this.fileOf(hash);
|
|
170691
170918
|
if (!fs17.existsSync(file)) fs17.writeFileSync(file, bytes);
|
|
170692
170919
|
return hash;
|
|
@@ -171186,6 +171413,10 @@ var init_dev_store = __esm({
|
|
|
171186
171413
|
this.sessionWorkOrders.delete(id);
|
|
171187
171414
|
}
|
|
171188
171415
|
async appendMessage(m2) {
|
|
171416
|
+
if (m2.messageKey) {
|
|
171417
|
+
const existing = await this.getMessageByKey(m2.messageKey);
|
|
171418
|
+
if (existing) return existing;
|
|
171419
|
+
}
|
|
171189
171420
|
const list = this.messages.get(m2.sessionId) ?? [];
|
|
171190
171421
|
const seq = (list.length ? Math.max(...list.map((x2) => x2.seq)) : 0) + 1;
|
|
171191
171422
|
const record8 = { ...m2, seq };
|
|
@@ -171193,6 +171424,26 @@ var init_dev_store = __esm({
|
|
|
171193
171424
|
this.messages.set(m2.sessionId, list);
|
|
171194
171425
|
return record8;
|
|
171195
171426
|
}
|
|
171427
|
+
async getMessageByKey(messageKey) {
|
|
171428
|
+
for (const list of this.messages.values()) {
|
|
171429
|
+
const hit = list.find((x2) => x2.messageKey === messageKey);
|
|
171430
|
+
if (hit) return hit;
|
|
171431
|
+
}
|
|
171432
|
+
return null;
|
|
171433
|
+
}
|
|
171434
|
+
async countMessages(sessionId) {
|
|
171435
|
+
return (this.messages.get(sessionId) ?? []).length;
|
|
171436
|
+
}
|
|
171437
|
+
/** 选择器搜索(ADR 会话投递 D8):与 PG 版同口径——三元组精确 + 标题/ID 前缀 + touchedAt 倒序。 */
|
|
171438
|
+
async searchSessionsForTarget(q) {
|
|
171439
|
+
const text = q.text?.trim().toLowerCase();
|
|
171440
|
+
const all = [...this.sessions.values()].filter((s2) => (s2.companyId ?? null) === q.companyId && s2.humanActorId === q.humanActorId && s2.aiActorId === q.aiActorId && !s2.analyzedRunId && (!text || (s2.title ?? "").toLowerCase().includes(text) || s2.id.toLowerCase().startsWith(text))).sort((a, b2) => b2.touchedAt.localeCompare(a.touchedAt) || b2.id.localeCompare(a.id));
|
|
171441
|
+
const page = all.slice(q.offset, q.offset + q.limit);
|
|
171442
|
+
return {
|
|
171443
|
+
items: page.map((s2) => ({ ...s2, messageCount: (this.messages.get(s2.id) ?? []).length })),
|
|
171444
|
+
hasMore: q.offset + q.limit < all.length
|
|
171445
|
+
};
|
|
171446
|
+
}
|
|
171196
171447
|
async updateMessage(id, patch) {
|
|
171197
171448
|
for (const list of this.messages.values()) {
|
|
171198
171449
|
const item = list.find((x2) => x2.id === id);
|
|
@@ -171277,6 +171528,94 @@ var init_dev_store = __esm({
|
|
|
171277
171528
|
fs17.writeFileSync(this.file, JSON.stringify(snap, null, 2));
|
|
171278
171529
|
}
|
|
171279
171530
|
};
|
|
171531
|
+
MemoryChatTurnStore = class {
|
|
171532
|
+
turns = /* @__PURE__ */ new Map();
|
|
171533
|
+
/** 同步临界区:故意不 await,保证 claim 是原子的。 */
|
|
171534
|
+
claimSync(input) {
|
|
171535
|
+
for (const t of this.turns.values()) {
|
|
171536
|
+
if (t.source === input.source && t.sourceRunId === input.sourceRunId) return { outcome: "resumed", turn: t };
|
|
171537
|
+
}
|
|
171538
|
+
for (const t of this.turns.values()) {
|
|
171539
|
+
if (t.chatSessionId === input.chatSessionId && (t.status === "reserved" || t.status === "running")) {
|
|
171540
|
+
return { outcome: "busy", activeTurn: t };
|
|
171541
|
+
}
|
|
171542
|
+
}
|
|
171543
|
+
const turn = {
|
|
171544
|
+
id: input.turnId,
|
|
171545
|
+
chatSessionId: input.chatSessionId,
|
|
171546
|
+
source: input.source,
|
|
171547
|
+
sourceRunId: input.sourceRunId,
|
|
171548
|
+
messageKey: input.messageKey,
|
|
171549
|
+
status: "reserved",
|
|
171550
|
+
dispatchId: null,
|
|
171551
|
+
assistantRunId: null,
|
|
171552
|
+
reservedAt: input.reservedAt,
|
|
171553
|
+
startedAt: null,
|
|
171554
|
+
completedAt: null,
|
|
171555
|
+
lastError: null
|
|
171556
|
+
};
|
|
171557
|
+
this.turns.set(turn.id, turn);
|
|
171558
|
+
return { outcome: "claimed", turn };
|
|
171559
|
+
}
|
|
171560
|
+
async claimTurn(input) {
|
|
171561
|
+
const claim = this.claimSync(input);
|
|
171562
|
+
if (claim.outcome === "claimed") this.persist();
|
|
171563
|
+
return claim;
|
|
171564
|
+
}
|
|
171565
|
+
async getTurn(turnId) {
|
|
171566
|
+
return this.turns.get(turnId) ?? null;
|
|
171567
|
+
}
|
|
171568
|
+
async getTurnBySourceRun(source, sourceRunId) {
|
|
171569
|
+
for (const t of this.turns.values()) if (t.source === source && t.sourceRunId === sourceRunId) return t;
|
|
171570
|
+
return null;
|
|
171571
|
+
}
|
|
171572
|
+
async activeTurn(chatSessionId) {
|
|
171573
|
+
for (const t of this.turns.values()) {
|
|
171574
|
+
if (t.chatSessionId === chatSessionId && (t.status === "reserved" || t.status === "running")) return t;
|
|
171575
|
+
}
|
|
171576
|
+
return null;
|
|
171577
|
+
}
|
|
171578
|
+
async settleTurn(turnId, patch) {
|
|
171579
|
+
const t = this.turns.get(turnId);
|
|
171580
|
+
if (!t) return;
|
|
171581
|
+
this.turns.set(turnId, {
|
|
171582
|
+
...t,
|
|
171583
|
+
status: patch.status,
|
|
171584
|
+
...patch.dispatchId !== void 0 ? { dispatchId: patch.dispatchId } : {},
|
|
171585
|
+
...patch.assistantRunId !== void 0 ? { assistantRunId: patch.assistantRunId } : {},
|
|
171586
|
+
...patch.startedAt !== void 0 ? { startedAt: patch.startedAt } : {},
|
|
171587
|
+
...patch.completedAt !== void 0 ? { completedAt: patch.completedAt } : {},
|
|
171588
|
+
...patch.lastError !== void 0 ? { lastError: patch.lastError } : {}
|
|
171589
|
+
});
|
|
171590
|
+
this.persist();
|
|
171591
|
+
}
|
|
171592
|
+
async listStaleActiveTurns(reservedBefore, limit = 50) {
|
|
171593
|
+
return [...this.turns.values()].filter((t) => (t.status === "reserved" || t.status === "running") && t.reservedAt < reservedBefore).sort((a, b2) => a.reservedAt.localeCompare(b2.reservedAt)).slice(0, limit);
|
|
171594
|
+
}
|
|
171595
|
+
/** 文件版覆写。内存版不落盘。 */
|
|
171596
|
+
persist() {
|
|
171597
|
+
}
|
|
171598
|
+
};
|
|
171599
|
+
FileChatTurnStore = class _FileChatTurnStore extends MemoryChatTurnStore {
|
|
171600
|
+
constructor(file) {
|
|
171601
|
+
super();
|
|
171602
|
+
this.file = file;
|
|
171603
|
+
}
|
|
171604
|
+
static async open(file) {
|
|
171605
|
+
const store = new _FileChatTurnStore(file);
|
|
171606
|
+
if (fs17.existsSync(file)) {
|
|
171607
|
+
const snap = JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
171608
|
+
for (const t of snap.turns ?? []) store.turns.set(t.id, t);
|
|
171609
|
+
} else {
|
|
171610
|
+
fs17.mkdirSync(path17.dirname(file), { recursive: true });
|
|
171611
|
+
fs17.writeFileSync(file, JSON.stringify({ turns: [] }, null, 2));
|
|
171612
|
+
}
|
|
171613
|
+
return store;
|
|
171614
|
+
}
|
|
171615
|
+
persist() {
|
|
171616
|
+
fs17.writeFileSync(this.file, JSON.stringify({ turns: [...this.turns.values()] }, null, 2));
|
|
171617
|
+
}
|
|
171618
|
+
};
|
|
171280
171619
|
MemoryReadMarkerStore = class _MemoryReadMarkerStore {
|
|
171281
171620
|
markers = /* @__PURE__ */ new Map();
|
|
171282
171621
|
static key(actorId, scope) {
|
|
@@ -171461,11 +171800,11 @@ function typeDefError(def, mode) {
|
|
|
171461
171800
|
}
|
|
171462
171801
|
return null;
|
|
171463
171802
|
}
|
|
171464
|
-
var
|
|
171803
|
+
var import_node_crypto24, RESERVED_FIELD_NAMES, ARTIFACT_TYPE_ACCENTS, TYPE_DEF_SCHEMA, TypesAdminService;
|
|
171465
171804
|
var init_types_admin = __esm({
|
|
171466
171805
|
"../server/src/types-admin.ts"() {
|
|
171467
171806
|
"use strict";
|
|
171468
|
-
|
|
171807
|
+
import_node_crypto24 = require("node:crypto");
|
|
171469
171808
|
init_zod();
|
|
171470
171809
|
init_src5();
|
|
171471
171810
|
init_config_audit();
|
|
@@ -171592,7 +171931,7 @@ var init_types_admin = __esm({
|
|
|
171592
171931
|
async trace(change, target, by, detail) {
|
|
171593
171932
|
try {
|
|
171594
171933
|
await this.audit?.({
|
|
171595
|
-
id: `reg_${(0,
|
|
171934
|
+
id: `reg_${(0, import_node_crypto24.randomUUID)()}`,
|
|
171596
171935
|
actor: by ?? SYSTEM_CONFIG_ACTOR,
|
|
171597
171936
|
kind: "registry_change",
|
|
171598
171937
|
target,
|
|
@@ -171740,11 +172079,11 @@ function roleDefError(def, mode) {
|
|
|
171740
172079
|
}
|
|
171741
172080
|
return null;
|
|
171742
172081
|
}
|
|
171743
|
-
var
|
|
172082
|
+
var import_node_crypto25, ACCENTS, ROLE_DEF_SCHEMA, RolesAdminService;
|
|
171744
172083
|
var init_roles_admin = __esm({
|
|
171745
172084
|
"../server/src/roles-admin.ts"() {
|
|
171746
172085
|
"use strict";
|
|
171747
|
-
|
|
172086
|
+
import_node_crypto25 = require("node:crypto");
|
|
171748
172087
|
init_zod();
|
|
171749
172088
|
init_src5();
|
|
171750
172089
|
init_config_audit();
|
|
@@ -171769,7 +172108,7 @@ var init_roles_admin = __esm({
|
|
|
171769
172108
|
async trace(change, target, by, detail) {
|
|
171770
172109
|
try {
|
|
171771
172110
|
await this.deps.audit?.({
|
|
171772
|
-
id: `reg_${(0,
|
|
172111
|
+
id: `reg_${(0, import_node_crypto25.randomUUID)()}`,
|
|
171773
172112
|
actor: by ?? SYSTEM_CONFIG_ACTOR,
|
|
171774
172113
|
kind: "registry_change",
|
|
171775
172114
|
target,
|
|
@@ -173747,7 +174086,7 @@ function wireRecoveredChatTurn(deps) {
|
|
|
173747
174086
|
const segText = assistantText;
|
|
173748
174087
|
const segParts = collectedParts();
|
|
173749
174088
|
const closingId = currentMsgId;
|
|
173750
|
-
const nextId = (0,
|
|
174089
|
+
const nextId = (0, import_node_crypto26.randomUUID)();
|
|
173751
174090
|
assistantText = "";
|
|
173752
174091
|
currentMsgId = nextId;
|
|
173753
174092
|
segmentBaseSeq = live.bufferedParts().reduce((max, p2) => p2.seq > max ? p2.seq : max, 0);
|
|
@@ -173760,7 +174099,7 @@ function wireRecoveredChatTurn(deps) {
|
|
|
173760
174099
|
...segParts.length ? { parts: segParts } : {}
|
|
173761
174100
|
}).catch(() => void 0);
|
|
173762
174101
|
await store.appendMessage({
|
|
173763
|
-
id: (0,
|
|
174102
|
+
id: (0, import_node_crypto26.randomUUID)(),
|
|
173764
174103
|
sessionId: plan.chatSessionId,
|
|
173765
174104
|
role: "user",
|
|
173766
174105
|
content: text,
|
|
@@ -173939,11 +174278,11 @@ async function reconcileChatExitFrame(deps) {
|
|
|
173939
174278
|
}
|
|
173940
174279
|
return false;
|
|
173941
174280
|
}
|
|
173942
|
-
var
|
|
174281
|
+
var import_node_crypto26, asObj3, partsOf, maxPartSeq, exitFailed, exitErrorText, runTerminalPatch;
|
|
173943
174282
|
var init_chat_recovery = __esm({
|
|
173944
174283
|
"../server/src/chat-recovery.ts"() {
|
|
173945
174284
|
"use strict";
|
|
173946
|
-
|
|
174285
|
+
import_node_crypto26 = require("node:crypto");
|
|
173947
174286
|
init_chat_parts();
|
|
173948
174287
|
init_sink();
|
|
173949
174288
|
init_resilient_appender();
|
|
@@ -173970,8 +174309,8 @@ var init_chat_recovery = __esm({
|
|
|
173970
174309
|
|
|
173971
174310
|
// ../server/src/auth/crypto.ts
|
|
173972
174311
|
function hashPassword(password) {
|
|
173973
|
-
const salt = (0,
|
|
173974
|
-
const dk = (0,
|
|
174312
|
+
const salt = (0, import_node_crypto27.randomBytes)(16);
|
|
174313
|
+
const dk = (0, import_node_crypto27.scryptSync)(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, maxmem: 64 * 1024 * 1024 });
|
|
173975
174314
|
return `scrypt$${SCRYPT_N}$${salt.toString("base64url")}$${dk.toString("base64url")}`;
|
|
173976
174315
|
}
|
|
173977
174316
|
function verifyPassword(password, stored) {
|
|
@@ -173988,8 +174327,8 @@ function verifyPassword(password, stored) {
|
|
|
173988
174327
|
return false;
|
|
173989
174328
|
}
|
|
173990
174329
|
if (expected.length === 0) return false;
|
|
173991
|
-
const dk = (0,
|
|
173992
|
-
return dk.length === expected.length && (0,
|
|
174330
|
+
const dk = (0, import_node_crypto27.scryptSync)(password, salt, expected.length, { N, maxmem: 64 * 1024 * 1024 });
|
|
174331
|
+
return dk.length === expected.length && (0, import_node_crypto27.timingSafeEqual)(dk, expected);
|
|
173993
174332
|
}
|
|
173994
174333
|
function b64urlJson(value) {
|
|
173995
174334
|
return Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
@@ -173997,17 +174336,17 @@ function b64urlJson(value) {
|
|
|
173997
174336
|
function signSession(claims, secret) {
|
|
173998
174337
|
const head = b64urlJson({ alg: "HS256", typ: "JWT" });
|
|
173999
174338
|
const body = b64urlJson(claims);
|
|
174000
|
-
const sig = (0,
|
|
174339
|
+
const sig = (0, import_node_crypto27.createHmac)("sha256", secret).update(`${head}.${body}`).digest("base64url");
|
|
174001
174340
|
return `${head}.${body}.${sig}`;
|
|
174002
174341
|
}
|
|
174003
174342
|
function verifySession(token, secret, nowMs) {
|
|
174004
174343
|
const parts = token.split(".");
|
|
174005
174344
|
if (parts.length !== 3) return null;
|
|
174006
174345
|
const [head, body, sig] = parts;
|
|
174007
|
-
const expected = (0,
|
|
174346
|
+
const expected = (0, import_node_crypto27.createHmac)("sha256", secret).update(`${head}.${body}`).digest("base64url");
|
|
174008
174347
|
const got = Buffer.from(sig);
|
|
174009
174348
|
const exp = Buffer.from(expected);
|
|
174010
|
-
if (got.length !== exp.length || !(0,
|
|
174349
|
+
if (got.length !== exp.length || !(0, import_node_crypto27.timingSafeEqual)(got, exp)) return null;
|
|
174011
174350
|
let claims;
|
|
174012
174351
|
try {
|
|
174013
174352
|
claims = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
|
|
@@ -174019,21 +174358,21 @@ function verifySession(token, secret, nowMs) {
|
|
|
174019
174358
|
return claims;
|
|
174020
174359
|
}
|
|
174021
174360
|
function generateCode() {
|
|
174022
|
-
return String((0,
|
|
174361
|
+
return String((0, import_node_crypto27.randomInt)(0, 1e6)).padStart(6, "0");
|
|
174023
174362
|
}
|
|
174024
174363
|
function hashCode(code, secret) {
|
|
174025
|
-
return (0,
|
|
174364
|
+
return (0, import_node_crypto27.createHmac)("sha256", secret).update(`code:${code}`).digest("base64url");
|
|
174026
174365
|
}
|
|
174027
174366
|
function safeEqualHash(a, b2) {
|
|
174028
174367
|
const ba = Buffer.from(a);
|
|
174029
174368
|
const bb = Buffer.from(b2);
|
|
174030
|
-
return ba.length === bb.length && (0,
|
|
174369
|
+
return ba.length === bb.length && (0, import_node_crypto27.timingSafeEqual)(ba, bb);
|
|
174031
174370
|
}
|
|
174032
|
-
var
|
|
174371
|
+
var import_node_crypto27, SCRYPT_N, SCRYPT_KEYLEN;
|
|
174033
174372
|
var init_crypto2 = __esm({
|
|
174034
174373
|
"../server/src/auth/crypto.ts"() {
|
|
174035
174374
|
"use strict";
|
|
174036
|
-
|
|
174375
|
+
import_node_crypto27 = require("node:crypto");
|
|
174037
174376
|
SCRYPT_N = 16384;
|
|
174038
174377
|
SCRYPT_KEYLEN = 32;
|
|
174039
174378
|
}
|
|
@@ -174961,13 +175300,13 @@ function variableKeyFromEnv(env = process.env) {
|
|
|
174961
175300
|
return buf;
|
|
174962
175301
|
}
|
|
174963
175302
|
if (env.NODE_ENV === "production") throw new Error("OASIS_VAR_KEY is required in production");
|
|
174964
|
-
return (0,
|
|
175303
|
+
return (0, import_node_crypto28.createHash)("sha256").update("oasis-dev-only-variable-key").digest();
|
|
174965
175304
|
}
|
|
174966
|
-
var
|
|
175305
|
+
var import_node_crypto28, REDACTED_MARKER, ActorsService, mask, changedKeys;
|
|
174967
175306
|
var init_service4 = __esm({
|
|
174968
175307
|
"../server/src/domains/actors/service.ts"() {
|
|
174969
175308
|
"use strict";
|
|
174970
|
-
|
|
175309
|
+
import_node_crypto28 = require("node:crypto");
|
|
174971
175310
|
init_skill_fetcher();
|
|
174972
175311
|
init_identity();
|
|
174973
175312
|
init_migrate();
|
|
@@ -175455,7 +175794,7 @@ ${input.description}
|
|
|
175455
175794
|
*/
|
|
175456
175795
|
buildSkillFile(skillId, path37, content, now) {
|
|
175457
175796
|
const bytes = new TextEncoder().encode(content);
|
|
175458
|
-
const blobHash = (0,
|
|
175797
|
+
const blobHash = (0, import_node_crypto28.createHash)("sha256").update(bytes).digest("hex");
|
|
175459
175798
|
return { skillId, path: path37, content, blobHash, size: bytes.length, updatedAt: now };
|
|
175460
175799
|
}
|
|
175461
175800
|
/**
|
|
@@ -175926,15 +176265,15 @@ ${input.description}
|
|
|
175926
176265
|
return hit ? { value: hit.value, ...hit.origin ? { origin: hit.origin } : {} } : null;
|
|
175927
176266
|
}
|
|
175928
176267
|
encrypt(plain) {
|
|
175929
|
-
const iv = (0,
|
|
175930
|
-
const cipher = (0,
|
|
176268
|
+
const iv = (0, import_node_crypto28.randomBytes)(12);
|
|
176269
|
+
const cipher = (0, import_node_crypto28.createCipheriv)("aes-256-gcm", this.opts.variableKey, iv);
|
|
175931
176270
|
const enc4 = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()]);
|
|
175932
176271
|
return [iv.toString("base64"), cipher.getAuthTag().toString("base64"), enc4.toString("base64")].join(".");
|
|
175933
176272
|
}
|
|
175934
176273
|
decrypt(packed) {
|
|
175935
176274
|
const [iv, tag, data] = packed.split(".");
|
|
175936
176275
|
if (!iv || !tag || typeof data !== "string") throw new Error("malformed ciphertext");
|
|
175937
|
-
const decipher = (0,
|
|
176276
|
+
const decipher = (0, import_node_crypto28.createDecipheriv)("aes-256-gcm", this.opts.variableKey, Buffer.from(iv, "base64"));
|
|
175938
176277
|
decipher.setAuthTag(Buffer.from(tag, "base64"));
|
|
175939
176278
|
return Buffer.concat([decipher.update(Buffer.from(data, "base64")), decipher.final()]).toString("utf8");
|
|
175940
176279
|
}
|
|
@@ -176898,7 +177237,7 @@ async function listSkillMetadataForActor(args) {
|
|
|
176898
177237
|
usedDirs.add(dir);
|
|
176899
177238
|
const sorted = [...metas].sort((a, b2) => a.path.localeCompare(b2.path));
|
|
176900
177239
|
let latest = "1970-01-01T00:00:00.000Z";
|
|
176901
|
-
const hasher = (0,
|
|
177240
|
+
const hasher = (0, import_node_crypto29.createHash)("sha256");
|
|
176902
177241
|
for (const m2 of sorted) {
|
|
176903
177242
|
if (m2.updatedAt > latest) latest = m2.updatedAt;
|
|
176904
177243
|
hasher.update(m2.path);
|
|
@@ -176923,11 +177262,11 @@ async function listSkillMetadataForActor(args) {
|
|
|
176923
177262
|
const dir = sanitizeSkillDir(c.name, c.slug);
|
|
176924
177263
|
if (usedDirs.has(dir)) continue;
|
|
176925
177264
|
usedDirs.add(dir);
|
|
176926
|
-
const hasher = (0,
|
|
177265
|
+
const hasher = (0, import_node_crypto29.createHash)("sha256");
|
|
176927
177266
|
for (const p2 of paths) {
|
|
176928
177267
|
hasher.update(p2);
|
|
176929
177268
|
hasher.update("\0");
|
|
176930
|
-
hasher.update((0,
|
|
177269
|
+
hasher.update((0, import_node_crypto29.createHash)("sha256").update(c.files[p2]).digest("hex"));
|
|
176931
177270
|
hasher.update("\0");
|
|
176932
177271
|
}
|
|
176933
177272
|
out.push({
|
|
@@ -176948,11 +177287,11 @@ async function listSkillMetadataForActor(args) {
|
|
|
176948
177287
|
const dir = sanitizeSkillDir(b2.name, b2.id);
|
|
176949
177288
|
if (usedDirs.has(dir)) continue;
|
|
176950
177289
|
usedDirs.add(dir);
|
|
176951
|
-
const hasher = (0,
|
|
177290
|
+
const hasher = (0, import_node_crypto29.createHash)("sha256");
|
|
176952
177291
|
for (const p2 of paths) {
|
|
176953
177292
|
hasher.update(p2);
|
|
176954
177293
|
hasher.update("\0");
|
|
176955
|
-
hasher.update((0,
|
|
177294
|
+
hasher.update((0, import_node_crypto29.createHash)("sha256").update(b2.files[p2]).digest("hex"));
|
|
176956
177295
|
hasher.update("\0");
|
|
176957
177296
|
}
|
|
176958
177297
|
out.push({
|
|
@@ -176972,7 +177311,7 @@ function builtinSkillToFiles(b2) {
|
|
|
176972
177311
|
skillId: `builtin:${b2.id}`,
|
|
176973
177312
|
path: path37,
|
|
176974
177313
|
content,
|
|
176975
|
-
blobHash: (0,
|
|
177314
|
+
blobHash: (0, import_node_crypto29.createHash)("sha256").update(content).digest("hex"),
|
|
176976
177315
|
size: Buffer.byteLength(content, "utf8"),
|
|
176977
177316
|
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
176978
177317
|
}));
|
|
@@ -176996,7 +177335,7 @@ function sanitizeSkillDir(name, fallbackId) {
|
|
|
176996
177335
|
if (byName) return byName;
|
|
176997
177336
|
const byId = fallbackId ? fold2(fallbackId) : "";
|
|
176998
177337
|
if (byId) return byId;
|
|
176999
|
-
return `skill-${(0,
|
|
177338
|
+
return `skill-${(0, import_node_crypto29.createHash)("sha256").update(name).digest("hex").slice(0, 8)}`;
|
|
177000
177339
|
}
|
|
177001
177340
|
async function materializeSkillFiles(args) {
|
|
177002
177341
|
const skills = await args.service.listInstalledSkillsForActor(args.actorId);
|
|
@@ -177029,7 +177368,7 @@ function connectorSkillToFiles(c) {
|
|
|
177029
177368
|
skillId: c.id,
|
|
177030
177369
|
path: path37,
|
|
177031
177370
|
content,
|
|
177032
|
-
blobHash: (0,
|
|
177371
|
+
blobHash: (0, import_node_crypto29.createHash)("sha256").update(content).digest("hex"),
|
|
177033
177372
|
size: Buffer.byteLength(content, "utf8"),
|
|
177034
177373
|
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
177035
177374
|
}));
|
|
@@ -177046,11 +177385,11 @@ function connectorSkillDisplayRows(connectorSkills, enabledConnectors) {
|
|
|
177046
177385
|
...s2.version !== void 0 ? { version: s2.version } : {}
|
|
177047
177386
|
}));
|
|
177048
177387
|
}
|
|
177049
|
-
var
|
|
177388
|
+
var import_node_crypto29;
|
|
177050
177389
|
var init_skill_materializer = __esm({
|
|
177051
177390
|
"../server/src/domains/actors/skill-materializer.ts"() {
|
|
177052
177391
|
"use strict";
|
|
177053
|
-
|
|
177392
|
+
import_node_crypto29 = require("node:crypto");
|
|
177054
177393
|
}
|
|
177055
177394
|
});
|
|
177056
177395
|
|
|
@@ -178278,7 +178617,7 @@ function createActorsDomain(opts) {
|
|
|
178278
178617
|
...kernel !== void 0 ? { onRolesChanged: (a, r) => kernel.setActorRoles(a, r) } : {},
|
|
178279
178618
|
audit: async (entry) => {
|
|
178280
178619
|
await opts.audit?.({
|
|
178281
|
-
id: `reg_${(0,
|
|
178620
|
+
id: `reg_${(0, import_node_crypto30.randomUUID)()}`,
|
|
178282
178621
|
actor: entry.by,
|
|
178283
178622
|
kind: "registry_change",
|
|
178284
178623
|
target: entry.actorId,
|
|
@@ -178320,11 +178659,11 @@ function createActorsDomain(opts) {
|
|
|
178320
178659
|
register: actorsDomain({ resolveCtx, ...opts.trace ? { trace: opts.trace } : {}, ...opts.listBuiltinSkills ? { listBuiltinSkills: opts.listBuiltinSkills } : {}, ...opts.getBuiltinSkills ? { getBuiltinSkills: opts.getBuiltinSkills } : {}, ...opts.getConnectorSkills ? { getConnectorSkills: opts.getConnectorSkills } : {}, ...opts.refreshConnectorSkills ? { refreshConnectorSkills: opts.refreshConnectorSkills } : {}, ...opts.memory ? { memory: opts.memory } : {}, ...opts.resolveDispatchScope ? { resolveDispatchScope: opts.resolveDispatchScope } : {}, ...opts.projectExists ? { projectExists: opts.projectExists } : {}, ...opts.credentialAudit ? { credentialAudit: opts.credentialAudit } : {}, ...opts.readCredentialAudit ? { readCredentialAudit: opts.readCredentialAudit } : {}, ...opts.credentialRevealLimits ? { credentialRevealLimits: opts.credentialRevealLimits } : {} })
|
|
178321
178660
|
};
|
|
178322
178661
|
}
|
|
178323
|
-
var
|
|
178662
|
+
var import_node_crypto30;
|
|
178324
178663
|
var init_actors = __esm({
|
|
178325
178664
|
"../server/src/domains/actors/index.ts"() {
|
|
178326
178665
|
"use strict";
|
|
178327
|
-
|
|
178666
|
+
import_node_crypto30 = require("node:crypto");
|
|
178328
178667
|
init_service4();
|
|
178329
178668
|
init_routes2();
|
|
178330
178669
|
init_service4();
|
|
@@ -179432,11 +179771,11 @@ var init_projects = __esm({
|
|
|
179432
179771
|
});
|
|
179433
179772
|
|
|
179434
179773
|
// ../server/src/domains/companies/service.ts
|
|
179435
|
-
var
|
|
179774
|
+
var import_node_crypto31, ROLES, INVITABLE_ROLES, INVITATION_TTL_MS, SLUG_RE, CompanyError, CompaniesService;
|
|
179436
179775
|
var init_service5 = __esm({
|
|
179437
179776
|
"../server/src/domains/companies/service.ts"() {
|
|
179438
179777
|
"use strict";
|
|
179439
|
-
|
|
179778
|
+
import_node_crypto31 = require("node:crypto");
|
|
179440
179779
|
ROLES = ["owner", "admin", "member"];
|
|
179441
179780
|
INVITABLE_ROLES = ["admin", "member"];
|
|
179442
179781
|
INVITATION_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -179509,7 +179848,7 @@ var init_service5 = __esm({
|
|
|
179509
179848
|
const existing = await this.store.getAccountByEmail(normalized4);
|
|
179510
179849
|
if (existing) return existing;
|
|
179511
179850
|
const account = {
|
|
179512
|
-
id: `actor:human:${(0,
|
|
179851
|
+
id: `actor:human:${(0, import_node_crypto31.randomUUID)()}`,
|
|
179513
179852
|
email: normalized4,
|
|
179514
179853
|
name: name ?? normalized4,
|
|
179515
179854
|
status: "active"
|
|
@@ -179673,7 +180012,7 @@ var init_service5 = __esm({
|
|
|
179673
180012
|
}
|
|
179674
180013
|
const nowMs = Date.parse(this.now());
|
|
179675
180014
|
const invitation = {
|
|
179676
|
-
id: `invitation:${(0,
|
|
180015
|
+
id: `invitation:${(0, import_node_crypto31.randomUUID)()}`,
|
|
179677
180016
|
companyId,
|
|
179678
180017
|
email: mail,
|
|
179679
180018
|
role,
|
|
@@ -180944,7 +181283,7 @@ function nodesDomain(deps) {
|
|
|
180944
181283
|
nodeId = incomingNodeId;
|
|
180945
181284
|
deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
|
|
180946
181285
|
} else {
|
|
180947
|
-
nodeId = `node-${(0,
|
|
181286
|
+
nodeId = `node-${(0, import_node_crypto32.randomUUID)().slice(0, 8)}`;
|
|
180948
181287
|
deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
|
|
180949
181288
|
}
|
|
180950
181289
|
const existingNode = await deps.nodeStore.getNode(nodeId);
|
|
@@ -181080,11 +181419,11 @@ function nodesDomain(deps) {
|
|
|
181080
181419
|
});
|
|
181081
181420
|
};
|
|
181082
181421
|
}
|
|
181083
|
-
var
|
|
181422
|
+
var import_node_crypto32, import_node_fs14, import_node_url6, import_node_path18;
|
|
181084
181423
|
var init_routes6 = __esm({
|
|
181085
181424
|
"../server/src/domains/nodes/routes.ts"() {
|
|
181086
181425
|
"use strict";
|
|
181087
|
-
|
|
181426
|
+
import_node_crypto32 = require("node:crypto");
|
|
181088
181427
|
import_node_fs14 = require("node:fs");
|
|
181089
181428
|
import_node_url6 = require("node:url");
|
|
181090
181429
|
import_node_path18 = require("node:path");
|
|
@@ -182700,13 +183039,13 @@ function nameKey(name) {
|
|
|
182700
183039
|
function cleanName(name) {
|
|
182701
183040
|
return name.trim().replace(/\s+/g, " ");
|
|
182702
183041
|
}
|
|
182703
|
-
var import_node_fs15, import_node_path19,
|
|
183042
|
+
var import_node_fs15, import_node_path19, import_node_crypto33, SEP, keyOf, prefixOf, MemoryWorkorderTagStore, FileWorkorderTagStore;
|
|
182704
183043
|
var init_tags = __esm({
|
|
182705
183044
|
"../server/src/domains/collab/tags.ts"() {
|
|
182706
183045
|
"use strict";
|
|
182707
183046
|
import_node_fs15 = __toESM(require("node:fs"), 1);
|
|
182708
183047
|
import_node_path19 = __toESM(require("node:path"), 1);
|
|
182709
|
-
|
|
183048
|
+
import_node_crypto33 = __toESM(require("node:crypto"), 1);
|
|
182710
183049
|
SEP = "::";
|
|
182711
183050
|
keyOf = (companyId, id) => `${companyId}${SEP}${id}`;
|
|
182712
183051
|
prefixOf = (companyId) => `${companyId}${SEP}`;
|
|
@@ -182724,7 +183063,7 @@ var init_tags = __esm({
|
|
|
182724
183063
|
if (!name) return null;
|
|
182725
183064
|
if (this.entries(companyId).some((t) => nameKey(t.name) === nameKey(name))) return null;
|
|
182726
183065
|
const tag = {
|
|
182727
|
-
id: `tag-${
|
|
183066
|
+
id: `tag-${import_node_crypto33.default.randomBytes(6).toString("hex")}`,
|
|
182728
183067
|
name,
|
|
182729
183068
|
...input.color?.trim() ? { color: input.color.trim() } : {},
|
|
182730
183069
|
...input.description?.trim() ? { description: input.description.trim() } : {}
|
|
@@ -183581,7 +183920,7 @@ function createBundle(root, target, input) {
|
|
|
183581
183920
|
}
|
|
183582
183921
|
}
|
|
183583
183922
|
const bytes = fs23.statSync(absBundle).size;
|
|
183584
|
-
const digest = (0,
|
|
183923
|
+
const digest = (0, import_node_crypto34.createHash)("sha256").update(fs23.readFileSync(absBundle)).digest("hex");
|
|
183585
183924
|
const relBase = `inputs/git-bundles/${safeRepo}-${commit.slice(0, 12)}`;
|
|
183586
183925
|
return {
|
|
183587
183926
|
absoluteBundlePath: absBundle,
|
|
@@ -183677,12 +184016,12 @@ function classifyGitError(fallback, err, where) {
|
|
|
183677
184016
|
function oneLine(msg) {
|
|
183678
184017
|
return msg.split("\n").map((s2) => s2.trim()).filter(Boolean).slice(0, 3).join(" ");
|
|
183679
184018
|
}
|
|
183680
|
-
var import_node_child_process14,
|
|
184019
|
+
var import_node_child_process14, import_node_crypto34, fs23, os6, path21, GitReadonlyBundleError, HEX40, FETCH_TIMEOUT_MS2;
|
|
183681
184020
|
var init_readonly_bundle = __esm({
|
|
183682
184021
|
"../server/src/git/readonly-bundle.ts"() {
|
|
183683
184022
|
"use strict";
|
|
183684
184023
|
import_node_child_process14 = require("node:child_process");
|
|
183685
|
-
|
|
184024
|
+
import_node_crypto34 = require("node:crypto");
|
|
183686
184025
|
fs23 = __toESM(require("node:fs"), 1);
|
|
183687
184026
|
os6 = __toESM(require("node:os"), 1);
|
|
183688
184027
|
path21 = __toESM(require("node:path"), 1);
|
|
@@ -183702,7 +184041,7 @@ var init_readonly_bundle = __esm({
|
|
|
183702
184041
|
|
|
183703
184042
|
// ../server/src/domains/collab/create-seeded-workorder.ts
|
|
183704
184043
|
function makeSeededWorkorderCreator(deps) {
|
|
183705
|
-
const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0,
|
|
184044
|
+
const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto35.randomUUID)().slice(0, 8)}`);
|
|
183706
184045
|
return async (input) => {
|
|
183707
184046
|
const workspace = input.idempotencyKey ? workspaceForKey(input.idempotencyKey) : genWorkspace();
|
|
183708
184047
|
if (input.idempotencyKey) {
|
|
@@ -183788,7 +184127,7 @@ function makeSeededWorkorderCreator(deps) {
|
|
|
183788
184127
|
};
|
|
183789
184128
|
}
|
|
183790
184129
|
function workspaceForKey(key) {
|
|
183791
|
-
return `ws:wo-${(0,
|
|
184130
|
+
return `ws:wo-${(0, import_node_crypto35.createHash)("sha256").update(key).digest("hex").slice(0, 8)}`;
|
|
183792
184131
|
}
|
|
183793
184132
|
function existingWorkorder(kernel, workspace) {
|
|
183794
184133
|
const arts = [...kernel.model.artifacts.values()].filter((a) => a.workspace === workspace);
|
|
@@ -183801,11 +184140,11 @@ function existingWorkorder(kernel, workspace) {
|
|
|
183801
184140
|
spawned: arts.map((a) => ({ id: a.id, type: a.type, owner: a.owner }))
|
|
183802
184141
|
};
|
|
183803
184142
|
}
|
|
183804
|
-
var
|
|
184143
|
+
var import_node_crypto35, enc2;
|
|
183805
184144
|
var init_create_seeded_workorder = __esm({
|
|
183806
184145
|
"../server/src/domains/collab/create-seeded-workorder.ts"() {
|
|
183807
184146
|
"use strict";
|
|
183808
|
-
|
|
184147
|
+
import_node_crypto35 = require("node:crypto");
|
|
183809
184148
|
init_ephemeral_project();
|
|
183810
184149
|
init_planner();
|
|
183811
184150
|
enc2 = (s2) => new TextEncoder().encode(s2);
|
|
@@ -184996,12 +185335,12 @@ function todoAction(node) {
|
|
|
184996
185335
|
if (node.progress.recoverability === "partial") return `\u8282\u70B9 ${node.nodeState}\uFF0Ccheckpoint \u90E8\u5206\u53EF\u6062\u590D\uFF0C\u9700\u5173\u6CE8\u5DF2\u6709\u4EA7\u51FA`;
|
|
184997
185336
|
return `\u8282\u70B9 ${node.nodeState}\uFF0Ccheckpoint \u4E0D\u53EF\u6062\u590D`;
|
|
184998
185337
|
}
|
|
184999
|
-
var
|
|
185338
|
+
var import_node_crypto36, DONE_STATES, BLOCKING_STATES, HANDOFF_OUTCOMES2, RESUME_EXTERNAL_EFFECT_LIMIT, RESUME_SNAPSHOT_PREFIX, RESUME_SNAPSHOT_SUFFIX, TODO_RANK, ExecutionContinuityService;
|
|
185000
185339
|
var init_service7 = __esm({
|
|
185001
185340
|
"../server/src/domains/execution-continuity/service.ts"() {
|
|
185002
185341
|
"use strict";
|
|
185003
185342
|
init_src2();
|
|
185004
|
-
|
|
185343
|
+
import_node_crypto36 = require("node:crypto");
|
|
185005
185344
|
init_src5();
|
|
185006
185345
|
DONE_STATES = /* @__PURE__ */ new Set(["succeeded", "no_change"]);
|
|
185007
185346
|
BLOCKING_STATES = /* @__PURE__ */ new Set(["stalled", "failed", "blocked"]);
|
|
@@ -185231,7 +185570,7 @@ var init_service7 = __esm({
|
|
|
185231
185570
|
if (typeof expectedHash !== "string" || !this.readBundleFile) return null;
|
|
185232
185571
|
const injectedResume = this.readBundleFile(attempt.id, "execution/RESUME.md");
|
|
185233
185572
|
if (!injectedResume) return null;
|
|
185234
|
-
const actualHash = (0,
|
|
185573
|
+
const actualHash = (0, import_node_crypto36.createHash)("sha256").update(injectedResume).digest("hex");
|
|
185235
185574
|
if (actualHash !== expectedHash) return null;
|
|
185236
185575
|
const recoverySnapshot = parseResumePackSnapshot(injectedResume);
|
|
185237
185576
|
if (!recoverySnapshot || recoverySnapshot.scenario !== "redispatch" || !recoverySnapshot.previousAttempt || recoverySnapshot.node.nodeId !== attempt.nodeId || recoverySnapshot.jobKey !== attempt.jobKey || recoverySnapshot.part !== attempt.part) return null;
|
|
@@ -185732,7 +186071,7 @@ function createChatSessionsDomain(opts) {
|
|
|
185732
186071
|
if (!text.trim()) throw new ApiError(400, "BAD_REQUEST", "text required");
|
|
185733
186072
|
const now = Date.now();
|
|
185734
186073
|
sweepDrafts(now);
|
|
185735
|
-
const id = `cd_${(0,
|
|
186074
|
+
const id = `cd_${(0, import_node_crypto37.randomUUID)()}`;
|
|
185736
186075
|
drafts.set(id, { text, actor: req.auth.actor, expiresAt: now + DRAFT_TTL_MS });
|
|
185737
186076
|
return { status: 201, body: { id, expiresInMs: DRAFT_TTL_MS } };
|
|
185738
186077
|
});
|
|
@@ -185765,7 +186104,7 @@ function createChatSessionsDomain(opts) {
|
|
|
185765
186104
|
const runtimeId = await currentRuntimeId(body.aiActorId) ?? "unknown";
|
|
185766
186105
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
185767
186106
|
const session = {
|
|
185768
|
-
id: (0,
|
|
186107
|
+
id: (0, import_node_crypto37.randomUUID)(),
|
|
185769
186108
|
humanActorId: req.auth.actor,
|
|
185770
186109
|
aiActorId: body.aiActorId,
|
|
185771
186110
|
runtimeId,
|
|
@@ -185838,7 +186177,7 @@ function createChatSessionsDomain(opts) {
|
|
|
185838
186177
|
if (body.role !== "user" && body.role !== "assistant") throw new ApiError(400, "BAD_REQUEST", "role must be user or assistant");
|
|
185839
186178
|
const role = body.role;
|
|
185840
186179
|
const msg = await store.appendMessage({
|
|
185841
|
-
id: (0,
|
|
186180
|
+
id: (0, import_node_crypto37.randomUUID)(),
|
|
185842
186181
|
sessionId: req.params.id,
|
|
185843
186182
|
role,
|
|
185844
186183
|
content: role === "user" ? stripInjectedChatContext(body.content) : body.content,
|
|
@@ -185848,6 +186187,47 @@ function createChatSessionsDomain(opts) {
|
|
|
185848
186187
|
await store.updateSession(req.params.id, { touchedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
185849
186188
|
return { status: 201, body: msg };
|
|
185850
186189
|
});
|
|
186190
|
+
router.get("/api/chat-sessions/:id/turns/active", async (req) => {
|
|
186191
|
+
if (!opts.chatTurns) throw new ApiError(404, "NOT_FOUND", "\u672C\u5B9E\u4F8B\u672A\u63A5\u4F1A\u8BDD\u8F6E\u6B21\u8D26\u672C");
|
|
186192
|
+
const session = await store.getSession(req.params.id);
|
|
186193
|
+
if (!session || session.humanActorId !== req.auth.actor) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
186194
|
+
const turn = await opts.chatTurns.activeTurn(req.params.id);
|
|
186195
|
+
return { status: 200, body: { turn } };
|
|
186196
|
+
});
|
|
186197
|
+
router.post("/api/chat-sessions/:id/turns/:turnId/settle", async (req) => {
|
|
186198
|
+
if (!opts.chatTurns) throw new ApiError(404, "NOT_FOUND", "\u672C\u5B9E\u4F8B\u672A\u63A5\u4F1A\u8BDD\u8F6E\u6B21\u8D26\u672C");
|
|
186199
|
+
const session = await store.getSession(req.params.id);
|
|
186200
|
+
if (!session || session.humanActorId !== req.auth.actor) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
186201
|
+
const turn = await opts.chatTurns.getTurn(req.params.turnId);
|
|
186202
|
+
if (!turn || turn.chatSessionId !== req.params.id) throw new ApiError(404, "NOT_FOUND", "turn not found");
|
|
186203
|
+
const body = req.body ?? {};
|
|
186204
|
+
if (turn.status !== "reserved" && turn.status !== "running") {
|
|
186205
|
+
return { status: 200, body: { settled: false, reason: "already_terminal", turn } };
|
|
186206
|
+
}
|
|
186207
|
+
if (body.force) {
|
|
186208
|
+
await opts.chatTurns.settleTurn(turn.id, {
|
|
186209
|
+
status: "cancelled",
|
|
186210
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
186211
|
+
lastError: `\u8FD0\u7EF4\u5F3A\u5236\u7F6E\u7EC8\u6001\uFF08${req.auth.actor}\uFF09\uFF1A${body.reason ?? "\u672A\u586B\u539F\u56E0"}`
|
|
186212
|
+
});
|
|
186213
|
+
return { status: 200, body: { settled: true, status: "cancelled", turn: await opts.chatTurns.getTurn(turn.id) } };
|
|
186214
|
+
}
|
|
186215
|
+
const outcome = await reconcileChatTurn(turn, {
|
|
186216
|
+
turns: opts.chatTurns,
|
|
186217
|
+
getRun: opts.getRun ?? (async () => null),
|
|
186218
|
+
now: Date.now(),
|
|
186219
|
+
// 运维入口不吃「宽限」——人是在明确要求现在就核实一次。
|
|
186220
|
+
noRunGraceMs: 0
|
|
186221
|
+
});
|
|
186222
|
+
if (!outcome.settled) {
|
|
186223
|
+
throw new ApiError(
|
|
186224
|
+
409,
|
|
186225
|
+
"CHAT_TURN_STILL_RUNNING",
|
|
186226
|
+
`\u8FD9\u4E00\u8F6E\u5728\u8D26\u672C\u91CC\u4ECD\u662F\u6D3B\u7684\uFF08${outcome.reason}\uFF09\uFF0C\u4E0D\u80FD\u7F6E\u7EC8\u6001\u3002\u786E\u8BA4\u6267\u884C\u4EBA\u5DF2\u7ECF\u6B7B\u4E86\u518D\u52A0 force=true\u3002`
|
|
186227
|
+
);
|
|
186228
|
+
}
|
|
186229
|
+
return { status: 200, body: { settled: true, status: outcome.status, reason: outcome.reason, turn: await opts.chatTurns.getTurn(turn.id) } };
|
|
186230
|
+
});
|
|
185851
186231
|
router.post("/api/chat-sessions/:id/work-orders", async (req) => {
|
|
185852
186232
|
const session = await store.getSession(req.params.id);
|
|
185853
186233
|
if (!session || session.humanActorId !== req.auth.actor) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
@@ -185943,16 +186323,17 @@ function createChatSessionsDomain(opts) {
|
|
|
185943
186323
|
});
|
|
185944
186324
|
};
|
|
185945
186325
|
}
|
|
185946
|
-
var
|
|
186326
|
+
var import_node_crypto37, WORKDIR_READ_MAX_BYTES;
|
|
185947
186327
|
var init_chat_sessions = __esm({
|
|
185948
186328
|
"../server/src/domains/chat-sessions/index.ts"() {
|
|
185949
186329
|
"use strict";
|
|
185950
|
-
|
|
186330
|
+
import_node_crypto37 = require("node:crypto");
|
|
185951
186331
|
init_chat_session();
|
|
185952
186332
|
init_router();
|
|
185953
186333
|
init_workorders();
|
|
185954
186334
|
init_chat_parts();
|
|
185955
186335
|
init_injected_context();
|
|
186336
|
+
init_chat_turn_gate();
|
|
185956
186337
|
init_project_bundle();
|
|
185957
186338
|
WORKDIR_READ_MAX_BYTES = 2 * 1024 * 1024;
|
|
185958
186339
|
}
|
|
@@ -186481,7 +186862,9 @@ var init_registry3 = __esm({
|
|
|
186481
186862
|
|
|
186482
186863
|
// ../server/src/domains/automations/attribution.ts
|
|
186483
186864
|
function automationSubstantiveChange(before, after) {
|
|
186484
|
-
return before.executionMode !== after.executionMode || (before.agentId ?? null) !== (after.agentId ?? null) || (before.playbookRef ?? null) !== (after.playbookRef ?? null) || !jsonEq(before.payload, after.payload) || (before.titleTemplate ?? null) !== (after.titleTemplate ?? null) || before.dispatch !== after.dispatch || before.enabled !== after.enabled
|
|
186865
|
+
return before.executionMode !== after.executionMode || (before.agentId ?? null) !== (after.agentId ?? null) || (before.playbookRef ?? null) !== (after.playbookRef ?? null) || !jsonEq(before.payload, after.payload) || (before.titleTemplate ?? null) !== (after.titleTemplate ?? null) || before.dispatch !== after.dispatch || before.enabled !== after.enabled || // 目标会话策略(ADR 会话投递 D1):改「发到哪儿」= 改怎么跑,问责随之转移。
|
|
186866
|
+
// 归一后比较,`null` 与 `{mode:"new_session"}` 是同一件事,不该被判成变更。
|
|
186867
|
+
!jsonEq(chatTargetKey(before), chatTargetKey(after)) || (before.ownerHumanActorId ?? null) !== (after.ownerHumanActorId ?? null);
|
|
186485
186868
|
}
|
|
186486
186869
|
function triggerSubstantiveChange(before, after) {
|
|
186487
186870
|
if (before.enabled !== after.enabled) return true;
|
|
@@ -186500,13 +186883,20 @@ function configSummaryOf(a) {
|
|
|
186500
186883
|
payload: a.payload ?? null,
|
|
186501
186884
|
titleTemplate: a.titleTemplate ?? null,
|
|
186502
186885
|
dispatch: a.dispatch,
|
|
186503
|
-
enabled: a.enabled
|
|
186886
|
+
enabled: a.enabled,
|
|
186887
|
+
chatTarget: chatTargetKey(a),
|
|
186888
|
+
ownerHumanActorId: a.ownerHumanActorId ?? null
|
|
186504
186889
|
};
|
|
186505
186890
|
}
|
|
186891
|
+
function chatTargetKey(a) {
|
|
186892
|
+
const t = normalizeChatTarget(a.chatTarget);
|
|
186893
|
+
return t.mode === "existing_session" ? { mode: t.mode, sessionId: t.sessionId } : { mode: "new_session" };
|
|
186894
|
+
}
|
|
186506
186895
|
var jsonEq;
|
|
186507
186896
|
var init_attribution = __esm({
|
|
186508
186897
|
"../server/src/domains/automations/attribution.ts"() {
|
|
186509
186898
|
"use strict";
|
|
186899
|
+
init_src2();
|
|
186510
186900
|
jsonEq = (a, b2) => JSON.stringify(a ?? null) === JSON.stringify(b2 ?? null);
|
|
186511
186901
|
}
|
|
186512
186902
|
});
|
|
@@ -187322,8 +187712,11 @@ var init_scheduler = __esm({
|
|
|
187322
187712
|
});
|
|
187323
187713
|
|
|
187324
187714
|
// ../server/src/domains/automations/service.ts
|
|
187715
|
+
function busyError(chatSessionId, blockedBy) {
|
|
187716
|
+
return `\u76EE\u6807\u4F1A\u8BDD ${chatSessionId} \u6B63\u6709\u4E00\u8F6E\u5728\u8DD1${blockedBy ? `\uFF08${blockedBy}\uFF09` : ""}\u2014\u2014\u672C\u6B21\u89E6\u53D1\u5DF2\u4E22\u5F03\uFF0C\u4E0D\u6392\u961F\u3001\u4E0D\u8865\u8DD1`;
|
|
187717
|
+
}
|
|
187325
187718
|
function genWebhookToken() {
|
|
187326
|
-
return `owt_${(0,
|
|
187719
|
+
return `owt_${(0, import_node_crypto38.randomBytes)(32).toString("base64url")}`;
|
|
187327
187720
|
}
|
|
187328
187721
|
function validateTitleTemplate(tpl) {
|
|
187329
187722
|
const residue = tpl.replace(DATE_TOKEN, "");
|
|
@@ -187379,11 +187772,12 @@ function appendSourceNote(brief, automation, source, atIso) {
|
|
|
187379
187772
|
---
|
|
187380
187773
|
\u672C\u5DE5\u5355\u7531\u81EA\u52A8\u5316\u300C${automation.name}\u300D\u4E8E ${atIso} \u89E6\u53D1\uFF08\u6765\u6E90\uFF1A${source}\uFF09\u3002\u5F00\u5DE5\u540E\u8BF7\u628A\u5DE5\u5355\u6807\u9898\u6539\u6210\u51C6\u786E\u53CD\u6620\u5B9E\u9645\u5DE5\u4F5C\u7684\u63CF\u8FF0\u3002`;
|
|
187381
187774
|
}
|
|
187382
|
-
var
|
|
187775
|
+
var import_node_crypto38, DATE_TOKEN, AutomationsService, EVENT_RETRY_BASE_MS, EVENT_RETRY_MAX_MS, EVENT_RETRY_MAX_ATTEMPTS, eventAttempts, eventLastAttemptAt, eventLastError, CHAT_REPLY_MAX;
|
|
187383
187776
|
var init_service8 = __esm({
|
|
187384
187777
|
"../server/src/domains/automations/service.ts"() {
|
|
187385
187778
|
"use strict";
|
|
187386
|
-
|
|
187779
|
+
import_node_crypto38 = require("node:crypto");
|
|
187780
|
+
init_src2();
|
|
187387
187781
|
init_registry3();
|
|
187388
187782
|
init_attribution();
|
|
187389
187783
|
init_scheduler();
|
|
@@ -187391,12 +187785,14 @@ var init_service8 = __esm({
|
|
|
187391
187785
|
AutomationsService = class {
|
|
187392
187786
|
store;
|
|
187393
187787
|
deps;
|
|
187788
|
+
targets;
|
|
187394
187789
|
genId;
|
|
187395
187790
|
now;
|
|
187396
187791
|
log;
|
|
187397
187792
|
constructor(opts) {
|
|
187398
187793
|
this.store = opts.store;
|
|
187399
187794
|
this.deps = opts.fire;
|
|
187795
|
+
if (opts.chatTargets) this.targets = opts.chatTargets;
|
|
187400
187796
|
this.genId = opts.genId ?? ((p2) => `${p2}_${Math.random().toString(36).slice(2, 12)}`);
|
|
187401
187797
|
this.now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
187402
187798
|
if (opts.log) this.log = opts.log;
|
|
@@ -187439,6 +187835,8 @@ var init_service8 = __esm({
|
|
|
187439
187835
|
if (input.enabled !== before.enabled) patch.pauseReason = null;
|
|
187440
187836
|
}
|
|
187441
187837
|
if (input.subscribers !== void 0) patch.subscribers = input.subscribers;
|
|
187838
|
+
if (input.chatTarget !== void 0) patch.chatTarget = input.chatTarget;
|
|
187839
|
+
if (input.ownerHumanActorId !== void 0) patch.ownerHumanActorId = input.ownerHumanActorId;
|
|
187442
187840
|
const updated = await this.store.updateAutomation(id, patch);
|
|
187443
187841
|
let substantive = automationSubstantiveChange(before, updated);
|
|
187444
187842
|
if (input.triggers !== void 0) {
|
|
@@ -187535,6 +187933,83 @@ var init_service8 = __esm({
|
|
|
187535
187933
|
createdAt: this.now().toISOString()
|
|
187536
187934
|
});
|
|
187537
187935
|
}
|
|
187936
|
+
/* ---------- 固定目标会话(ADR 会话投递 D1/D3/D8) ---------- */
|
|
187937
|
+
/** 固定会话功能是否可用(接缝 + 轮次账本都在才算)。前端读能力位,不自己按部署形态猜。 */
|
|
187938
|
+
chatTargetSupported() {
|
|
187939
|
+
return Boolean(this.targets && this.deps.chatTurns);
|
|
187940
|
+
}
|
|
187941
|
+
/** 鉴权 actor → 人类归属者(D3)。 */
|
|
187942
|
+
resolveOwnerHuman(actor) {
|
|
187943
|
+
return this.targets ? this.targets.resolveOwnerHuman(actor) : Promise.resolve(null);
|
|
187944
|
+
}
|
|
187945
|
+
/**
|
|
187946
|
+
* 保存期校验(D3):目标必须当场可投递。返回 null = 通过,否则给出具体 issue。
|
|
187947
|
+
* **不做任何自动修正**——不改绑会话的 AI 身份、不替换归属人、不回退成新会话。
|
|
187948
|
+
*/
|
|
187949
|
+
async validateChatTarget(a, sessionId) {
|
|
187950
|
+
if (!this.targets) return "session_missing";
|
|
187951
|
+
const r = await this.targets.inspect({
|
|
187952
|
+
companyId: a.companyId,
|
|
187953
|
+
agentId: a.agentId,
|
|
187954
|
+
ownerHumanActorId: a.ownerHumanActorId,
|
|
187955
|
+
sessionId
|
|
187956
|
+
});
|
|
187957
|
+
return r.ok ? null : r.issue;
|
|
187958
|
+
}
|
|
187959
|
+
/** 详情/列表用的目标只读投影(含成本观测)。非固定会话返回 null。 */
|
|
187960
|
+
async chatTargetView(a) {
|
|
187961
|
+
const target = normalizeChatTarget(a.chatTarget);
|
|
187962
|
+
if (target.mode !== "existing_session") return null;
|
|
187963
|
+
if (!this.targets) {
|
|
187964
|
+
return { sessionId: target.sessionId, available: false, issue: "session_missing", title: null, touchedAt: null, messageCount: null };
|
|
187965
|
+
}
|
|
187966
|
+
const r = await this.targets.inspect({
|
|
187967
|
+
companyId: a.companyId,
|
|
187968
|
+
agentId: a.agentId,
|
|
187969
|
+
ownerHumanActorId: a.ownerHumanActorId,
|
|
187970
|
+
sessionId: target.sessionId
|
|
187971
|
+
});
|
|
187972
|
+
if (r.ok) {
|
|
187973
|
+
return { sessionId: target.sessionId, available: true, title: r.title, touchedAt: r.touchedAt, messageCount: r.messageCount };
|
|
187974
|
+
}
|
|
187975
|
+
return {
|
|
187976
|
+
sessionId: target.sessionId,
|
|
187977
|
+
available: false,
|
|
187978
|
+
issue: r.issue,
|
|
187979
|
+
title: r.title ?? null,
|
|
187980
|
+
touchedAt: r.touchedAt ?? null,
|
|
187981
|
+
messageCount: null
|
|
187982
|
+
};
|
|
187983
|
+
}
|
|
187984
|
+
/** 选择器搜索(D8)。接缝缺省时给空集合而不是报错——前端展示「不可用」即可。 */
|
|
187985
|
+
async searchChatTargets(args) {
|
|
187986
|
+
if (!this.targets) return { items: [], hasMore: false };
|
|
187987
|
+
return this.targets.search(args);
|
|
187988
|
+
}
|
|
187989
|
+
/**
|
|
187990
|
+
* 「为这条自动化新建长期目标会话」的**服务端复合入口**(D1):建会话 + 回填 chatTarget。
|
|
187991
|
+
*
|
|
187992
|
+
* 之所以不让前端拼「建会话 → 更新自动化」:后者中途失败会留下一个没有来源、谁也不认领的
|
|
187993
|
+
* 孤儿会话。这里的补偿方向刻意选成「回填失败就把刚建的会话删掉」——宁可这次白建,
|
|
187994
|
+
* 也不让一个自动化指着半个配置。
|
|
187995
|
+
*/
|
|
187996
|
+
async createChatTargetSession(automation, editor) {
|
|
187997
|
+
if (!this.targets) throw new Error("\u672C\u5B9E\u4F8B\u672A\u63A5\u4F1A\u8BDD\u76EE\u6807\u63A5\u7F1D");
|
|
187998
|
+
if (automation.executionMode !== "chat" || !automation.agentId) throw new Error("\u53EA\u6709 chat \u6A21\u5F0F\u4E14\u5DF2\u8BBE\u6267\u884C\u4EBA\u7684\u81EA\u52A8\u5316\u624D\u80FD\u5EFA\u957F\u671F\u76EE\u6807\u4F1A\u8BDD");
|
|
187999
|
+
if (!automation.ownerHumanActorId) throw new Error("\u8FD9\u6761\u81EA\u52A8\u5316\u6CA1\u6709\u53EF\u7528\u7684\u4EBA\u7C7B\u5F52\u5C5E\u8005\uFF0C\u65E0\u6CD5\u5EFA\u957F\u671F\u76EE\u6807\u4F1A\u8BDD");
|
|
188000
|
+
const { sessionId } = await this.targets.createTargetSession({
|
|
188001
|
+
companyId: automation.companyId,
|
|
188002
|
+
agentId: automation.agentId,
|
|
188003
|
+
ownerHumanActorId: automation.ownerHumanActorId,
|
|
188004
|
+
title: `\u81EA\u52A8\u5316 \xB7 ${automation.name}`.slice(0, 80)
|
|
188005
|
+
});
|
|
188006
|
+
try {
|
|
188007
|
+
return await this.updateAutomation(automation.id, { chatTarget: { mode: "existing_session", sessionId } }, editor);
|
|
188008
|
+
} catch (e) {
|
|
188009
|
+
await this.targets.deleteSession(sessionId).catch(() => void 0);
|
|
188010
|
+
throw e;
|
|
188011
|
+
}
|
|
188012
|
+
}
|
|
187538
188013
|
/* ---------- firing(ADR 0156 D1/D3) ---------- */
|
|
187539
188014
|
/**
|
|
187540
188015
|
* 触发一次协作。链路:幂等落 run(pending) → 准入检查 → 真剧本解析 → SeededWorkorderCreator 建单
|
|
@@ -187576,7 +188051,7 @@ var init_service8 = __esm({
|
|
|
187576
188051
|
*/
|
|
187577
188052
|
async dispatchRun(automation, trigger, run, source, opts = {}) {
|
|
187578
188053
|
const skip = await this.admissionSkip(automation, source);
|
|
187579
|
-
if (skip) return this.settleSkip(run, skip.reasonCode, skip.error);
|
|
188054
|
+
if (skip) return this.settleSkip(run, skip.reasonCode, skip.error, skip.result);
|
|
187580
188055
|
if (automation.executionMode === "chat") {
|
|
187581
188056
|
return this.fireChat(automation, trigger, run, opts);
|
|
187582
188057
|
}
|
|
@@ -187719,7 +188194,10 @@ var init_service8 = __esm({
|
|
|
187719
188194
|
if (!automation.enabled) return { reasonCode: "automation_paused", error: "\u81EA\u52A8\u5316\u5DF2\u6682\u505C" };
|
|
187720
188195
|
if (automation.executionMode === "chat") {
|
|
187721
188196
|
if (!automation.agentId) return { reasonCode: "config_error", error: "chat \u6A21\u5F0F\u7F3A\u5C11\u6267\u884C\u4EBA\uFF08agentId\uFF09" };
|
|
187722
|
-
if (!this.deps.
|
|
188197
|
+
if (!this.deps.chat) return { reasonCode: "config_error", error: "\u672C\u5B9E\u4F8B\u672A\u63A5 chat \u6267\u884C" };
|
|
188198
|
+
if (!this.deps.chatTurns) {
|
|
188199
|
+
return { reasonCode: "config_error", error: "\u672C\u5B9E\u4F8B\u672A\u63A5\u4F1A\u8BDD\u8F6E\u6B21\u8D26\u672C\uFF08\u65E0\u6CD5\u5224\u5B9A\u76EE\u6807\u4F1A\u8BDD\u662F\u5426\u5728\u8DD1\uFF09" };
|
|
188200
|
+
}
|
|
187723
188201
|
if (source === "event" && !this.deps.chatSupportsIdempotency) {
|
|
187724
188202
|
return { reasonCode: "config_error", error: "\u5BF9\u8BDD\u6267\u884C\u6682\u4E0D\u652F\u6301\u8BA2\u9605\u89E6\u53D1\uFF08chat \u9002\u914D\u5668\u7F3A\u6301\u4E45\u5E42\u7B49\u952E\uFF09" };
|
|
187725
188203
|
}
|
|
@@ -187736,29 +188214,67 @@ var init_service8 = __esm({
|
|
|
187736
188214
|
return { reasonCode: "config_error", error: `\u5267\u672C ${automation.playbookRef} \u4E0D\u652F\u6301\u5EFA\u5355` };
|
|
187737
188215
|
}
|
|
187738
188216
|
if (automation.projectId && this.deps.projectExists && !await this.deps.projectExists(automation.projectId)) {
|
|
187739
|
-
return {
|
|
188217
|
+
return {
|
|
188218
|
+
reasonCode: "target_unavailable",
|
|
188219
|
+
error: `\u76EE\u6807\u9879\u76EE\u4E0D\u5B58\u5728\uFF1A${automation.projectId}`,
|
|
188220
|
+
result: { targetKind: "project", projectId: automation.projectId }
|
|
188221
|
+
};
|
|
187740
188222
|
}
|
|
187741
188223
|
return null;
|
|
187742
188224
|
}
|
|
187743
188225
|
/**
|
|
187744
|
-
* chat 模式执行(ADR 0159
|
|
187745
|
-
*
|
|
188226
|
+
* chat 模式执行(ADR 0159 + 会话投递 D2)。三步各自可单测、职责不重叠:
|
|
188227
|
+
*
|
|
188228
|
+
* 1. **解析目标**(不写消息、不 dispatch):`new_session` 由 run id 确定性映射出一个会话,
|
|
188229
|
+
* `existing_session` 读固定会话并复查 D3 五条。
|
|
188230
|
+
* 2. **持久占位**:拿到 active slot 才有资格产生副作用;拿不到 = 别人在跑 → 本次触发丢弃。
|
|
188231
|
+
* 3. **消费占位**:写确定性消息、真 dispatch、收流收口。
|
|
188232
|
+
*
|
|
188233
|
+
* 进程重启会丢 onDone 回调——syncRuns 对超时 running 兜底回收(chat_lost)。
|
|
187746
188234
|
*/
|
|
187747
188235
|
async fireChat(automation, trigger, run, opts) {
|
|
187748
188236
|
const now = this.now();
|
|
187749
188237
|
const tz = trigger?.schedule?.tz;
|
|
187750
188238
|
const title = automation.titleTemplate ? automation.titleTemplate.replace(DATE_TOKEN, renderDate(now, tz)) : `${automation.name} ${renderDate(now, tz)}`;
|
|
187751
188239
|
const prompt = buildChatPrompt(automation, title, opts.envelope);
|
|
187752
|
-
|
|
188240
|
+
let target;
|
|
187753
188241
|
try {
|
|
187754
|
-
|
|
187755
|
-
|
|
188242
|
+
target = await this.deps.chat.resolveTarget({ automation, runId: run.id, title });
|
|
188243
|
+
} catch (e) {
|
|
188244
|
+
return this.failChatRun(run, e instanceof Error ? e.message : String(e));
|
|
188245
|
+
}
|
|
188246
|
+
if (!target.ok) return this.settleSkip(run, target.reasonCode, target.error, target.result);
|
|
188247
|
+
const claim = await this.claimChatTurn(run, target.chatSessionId).catch((e) => e);
|
|
188248
|
+
if (claim instanceof Error) return this.failChatRun(run, claim.message);
|
|
188249
|
+
if (claim.outcome === "busy") {
|
|
188250
|
+
await this.store.settleRun(run.id, {
|
|
188251
|
+
status: "skipped",
|
|
188252
|
+
reasonCode: "session_busy",
|
|
188253
|
+
error: busyError(target.chatSessionId, claim.activeTurn.sourceRunId),
|
|
188254
|
+
result: { chatSessionId: target.chatSessionId, blockedByTurnId: claim.activeTurn.id },
|
|
188255
|
+
completedAt: this.now().toISOString()
|
|
188256
|
+
});
|
|
188257
|
+
this.log?.(`[automations] run ${run.id} \u8DF3\u8FC7\uFF1A\u76EE\u6807\u4F1A\u8BDD ${target.chatSessionId} \u6B63\u5FD9\uFF08active turn ${claim.activeTurn.id}\uFF09`);
|
|
188258
|
+
return await this.store.getRun(run.id);
|
|
188259
|
+
}
|
|
188260
|
+
const turn = claim.turn;
|
|
188261
|
+
const chatSessionId = target.chatSessionId;
|
|
188262
|
+
try {
|
|
188263
|
+
await this.deps.chat.dispatchTurn(
|
|
188264
|
+
{
|
|
188265
|
+
automation,
|
|
188266
|
+
chatSessionId,
|
|
188267
|
+
turnId: turn.id,
|
|
188268
|
+
messageKey: turn.messageKey,
|
|
188269
|
+
prompt,
|
|
188270
|
+
runId: run.id
|
|
188271
|
+
},
|
|
187756
188272
|
async (out) => {
|
|
187757
188273
|
try {
|
|
187758
188274
|
if (out.ok) {
|
|
187759
188275
|
await this.store.settleRun(run.id, {
|
|
187760
188276
|
status: "succeeded",
|
|
187761
|
-
result: { chatSessionId, ...out.reply ? { reply: clipReply(out.reply) } : {} },
|
|
188277
|
+
result: { chatSessionId, turnId: turn.id, ...out.reply ? { reply: clipReply(out.reply) } : {} },
|
|
187762
188278
|
completedAt: this.now().toISOString()
|
|
187763
188279
|
});
|
|
187764
188280
|
} else {
|
|
@@ -187766,7 +188282,7 @@ var init_service8 = __esm({
|
|
|
187766
188282
|
status: "failed",
|
|
187767
188283
|
error: out.error ?? "\u4F1A\u8BDD\u6267\u884C\u5931\u8D25",
|
|
187768
188284
|
reasonCode: "spawn_failed",
|
|
187769
|
-
result: { chatSessionId },
|
|
188285
|
+
result: { chatSessionId, turnId: turn.id },
|
|
187770
188286
|
completedAt: this.now().toISOString()
|
|
187771
188287
|
});
|
|
187772
188288
|
}
|
|
@@ -187777,26 +188293,56 @@ var init_service8 = __esm({
|
|
|
187777
188293
|
);
|
|
187778
188294
|
await this.store.settleRun(run.id, {
|
|
187779
188295
|
status: "running",
|
|
187780
|
-
result: { chatSessionId },
|
|
188296
|
+
result: { chatSessionId, turnId: turn.id },
|
|
187781
188297
|
completedAt: null
|
|
187782
188298
|
});
|
|
187783
188299
|
return await this.store.getRun(run.id);
|
|
187784
188300
|
} catch (e) {
|
|
187785
188301
|
const msg = e instanceof Error ? e.message : String(e);
|
|
187786
|
-
await this.
|
|
187787
|
-
|
|
187788
|
-
|
|
187789
|
-
|
|
187790
|
-
|
|
188302
|
+
await this.deps.chatTurns.settleTurn(turn.id, { status: "failed", completedAt: this.now().toISOString(), lastError: msg }).catch((err) => this.log?.(`[automations] \u8F6E\u6B21\u6536\u53E3\u5931\u8D25 ${turn.id}: ${String(err)}`));
|
|
188303
|
+
return this.failChatRun(run, msg, { chatSessionId, turnId: turn.id });
|
|
188304
|
+
}
|
|
188305
|
+
}
|
|
188306
|
+
/**
|
|
188307
|
+
* 占位(ADR 会话投递 D5)。存储层给了复合操作就走复合(claim 与 busy 落账同一事务);
|
|
188308
|
+
* 没给则退回两步——单进程内存实现语义等价,多实例部署一律有复合实现。
|
|
188309
|
+
*/
|
|
188310
|
+
async claimChatTurn(run, chatSessionId) {
|
|
188311
|
+
const input = {
|
|
188312
|
+
turnId: this.genId("cturn"),
|
|
188313
|
+
chatSessionId,
|
|
188314
|
+
source: "automation",
|
|
188315
|
+
sourceRunId: automationTurnSourceRunId(run.id),
|
|
188316
|
+
messageKey: automationTurnMessageKey(run.id),
|
|
188317
|
+
reservedAt: this.now().toISOString()
|
|
188318
|
+
};
|
|
188319
|
+
if (this.store.claimChatTurnForRun) {
|
|
188320
|
+
return this.store.claimChatTurnForRun({
|
|
188321
|
+
...input,
|
|
188322
|
+
automationRunId: run.id,
|
|
188323
|
+
busyError: busyError(chatSessionId, ""),
|
|
188324
|
+
now: this.now().toISOString()
|
|
187791
188325
|
});
|
|
187792
|
-
return await this.store.getRun(run.id);
|
|
187793
188326
|
}
|
|
188327
|
+
return this.deps.chatTurns.claimTurn(input);
|
|
188328
|
+
}
|
|
188329
|
+
/** chat 路径的失败收口(基础设施故障,非 event 源,ADR 会话投递 D7)。 */
|
|
188330
|
+
async failChatRun(run, error2, result) {
|
|
188331
|
+
await this.store.settleRun(run.id, {
|
|
188332
|
+
status: "failed",
|
|
188333
|
+
error: error2,
|
|
188334
|
+
reasonCode: "spawn_failed",
|
|
188335
|
+
...result !== void 0 ? { result } : {},
|
|
188336
|
+
completedAt: this.now().toISOString()
|
|
188337
|
+
});
|
|
188338
|
+
return await this.store.getRun(run.id);
|
|
187794
188339
|
}
|
|
187795
|
-
async settleSkip(run, reasonCode, error2) {
|
|
188340
|
+
async settleSkip(run, reasonCode, error2, result) {
|
|
187796
188341
|
await this.store.settleRun(run.id, {
|
|
187797
188342
|
status: "skipped",
|
|
187798
188343
|
reasonCode,
|
|
187799
188344
|
error: error2,
|
|
188345
|
+
...result !== void 0 ? { result } : {},
|
|
187800
188346
|
completedAt: this.now().toISOString()
|
|
187801
188347
|
});
|
|
187802
188348
|
return await this.store.getRun(run.id);
|
|
@@ -188035,11 +188581,11 @@ function verifySignature(rawBody, headers, secret) {
|
|
|
188035
188581
|
if (!secret) return "not_required";
|
|
188036
188582
|
const given = header1(headers, "x-hub-signature-256");
|
|
188037
188583
|
if (!given) return "missing";
|
|
188038
|
-
const expected = `sha256=${(0,
|
|
188584
|
+
const expected = `sha256=${(0, import_node_crypto39.createHmac)("sha256", secret).update(rawBody).digest("hex")}`;
|
|
188039
188585
|
const a = Buffer.from(given);
|
|
188040
188586
|
const b2 = Buffer.from(expected);
|
|
188041
188587
|
if (a.length !== b2.length) return "invalid";
|
|
188042
|
-
return (0,
|
|
188588
|
+
return (0, import_node_crypto39.timingSafeEqual)(a, b2) ? "valid" : "invalid";
|
|
188043
188589
|
}
|
|
188044
188590
|
function eventAllowed(filters, envelope) {
|
|
188045
188591
|
if (!filters || filters.length === 0) return true;
|
|
@@ -188069,11 +188615,11 @@ function splitEvent(envelope) {
|
|
|
188069
188615
|
}
|
|
188070
188616
|
return { eventName, actionCandidates: candidates };
|
|
188071
188617
|
}
|
|
188072
|
-
var
|
|
188618
|
+
var import_node_crypto39, MAX_BODY_BYTES, AutomationWebhookService, header1, PROVIDER_PREFIXES;
|
|
188073
188619
|
var init_webhook = __esm({
|
|
188074
188620
|
"../server/src/domains/automations/webhook.ts"() {
|
|
188075
188621
|
"use strict";
|
|
188076
|
-
|
|
188622
|
+
import_node_crypto39 = require("node:crypto");
|
|
188077
188623
|
MAX_BODY_BYTES = 256 * 1024;
|
|
188078
188624
|
AutomationWebhookService = class {
|
|
188079
188625
|
store;
|
|
@@ -188360,7 +188906,9 @@ function buildAutomationSummary(automation, triggers, recent, canWrite) {
|
|
|
188360
188906
|
nextRunAt,
|
|
188361
188907
|
recent: ordered.slice(0, RECENT_LIMIT).map(stripRunPayload),
|
|
188362
188908
|
canWrite,
|
|
188363
|
-
capabilities: { eventTrigger: { supported: true } }
|
|
188909
|
+
capabilities: { eventTrigger: { supported: true } },
|
|
188910
|
+
// 固定目标会话的只读投影要查会话表,纯派生函数够不着——路由层用 service.chatTargetView 覆盖。
|
|
188911
|
+
chatTargetView: null
|
|
188364
188912
|
};
|
|
188365
188913
|
}
|
|
188366
188914
|
function deriveNextRunAt(triggers) {
|
|
@@ -188474,6 +189022,23 @@ function assertModeConfig(mode, agentId, playbookRef) {
|
|
|
188474
189022
|
if (!playbookRef?.trim()) throw new ApiError(400, "BAD_REQUEST", "workorder \u6A21\u5F0F\u7F3A\u5C11 playbookRef");
|
|
188475
189023
|
assertPlaybook(playbookRef);
|
|
188476
189024
|
}
|
|
189025
|
+
function validateChatTarget(raw, mode) {
|
|
189026
|
+
if (raw === void 0) return void 0;
|
|
189027
|
+
if (raw === null) return null;
|
|
189028
|
+
if (mode !== "chat") throw new ApiError(400, "BAD_REQUEST", "chatTarget \u53EA\u5728\u5BF9\u8BDD\u6267\u884C\uFF08chat\uFF09\u6A21\u5F0F\u4E0B\u6709\u610F\u4E49");
|
|
189029
|
+
const t = raw;
|
|
189030
|
+
if (t?.mode === "new_session") {
|
|
189031
|
+
if (t.sessionId !== void 0) throw new ApiError(400, "BAD_REQUEST", "chatTarget.mode=new_session \u65F6\u4E0D\u80FD\u5E26 sessionId");
|
|
189032
|
+
return { mode: "new_session" };
|
|
189033
|
+
}
|
|
189034
|
+
if (t?.mode === "existing_session") {
|
|
189035
|
+
if (typeof t.sessionId !== "string" || !t.sessionId.trim()) {
|
|
189036
|
+
throw new ApiError(400, "BAD_REQUEST", "chatTarget.mode=existing_session \u9700\u8981 sessionId");
|
|
189037
|
+
}
|
|
189038
|
+
return { mode: "existing_session", sessionId: t.sessionId.trim() };
|
|
189039
|
+
}
|
|
189040
|
+
throw new ApiError(400, "BAD_REQUEST", "chatTarget.mode \u53EA\u80FD\u662F new_session \u6216 existing_session");
|
|
189041
|
+
}
|
|
188477
189042
|
function assertTitleTemplate(tpl) {
|
|
188478
189043
|
if (!tpl) return;
|
|
188479
189044
|
const unknown2 = validateTitleTemplate(tpl);
|
|
@@ -188548,7 +189113,9 @@ function automationsDomain(opts) {
|
|
|
188548
189113
|
return {
|
|
188549
189114
|
...buildAutomationSummary(automation, decorated, recent, canWrite),
|
|
188550
189115
|
// 能力位服务端算(ADR 0163 §10):前端只消费不推断,否则前后端两套规则必漂移。
|
|
188551
|
-
capabilities: { eventTrigger: service.eventTriggerCapability(automation) }
|
|
189116
|
+
capabilities: { eventTrigger: service.eventTriggerCapability(automation) },
|
|
189117
|
+
// 固定目标会话的可用性同理:D3 五条只在服务端有真值,前端复制一份必然漂移。
|
|
189118
|
+
chatTargetView: await service.chatTargetView(automation)
|
|
188552
189119
|
};
|
|
188553
189120
|
};
|
|
188554
189121
|
const assertEventTriggerWritable = async (mode, cfg, existing, req) => {
|
|
@@ -188578,6 +189145,15 @@ function automationsDomain(opts) {
|
|
|
188578
189145
|
throw new ApiError(400, "EVENT_TRIGGER_UNSUPPORTED", "\u8FD9\u6761\u81EA\u52A8\u5316\u6709\u8BA2\u9605\u89E6\u53D1\u5668\uFF0C\u6539\u6210\u5BF9\u8BDD\u6267\u884C\u4F1A\u5931\u53BB\u6301\u4E45\u5E42\u7B49\u4FDD\u8BC1\u2014\u2014\u8BF7\u5148\u5220\u9664\u8BA2\u9605\u89E6\u53D1\u5668");
|
|
188579
189146
|
}
|
|
188580
189147
|
};
|
|
189148
|
+
const assertChatTargetUsable = async (a, target) => {
|
|
189149
|
+
if (target?.mode !== "existing_session") return;
|
|
189150
|
+
if (!service.chatTargetSupported()) {
|
|
189151
|
+
throw new ApiError(400, "CHAT_TARGET_UNSUPPORTED", "\u672C\u5B9E\u4F8B\u672A\u63A5\u4F1A\u8BDD\u8F6E\u6B21\u8D26\u672C\uFF0C\u6682\u4E0D\u652F\u6301\u56FA\u5B9A\u76EE\u6807\u4F1A\u8BDD");
|
|
189152
|
+
}
|
|
189153
|
+
const issue2 = await service.validateChatTarget(a, target.sessionId);
|
|
189154
|
+
if (issue2) throw new ApiError(400, "CHAT_TARGET_UNAVAILABLE", TARGET_ISSUE_MESSAGE[issue2]);
|
|
189155
|
+
};
|
|
189156
|
+
const resolveOwner2 = async (existing, req) => existing ?? await service.resolveOwnerHuman(req.auth.actor);
|
|
188581
189157
|
return (router) => {
|
|
188582
189158
|
router.get("/api/automations/templates", async () => {
|
|
188583
189159
|
const body = { items: AUTOMATION_TEMPLATES };
|
|
@@ -188591,6 +189167,32 @@ function automationsDomain(opts) {
|
|
|
188591
189167
|
const body = { next: cronNextN(expr, tz, 3) };
|
|
188592
189168
|
return { status: 200, body };
|
|
188593
189169
|
});
|
|
189170
|
+
router.get("/api/automations/chat-session-options", async (req) => {
|
|
189171
|
+
const agentId = req.query?.get("agentId") ?? "";
|
|
189172
|
+
if (!agentId.startsWith("actor:agent:")) throw new ApiError(400, "BAD_REQUEST", "\u9700\u8981 agentId\uFF08actor:agent:*\uFF09");
|
|
189173
|
+
if (!service.chatTargetSupported()) {
|
|
189174
|
+
throw new ApiError(400, "CHAT_TARGET_UNSUPPORTED", "\u672C\u5B9E\u4F8B\u672A\u63A5\u4F1A\u8BDD\u8F6E\u6B21\u8D26\u672C\uFF0C\u6682\u4E0D\u652F\u6301\u56FA\u5B9A\u76EE\u6807\u4F1A\u8BDD");
|
|
189175
|
+
}
|
|
189176
|
+
const owner = await service.resolveOwnerHuman(req.auth.actor);
|
|
189177
|
+
if (!owner) {
|
|
189178
|
+
const empty = { items: [], hasMore: false };
|
|
189179
|
+
return { status: 200, body: empty };
|
|
189180
|
+
}
|
|
189181
|
+
const limitRaw = Number(req.query?.get("limit"));
|
|
189182
|
+
const offsetRaw = Number(req.query?.get("offset"));
|
|
189183
|
+
const limit = Number.isInteger(limitRaw) && limitRaw > 0 ? Math.min(limitRaw, 50) : 20;
|
|
189184
|
+
const offset = Number.isInteger(offsetRaw) && offsetRaw > 0 ? offsetRaw : 0;
|
|
189185
|
+
const text = req.query?.get("q")?.trim();
|
|
189186
|
+
const body = await service.searchChatTargets({
|
|
189187
|
+
companyId: companyOf(req),
|
|
189188
|
+
agentId,
|
|
189189
|
+
ownerHumanActorId: owner,
|
|
189190
|
+
...text ? { text } : {},
|
|
189191
|
+
limit,
|
|
189192
|
+
offset
|
|
189193
|
+
});
|
|
189194
|
+
return { status: 200, body };
|
|
189195
|
+
});
|
|
188594
189196
|
router.get("/api/automations", async (req) => {
|
|
188595
189197
|
const includeArchived = req.query.get("includeArchived") === "1";
|
|
188596
189198
|
const automations = await service.listAutomations(companyOf(req), { includeArchived });
|
|
@@ -188644,12 +189246,30 @@ function automationsDomain(opts) {
|
|
|
188644
189246
|
const subscribers = assertActorIds(b2.subscribers, "subscribers");
|
|
188645
189247
|
const triggers = validateTriggers(b2.triggers);
|
|
188646
189248
|
await assertEventTriggerInputs(mode, triggers, [], req);
|
|
189249
|
+
const chatTarget = validateChatTarget(b2.chatTarget, mode);
|
|
189250
|
+
const createTargetSession = Boolean(b2.createChatTargetSession);
|
|
189251
|
+
if (createTargetSession) {
|
|
189252
|
+
if (mode !== "chat") throw new ApiError(400, "BAD_REQUEST", "createChatTargetSession \u53EA\u5728\u5BF9\u8BDD\u6267\u884C\uFF08chat\uFF09\u6A21\u5F0F\u4E0B\u6709\u610F\u4E49");
|
|
189253
|
+
if (chatTarget?.mode === "existing_session") {
|
|
189254
|
+
throw new ApiError(400, "BAD_REQUEST", "createChatTargetSession \u4E0E chatTarget.existing_session \u4E92\u65A5");
|
|
189255
|
+
}
|
|
189256
|
+
if (!service.chatTargetSupported()) {
|
|
189257
|
+
throw new ApiError(400, "CHAT_TARGET_UNSUPPORTED", "\u672C\u5B9E\u4F8B\u672A\u63A5\u4F1A\u8BDD\u8F6E\u6B21\u8D26\u672C\uFF0C\u6682\u4E0D\u652F\u6301\u56FA\u5B9A\u76EE\u6807\u4F1A\u8BDD");
|
|
189258
|
+
}
|
|
189259
|
+
}
|
|
189260
|
+
const ownerHumanActorId = mode === "chat" ? await service.resolveOwnerHuman(req.auth.actor) : null;
|
|
189261
|
+
if (mode === "chat" && !ownerHumanActorId && (chatTarget?.mode === "existing_session" || createTargetSession)) {
|
|
189262
|
+
throw new ApiError(400, "CHAT_TARGET_NO_OWNER", "\u89E3\u6790\u4E0D\u5230\u4EBA\u7C7B\u5F52\u5C5E\u8005\uFF0C\u65E0\u6CD5\u914D\u7F6E\u56FA\u5B9A\u76EE\u6807\u4F1A\u8BDD");
|
|
189263
|
+
}
|
|
189264
|
+
await assertChatTargetUsable({ companyId: companyOf(req), agentId: b2.agentId ?? null, ownerHumanActorId }, chatTarget);
|
|
188647
189265
|
const created = await service.createAutomation({
|
|
188648
189266
|
companyId: companyOf(req),
|
|
188649
189267
|
name: b2.name,
|
|
188650
189268
|
...b2.description !== void 0 ? { description: b2.description } : {},
|
|
188651
189269
|
executionMode: mode,
|
|
188652
189270
|
...b2.agentId !== void 0 ? { agentId: b2.agentId } : {},
|
|
189271
|
+
...chatTarget !== void 0 ? { chatTarget } : {},
|
|
189272
|
+
...ownerHumanActorId ? { ownerHumanActorId } : {},
|
|
188653
189273
|
...b2.projectId !== void 0 ? { projectId: b2.projectId } : {},
|
|
188654
189274
|
...b2.playbookRef !== void 0 ? { playbookRef: b2.playbookRef } : {},
|
|
188655
189275
|
...b2.payload !== void 0 ? { payload: b2.payload } : {},
|
|
@@ -188661,7 +189281,8 @@ function automationsDomain(opts) {
|
|
|
188661
189281
|
// 一律取鉴权身份,不收请求体(归属不可伪造)
|
|
188662
189282
|
...triggers !== void 0 ? { triggers } : {}
|
|
188663
189283
|
});
|
|
188664
|
-
|
|
189284
|
+
const withTarget = createTargetSession ? await service.createChatTargetSession(created, req.auth.actor) : created;
|
|
189285
|
+
return { status: 201, body: await summarize3(withTarget, req) };
|
|
188665
189286
|
});
|
|
188666
189287
|
router.patch("/api/automations/:id", async (req) => {
|
|
188667
189288
|
const automation = await mustGet(req);
|
|
@@ -188680,6 +189301,14 @@ function automationsDomain(opts) {
|
|
|
188680
189301
|
const kept = triggers !== void 0 ? [] : (await service.listTriggers(automation.id)).filter((t) => t.kind === "event" && t.event).map((t) => t.event);
|
|
188681
189302
|
await assertEventTriggerInputs(effMode, triggers, kept, req);
|
|
188682
189303
|
if (triggers === void 0) await assertModeKeepsEventTriggers(automation, effMode);
|
|
189304
|
+
const chatTarget = validateChatTarget(b2.chatTarget, effMode);
|
|
189305
|
+
const effTarget = chatTarget !== void 0 ? chatTarget : automation.chatTarget;
|
|
189306
|
+
const nextTarget = effMode === "workorder" ? null : effTarget;
|
|
189307
|
+
const ownerHumanActorId = effMode === "chat" ? await resolveOwner2(automation.ownerHumanActorId, req) : null;
|
|
189308
|
+
if (effMode === "chat" && nextTarget?.mode === "existing_session" && !ownerHumanActorId) {
|
|
189309
|
+
throw new ApiError(400, "CHAT_TARGET_NO_OWNER", "\u89E3\u6790\u4E0D\u5230\u4EBA\u7C7B\u5F52\u5C5E\u8005\uFF0C\u65E0\u6CD5\u914D\u7F6E\u56FA\u5B9A\u76EE\u6807\u4F1A\u8BDD");
|
|
189310
|
+
}
|
|
189311
|
+
await assertChatTargetUsable({ companyId: automation.companyId, agentId: effAgent ?? null, ownerHumanActorId }, nextTarget);
|
|
188683
189312
|
const updated = await service.updateAutomation(
|
|
188684
189313
|
automation.id,
|
|
188685
189314
|
{
|
|
@@ -188694,12 +189323,28 @@ function automationsDomain(opts) {
|
|
|
188694
189323
|
...b2.dispatch !== void 0 ? { dispatch: Boolean(b2.dispatch) } : {},
|
|
188695
189324
|
...b2.enabled !== void 0 ? { enabled: b2.enabled } : {},
|
|
188696
189325
|
...subscribers !== void 0 ? { subscribers } : {},
|
|
188697
|
-
...triggers !== void 0 ? { triggers } : {}
|
|
189326
|
+
...triggers !== void 0 ? { triggers } : {},
|
|
189327
|
+
...nextTarget !== automation.chatTarget ? { chatTarget: nextTarget } : {},
|
|
189328
|
+
...ownerHumanActorId !== automation.ownerHumanActorId ? { ownerHumanActorId } : {}
|
|
188698
189329
|
},
|
|
188699
189330
|
req.auth.actor
|
|
188700
189331
|
);
|
|
188701
189332
|
return { status: 200, body: await summarize3(updated, req) };
|
|
188702
189333
|
});
|
|
189334
|
+
router.post("/api/automations/:id/chat-target-session", async (req) => {
|
|
189335
|
+
const automation = await mustGet(req);
|
|
189336
|
+
await requireWrite(automation, req);
|
|
189337
|
+
if (automation.executionMode !== "chat") throw new ApiError(400, "BAD_REQUEST", "\u53EA\u6709\u5BF9\u8BDD\u6267\u884C\uFF08chat\uFF09\u6A21\u5F0F\u624D\u6709\u76EE\u6807\u4F1A\u8BDD");
|
|
189338
|
+
if (!automation.agentId) throw new ApiError(400, "BAD_REQUEST", "\u5148\u7ED9\u8FD9\u6761\u81EA\u52A8\u5316\u8BBE\u7F6E\u6267\u884C\u4EBA");
|
|
189339
|
+
if (!service.chatTargetSupported()) {
|
|
189340
|
+
throw new ApiError(400, "CHAT_TARGET_UNSUPPORTED", "\u672C\u5B9E\u4F8B\u672A\u63A5\u4F1A\u8BDD\u8F6E\u6B21\u8D26\u672C\uFF0C\u6682\u4E0D\u652F\u6301\u56FA\u5B9A\u76EE\u6807\u4F1A\u8BDD");
|
|
189341
|
+
}
|
|
189342
|
+
const owner = await resolveOwner2(automation.ownerHumanActorId, req);
|
|
189343
|
+
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");
|
|
189344
|
+
const withOwner = automation.ownerHumanActorId ? automation : await service.updateAutomation(automation.id, { ownerHumanActorId: owner }, req.auth.actor);
|
|
189345
|
+
const updated = await service.createChatTargetSession(withOwner, req.auth.actor);
|
|
189346
|
+
return { status: 201, body: await summarize3(updated, req) };
|
|
189347
|
+
});
|
|
188703
189348
|
router.post("/api/automations/:id/enabled", async (req) => {
|
|
188704
189349
|
const automation = await mustGet(req);
|
|
188705
189350
|
await requireWrite(automation, req);
|
|
@@ -188847,7 +189492,7 @@ function automationsDomain(opts) {
|
|
|
188847
189492
|
});
|
|
188848
189493
|
};
|
|
188849
189494
|
}
|
|
188850
|
-
var RECENT_LIMIT2;
|
|
189495
|
+
var RECENT_LIMIT2, TARGET_ISSUE_MESSAGE;
|
|
188851
189496
|
var init_routes9 = __esm({
|
|
188852
189497
|
"../server/src/domains/automations/routes.ts"() {
|
|
188853
189498
|
"use strict";
|
|
@@ -188860,6 +189505,13 @@ var init_routes9 = __esm({
|
|
|
188860
189505
|
init_registry3();
|
|
188861
189506
|
init_migrate();
|
|
188862
189507
|
RECENT_LIMIT2 = 5;
|
|
189508
|
+
TARGET_ISSUE_MESSAGE = {
|
|
189509
|
+
session_missing: "\u76EE\u6807\u4F1A\u8BDD\u4E0D\u5B58\u5728\u6216\u5DF2\u88AB\u5220\u9664",
|
|
189510
|
+
cross_company: "\u76EE\u6807\u4F1A\u8BDD\u5C5E\u4E8E\u5176\u5B83\u516C\u53F8\uFF0C\u4E0D\u80FD\u8DE8\u516C\u53F8\u6295\u9012",
|
|
189511
|
+
company_unknown: "\u8FD9\u6761\u5386\u53F2\u4F1A\u8BDD\u6CA1\u6709\u516C\u53F8\u5F52\u5C5E\uFF0C\u4E0D\u80FD\u4F5C\u4E3A\u56FA\u5B9A\u76EE\u6807\u2014\u2014\u8BF7\u65B0\u5EFA\u4E00\u4E2A\u957F\u671F\u4F1A\u8BDD",
|
|
189512
|
+
owner_mismatch: "\u76EE\u6807\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u8FD9\u6761\u81EA\u52A8\u5316\u7684\u5F52\u5C5E\u4EBA",
|
|
189513
|
+
agent_mismatch: "\u76EE\u6807\u4F1A\u8BDD\u7684 AI \u8EAB\u4EFD\u4E0E\u6267\u884C\u4EBA\u4E0D\u4E00\u81F4\u2014\u2014\u8BF7\u6362\u4E00\u4E2A\u4F1A\u8BDD\u6216\u6539\u6267\u884C\u4EBA\uFF08\u4E0D\u4F1A\u81EA\u52A8\u6539\u7ED1\uFF09"
|
|
189514
|
+
};
|
|
188863
189515
|
}
|
|
188864
189516
|
});
|
|
188865
189517
|
|
|
@@ -188932,6 +189584,7 @@ function createAutomationsDomain(opts) {
|
|
|
188932
189584
|
const service = new AutomationsService({
|
|
188933
189585
|
store: opts.store,
|
|
188934
189586
|
fire: opts.fire,
|
|
189587
|
+
...opts.chatTargets ? { chatTargets: opts.chatTargets } : {},
|
|
188935
189588
|
...opts.genId ? { genId: opts.genId } : {},
|
|
188936
189589
|
...opts.now ? { now: opts.now } : {},
|
|
188937
189590
|
...opts.log ? { log: opts.log } : {}
|
|
@@ -189116,7 +189769,7 @@ function playbooksDomain(opts) {
|
|
|
189116
189769
|
opts.overrides.set(companyOf(req), ref2, nodeKey, nextOverride);
|
|
189117
189770
|
try {
|
|
189118
189771
|
await opts.audit?.({
|
|
189119
|
-
id: `reg_${(0,
|
|
189772
|
+
id: `reg_${(0, import_node_crypto40.randomUUID)()}`,
|
|
189120
189773
|
actor: req.auth.actor,
|
|
189121
189774
|
kind: "registry_change",
|
|
189122
189775
|
target: `playbook:${ref2}#${nodeKey}`,
|
|
@@ -189133,11 +189786,11 @@ function playbooksDomain(opts) {
|
|
|
189133
189786
|
});
|
|
189134
189787
|
};
|
|
189135
189788
|
}
|
|
189136
|
-
var
|
|
189789
|
+
var import_node_crypto40;
|
|
189137
189790
|
var init_routes10 = __esm({
|
|
189138
189791
|
"../server/src/domains/playbooks/routes.ts"() {
|
|
189139
189792
|
"use strict";
|
|
189140
|
-
|
|
189793
|
+
import_node_crypto40 = require("node:crypto");
|
|
189141
189794
|
init_router();
|
|
189142
189795
|
init_registry3();
|
|
189143
189796
|
init_planner();
|
|
@@ -189249,17 +189902,17 @@ function completionFingerprint(workspace, members) {
|
|
|
189249
189902
|
workspace,
|
|
189250
189903
|
members: [...members].sort((a, b2) => a.artifactId < b2.artifactId ? -1 : a.artifactId > b2.artifactId ? 1 : 0).map((m2) => ({ artifactId: m2.artifactId, currentRevisionId: m2.currentRevisionId ?? null }))
|
|
189251
189904
|
});
|
|
189252
|
-
return (0,
|
|
189905
|
+
return (0, import_node_crypto41.createHash)("sha256").update(canonical).digest("hex");
|
|
189253
189906
|
}
|
|
189254
189907
|
function eventConsumptionKey(args) {
|
|
189255
189908
|
const raw = `project-event:${EVENT_KEY_VERSION}:${args.triggerId}:${args.event}:${args.workspace}:${args.fingerprint}`;
|
|
189256
|
-
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0,
|
|
189909
|
+
return raw.length <= 200 ? raw : `project-event:${EVENT_KEY_VERSION}:sha256:${(0, import_node_crypto41.createHash)("sha256").update(raw).digest("hex")}`;
|
|
189257
189910
|
}
|
|
189258
|
-
var
|
|
189911
|
+
var import_node_crypto41, EVENT_KEY_VERSION, EMPTY_METRICS, AUTOMATION_EVENT_HANDLERS, ProjectEventPoller;
|
|
189259
189912
|
var init_project_event_poller = __esm({
|
|
189260
189913
|
"../server/src/automations/project-event-poller.ts"() {
|
|
189261
189914
|
"use strict";
|
|
189262
|
-
|
|
189915
|
+
import_node_crypto41 = require("node:crypto");
|
|
189263
189916
|
EVENT_KEY_VERSION = "v1";
|
|
189264
189917
|
EMPTY_METRICS = () => ({
|
|
189265
189918
|
scanDurationMs: 0,
|
|
@@ -189478,11 +190131,11 @@ function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
|
|
|
189478
190131
|
entry.appendWaiters.push({ resolve: resolve10, timer });
|
|
189479
190132
|
});
|
|
189480
190133
|
}
|
|
189481
|
-
var
|
|
190134
|
+
var import_node_crypto42, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_IDS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
|
|
189482
190135
|
var init_daemon_adapter = __esm({
|
|
189483
190136
|
"../server/src/daemon-adapter.ts"() {
|
|
189484
190137
|
"use strict";
|
|
189485
|
-
|
|
190138
|
+
import_node_crypto42 = require("node:crypto");
|
|
189486
190139
|
init_src2();
|
|
189487
190140
|
STASH_TTL_MS = 5 * 6e4;
|
|
189488
190141
|
STASH_MAX_FRAMES_PER_ID = 500;
|
|
@@ -189498,6 +190151,7 @@ var init_daemon_adapter = __esm({
|
|
|
189498
190151
|
this.log = opts.log ?? ((m2) => console.warn(m2));
|
|
189499
190152
|
this.health = opts.health;
|
|
189500
190153
|
this.stashEnabled = opts.stashUnknownFrames ?? false;
|
|
190154
|
+
this.onSettleWithoutFrame = opts.onSettleWithoutFrame;
|
|
189501
190155
|
hub.addMessageListener((_daemonId, msg) => this.onDaemonMessage(msg));
|
|
189502
190156
|
hub.addDisconnectListener((daemonId) => this.onNodeDown(daemonId));
|
|
189503
190157
|
hub.addConnectListener((daemon) => this.onNodeUp(daemon));
|
|
@@ -189517,6 +190171,8 @@ var init_daemon_adapter = __esm({
|
|
|
189517
190171
|
log;
|
|
189518
190172
|
health;
|
|
189519
190173
|
stashEnabled;
|
|
190174
|
+
/** 服务端自判死时的回调(见 DaemonHubAdapterOptions.onSettleWithoutFrame)。 */
|
|
190175
|
+
onSettleWithoutFrame;
|
|
189520
190176
|
/** 未知会话帧暂存(stashUnknownFrames 开启时):dispatchId → 断链/重启窗口补发上来的帧。 */
|
|
189521
190177
|
stash = /* @__PURE__ */ new Map();
|
|
189522
190178
|
/** 断联节点 → 收割定时器。重连取消;到期收割。 */
|
|
@@ -189558,7 +190214,15 @@ var init_daemon_adapter = __esm({
|
|
|
189558
190214
|
}
|
|
189559
190215
|
}
|
|
189560
190216
|
/** 统一结算一次会话退出:清 ack 定时器、置 exited、触发回调、从 pending 摘除。幂等(已退出即跳过)。 */
|
|
189561
|
-
|
|
190217
|
+
/**
|
|
190218
|
+
* 收尾一次派发。
|
|
190219
|
+
*
|
|
190220
|
+
* `fromFrame` = 这次收尾是不是**节点报上来的真退出帧**触发的。false(默认)意味着服务端
|
|
190221
|
+
* 自己判的死——存在性快照 / 会话失联收割 / socket 非 OPEN。那三条走不到 serve 挂在 hub
|
|
190222
|
+
* message listener 上的 work.response 桥,引擎那条 work 会一直挂 running 直到 30 分钟超时,
|
|
190223
|
+
* 所以这里要显式喊一声 `onSettleWithoutFrame`。**新增判死路径时默认值就是对的**,别顺手传 true。
|
|
190224
|
+
*/
|
|
190225
|
+
settle(dispatchId, info, fromFrame = false) {
|
|
189562
190226
|
const entry = this.pending.get(dispatchId);
|
|
189563
190227
|
if (!entry || entry.exited) return;
|
|
189564
190228
|
if (entry.ackTimer) {
|
|
@@ -189583,6 +190247,13 @@ var init_daemon_adapter = __esm({
|
|
|
189583
190247
|
this.settledDispatchIds.delete(v2.value);
|
|
189584
190248
|
}
|
|
189585
190249
|
}
|
|
190250
|
+
if (!fromFrame) {
|
|
190251
|
+
try {
|
|
190252
|
+
this.onSettleWithoutFrame?.(dispatchId, info);
|
|
190253
|
+
} catch (e) {
|
|
190254
|
+
this.log(`[dispatch-delivery] onSettleWithoutFrame \u629B\u9519\uFF08\u4E0D\u5F71\u54CD\u6536\u5C3E\uFF09\uFF1A${String(e)}`);
|
|
190255
|
+
}
|
|
190256
|
+
}
|
|
189586
190257
|
}
|
|
189587
190258
|
/** 当前在途(未退出)会话数;传 runtimeKind 时收窄到单个 runtime 实例。 */
|
|
189588
190259
|
activeRunCount(nodeId, runtimeKind) {
|
|
@@ -189720,7 +190391,7 @@ var init_daemon_adapter = __esm({
|
|
|
189720
190391
|
if (entry) this.health?.recordReachable(entry.nodeId);
|
|
189721
190392
|
} else if (msg.type === "session_exited") {
|
|
189722
190393
|
const info = msg.info.reason || msg.info.code !== null ? msg.info : { ...msg.info, reason: "error" };
|
|
189723
|
-
if (this.pending.has(msg.dispatchId)) this.settle(msg.dispatchId, info);
|
|
190394
|
+
if (this.pending.has(msg.dispatchId)) this.settle(msg.dispatchId, info, true);
|
|
189724
190395
|
else if (this.stashEnabled) this.stashFrame(msg.dispatchId, { type: "exit", info });
|
|
189725
190396
|
} else if (msg.type === "session_event") {
|
|
189726
190397
|
this.confirmDelivery(msg.dispatchId, "started");
|
|
@@ -189744,7 +190415,7 @@ var init_daemon_adapter = __esm({
|
|
|
189744
190415
|
async spawn(job) {
|
|
189745
190416
|
const nodeId = job.binding?.nodeId;
|
|
189746
190417
|
if (!nodeId) throw new Error("DaemonHubAdapter \u9700\u8981 job.binding.nodeId\uFF08\u8DEF\u7531\u9519\u8BEF\uFF09");
|
|
189747
|
-
const dispatchId = job.dispatchId ?? `dispatch:${(0,
|
|
190418
|
+
const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto42.randomUUID)()}`;
|
|
189748
190419
|
const entry = {
|
|
189749
190420
|
nodeId,
|
|
189750
190421
|
...job.binding?.runtimeKind ? { runtimeKind: job.binding.runtimeKind } : {},
|
|
@@ -189901,7 +190572,7 @@ var init_daemon_adapter = __esm({
|
|
|
189901
190572
|
}));
|
|
189902
190573
|
}
|
|
189903
190574
|
request(nodeId, buildFrame) {
|
|
189904
|
-
const requestId = (0,
|
|
190575
|
+
const requestId = (0, import_node_crypto42.randomUUID)();
|
|
189905
190576
|
const sent = this.hub.dispatch(nodeId, buildFrame(requestId));
|
|
189906
190577
|
if (!sent) return Promise.resolve({ ok: false, code: "NODE_OFFLINE" });
|
|
189907
190578
|
return new Promise((resolve10) => {
|
|
@@ -190009,13 +190680,13 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
|
|
|
190009
190680
|
if (sha(body) === lastPushedHash) return { kind: "echo" };
|
|
190010
190681
|
return { kind: "human-edit", content: body, updatedBy: page.updatedBy };
|
|
190011
190682
|
}
|
|
190012
|
-
var
|
|
190683
|
+
var import_node_crypto43, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
|
|
190013
190684
|
var init_engine = __esm({
|
|
190014
190685
|
"../server/src/mirror/engine.ts"() {
|
|
190015
190686
|
"use strict";
|
|
190016
|
-
|
|
190687
|
+
import_node_crypto43 = require("node:crypto");
|
|
190017
190688
|
init_src2();
|
|
190018
|
-
sha = (s2) => (0,
|
|
190689
|
+
sha = (s2) => (0, import_node_crypto43.createHash)("sha256").update(s2, "utf8").digest("hex");
|
|
190019
190690
|
enc3 = (s2) => new TextEncoder().encode(s2);
|
|
190020
190691
|
dec = (b2) => new TextDecoder().decode(b2);
|
|
190021
190692
|
MirrorEngine = class {
|
|
@@ -190222,11 +190893,11 @@ function humanExitCause(exit) {
|
|
|
190222
190893
|
const base = (exit.reason ? label[exit.reason] : void 0) ?? `\u4F1A\u8BDD\u5F02\u5E38\u7ED3\u675F\uFF08${exit.reason ?? "\u65E0\u9000\u51FA\u4FE1\u606F"}\uFF09`;
|
|
190223
190894
|
return exit.errorMessage ? `${base}\uFF1A${exit.errorMessage.slice(0, 200)}` : base;
|
|
190224
190895
|
}
|
|
190225
|
-
var
|
|
190896
|
+
var import_node_crypto44, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_ESCALATION_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
|
|
190226
190897
|
var init_worker = __esm({
|
|
190227
190898
|
"../server/src/coordinator/worker.ts"() {
|
|
190228
190899
|
"use strict";
|
|
190229
|
-
|
|
190900
|
+
import_node_crypto44 = require("node:crypto");
|
|
190230
190901
|
init_src5();
|
|
190231
190902
|
init_identity();
|
|
190232
190903
|
AUTONOMOUS_ETHOS = `\u4F60\u662F\u8FD9\u4E2A\u5DE5\u5355\u7684**\u7BA1\u7406\u8005**\u2014\u2014\u804C\u8D23\u662F\u8BA9\u5B83\u987A\u7545\u8DD1\u5B8C\u3002\u7CFB\u7EDF\u5728\u67D0\u4E2A\u8282\u70B9\u5361\u4F4F\u3001\u673A\u68B0\u5206\u8BCA\u786E\u8BA4"\u9700\u8981\u4F60"\u65F6\u5524\u8D77\u4F60\uFF08\u65E0\u4EBA\u5728\u573A\uFF0C\u4F60\u8FD9\u4E00\u8F6E\u628A\u80FD\u505A\u7684\u505A\u6389\uFF09\u3002\u4F60\u7684\u624B\u6BB5\u5F88\u5BBD\uFF1A
|
|
@@ -190473,7 +191144,7 @@ ${HIGH_RISK_COMMANDS}`;
|
|
|
190473
191144
|
return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
|
|
190474
191145
|
}
|
|
190475
191146
|
evaluationKey(kind, artifactId, evidence) {
|
|
190476
|
-
const fingerprint = (0,
|
|
191147
|
+
const fingerprint = (0, import_node_crypto44.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
|
|
190477
191148
|
return `${kind}:${artifactId}:${fingerprint}`;
|
|
190478
191149
|
}
|
|
190479
191150
|
artifactEvidence(id) {
|
|
@@ -190850,8 +191521,8 @@ ${ctx.nodeFault}
|
|
|
190850
191521
|
this.deps.log?.(`[coordinator] ${workspace} \u5168\u5C40\u4E0A\u4E0B\u6587\u8BFB\u53D6\u5931\u8D25\uFF0C\u7EE7\u7EED\u6CBF\u7528\u539F\u534F\u8C03\u8005\u4EFB\u52A1\uFF1A${String(error2)}`);
|
|
190851
191522
|
}
|
|
190852
191523
|
}
|
|
190853
|
-
const runtimeSessionId = opts?.resumeSessionId ?? (0,
|
|
190854
|
-
const coordinatorRunId = `coordinate:${(0,
|
|
191524
|
+
const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto44.randomUUID)();
|
|
191525
|
+
const coordinatorRunId = `coordinate:${(0, import_node_crypto44.randomUUID)()}`;
|
|
190855
191526
|
const taskWithContext = coordinatorContext ? [
|
|
190856
191527
|
task,
|
|
190857
191528
|
``,
|
|
@@ -190892,7 +191563,7 @@ ${ctx.nodeFault}
|
|
|
190892
191563
|
const startedAtMs = Date.now();
|
|
190893
191564
|
let trajectoryStarted = false;
|
|
190894
191565
|
if (this.deps.trajectory) {
|
|
190895
|
-
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content]) => [name, (0,
|
|
191566
|
+
const bundleManifest = Object.fromEntries(Object.entries(job.bundle.files).map(([name, content]) => [name, (0, import_node_crypto44.createHash)("sha256").update(content).digest("hex")]));
|
|
190896
191567
|
const session = {
|
|
190897
191568
|
runId: coordinatorRunId,
|
|
190898
191569
|
runtimeSessionId,
|
|
@@ -191258,6 +191929,7 @@ var init_src10 = __esm({
|
|
|
191258
191929
|
init_recovery_plan();
|
|
191259
191930
|
init_live_chat();
|
|
191260
191931
|
init_chat_recovery();
|
|
191932
|
+
init_chat_turn_gate();
|
|
191261
191933
|
init_crypto2();
|
|
191262
191934
|
init_new_engine();
|
|
191263
191935
|
init_daemon_hub();
|
|
@@ -191288,6 +191960,7 @@ var init_src10 = __esm({
|
|
|
191288
191960
|
init_execution_continuity2();
|
|
191289
191961
|
init_chat_sessions();
|
|
191290
191962
|
init_dev_store();
|
|
191963
|
+
init_continuation();
|
|
191291
191964
|
init_knowledge2();
|
|
191292
191965
|
init_automations();
|
|
191293
191966
|
init_automations();
|
|
@@ -191315,11 +191988,11 @@ var init_src10 = __esm({
|
|
|
191315
191988
|
});
|
|
191316
191989
|
|
|
191317
191990
|
// ../storage/src/postgres.ts
|
|
191318
|
-
var
|
|
191991
|
+
var import_node_crypto45, ident3, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
|
|
191319
191992
|
var init_postgres = __esm({
|
|
191320
191993
|
"../storage/src/postgres.ts"() {
|
|
191321
191994
|
"use strict";
|
|
191322
|
-
|
|
191995
|
+
import_node_crypto45 = require("node:crypto");
|
|
191323
191996
|
init_esm();
|
|
191324
191997
|
init_src2();
|
|
191325
191998
|
ident3 = (s2) => {
|
|
@@ -191498,7 +192171,7 @@ var init_postgres = __esm({
|
|
|
191498
192171
|
return new _PostgresBlobStore(pool, schema);
|
|
191499
192172
|
}
|
|
191500
192173
|
async put(bytes) {
|
|
191501
|
-
const hash = (0,
|
|
192174
|
+
const hash = (0, import_node_crypto45.createHash)("sha256").update(bytes).digest("hex");
|
|
191502
192175
|
await this.pool.query(
|
|
191503
192176
|
`INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
|
|
191504
192177
|
[hash, Buffer.from(bytes), bytes.byteLength, sniffContentType(bytes) ?? null]
|
|
@@ -195766,6 +196439,144 @@ var init_postgres_trace = __esm({
|
|
|
195766
196439
|
}
|
|
195767
196440
|
});
|
|
195768
196441
|
|
|
196442
|
+
// ../storage/src/postgres-chat-turns.ts
|
|
196443
|
+
async function ensureChatTurnsTable(pool, schema = "public") {
|
|
196444
|
+
const s2 = ident10(schema);
|
|
196445
|
+
await pool.query(`CREATE SCHEMA IF NOT EXISTS "${s2}"`);
|
|
196446
|
+
await pool.query(`
|
|
196447
|
+
CREATE TABLE IF NOT EXISTS "${s2}".chat_session_turns (
|
|
196448
|
+
id text PRIMARY KEY,
|
|
196449
|
+
chat_session_id text NOT NULL,
|
|
196450
|
+
source text NOT NULL,
|
|
196451
|
+
source_run_id text NOT NULL,
|
|
196452
|
+
message_key text NOT NULL,
|
|
196453
|
+
status text NOT NULL,
|
|
196454
|
+
dispatch_id text,
|
|
196455
|
+
assistant_run_id text,
|
|
196456
|
+
reserved_at timestamptz NOT NULL,
|
|
196457
|
+
started_at timestamptz,
|
|
196458
|
+
completed_at timestamptz,
|
|
196459
|
+
last_error text
|
|
196460
|
+
)`);
|
|
196461
|
+
await pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS chat_session_turns_source_uq ON "${s2}".chat_session_turns (source, source_run_id)`);
|
|
196462
|
+
await pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS chat_session_turns_msgkey_uq ON "${s2}".chat_session_turns (message_key)`);
|
|
196463
|
+
await pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS chat_session_turns_active_uq ON "${s2}".chat_session_turns (chat_session_id) WHERE status IN ('reserved','running')`);
|
|
196464
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS chat_session_turns_stale_idx ON "${s2}".chat_session_turns (reserved_at) WHERE status IN ('reserved','running')`);
|
|
196465
|
+
}
|
|
196466
|
+
var ident10, PostgresChatTurnStore, isUniqueViolation2, iso3, rowToTurn;
|
|
196467
|
+
var init_postgres_chat_turns = __esm({
|
|
196468
|
+
"../storage/src/postgres-chat-turns.ts"() {
|
|
196469
|
+
"use strict";
|
|
196470
|
+
init_esm();
|
|
196471
|
+
ident10 = (s2) => {
|
|
196472
|
+
if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
|
|
196473
|
+
return s2;
|
|
196474
|
+
};
|
|
196475
|
+
PostgresChatTurnStore = class _PostgresChatTurnStore {
|
|
196476
|
+
constructor(pool, schema) {
|
|
196477
|
+
this.pool = pool;
|
|
196478
|
+
this.s = `"${ident10(schema)}"`;
|
|
196479
|
+
}
|
|
196480
|
+
s;
|
|
196481
|
+
static async open(pool, schema = "public") {
|
|
196482
|
+
await ensureChatTurnsTable(pool, schema);
|
|
196483
|
+
return new _PostgresChatTurnStore(pool, schema);
|
|
196484
|
+
}
|
|
196485
|
+
async claimTurn(input) {
|
|
196486
|
+
try {
|
|
196487
|
+
const r = await this.pool.query(
|
|
196488
|
+
`INSERT INTO ${this.s}.chat_session_turns
|
|
196489
|
+
(id, chat_session_id, source, source_run_id, message_key, status, reserved_at)
|
|
196490
|
+
VALUES ($1,$2,$3,$4,$5,'reserved',$6)
|
|
196491
|
+
RETURNING *`,
|
|
196492
|
+
[input.turnId, input.chatSessionId, input.source, input.sourceRunId, input.messageKey, input.reservedAt]
|
|
196493
|
+
);
|
|
196494
|
+
return { outcome: "claimed", turn: rowToTurn(r.rows[0]) };
|
|
196495
|
+
} catch (err) {
|
|
196496
|
+
if (!isUniqueViolation2(err)) throw err;
|
|
196497
|
+
const mine = await this.getTurnBySourceRun(input.source, input.sourceRunId);
|
|
196498
|
+
if (mine) return { outcome: "resumed", turn: mine };
|
|
196499
|
+
const active = await this.activeTurn(input.chatSessionId);
|
|
196500
|
+
if (active) return { outcome: "busy", activeTurn: active };
|
|
196501
|
+
throw err;
|
|
196502
|
+
}
|
|
196503
|
+
}
|
|
196504
|
+
async getTurn(turnId) {
|
|
196505
|
+
const r = await this.pool.query(`SELECT * FROM ${this.s}.chat_session_turns WHERE id = $1`, [turnId]);
|
|
196506
|
+
return r.rows[0] ? rowToTurn(r.rows[0]) : null;
|
|
196507
|
+
}
|
|
196508
|
+
async getTurnBySourceRun(source, sourceRunId) {
|
|
196509
|
+
const r = await this.pool.query(
|
|
196510
|
+
`SELECT * FROM ${this.s}.chat_session_turns WHERE source = $1 AND source_run_id = $2`,
|
|
196511
|
+
[source, sourceRunId]
|
|
196512
|
+
);
|
|
196513
|
+
return r.rows[0] ? rowToTurn(r.rows[0]) : null;
|
|
196514
|
+
}
|
|
196515
|
+
async activeTurn(chatSessionId) {
|
|
196516
|
+
const r = await this.pool.query(
|
|
196517
|
+
`SELECT * FROM ${this.s}.chat_session_turns
|
|
196518
|
+
WHERE chat_session_id = $1 AND status IN ('reserved','running') LIMIT 1`,
|
|
196519
|
+
[chatSessionId]
|
|
196520
|
+
);
|
|
196521
|
+
return r.rows[0] ? rowToTurn(r.rows[0]) : null;
|
|
196522
|
+
}
|
|
196523
|
+
async settleTurn(turnId, patch) {
|
|
196524
|
+
const sets = [];
|
|
196525
|
+
const args = [];
|
|
196526
|
+
args.push(patch.status);
|
|
196527
|
+
sets.push(`status = $${args.length}`);
|
|
196528
|
+
if (patch.dispatchId !== void 0) {
|
|
196529
|
+
args.push(patch.dispatchId);
|
|
196530
|
+
sets.push(`dispatch_id = $${args.length}`);
|
|
196531
|
+
}
|
|
196532
|
+
if (patch.assistantRunId !== void 0) {
|
|
196533
|
+
args.push(patch.assistantRunId);
|
|
196534
|
+
sets.push(`assistant_run_id = $${args.length}`);
|
|
196535
|
+
}
|
|
196536
|
+
if (patch.startedAt !== void 0) {
|
|
196537
|
+
args.push(patch.startedAt);
|
|
196538
|
+
sets.push(`started_at = $${args.length}`);
|
|
196539
|
+
}
|
|
196540
|
+
if (patch.completedAt !== void 0) {
|
|
196541
|
+
args.push(patch.completedAt);
|
|
196542
|
+
sets.push(`completed_at = $${args.length}`);
|
|
196543
|
+
}
|
|
196544
|
+
if (patch.lastError !== void 0) {
|
|
196545
|
+
args.push(patch.lastError);
|
|
196546
|
+
sets.push(`last_error = $${args.length}`);
|
|
196547
|
+
}
|
|
196548
|
+
args.push(turnId);
|
|
196549
|
+
await this.pool.query(`UPDATE ${this.s}.chat_session_turns SET ${sets.join(", ")} WHERE id = $${args.length}`, args);
|
|
196550
|
+
}
|
|
196551
|
+
async listStaleActiveTurns(reservedBefore, limit = 50) {
|
|
196552
|
+
const r = await this.pool.query(
|
|
196553
|
+
`SELECT * FROM ${this.s}.chat_session_turns
|
|
196554
|
+
WHERE status IN ('reserved','running') AND reserved_at < $1
|
|
196555
|
+
ORDER BY reserved_at ASC LIMIT $2`,
|
|
196556
|
+
[reservedBefore, limit]
|
|
196557
|
+
);
|
|
196558
|
+
return r.rows.map(rowToTurn);
|
|
196559
|
+
}
|
|
196560
|
+
};
|
|
196561
|
+
isUniqueViolation2 = (err) => Boolean(err && typeof err === "object" && err.code === "23505");
|
|
196562
|
+
iso3 = (v2) => v2 != null ? new Date(v2).toISOString() : null;
|
|
196563
|
+
rowToTurn = (row) => ({
|
|
196564
|
+
id: row.id,
|
|
196565
|
+
chatSessionId: row.chat_session_id,
|
|
196566
|
+
source: row.source,
|
|
196567
|
+
sourceRunId: row.source_run_id,
|
|
196568
|
+
messageKey: row.message_key,
|
|
196569
|
+
status: row.status,
|
|
196570
|
+
dispatchId: row.dispatch_id ?? null,
|
|
196571
|
+
assistantRunId: row.assistant_run_id ?? null,
|
|
196572
|
+
reservedAt: iso3(row.reserved_at),
|
|
196573
|
+
startedAt: iso3(row.started_at),
|
|
196574
|
+
completedAt: iso3(row.completed_at),
|
|
196575
|
+
lastError: row.last_error ?? null
|
|
196576
|
+
});
|
|
196577
|
+
}
|
|
196578
|
+
});
|
|
196579
|
+
|
|
195769
196580
|
// ../storage/src/postgres-automations.ts
|
|
195770
196581
|
function storedEventConfig(t) {
|
|
195771
196582
|
return {
|
|
@@ -195809,26 +196620,27 @@ function genWebhookToken2() {
|
|
|
195809
196620
|
const b64 = btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
195810
196621
|
return `owt_${b64}`;
|
|
195811
196622
|
}
|
|
195812
|
-
var
|
|
196623
|
+
var ident11, genId, iso4, PostgresAutomationStore, chatTurnIso, rowToChatTurn, rowToAutomation, normalizeStoredChatTarget, rowToTrigger, rowToRun2, rowToDelivery;
|
|
195813
196624
|
var init_postgres_automations = __esm({
|
|
195814
196625
|
"../storage/src/postgres-automations.ts"() {
|
|
195815
196626
|
"use strict";
|
|
195816
196627
|
init_esm();
|
|
196628
|
+
init_postgres_chat_turns();
|
|
195817
196629
|
init_src2();
|
|
195818
|
-
|
|
196630
|
+
ident11 = (s2) => {
|
|
195819
196631
|
if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
|
|
195820
196632
|
return s2;
|
|
195821
196633
|
};
|
|
195822
196634
|
genId = (prefix) => `${prefix}_${Math.random().toString(36).slice(2, 12)}`;
|
|
195823
|
-
|
|
196635
|
+
iso4 = (v2) => v2 != null ? new Date(v2).toISOString() : null;
|
|
195824
196636
|
PostgresAutomationStore = class _PostgresAutomationStore {
|
|
195825
196637
|
constructor(pool, schema) {
|
|
195826
196638
|
this.pool = pool;
|
|
195827
|
-
this.s = `"${
|
|
196639
|
+
this.s = `"${ident11(schema)}"`;
|
|
195828
196640
|
}
|
|
195829
196641
|
s;
|
|
195830
196642
|
static async open(pool, schema = "public") {
|
|
195831
|
-
const s2 =
|
|
196643
|
+
const s2 = ident11(schema);
|
|
195832
196644
|
await pool.query(`CREATE SCHEMA IF NOT EXISTS "${s2}"`);
|
|
195833
196645
|
await pool.query(`
|
|
195834
196646
|
CREATE TABLE IF NOT EXISTS "${s2}".automations (
|
|
@@ -195853,7 +196665,11 @@ var init_postgres_automations = __esm({
|
|
|
195853
196665
|
`ADD COLUMN IF NOT EXISTS pause_reason text`,
|
|
195854
196666
|
`ADD COLUMN IF NOT EXISTS archived_at text`,
|
|
195855
196667
|
`ADD COLUMN IF NOT EXISTS subscribers jsonb NOT NULL DEFAULT '[]'::jsonb`,
|
|
195856
|
-
`ADD COLUMN IF NOT EXISTS collaborators jsonb NOT NULL DEFAULT '[]'::jsonb
|
|
196668
|
+
`ADD COLUMN IF NOT EXISTS collaborators jsonb NOT NULL DEFAULT '[]'::jsonb`,
|
|
196669
|
+
// ADR 会话投递 D1:chat 模式的目标会话策略。NULL = 每次新开会话(存量零变化)。
|
|
196670
|
+
`ADD COLUMN IF NOT EXISTS chat_target jsonb`,
|
|
196671
|
+
// ADR 会话投递 D3:固定会话的人类归属者(进规则快照,不随触发漂移)。
|
|
196672
|
+
`ADD COLUMN IF NOT EXISTS owner_human_actor_id text`
|
|
195857
196673
|
]) {
|
|
195858
196674
|
await pool.query(`ALTER TABLE "${s2}".automations ${ddl}`);
|
|
195859
196675
|
}
|
|
@@ -195944,6 +196760,7 @@ var init_postgres_automations = __esm({
|
|
|
195944
196760
|
created_at text NOT NULL
|
|
195945
196761
|
)`);
|
|
195946
196762
|
await pool.query(`CREATE INDEX IF NOT EXISTS automation_rule_versions_idx ON "${s2}".automation_rule_versions (automation_id, created_at DESC)`);
|
|
196763
|
+
await ensureChatTurnsTable(pool, schema);
|
|
195947
196764
|
return new _PostgresAutomationStore(pool, schema);
|
|
195948
196765
|
}
|
|
195949
196766
|
now() {
|
|
@@ -195972,13 +196789,15 @@ var init_postgres_automations = __esm({
|
|
|
195972
196789
|
collaborators: [],
|
|
195973
196790
|
createdBy: input.createdBy ?? null,
|
|
195974
196791
|
createdAt: now,
|
|
195975
|
-
updatedAt: now
|
|
196792
|
+
updatedAt: now,
|
|
196793
|
+
chatTarget: input.chatTarget ?? null,
|
|
196794
|
+
ownerHumanActorId: input.ownerHumanActorId ?? null
|
|
195976
196795
|
};
|
|
195977
196796
|
await this.pool.query(
|
|
195978
196797
|
`INSERT INTO ${this.s}.automations
|
|
195979
196798
|
(id, company_id, name, description, execution_mode, agent_id, project_id, playbook_ref, payload, title_template, dispatch,
|
|
195980
|
-
enabled, pause_reason, archived_at, subscribers, collaborators, created_by, created_at, updated_at)
|
|
195981
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9::jsonb,$10,$11,$12,$13,$14,$15::jsonb,$16::jsonb,$17,$18,$19)`,
|
|
196799
|
+
enabled, pause_reason, archived_at, subscribers, collaborators, created_by, created_at, updated_at, chat_target, owner_human_actor_id)
|
|
196800
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9::jsonb,$10,$11,$12,$13,$14,$15::jsonb,$16::jsonb,$17,$18,$19,$20::jsonb,$21)`,
|
|
195982
196801
|
[
|
|
195983
196802
|
a.id,
|
|
195984
196803
|
a.companyId,
|
|
@@ -195998,7 +196817,9 @@ var init_postgres_automations = __esm({
|
|
|
195998
196817
|
JSON.stringify(a.collaborators),
|
|
195999
196818
|
a.createdBy,
|
|
196000
196819
|
a.createdAt,
|
|
196001
|
-
a.updatedAt
|
|
196820
|
+
a.updatedAt,
|
|
196821
|
+
a.chatTarget !== null ? JSON.stringify(a.chatTarget) : null,
|
|
196822
|
+
a.ownerHumanActorId
|
|
196002
196823
|
]
|
|
196003
196824
|
);
|
|
196004
196825
|
if (input.triggers?.length) await this.replaceTriggers(id, input.triggers);
|
|
@@ -196031,7 +196852,9 @@ var init_postgres_automations = __esm({
|
|
|
196031
196852
|
pauseReason: { col: "pause_reason" },
|
|
196032
196853
|
archivedAt: { col: "archived_at" },
|
|
196033
196854
|
subscribers: { col: "subscribers", json: true },
|
|
196034
|
-
collaborators: { col: "collaborators", json: true }
|
|
196855
|
+
collaborators: { col: "collaborators", json: true },
|
|
196856
|
+
chatTarget: { col: "chat_target", json: true },
|
|
196857
|
+
ownerHumanActorId: { col: "owner_human_actor_id" }
|
|
196035
196858
|
};
|
|
196036
196859
|
async updateAutomation(id, patch) {
|
|
196037
196860
|
const sets = [];
|
|
@@ -196419,7 +197242,7 @@ var init_postgres_automations = __esm({
|
|
|
196419
197242
|
);
|
|
196420
197243
|
return r.rows.map((row) => ({
|
|
196421
197244
|
trigger: rowToTrigger(row),
|
|
196422
|
-
plannedAt:
|
|
197245
|
+
plannedAt: iso4(row.planned_at_old)
|
|
196423
197246
|
}));
|
|
196424
197247
|
}
|
|
196425
197248
|
async rescheduleTrigger(triggerId, nextRunAt, lastFiredAt) {
|
|
@@ -196475,7 +197298,83 @@ var init_postgres_automations = __esm({
|
|
|
196475
197298
|
);
|
|
196476
197299
|
return r.rows[0] ? rowToRun2(r.rows[0]) : null;
|
|
196477
197300
|
}
|
|
197301
|
+
/**
|
|
197302
|
+
* 复合占位(ADR 会话投递 D5 第 4 步)。一个事务、三种出口:
|
|
197303
|
+
* - INSERT 成功 → `claimed`,调用方才可以开始产生副作用;
|
|
197304
|
+
* - 撞 `(source, source_run_id)` → `resumed`,同一触发重来,取回同一轮(**不是** busy,也不另落 run);
|
|
197305
|
+
* - 撞每会话 active 唯一索引 → `busy`:**在同一事务里**把这条 automation run 落
|
|
197306
|
+
* `skipped/session_busy/completedAt`,然后提交。两件事一起成立或一起不成立,中间没有窗口。
|
|
197307
|
+
*
|
|
197308
|
+
* 触发幂等键(`planned_at` / `idempotency_key`)**照旧保留在行上不清空**——清了就等于允许
|
|
197309
|
+
* 下一次重扫补跑这次已经明确丢弃的触发。
|
|
197310
|
+
*/
|
|
197311
|
+
async claimChatTurnForRun(input) {
|
|
197312
|
+
const client = await this.pool.connect();
|
|
197313
|
+
try {
|
|
197314
|
+
await client.query("BEGIN");
|
|
197315
|
+
try {
|
|
197316
|
+
const r = await client.query(
|
|
197317
|
+
`INSERT INTO ${this.s}.chat_session_turns
|
|
197318
|
+
(id, chat_session_id, source, source_run_id, message_key, status, reserved_at)
|
|
197319
|
+
VALUES ($1,$2,$3,$4,$5,'reserved',$6)
|
|
197320
|
+
RETURNING *`,
|
|
197321
|
+
[input.turnId, input.chatSessionId, input.source, input.sourceRunId, input.messageKey, input.reservedAt]
|
|
197322
|
+
);
|
|
197323
|
+
await client.query("COMMIT");
|
|
197324
|
+
return { outcome: "claimed", turn: rowToChatTurn(r.rows[0]) };
|
|
197325
|
+
} catch (err) {
|
|
197326
|
+
if (!isUniqueViolation2(err)) throw err;
|
|
197327
|
+
await client.query("ROLLBACK");
|
|
197328
|
+
await client.query("BEGIN");
|
|
197329
|
+
const mine = await client.query(
|
|
197330
|
+
`SELECT * FROM ${this.s}.chat_session_turns WHERE source = $1 AND source_run_id = $2`,
|
|
197331
|
+
[input.source, input.sourceRunId]
|
|
197332
|
+
);
|
|
197333
|
+
if (mine.rows[0]) {
|
|
197334
|
+
await client.query("COMMIT");
|
|
197335
|
+
return { outcome: "resumed", turn: rowToChatTurn(mine.rows[0]) };
|
|
197336
|
+
}
|
|
197337
|
+
const active = await client.query(
|
|
197338
|
+
`SELECT * FROM ${this.s}.chat_session_turns
|
|
197339
|
+
WHERE chat_session_id = $1 AND status IN ('reserved','running') LIMIT 1`,
|
|
197340
|
+
[input.chatSessionId]
|
|
197341
|
+
);
|
|
197342
|
+
if (!active.rows[0]) {
|
|
197343
|
+
await client.query("ROLLBACK");
|
|
197344
|
+
throw err;
|
|
197345
|
+
}
|
|
197346
|
+
await client.query(
|
|
197347
|
+
`UPDATE ${this.s}.automation_runs
|
|
197348
|
+
SET status = 'skipped', reason_code = 'session_busy', error = $2, completed_at = $3
|
|
197349
|
+
WHERE id = $1`,
|
|
197350
|
+
[input.automationRunId, input.busyError, input.now]
|
|
197351
|
+
);
|
|
197352
|
+
await client.query("COMMIT");
|
|
197353
|
+
return { outcome: "busy", activeTurn: rowToChatTurn(active.rows[0]) };
|
|
197354
|
+
}
|
|
197355
|
+
} catch (e) {
|
|
197356
|
+
await client.query("ROLLBACK").catch(() => void 0);
|
|
197357
|
+
throw e;
|
|
197358
|
+
} finally {
|
|
197359
|
+
client.release();
|
|
197360
|
+
}
|
|
197361
|
+
}
|
|
196478
197362
|
};
|
|
197363
|
+
chatTurnIso = (v2) => v2 != null ? new Date(v2).toISOString() : null;
|
|
197364
|
+
rowToChatTurn = (row) => ({
|
|
197365
|
+
id: row.id,
|
|
197366
|
+
chatSessionId: row.chat_session_id,
|
|
197367
|
+
source: row.source,
|
|
197368
|
+
sourceRunId: row.source_run_id,
|
|
197369
|
+
messageKey: row.message_key,
|
|
197370
|
+
status: row.status,
|
|
197371
|
+
dispatchId: row.dispatch_id ?? null,
|
|
197372
|
+
assistantRunId: row.assistant_run_id ?? null,
|
|
197373
|
+
reservedAt: chatTurnIso(row.reserved_at),
|
|
197374
|
+
startedAt: chatTurnIso(row.started_at),
|
|
197375
|
+
completedAt: chatTurnIso(row.completed_at),
|
|
197376
|
+
lastError: row.last_error ?? null
|
|
197377
|
+
});
|
|
196479
197378
|
rowToAutomation = (row) => ({
|
|
196480
197379
|
id: row.id,
|
|
196481
197380
|
companyId: row.company_id ?? "",
|
|
@@ -196495,8 +197394,19 @@ var init_postgres_automations = __esm({
|
|
|
196495
197394
|
collaborators: row.collaborators ?? [],
|
|
196496
197395
|
createdBy: row.created_by ?? null,
|
|
196497
197396
|
createdAt: row.created_at,
|
|
196498
|
-
updatedAt: row.updated_at
|
|
197397
|
+
updatedAt: row.updated_at,
|
|
197398
|
+
// NULL / 脏值一律读成「每次新开会话」——发布前后行为一致(ADR 会话投递 §6)。
|
|
197399
|
+
chatTarget: normalizeStoredChatTarget(row.chat_target),
|
|
197400
|
+
ownerHumanActorId: row.owner_human_actor_id ?? null
|
|
196499
197401
|
});
|
|
197402
|
+
normalizeStoredChatTarget = (raw) => {
|
|
197403
|
+
const t = raw;
|
|
197404
|
+
if (t?.mode === "existing_session" && typeof t.sessionId === "string" && t.sessionId) {
|
|
197405
|
+
return { mode: "existing_session", sessionId: t.sessionId };
|
|
197406
|
+
}
|
|
197407
|
+
if (t?.mode === "new_session") return { mode: "new_session" };
|
|
197408
|
+
return null;
|
|
197409
|
+
};
|
|
196500
197410
|
rowToTrigger = (row) => {
|
|
196501
197411
|
const t = {
|
|
196502
197412
|
id: row.id,
|
|
@@ -196510,9 +197420,9 @@ var init_postgres_automations = __esm({
|
|
|
196510
197420
|
t.schedule = {
|
|
196511
197421
|
cron: row.cron ?? "",
|
|
196512
197422
|
tz: row.tz ?? "UTC",
|
|
196513
|
-
nextRunAt:
|
|
197423
|
+
nextRunAt: iso4(row.next_run_at),
|
|
196514
197424
|
lastFiredAt: row.last_fired_at ?? null,
|
|
196515
|
-
claimedAt:
|
|
197425
|
+
claimedAt: iso4(row.claimed_at)
|
|
196516
197426
|
};
|
|
196517
197427
|
}
|
|
196518
197428
|
if (t.kind === "webhook") {
|
|
@@ -196542,7 +197452,7 @@ var init_postgres_automations = __esm({
|
|
|
196542
197452
|
status: row.status,
|
|
196543
197453
|
spawnedWorkspaceId: row.spawned_workspace_id ?? null,
|
|
196544
197454
|
spawnedArtifactId: row.spawned_artifact_id ?? null,
|
|
196545
|
-
plannedAt:
|
|
197455
|
+
plannedAt: iso4(row.planned_at),
|
|
196546
197456
|
deliveryId: row.delivery_id ?? null,
|
|
196547
197457
|
idempotencyKey: row.idempotency_key ?? null,
|
|
196548
197458
|
ruleVersionId: row.rule_version_id ?? null,
|
|
@@ -196574,24 +197484,24 @@ var init_postgres_automations = __esm({
|
|
|
196574
197484
|
});
|
|
196575
197485
|
|
|
196576
197486
|
// ../storage/src/postgres-chat-sessions.ts
|
|
196577
|
-
var
|
|
197487
|
+
var ident12, PostgresChatSessionStore, rowToSession, rowToSessionWithQuality, rowToMessage;
|
|
196578
197488
|
var init_postgres_chat_sessions = __esm({
|
|
196579
197489
|
"../storage/src/postgres-chat-sessions.ts"() {
|
|
196580
197490
|
"use strict";
|
|
196581
197491
|
init_esm();
|
|
196582
197492
|
init_chat_session();
|
|
196583
|
-
|
|
197493
|
+
ident12 = (s2) => {
|
|
196584
197494
|
if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
|
|
196585
197495
|
return s2;
|
|
196586
197496
|
};
|
|
196587
197497
|
PostgresChatSessionStore = class _PostgresChatSessionStore {
|
|
196588
197498
|
constructor(pool, schema) {
|
|
196589
197499
|
this.pool = pool;
|
|
196590
|
-
this.s = `"${
|
|
197500
|
+
this.s = `"${ident12(schema)}"`;
|
|
196591
197501
|
}
|
|
196592
197502
|
s;
|
|
196593
197503
|
static async open(pool, schema = "public") {
|
|
196594
|
-
const s2 =
|
|
197504
|
+
const s2 = ident12(schema);
|
|
196595
197505
|
await pool.query(`CREATE SCHEMA IF NOT EXISTS "${s2}"`);
|
|
196596
197506
|
await pool.query(`
|
|
196597
197507
|
CREATE TABLE IF NOT EXISTS "${s2}".chat_sessions (
|
|
@@ -196634,6 +197544,10 @@ var init_postgres_chat_sessions = __esm({
|
|
|
196634
197544
|
)
|
|
196635
197545
|
UPDATE "${s2}".chat_messages m SET seq = ranked.rn FROM ranked WHERE m.id = ranked.id AND m.seq <> ranked.rn`);
|
|
196636
197546
|
await pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS chat_messages_session_seq_uq ON "${s2}".chat_messages (session_id, seq)`);
|
|
197547
|
+
await pool.query(`ALTER TABLE "${s2}".chat_sessions ADD COLUMN IF NOT EXISTS company_id text`);
|
|
197548
|
+
await pool.query(`CREATE INDEX IF NOT EXISTS chat_sessions_target_idx ON "${s2}".chat_sessions (company_id, human_actor_id, ai_actor_id, touched_at DESC)`);
|
|
197549
|
+
await pool.query(`ALTER TABLE "${s2}".chat_messages ADD COLUMN IF NOT EXISTS message_key text`);
|
|
197550
|
+
await pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS chat_messages_key_uq ON "${s2}".chat_messages (message_key) WHERE message_key IS NOT NULL`);
|
|
196637
197551
|
await pool.query(`
|
|
196638
197552
|
CREATE TABLE IF NOT EXISTS "${s2}".chat_session_work_orders (
|
|
196639
197553
|
session_id text NOT NULL,
|
|
@@ -196645,9 +197559,9 @@ var init_postgres_chat_sessions = __esm({
|
|
|
196645
197559
|
}
|
|
196646
197560
|
async createSession(s2) {
|
|
196647
197561
|
await this.pool.query(
|
|
196648
|
-
`INSERT INTO ${this.s}.chat_sessions (id, human_actor_id, ai_actor_id, runtime_id, runtime_kind, runtime_session_id, title, touched_at, created_at, workspace, analyzed_run_id, project_id, escalation_id)
|
|
196649
|
-
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13)`,
|
|
196650
|
-
[s2.id, s2.humanActorId, s2.aiActorId, s2.runtimeId, s2.runtimeKind ?? null, s2.runtimeSessionId ?? null, s2.title ?? null, s2.touchedAt, s2.createdAt, s2.workspace ?? null, s2.analyzedRunId ?? null, s2.projectId ?? null, s2.escalationId ?? null]
|
|
197562
|
+
`INSERT INTO ${this.s}.chat_sessions (id, human_actor_id, ai_actor_id, runtime_id, runtime_kind, runtime_session_id, title, touched_at, created_at, workspace, analyzed_run_id, project_id, escalation_id, company_id)
|
|
197563
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14)`,
|
|
197564
|
+
[s2.id, s2.humanActorId, s2.aiActorId, s2.runtimeId, s2.runtimeKind ?? null, s2.runtimeSessionId ?? null, s2.title ?? null, s2.touchedAt, s2.createdAt, s2.workspace ?? null, s2.analyzedRunId ?? null, s2.projectId ?? null, s2.escalationId ?? null, s2.companyId ?? null]
|
|
196651
197565
|
);
|
|
196652
197566
|
}
|
|
196653
197567
|
async listSessions(humanActorId) {
|
|
@@ -196760,11 +197674,11 @@ var init_postgres_chat_sessions = __esm({
|
|
|
196760
197674
|
async appendMessage(m2) {
|
|
196761
197675
|
const insert = async () => {
|
|
196762
197676
|
const r = await this.pool.query(
|
|
196763
|
-
`INSERT INTO ${this.s}.chat_messages (id, session_id, role, content, seq, created_at, run_id, parts, attachments, status, completed_at)
|
|
196764
|
-
SELECT $1,$2,$3,$4, COALESCE(MAX(seq),0)+1, $5,$6,$7,$8,$9,$10
|
|
197677
|
+
`INSERT INTO ${this.s}.chat_messages (id, session_id, role, content, seq, created_at, run_id, parts, attachments, status, completed_at, message_key)
|
|
197678
|
+
SELECT $1,$2,$3,$4, COALESCE(MAX(seq),0)+1, $5,$6,$7,$8,$9,$10,$11
|
|
196765
197679
|
FROM ${this.s}.chat_messages WHERE session_id = $2
|
|
196766
197680
|
RETURNING seq`,
|
|
196767
|
-
[m2.id, m2.sessionId, m2.role, m2.content, m2.createdAt, m2.runId ?? null, m2.parts !== void 0 ? JSON.stringify(m2.parts) : null, m2.attachments !== void 0 ? JSON.stringify(m2.attachments) : null, m2.status ?? null, m2.completedAt ?? null]
|
|
197681
|
+
[m2.id, m2.sessionId, m2.role, m2.content, m2.createdAt, m2.runId ?? null, m2.parts !== void 0 ? JSON.stringify(m2.parts) : null, m2.attachments !== void 0 ? JSON.stringify(m2.attachments) : null, m2.status ?? null, m2.completedAt ?? null, m2.messageKey ?? null]
|
|
196768
197682
|
);
|
|
196769
197683
|
return Number(r.rows[0].seq);
|
|
196770
197684
|
};
|
|
@@ -196772,12 +197686,87 @@ var init_postgres_chat_sessions = __esm({
|
|
|
196772
197686
|
try {
|
|
196773
197687
|
return { ...m2, seq: await insert() };
|
|
196774
197688
|
} catch (err) {
|
|
196775
|
-
const
|
|
196776
|
-
if (
|
|
197689
|
+
const isUniqueViolation3 = err && typeof err === "object" && err.code === "23505";
|
|
197690
|
+
if (isUniqueViolation3 && m2.messageKey && String(err.constraint ?? "").includes("chat_messages_key_uq")) {
|
|
197691
|
+
const existing = await this.getMessageByKey(m2.messageKey);
|
|
197692
|
+
if (existing) return existing;
|
|
197693
|
+
}
|
|
197694
|
+
if (isUniqueViolation3 && attempt < 10) continue;
|
|
196777
197695
|
throw err;
|
|
196778
197696
|
}
|
|
196779
197697
|
}
|
|
196780
197698
|
}
|
|
197699
|
+
/** 按幂等键取回消息(崩溃重放路径)。 */
|
|
197700
|
+
async getMessageByKey(messageKey) {
|
|
197701
|
+
const r = await this.pool.query(`SELECT * FROM ${this.s}.chat_messages WHERE message_key = $1`, [messageKey]);
|
|
197702
|
+
return r.rows[0] ? rowToMessage(r.rows[0]) : null;
|
|
197703
|
+
}
|
|
197704
|
+
async countMessages(sessionId) {
|
|
197705
|
+
const r = await this.pool.query(`SELECT count(*)::int AS n FROM ${this.s}.chat_messages WHERE session_id = $1`, [sessionId]);
|
|
197706
|
+
return Number(r.rows[0]?.n ?? 0);
|
|
197707
|
+
}
|
|
197708
|
+
/**
|
|
197709
|
+
* 选择器搜索(ADR 会话投递 D8):`(company, human, ai)` 三元组精确圈定,标题 ILIKE **或** id 前缀命中。
|
|
197710
|
+
* 分析会话排除在外(它们不进主聊天列表,更不该当自动化的长期目标)。
|
|
197711
|
+
* 多取一条判 `hasMore`,避免再跑一次 count。
|
|
197712
|
+
*/
|
|
197713
|
+
async searchSessionsForTarget(q) {
|
|
197714
|
+
const args = [q.companyId, q.humanActorId, q.aiActorId];
|
|
197715
|
+
let where = `s.company_id = $1 AND s.human_actor_id = $2 AND s.ai_actor_id = $3 AND s.analyzed_run_id IS NULL`;
|
|
197716
|
+
const text = q.text?.trim();
|
|
197717
|
+
if (text) {
|
|
197718
|
+
const literal2 = text.replace(/[%_\\]/g, (c) => `\\${c}`);
|
|
197719
|
+
args.push(`%${literal2}%`);
|
|
197720
|
+
args.push(`${literal2}%`);
|
|
197721
|
+
where += ` AND (s.title ILIKE $${args.length - 1} ESCAPE '\\' OR s.id LIKE $${args.length} ESCAPE '\\')`;
|
|
197722
|
+
}
|
|
197723
|
+
args.push(q.limit + 1, q.offset);
|
|
197724
|
+
const r = await this.pool.query(
|
|
197725
|
+
`SELECT s.*, (SELECT count(*)::int FROM ${this.s}.chat_messages m WHERE m.session_id = s.id) AS message_count
|
|
197726
|
+
FROM ${this.s}.chat_sessions s
|
|
197727
|
+
WHERE ${where}
|
|
197728
|
+
ORDER BY s.touched_at DESC, s.id DESC
|
|
197729
|
+
LIMIT $${args.length - 1} OFFSET $${args.length}`,
|
|
197730
|
+
args
|
|
197731
|
+
);
|
|
197732
|
+
const hasMore = r.rows.length > q.limit;
|
|
197733
|
+
const rows = hasMore ? r.rows.slice(0, q.limit) : r.rows;
|
|
197734
|
+
return {
|
|
197735
|
+
items: rows.map((row) => ({ ...rowToSession(row), messageCount: Number(row.message_count ?? 0) })),
|
|
197736
|
+
hasMore
|
|
197737
|
+
};
|
|
197738
|
+
}
|
|
197739
|
+
/**
|
|
197740
|
+
* 存量会话的公司回填(一次性、幂等、**只填能唯一判定的行**)。
|
|
197741
|
+
*
|
|
197742
|
+
* 判据只认一种:会话归属人在 `company_members` 里**只出现在一家公司**(agent 不是账号、
|
|
197743
|
+
* 不在这张表里,所以实际生效的是归属人这一条)。命中多家或一家都命不中 → 保持 NULL。
|
|
197744
|
+
*
|
|
197745
|
+
* 这不是保守过头——用「现在的成员关系」追认「过去的创建事实」,一个换过公司的人就能把旧会话
|
|
197746
|
+
* 认到新公司名下,而那是跨公司泄漏。判不出来的代价只是「不能被自动化选作固定目标」,
|
|
197747
|
+
* 用户新建一个长期会话即可。
|
|
197748
|
+
*
|
|
197749
|
+
* 返回真正回填的行数(稳态为 0)。表不存在(无控制面)时直接跳过。
|
|
197750
|
+
*/
|
|
197751
|
+
async backfillCompanyIds() {
|
|
197752
|
+
const exists = await this.pool.query(
|
|
197753
|
+
`SELECT to_regclass($1) IS NOT NULL AS ok`,
|
|
197754
|
+
[`${this.s}.company_members`.replace(/"/g, "")]
|
|
197755
|
+
);
|
|
197756
|
+
if (!exists.rows[0]?.ok) return 0;
|
|
197757
|
+
const r = await this.pool.query(`
|
|
197758
|
+
WITH candidate AS (
|
|
197759
|
+
SELECT s.id, min(m.company_id) AS company_id, count(DISTINCT m.company_id) AS n
|
|
197760
|
+
FROM ${this.s}.chat_sessions s
|
|
197761
|
+
JOIN ${this.s}.company_members m ON m.actor_id IN (s.human_actor_id, s.ai_actor_id)
|
|
197762
|
+
WHERE s.company_id IS NULL
|
|
197763
|
+
GROUP BY s.id
|
|
197764
|
+
HAVING count(DISTINCT m.company_id) = 1
|
|
197765
|
+
)
|
|
197766
|
+
UPDATE ${this.s}.chat_sessions s SET company_id = c.company_id
|
|
197767
|
+
FROM candidate c WHERE s.id = c.id AND s.company_id IS NULL`);
|
|
197768
|
+
return r.rowCount ?? 0;
|
|
197769
|
+
}
|
|
196781
197770
|
async updateMessage(id, patch) {
|
|
196782
197771
|
const sets = [];
|
|
196783
197772
|
const args = [];
|
|
@@ -196858,6 +197847,7 @@ var init_postgres_chat_sessions = __esm({
|
|
|
196858
197847
|
};
|
|
196859
197848
|
rowToSession = (row) => ({
|
|
196860
197849
|
id: row.id,
|
|
197850
|
+
companyId: row.company_id ?? null,
|
|
196861
197851
|
humanActorId: row.human_actor_id,
|
|
196862
197852
|
aiActorId: row.ai_actor_id,
|
|
196863
197853
|
runtimeId: row.runtime_id,
|
|
@@ -196889,30 +197879,33 @@ var init_postgres_chat_sessions = __esm({
|
|
|
196889
197879
|
...row.parts != null ? { parts: row.parts } : {},
|
|
196890
197880
|
...row.attachments != null ? { attachments: row.attachments } : {},
|
|
196891
197881
|
...row.status != null ? { status: row.status } : {},
|
|
196892
|
-
...row.completed_at != null ? { completedAt: new Date(row.completed_at).toISOString() } : {}
|
|
197882
|
+
...row.completed_at != null ? { completedAt: new Date(row.completed_at).toISOString() } : {},
|
|
197883
|
+
// 幂等键必须**读得回来**:写进去却映射不出来,等于这一列只对唯一索引有效,对代码不可见。
|
|
197884
|
+
// 固定会话的续跑历史要按它把「本轮那条 user 消息」排掉,漏了它那条消息会既当历史又当正文。
|
|
197885
|
+
...row.message_key != null ? { messageKey: row.message_key } : {}
|
|
196893
197886
|
});
|
|
196894
197887
|
}
|
|
196895
197888
|
});
|
|
196896
197889
|
|
|
196897
197890
|
// ../storage/src/postgres-nodes.ts
|
|
196898
|
-
var
|
|
197891
|
+
var import_node_crypto46, ident13, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToRuntime;
|
|
196899
197892
|
var init_postgres_nodes = __esm({
|
|
196900
197893
|
"../storage/src/postgres-nodes.ts"() {
|
|
196901
197894
|
"use strict";
|
|
196902
|
-
|
|
197895
|
+
import_node_crypto46 = require("node:crypto");
|
|
196903
197896
|
init_esm();
|
|
196904
|
-
|
|
197897
|
+
ident13 = (s2) => {
|
|
196905
197898
|
if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
|
|
196906
197899
|
return s2;
|
|
196907
197900
|
};
|
|
196908
197901
|
PostgresNodeStore = class _PostgresNodeStore {
|
|
196909
197902
|
constructor(pool, schema) {
|
|
196910
197903
|
this.pool = pool;
|
|
196911
|
-
this.s = `"${
|
|
197904
|
+
this.s = `"${ident13(schema)}"`;
|
|
196912
197905
|
}
|
|
196913
197906
|
s;
|
|
196914
197907
|
static async open(pool, schema = "public") {
|
|
196915
|
-
const s2 =
|
|
197908
|
+
const s2 = ident13(schema);
|
|
196916
197909
|
await pool.query(`CREATE SCHEMA IF NOT EXISTS "${s2}"`);
|
|
196917
197910
|
await pool.query(`
|
|
196918
197911
|
CREATE TABLE IF NOT EXISTS "${s2}".nodes (
|
|
@@ -197034,12 +198027,12 @@ var init_postgres_nodes = __esm({
|
|
|
197034
198027
|
PostgresNodeTokenStore = class _PostgresNodeTokenStore {
|
|
197035
198028
|
constructor(pool, schema) {
|
|
197036
198029
|
this.pool = pool;
|
|
197037
|
-
this.s = `"${
|
|
198030
|
+
this.s = `"${ident13(schema)}"`;
|
|
197038
198031
|
}
|
|
197039
198032
|
s;
|
|
197040
198033
|
cache = /* @__PURE__ */ new Map();
|
|
197041
198034
|
static async open(pool, schema = "public") {
|
|
197042
|
-
const s2 =
|
|
198035
|
+
const s2 = ident13(schema);
|
|
197043
198036
|
await pool.query(`CREATE SCHEMA IF NOT EXISTS "${s2}"`);
|
|
197044
198037
|
await pool.query(`CREATE TABLE IF NOT EXISTS "${s2}".node_tokens (token text PRIMARY KEY, node_id text NOT NULL)`);
|
|
197045
198038
|
const store = new _PostgresNodeTokenStore(pool, schema);
|
|
@@ -197048,7 +198041,7 @@ var init_postgres_nodes = __esm({
|
|
|
197048
198041
|
return store;
|
|
197049
198042
|
}
|
|
197050
198043
|
issue(nodeId) {
|
|
197051
|
-
const token = `ont_${(0,
|
|
198044
|
+
const token = `ont_${(0, import_node_crypto46.randomBytes)(24).toString("base64url")}`;
|
|
197052
198045
|
this.cache.set(token, nodeId);
|
|
197053
198046
|
void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token, nodeId]);
|
|
197054
198047
|
return token;
|
|
@@ -197100,23 +198093,23 @@ function rowToPrice(row) {
|
|
|
197100
198093
|
updatedAt: new Date(row["updated_at"]).toISOString()
|
|
197101
198094
|
};
|
|
197102
198095
|
}
|
|
197103
|
-
var
|
|
198096
|
+
var ident14, PostgresModelPriceStore;
|
|
197104
198097
|
var init_postgres_model_prices = __esm({
|
|
197105
198098
|
"../storage/src/postgres-model-prices.ts"() {
|
|
197106
198099
|
"use strict";
|
|
197107
198100
|
init_esm();
|
|
197108
|
-
|
|
198101
|
+
ident14 = (s2) => {
|
|
197109
198102
|
if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
|
|
197110
198103
|
return s2;
|
|
197111
198104
|
};
|
|
197112
198105
|
PostgresModelPriceStore = class _PostgresModelPriceStore {
|
|
197113
198106
|
constructor(pool, schema) {
|
|
197114
198107
|
this.pool = pool;
|
|
197115
|
-
this.s = `"${
|
|
198108
|
+
this.s = `"${ident14(schema)}"`;
|
|
197116
198109
|
}
|
|
197117
198110
|
s;
|
|
197118
198111
|
static async open(pool, schema = "public") {
|
|
197119
|
-
const s2 =
|
|
198112
|
+
const s2 = ident14(schema);
|
|
197120
198113
|
await pool.query(`CREATE SCHEMA IF NOT EXISTS "${s2}"`);
|
|
197121
198114
|
await pool.query(`
|
|
197122
198115
|
CREATE TABLE IF NOT EXISTS "${s2}".model_prices (
|
|
@@ -197213,24 +198206,24 @@ async function backfillTypeRegistryFromFile(store, file) {
|
|
|
197213
198206
|
console.log(`[type-registry-backfill] \u51B3\u7B56 0062 \u56DE\u586B\uFF1A${defs.length} \u4E2A\u4EA7\u7269\u7C7B\u578B\u5DF2\u8FC1\u5165 Postgres`);
|
|
197214
198207
|
return { filled: defs.length };
|
|
197215
198208
|
}
|
|
197216
|
-
var import_node_fs18,
|
|
198209
|
+
var import_node_fs18, ident15, PostgresTypeRegistryStore;
|
|
197217
198210
|
var init_postgres_type_registry = __esm({
|
|
197218
198211
|
"../storage/src/postgres-type-registry.ts"() {
|
|
197219
198212
|
"use strict";
|
|
197220
198213
|
import_node_fs18 = __toESM(require("node:fs"), 1);
|
|
197221
198214
|
init_esm();
|
|
197222
|
-
|
|
198215
|
+
ident15 = (s2) => {
|
|
197223
198216
|
if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
|
|
197224
198217
|
return s2;
|
|
197225
198218
|
};
|
|
197226
198219
|
PostgresTypeRegistryStore = class _PostgresTypeRegistryStore {
|
|
197227
198220
|
constructor(pool, schema) {
|
|
197228
198221
|
this.pool = pool;
|
|
197229
|
-
this.s = `"${
|
|
198222
|
+
this.s = `"${ident15(schema)}"`;
|
|
197230
198223
|
}
|
|
197231
198224
|
s;
|
|
197232
198225
|
static async open(pool, schema = "public") {
|
|
197233
|
-
const s2 =
|
|
198226
|
+
const s2 = ident15(schema);
|
|
197234
198227
|
await pool.query(`CREATE SCHEMA IF NOT EXISTS "${s2}"`);
|
|
197235
198228
|
await pool.query(`
|
|
197236
198229
|
CREATE TABLE IF NOT EXISTS "${s2}".artifact_types (
|
|
@@ -197260,14 +198253,14 @@ var init_postgres_type_registry = __esm({
|
|
|
197260
198253
|
});
|
|
197261
198254
|
|
|
197262
198255
|
// ../storage/src/postgres-actor-memory.ts
|
|
197263
|
-
var
|
|
198256
|
+
var import_node_crypto47, matchClause, ident16, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
|
|
197264
198257
|
var init_postgres_actor_memory = __esm({
|
|
197265
198258
|
"../storage/src/postgres-actor-memory.ts"() {
|
|
197266
198259
|
"use strict";
|
|
197267
|
-
|
|
198260
|
+
import_node_crypto47 = require("node:crypto");
|
|
197268
198261
|
init_src2();
|
|
197269
198262
|
matchClause = (q) => q.requireMatch && q.keywords.length > 0 ? " WHERE m > 0" : "";
|
|
197270
|
-
|
|
198263
|
+
ident16 = (s2) => {
|
|
197271
198264
|
if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
|
|
197272
198265
|
return s2;
|
|
197273
198266
|
};
|
|
@@ -197275,11 +198268,11 @@ var init_postgres_actor_memory = __esm({
|
|
|
197275
198268
|
constructor(pool, schema, trigram) {
|
|
197276
198269
|
this.pool = pool;
|
|
197277
198270
|
this.trigram = trigram;
|
|
197278
|
-
this.s = `"${
|
|
198271
|
+
this.s = `"${ident16(schema)}"`;
|
|
197279
198272
|
}
|
|
197280
198273
|
s;
|
|
197281
198274
|
static async open(pool, schema = "public") {
|
|
197282
|
-
const s2 =
|
|
198275
|
+
const s2 = ident16(schema);
|
|
197283
198276
|
await pool.query(`CREATE SCHEMA IF NOT EXISTS "${s2}"`);
|
|
197284
198277
|
await pool.query(`
|
|
197285
198278
|
CREATE TABLE IF NOT EXISTS "${s2}".actor_memories (
|
|
@@ -197469,7 +198462,7 @@ var init_postgres_actor_memory = __esm({
|
|
|
197469
198462
|
}
|
|
197470
198463
|
async write(input, now) {
|
|
197471
198464
|
if (input.memId === void 0) {
|
|
197472
|
-
const memId = `mem:${(0,
|
|
198465
|
+
const memId = `mem:${(0, import_node_crypto47.randomUUID)()}`;
|
|
197473
198466
|
const r2 = await this.pool.query(
|
|
197474
198467
|
`INSERT INTO ${this.s}.actor_memories
|
|
197475
198468
|
(mem_id, actor_id, project_id, keywords, content, version, created_at, updated_at, accessed_at, source_artifact_id, source_session_id)
|
|
@@ -197563,23 +198556,23 @@ var init_postgres_actor_memory = __esm({
|
|
|
197563
198556
|
});
|
|
197564
198557
|
|
|
197565
198558
|
// ../storage/src/postgres-inbox-read.ts
|
|
197566
|
-
var
|
|
198559
|
+
var ident17, PostgresReadMarkerStore;
|
|
197567
198560
|
var init_postgres_inbox_read = __esm({
|
|
197568
198561
|
"../storage/src/postgres-inbox-read.ts"() {
|
|
197569
198562
|
"use strict";
|
|
197570
198563
|
init_esm();
|
|
197571
|
-
|
|
198564
|
+
ident17 = (s2) => {
|
|
197572
198565
|
if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
|
|
197573
198566
|
return s2;
|
|
197574
198567
|
};
|
|
197575
198568
|
PostgresReadMarkerStore = class _PostgresReadMarkerStore {
|
|
197576
198569
|
constructor(pool, schema) {
|
|
197577
198570
|
this.pool = pool;
|
|
197578
|
-
this.s = `"${
|
|
198571
|
+
this.s = `"${ident17(schema)}"`;
|
|
197579
198572
|
}
|
|
197580
198573
|
s;
|
|
197581
198574
|
static async open(pool, schema = "public") {
|
|
197582
|
-
const s2 =
|
|
198575
|
+
const s2 = ident17(schema);
|
|
197583
198576
|
await pool.query(`CREATE SCHEMA IF NOT EXISTS "${s2}"`);
|
|
197584
198577
|
await pool.query(`
|
|
197585
198578
|
CREATE TABLE IF NOT EXISTS "${s2}".inbox_read_markers (
|
|
@@ -197657,18 +198650,18 @@ function rowToRecord2(r) {
|
|
|
197657
198650
|
reason: r.reason
|
|
197658
198651
|
};
|
|
197659
198652
|
}
|
|
197660
|
-
var
|
|
198653
|
+
var ident18, PostgresDispatchStore;
|
|
197661
198654
|
var init_postgres_dispatches = __esm({
|
|
197662
198655
|
"../storage/src/postgres-dispatches.ts"() {
|
|
197663
198656
|
"use strict";
|
|
197664
|
-
|
|
198657
|
+
ident18 = (schema) => schema.replace(/[^a-zA-Z0-9_]/g, "");
|
|
197665
198658
|
PostgresDispatchStore = class _PostgresDispatchStore {
|
|
197666
198659
|
constructor(pool, s2) {
|
|
197667
198660
|
this.pool = pool;
|
|
197668
198661
|
this.s = s2;
|
|
197669
198662
|
}
|
|
197670
198663
|
static async open(pool, schema = "public") {
|
|
197671
|
-
const s2 =
|
|
198664
|
+
const s2 = ident18(schema);
|
|
197672
198665
|
await pool.query(`CREATE SCHEMA IF NOT EXISTS "${s2}"`);
|
|
197673
198666
|
await pool.query(`
|
|
197674
198667
|
CREATE TABLE IF NOT EXISTS "${s2}".dispatches (
|
|
@@ -197806,6 +198799,7 @@ __export(src_exports, {
|
|
|
197806
198799
|
PostgresBlobStore: () => PostgresBlobStore,
|
|
197807
198800
|
PostgresChannelStore: () => PostgresChannelStore,
|
|
197808
198801
|
PostgresChatSessionStore: () => PostgresChatSessionStore,
|
|
198802
|
+
PostgresChatTurnStore: () => PostgresChatTurnStore,
|
|
197809
198803
|
PostgresControlPlaneStore: () => PostgresControlPlaneStore,
|
|
197810
198804
|
PostgresDispatchStore: () => PostgresDispatchStore,
|
|
197811
198805
|
PostgresHumanPrefsStore: () => PostgresHumanPrefsStore,
|
|
@@ -197822,8 +198816,10 @@ __export(src_exports, {
|
|
|
197822
198816
|
buildTrigger: () => buildTrigger,
|
|
197823
198817
|
createPgPool: () => createPgPool,
|
|
197824
198818
|
dropSchemaIfExists: () => dropSchemaIfExists,
|
|
198819
|
+
ensureChatTurnsTable: () => ensureChatTurnsTable,
|
|
197825
198820
|
genWebhookToken: () => genWebhookToken2,
|
|
197826
198821
|
hasPgUnstorable: () => hasPgUnstorable,
|
|
198822
|
+
isUniqueViolation: () => isUniqueViolation2,
|
|
197827
198823
|
scrubPgJson: () => scrubPgJson,
|
|
197828
198824
|
scrubPgString: () => scrubPgString
|
|
197829
198825
|
});
|
|
@@ -197841,6 +198837,7 @@ var init_src11 = __esm({
|
|
|
197841
198837
|
init_pg_sanitize();
|
|
197842
198838
|
init_postgres_automations();
|
|
197843
198839
|
init_postgres_chat_sessions();
|
|
198840
|
+
init_postgres_chat_turns();
|
|
197844
198841
|
init_postgres_nodes();
|
|
197845
198842
|
init_postgres_model_prices();
|
|
197846
198843
|
init_postgres_type_registry();
|
|
@@ -197982,20 +198979,20 @@ var fs42 = __toESM(require("node:fs"));
|
|
|
197982
198979
|
var os13 = __toESM(require("node:os"));
|
|
197983
198980
|
var path36 = __toESM(require("node:path"));
|
|
197984
198981
|
var import_node_child_process20 = require("node:child_process");
|
|
197985
|
-
var
|
|
198982
|
+
var import_node_crypto54 = require("node:crypto");
|
|
197986
198983
|
|
|
197987
198984
|
// ../cli/src/cli.ts
|
|
197988
198985
|
var fs37 = __toESM(require("node:fs"), 1);
|
|
197989
198986
|
var os11 = __toESM(require("node:os"), 1);
|
|
197990
198987
|
var path31 = __toESM(require("node:path"), 1);
|
|
197991
|
-
var
|
|
198988
|
+
var import_node_crypto52 = require("node:crypto");
|
|
197992
198989
|
|
|
197993
198990
|
// ../cli/src/serve.ts
|
|
197994
198991
|
var fs31 = __toESM(require("node:fs"), 1);
|
|
197995
198992
|
var os7 = __toESM(require("node:os"), 1);
|
|
197996
198993
|
var path25 = __toESM(require("node:path"), 1);
|
|
197997
198994
|
var import_node_child_process15 = require("node:child_process");
|
|
197998
|
-
var
|
|
198995
|
+
var import_node_crypto48 = require("node:crypto");
|
|
197999
198996
|
var import_node_url7 = require("node:url");
|
|
198000
198997
|
init_src5();
|
|
198001
198998
|
init_src10();
|
|
@@ -198259,6 +199256,14 @@ init_src10();
|
|
|
198259
199256
|
init_src9();
|
|
198260
199257
|
init_src2();
|
|
198261
199258
|
init_trajectory();
|
|
199259
|
+
function deterministicUuid(seed) {
|
|
199260
|
+
const h = (0, import_node_crypto48.createHash)("sha256").update(seed).digest();
|
|
199261
|
+
const b2 = Buffer.from(h.subarray(0, 16));
|
|
199262
|
+
b2[6] = b2[6] & 15 | 80;
|
|
199263
|
+
b2[8] = b2[8] & 63 | 128;
|
|
199264
|
+
const hex = b2.toString("hex");
|
|
199265
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
199266
|
+
}
|
|
198262
199267
|
function builtinSkillsDir() {
|
|
198263
199268
|
const override = process.env["OASIS_BUILTIN_SKILLS_DIR"]?.trim();
|
|
198264
199269
|
if (override) return override;
|
|
@@ -198886,11 +199891,19 @@ async function startServe(opts) {
|
|
|
198886
199891
|
let projectStateStore;
|
|
198887
199892
|
let artifactStateStore;
|
|
198888
199893
|
let chatSessionStore;
|
|
199894
|
+
let chatTurnStore;
|
|
198889
199895
|
let readMarkerStore;
|
|
198890
199896
|
if (pgDsn && pgPool) {
|
|
198891
199897
|
projectStateStore = await PostgresProjectStateStore.open(pgPool, pgSchema);
|
|
198892
199898
|
artifactStateStore = await PostgresArtifactStateStore.open(pgPool, pgSchema);
|
|
198893
|
-
|
|
199899
|
+
const pgChatSessions = await PostgresChatSessionStore.open(pgPool, pgSchema);
|
|
199900
|
+
chatSessionStore = pgChatSessions;
|
|
199901
|
+
chatTurnStore = await PostgresChatTurnStore.open(pgPool, pgSchema);
|
|
199902
|
+
const backfilled = await pgChatSessions.backfillCompanyIds().catch((e) => {
|
|
199903
|
+
console.warn(`[serve] \u4F1A\u8BDD\u516C\u53F8\u5F52\u5C5E\u56DE\u586B\u8DF3\u8FC7\uFF1A${String(e)}`);
|
|
199904
|
+
return 0;
|
|
199905
|
+
});
|
|
199906
|
+
if (backfilled > 0) console.log(`[serve] \u4F1A\u8BDD\u516C\u53F8\u5F52\u5C5E\uFF1A\u56DE\u586B ${backfilled} \u6761\uFF08\u552F\u4E00\u53EF\u5224\u5B9A\u7684\u5386\u53F2\u4F1A\u8BDD\uFF09`);
|
|
198894
199907
|
const pgReadMarkers = await PostgresReadMarkerStore.open(pgPool, pgSchema);
|
|
198895
199908
|
readMarkerStore = pgReadMarkers;
|
|
198896
199909
|
const seeded = await pgReadMarkers.seedFromChatSessions();
|
|
@@ -198902,6 +199915,7 @@ async function startServe(opts) {
|
|
|
198902
199915
|
projectStateStore = await FileProjectStateStore.open(path25.join(opts.dir, "artifact-document-projects.json"));
|
|
198903
199916
|
artifactStateStore = await FileArtifactStateStore.open(path25.join(opts.dir, "artifact-document-state.json"));
|
|
198904
199917
|
chatSessionStore = await FileChatSessionStore.open(path25.join(opts.dir, "chat-sessions.json"));
|
|
199918
|
+
chatTurnStore = await FileChatTurnStore.open(path25.join(opts.dir, "chat-session-turns.json"));
|
|
198905
199919
|
readMarkerStore = await FileReadMarkerStore.open(path25.join(opts.dir, "inbox-read-markers.json"));
|
|
198906
199920
|
console.log("[serve] \u4EA4\u4ED8\u7269\u72B6\u6001\u4F53\u7CFB\uFF1A\u672C\u5730 JSON dev store");
|
|
198907
199921
|
console.log("[serve] \u8282\u70B9/\u8FD0\u884C\u65F6\u4F53\u7CFB\uFF1A\u672C\u5730 JSON dev store");
|
|
@@ -199094,6 +200108,19 @@ async function startServe(opts) {
|
|
|
199094
200108
|
}
|
|
199095
200109
|
});
|
|
199096
200110
|
let automationDispatchChat = null;
|
|
200111
|
+
const inspectChatTarget = async (args) => {
|
|
200112
|
+
const session = await chatSessionStore.getSession(args.sessionId).catch(() => null);
|
|
200113
|
+
if (!session) return { ok: false, issue: "session_missing" };
|
|
200114
|
+
const base = { title: session.title ?? null, touchedAt: session.touchedAt };
|
|
200115
|
+
if (!session.companyId) return { ok: false, issue: "company_unknown", ...base };
|
|
200116
|
+
if (session.companyId !== args.companyId) return { ok: false, issue: "cross_company", ...base };
|
|
200117
|
+
if (!args.ownerHumanActorId || session.humanActorId !== args.ownerHumanActorId) {
|
|
200118
|
+
return { ok: false, issue: "owner_mismatch", ...base };
|
|
200119
|
+
}
|
|
200120
|
+
if (!args.agentId || session.aiActorId !== args.agentId) return { ok: false, issue: "agent_mismatch", ...base };
|
|
200121
|
+
const messageCount = chatSessionStore.countMessages ? await chatSessionStore.countMessages(args.sessionId).catch(() => 0) : (await chatSessionStore.listMessages(args.sessionId).catch(() => [])).length;
|
|
200122
|
+
return { ok: true, title: session.title ?? null, touchedAt: session.touchedAt, messageCount };
|
|
200123
|
+
};
|
|
199097
200124
|
const automations = createAutomationsDomain({
|
|
199098
200125
|
store: automationStore,
|
|
199099
200126
|
fire: {
|
|
@@ -199117,48 +200144,131 @@ async function startServe(opts) {
|
|
|
199117
200144
|
workorderState: makeAutomationWorkorderStateResolver(kernel),
|
|
199118
200145
|
// 回复抓取(ADR 0157):工单 done 时把最终交付物正文并进 run.result.reply,运行历史直接展示。
|
|
199119
200146
|
workorderReply: makeAutomationReplyResolver(kernel, blobs),
|
|
199120
|
-
//
|
|
199121
|
-
|
|
199122
|
-
|
|
199123
|
-
|
|
199124
|
-
|
|
199125
|
-
|
|
199126
|
-
|
|
199127
|
-
|
|
199128
|
-
|
|
199129
|
-
|
|
199130
|
-
|
|
199131
|
-
|
|
199132
|
-
|
|
199133
|
-
|
|
199134
|
-
|
|
199135
|
-
|
|
199136
|
-
|
|
199137
|
-
|
|
199138
|
-
|
|
199139
|
-
|
|
199140
|
-
|
|
199141
|
-
|
|
199142
|
-
|
|
199143
|
-
|
|
199144
|
-
|
|
199145
|
-
|
|
199146
|
-
|
|
199147
|
-
|
|
199148
|
-
|
|
199149
|
-
|
|
199150
|
-
|
|
200147
|
+
// 轮次账本(ADR 会话投递 D4):busy 的唯一口径。
|
|
200148
|
+
chatTurns: chatTurnStore,
|
|
200149
|
+
// chat 执行(ADR 0159 + 会话投递 D2):**建会话与派发已经拆开**。
|
|
200150
|
+
// resolveTarget —— 只决定「发到哪个会话」;
|
|
200151
|
+
// dispatchTurn —— 只消费一条已经持久占位的 turn(写消息 + 真 dispatch + 收流)。
|
|
200152
|
+
// 拆开之前这两件事挤在一个 runChat 里,于是「发到已有会话」无处插入、「会话在跑吗」无处判定。
|
|
200153
|
+
chat: {
|
|
200154
|
+
async resolveTarget({ automation, runId, title }) {
|
|
200155
|
+
const target = normalizeChatTarget(automation.chatTarget);
|
|
200156
|
+
const agentId = automation.agentId;
|
|
200157
|
+
if (target.mode === "existing_session") {
|
|
200158
|
+
const check2 = await inspectChatTarget({
|
|
200159
|
+
companyId: automation.companyId,
|
|
200160
|
+
agentId: automation.agentId,
|
|
200161
|
+
ownerHumanActorId: automation.ownerHumanActorId,
|
|
200162
|
+
sessionId: target.sessionId
|
|
200163
|
+
});
|
|
200164
|
+
if (!check2.ok) {
|
|
200165
|
+
return {
|
|
200166
|
+
ok: false,
|
|
200167
|
+
reasonCode: "target_unavailable",
|
|
200168
|
+
error: `\u56FA\u5B9A\u76EE\u6807\u4F1A\u8BDD\u4E0D\u53EF\u7528\uFF08${check2.issue}\uFF09\uFF1A${target.sessionId}`,
|
|
200169
|
+
result: { targetKind: "chat_session", chatSessionId: target.sessionId, targetIssue: check2.issue }
|
|
200170
|
+
};
|
|
200171
|
+
}
|
|
200172
|
+
return { ok: true, chatSessionId: target.sessionId };
|
|
200173
|
+
}
|
|
200174
|
+
const chatSessionId = deterministicUuid(`automation-chat-session:${runId}`);
|
|
200175
|
+
const existing = await chatSessionStore.getSession(chatSessionId);
|
|
200176
|
+
if (existing) return { ok: true, chatSessionId };
|
|
200177
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
200178
|
+
try {
|
|
200179
|
+
await chatSessionStore.createSession({
|
|
200180
|
+
id: chatSessionId,
|
|
200181
|
+
companyId: automation.companyId,
|
|
200182
|
+
humanActorId: automation.ownerHumanActorId ?? agentId,
|
|
200183
|
+
aiActorId: agentId,
|
|
200184
|
+
runtimeId: "",
|
|
200185
|
+
runtimeSessionId: null,
|
|
200186
|
+
title: `\u81EA\u52A8\u5316 \xB7 ${title}`.slice(0, 80),
|
|
200187
|
+
touchedAt: nowIso,
|
|
200188
|
+
createdAt: nowIso
|
|
200189
|
+
});
|
|
200190
|
+
} catch (e) {
|
|
200191
|
+
if (!await chatSessionStore.getSession(chatSessionId)) throw e;
|
|
200192
|
+
}
|
|
200193
|
+
return { ok: true, chatSessionId };
|
|
200194
|
+
},
|
|
200195
|
+
async dispatchTurn({ automation, chatSessionId, turnId, messageKey, prompt }, onDone) {
|
|
200196
|
+
if (!automationDispatchChat) throw new Error("chat \u6D3E\u53D1\u5C1A\u672A\u5C31\u7EEA\uFF08serve \u542F\u52A8\u4E2D\uFF09");
|
|
200197
|
+
const agentId = automation.agentId;
|
|
200198
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
200199
|
+
await chatSessionStore.appendMessage({
|
|
200200
|
+
id: deterministicUuid(`automation-chat-message:${messageKey}`),
|
|
200201
|
+
sessionId: chatSessionId,
|
|
200202
|
+
role: "user",
|
|
200203
|
+
content: prompt,
|
|
200204
|
+
createdAt: nowIso,
|
|
200205
|
+
messageKey
|
|
200206
|
+
});
|
|
200207
|
+
await chatSessionStore.updateSession(chatSessionId, { touchedAt: nowIso }).catch(() => void 0);
|
|
200208
|
+
const targetSession = await chatSessionStore.getSession(chatSessionId).catch(() => null);
|
|
200209
|
+
const agentBinding = await registryStore.getBinding(agentId).catch(() => null);
|
|
200210
|
+
const plan = targetSession ? await planChatContinuation({
|
|
200211
|
+
session: targetSession,
|
|
200212
|
+
userMessage: prompt,
|
|
200213
|
+
listMessages: (sid, limit) => chatSessionStore.listMessages(sid, limit),
|
|
200214
|
+
currentRuntime: agentBinding?.status === "active" ? { nodeId: agentBinding.nodeId, runtimeKind: agentBinding.runtimeKind } : null,
|
|
200215
|
+
excludeMessageKey: messageKey
|
|
200216
|
+
}) : null;
|
|
200217
|
+
const session = await automationDispatchChat({
|
|
200218
|
+
actorId: agentId,
|
|
200219
|
+
message: plan?.runtimeMessage ?? prompt,
|
|
200220
|
+
...plan?.effectiveSessionId ? { sessionId: plan.effectiveSessionId } : {},
|
|
200221
|
+
...plan?.fallbackMessage ? { fallbackMessage: plan.fallbackMessage } : {},
|
|
200222
|
+
chatSessionId,
|
|
200223
|
+
companyId: automation.companyId
|
|
200224
|
+
});
|
|
200225
|
+
if (plan?.currentRuntimeId) {
|
|
200226
|
+
await chatSessionStore.updateSession(chatSessionId, {
|
|
200227
|
+
runtimeId: plan.currentRuntimeId,
|
|
200228
|
+
...plan.currentRuntimeKind ? { runtimeKind: plan.currentRuntimeKind } : {},
|
|
200229
|
+
runtimeSessionId: session.nativeSessionId ?? session.id
|
|
199151
200230
|
}).catch(() => void 0);
|
|
199152
200231
|
}
|
|
199153
|
-
await
|
|
199154
|
-
|
|
199155
|
-
|
|
199156
|
-
|
|
199157
|
-
|
|
200232
|
+
await chatTurnStore.settleTurn(turnId, {
|
|
200233
|
+
status: "running",
|
|
200234
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
200235
|
+
...session.runId ? { assistantRunId: session.runId, dispatchId: session.runId } : {}
|
|
200236
|
+
}).catch((e) => console.warn(`[automations] \u8F6E\u6B21\u8F6C running \u5931\u8D25 ${turnId}: ${String(e)}`));
|
|
200237
|
+
let buf = "";
|
|
200238
|
+
session.onOutput((c) => {
|
|
200239
|
+
buf += c;
|
|
200240
|
+
});
|
|
200241
|
+
void session.done.then(async () => {
|
|
200242
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
200243
|
+
if (buf || session.runId) {
|
|
200244
|
+
await chatSessionStore.appendMessage({
|
|
200245
|
+
id: (0, import_node_crypto48.randomUUID)(),
|
|
200246
|
+
sessionId: chatSessionId,
|
|
200247
|
+
role: "assistant",
|
|
200248
|
+
content: buf,
|
|
200249
|
+
createdAt: finishedAt,
|
|
200250
|
+
...session.runId ? { runId: session.runId } : {}
|
|
200251
|
+
}).catch(() => void 0);
|
|
200252
|
+
}
|
|
200253
|
+
await chatSessionStore.updateSession(chatSessionId, {
|
|
200254
|
+
...plan?.currentRuntimeId ? { runtimeId: plan.currentRuntimeId } : {},
|
|
200255
|
+
...plan?.currentRuntimeKind ? { runtimeKind: plan.currentRuntimeKind } : {},
|
|
200256
|
+
runtimeSessionId: session.nativeSessionId ?? session.id,
|
|
200257
|
+
touchedAt: finishedAt
|
|
200258
|
+
}).catch(() => void 0);
|
|
200259
|
+
await chatTurnStore.settleTurn(turnId, { status: "succeeded", completedAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
|
|
200260
|
+
await onDone({ ok: true, reply: buf });
|
|
200261
|
+
}).catch(async (err) => {
|
|
200262
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
200263
|
+
await chatTurnStore.settleTurn(turnId, { status: "failed", completedAt: (/* @__PURE__ */ new Date()).toISOString(), lastError: msg }).catch(() => void 0);
|
|
200264
|
+
await onDone({ ok: false, error: msg });
|
|
200265
|
+
});
|
|
200266
|
+
}
|
|
199158
200267
|
},
|
|
199159
|
-
// 订阅触发 × chat 的 fail-closed 开关(ADR 0163 §4.4
|
|
199160
|
-
//
|
|
199161
|
-
//
|
|
200268
|
+
// 订阅触发 × chat 的 fail-closed 开关(ADR 0163 §4.4 / 会话投递 §4)。
|
|
200269
|
+
// 本次交付补齐了持久 messageKey、turn 占位与确定性 run→session 映射,但 §4.2 的 8 条
|
|
200270
|
+
// 开闸条件里还有几条没有证据(真库并发、多进程崩溃点、dispatch 侧稳定幂等查询、指标告警),
|
|
200271
|
+
// **本 ADR 明确不授权改这里**。放开是一次独立变更,须先补齐那些证据。
|
|
199162
200272
|
chatSupportsIdempotency: false,
|
|
199163
200273
|
// chat 准入(≈ multica AgentReadiness):在岗 + 有 active runtime 绑定,注定失败的触发别去开会话。
|
|
199164
200274
|
agentReady: async (agentId) => {
|
|
@@ -199173,6 +200283,51 @@ async function startServe(opts) {
|
|
|
199173
200283
|
return { ok: true };
|
|
199174
200284
|
}
|
|
199175
200285
|
},
|
|
200286
|
+
// 固定目标会话接缝(ADR 会话投递 D3/D8):可用性判据、选择器搜索、长期会话创建三件事
|
|
200287
|
+
// 一律在服务端,前端只消费结论。
|
|
200288
|
+
chatTargets: {
|
|
200289
|
+
inspect: inspectChatTarget,
|
|
200290
|
+
createTargetSession: async ({ companyId, agentId, ownerHumanActorId, title }) => {
|
|
200291
|
+
const sessionId = (0, import_node_crypto48.randomUUID)();
|
|
200292
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
200293
|
+
const binding = await registryStore.getBinding(agentId).catch(() => null);
|
|
200294
|
+
await chatSessionStore.createSession({
|
|
200295
|
+
id: sessionId,
|
|
200296
|
+
companyId,
|
|
200297
|
+
humanActorId: ownerHumanActorId,
|
|
200298
|
+
aiActorId: agentId,
|
|
200299
|
+
runtimeId: binding?.nodeId ?? "",
|
|
200300
|
+
runtimeSessionId: null,
|
|
200301
|
+
title,
|
|
200302
|
+
touchedAt: nowIso,
|
|
200303
|
+
createdAt: nowIso
|
|
200304
|
+
});
|
|
200305
|
+
return { sessionId };
|
|
200306
|
+
},
|
|
200307
|
+
search: async ({ companyId, agentId, ownerHumanActorId, text, limit, offset }) => {
|
|
200308
|
+
if (!chatSessionStore.searchSessionsForTarget) return { items: [], hasMore: false };
|
|
200309
|
+
const page = await chatSessionStore.searchSessionsForTarget({
|
|
200310
|
+
companyId,
|
|
200311
|
+
humanActorId: ownerHumanActorId,
|
|
200312
|
+
aiActorId: agentId,
|
|
200313
|
+
...text ? { text } : {},
|
|
200314
|
+
limit,
|
|
200315
|
+
offset
|
|
200316
|
+
});
|
|
200317
|
+
return {
|
|
200318
|
+
items: page.items.map((x2) => ({ id: x2.id, title: x2.title ?? null, touchedAt: x2.touchedAt, messageCount: x2.messageCount })),
|
|
200319
|
+
hasMore: page.hasMore
|
|
200320
|
+
};
|
|
200321
|
+
},
|
|
200322
|
+
deleteSession: async (sessionId) => {
|
|
200323
|
+
await chatSessionStore.deleteSession(sessionId);
|
|
200324
|
+
},
|
|
200325
|
+
resolveOwnerHuman: async (actor) => {
|
|
200326
|
+
if (actor.startsWith("actor:human:")) return actor;
|
|
200327
|
+
const bound = await assistantBindStore.getByAgent(actor).catch(() => null);
|
|
200328
|
+
return bound?.humanActorId ?? null;
|
|
200329
|
+
}
|
|
200330
|
+
},
|
|
199176
200331
|
isAdmin: async (companyId, actor) => {
|
|
199177
200332
|
const member = await controlPlaneStore.getMember(companyId, actor);
|
|
199178
200333
|
return member?.role === "owner" || member?.role === "admin";
|
|
@@ -199607,7 +200762,7 @@ async function startServe(opts) {
|
|
|
199607
200762
|
}));
|
|
199608
200763
|
}
|
|
199609
200764
|
const limits = { wallClockMs: wallClockForKind("planner") };
|
|
199610
|
-
const artifactId = `artifact:planner:${(0,
|
|
200765
|
+
const artifactId = `artifact:planner:${(0, import_node_crypto48.randomUUID)()}`;
|
|
199611
200766
|
const handle = await chatRemoteAdapter.spawn({
|
|
199612
200767
|
actor: planner.id,
|
|
199613
200768
|
// companyId 同协调者:planner 用的就是默认公司的 actors 服务,漏签会让它一调公司域端点就 404。
|
|
@@ -199701,6 +200856,9 @@ async function startServe(opts) {
|
|
|
199701
200856
|
store: chatSessionStore,
|
|
199702
200857
|
registry: registryStore,
|
|
199703
200858
|
trace: traceStore,
|
|
200859
|
+
// 会话槽的观测与运维出口(ADR 会话投递 D4):看这条会话占着哪一轮、把卡死的那一轮置终态。
|
|
200860
|
+
chatTurns: chatTurnStore,
|
|
200861
|
+
getRun: (id) => traceStore.getRun(id),
|
|
199704
200862
|
kernel,
|
|
199705
200863
|
artifactState: artifactStateStore,
|
|
199706
200864
|
workdir: () => workdirBridge ?? void 0,
|
|
@@ -199711,6 +200869,8 @@ async function startServe(opts) {
|
|
|
199711
200869
|
assistants: assistantsService,
|
|
199712
200870
|
liveChat,
|
|
199713
200871
|
...chatSessionStore ? { chatSession: chatSessionStore } : {},
|
|
200872
|
+
// ADR 会话投递 D4:/api/chat 与渠道入站据它占同一个会话槽(自动化侧经 automations 域接同一实例)。
|
|
200873
|
+
chatTurns: chatTurnStore,
|
|
199714
200874
|
knowledge: {
|
|
199715
200875
|
configStore: knowledgeConfigStore,
|
|
199716
200876
|
runStore: knowledgeRunStore,
|
|
@@ -200024,10 +201184,10 @@ async function startServe(opts) {
|
|
|
200024
201184
|
{ nodeId: priorChatSession?.runtimeId, runtimeKind: priorChatSession?.runtimeKind },
|
|
200025
201185
|
{ nodeId: binding.nodeId, runtimeKind: binding.runtimeKind }
|
|
200026
201186
|
) : false;
|
|
200027
|
-
const runtimeSessionId = sessionId ?? (0,
|
|
201187
|
+
const runtimeSessionId = sessionId ?? (0, import_node_crypto48.randomUUID)();
|
|
200028
201188
|
const resumeRuntimeSession = Boolean(sessionId);
|
|
200029
|
-
const traceRunId = `chat-run:${(0,
|
|
200030
|
-
const artifactId = `artifact:chat:${(0,
|
|
201189
|
+
const traceRunId = `chat-run:${(0, import_node_crypto48.randomUUID)()}`;
|
|
201190
|
+
const artifactId = `artifact:chat:${(0, import_node_crypto48.randomUUID)()}`;
|
|
200031
201191
|
const traceStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
200032
201192
|
let lastProgressTouchMs = 0;
|
|
200033
201193
|
const PROGRESS_TOUCH_THROTTLE_MS2 = 2e4;
|
|
@@ -200575,6 +201735,20 @@ async function startServe(opts) {
|
|
|
200575
201735
|
chatSweepTimer.unref?.();
|
|
200576
201736
|
}
|
|
200577
201737
|
}
|
|
201738
|
+
const chatTurnOrphanGraceMs = Number(process.env.OASIS_CHAT_TURN_ORPHAN_GRACE_MS ?? 10 * 6e4);
|
|
201739
|
+
const chatTurnSweepTimer = setInterval(() => {
|
|
201740
|
+
void sweepStaleChatTurns({
|
|
201741
|
+
turns: chatTurnStore,
|
|
201742
|
+
getRun: (id) => traceStore.getRun(id),
|
|
201743
|
+
// 本进程在飞的轮不动——它自己的收尾路径会写终态(liveChat 只认人工/渠道那条,自动化轮
|
|
201744
|
+
// 在 dispatch 后立刻有 assistantRunId、其 run 处于 running,走上面的权威判据同样保住)。
|
|
201745
|
+
isOwned: (turn) => Boolean(turn.assistantRunId && liveChat.runFor(turn.chatSessionId) === turn.assistantRunId),
|
|
201746
|
+
now: Date.now(),
|
|
201747
|
+
noRunGraceMs: chatTurnOrphanGraceMs,
|
|
201748
|
+
log: (m2) => console.log(m2)
|
|
201749
|
+
}).catch((err) => console.error(`[chat-turn-sweep] tick \u5931\u8D25: ${String(err)}`));
|
|
201750
|
+
}, 3e4);
|
|
201751
|
+
chatTurnSweepTimer.unref?.();
|
|
200578
201752
|
const hubAdapterOpts = {
|
|
200579
201753
|
log: (m2) => console.warn(m2),
|
|
200580
201754
|
health: nodeHealth,
|
|
@@ -200586,7 +201760,16 @@ async function startServe(opts) {
|
|
|
200586
201760
|
}
|
|
200587
201761
|
};
|
|
200588
201762
|
chatRemoteAdapter = new DaemonHubAdapter(hub, { ...hubAdapterOpts, stashUnknownFrames: true });
|
|
200589
|
-
dispatchRemoteAdapter = new DaemonHubAdapter(hub, {
|
|
201763
|
+
dispatchRemoteAdapter = new DaemonHubAdapter(hub, {
|
|
201764
|
+
...hubAdapterOpts,
|
|
201765
|
+
stashUnknownFrames: true,
|
|
201766
|
+
// 服务端自判死(存在性快照 / 会话失联收割 / socket 非 OPEN)没有退出帧,走不到下面那个
|
|
201767
|
+
// message listener 里的 work.response 桥 → work 空转到 30 分钟超时。这里补上同一半逻辑。
|
|
201768
|
+
// 只挂 dispatch 路:chat 路的派发不对应 work,它自有 chat-recovery 收尾。
|
|
201769
|
+
onSettleWithoutFrame: (dispatchId, info) => {
|
|
201770
|
+
void bridgeServerSideExitToEngine(dispatchId, info);
|
|
201771
|
+
}
|
|
201772
|
+
});
|
|
200590
201773
|
let newEngineProduce = null;
|
|
200591
201774
|
let newEngineReplyWork = null;
|
|
200592
201775
|
let newEngineReview = null;
|
|
@@ -200622,6 +201805,51 @@ async function startServe(opts) {
|
|
|
200622
201805
|
const reviewToSession = /* @__PURE__ */ new Map();
|
|
200623
201806
|
const dispatchToReview = /* @__PURE__ */ new Map();
|
|
200624
201807
|
let busRef = null;
|
|
201808
|
+
async function bridgeServerSideExitToEngine(dispatchId, info) {
|
|
201809
|
+
const bus = busRef;
|
|
201810
|
+
if (!bus) return;
|
|
201811
|
+
const outcome = info.code === 0 ? "completed" : "failed";
|
|
201812
|
+
const detail = {
|
|
201813
|
+
reason: `server-side settle: ${info.reason ?? "unknown"}`,
|
|
201814
|
+
...info.errorMessage ? { errorMessage: info.errorMessage } : {}
|
|
201815
|
+
};
|
|
201816
|
+
try {
|
|
201817
|
+
const mapping = dispatchToWork.get(dispatchId);
|
|
201818
|
+
if (mapping) {
|
|
201819
|
+
dispatchToWork.delete(dispatchId);
|
|
201820
|
+
workToSession.delete(mapping.workId);
|
|
201821
|
+
console.log(`[new-engine] \u670D\u52A1\u7AEF\u81EA\u5224\u6B7B\uFF08\u65E0\u9000\u51FA\u5E27\uFF09\uFF1A${dispatchId} \u2192 work.response(${outcome}) ${mapping.workId}`);
|
|
201822
|
+
await bus.submit({
|
|
201823
|
+
companyId: "",
|
|
201824
|
+
workorderId: mapping.workorderId,
|
|
201825
|
+
actorId: SYSTEM_ACTOR,
|
|
201826
|
+
event: {
|
|
201827
|
+
kind: "work.response",
|
|
201828
|
+
workorderId: mapping.workorderId,
|
|
201829
|
+
workId: mapping.workId,
|
|
201830
|
+
outcome,
|
|
201831
|
+
detail
|
|
201832
|
+
}
|
|
201833
|
+
});
|
|
201834
|
+
} else {
|
|
201835
|
+
await fallbackDispatchExitToWork({ dispatchId, info }, bus);
|
|
201836
|
+
}
|
|
201837
|
+
const revMapping = dispatchToReview.get(dispatchId);
|
|
201838
|
+
if (revMapping) {
|
|
201839
|
+
dispatchToReview.delete(dispatchId);
|
|
201840
|
+
reviewToSession.delete(revMapping.reviewId);
|
|
201841
|
+
console.log(`[new-engine] \u670D\u52A1\u7AEF\u81EA\u5224\u6B7B\uFF08\u65E0\u9000\u51FA\u5E27\uFF09\uFF1A${dispatchId} \u2192 review.timeout ${revMapping.reviewId}`);
|
|
201842
|
+
await bus.submit({
|
|
201843
|
+
companyId: "",
|
|
201844
|
+
workorderId: revMapping.workorderId,
|
|
201845
|
+
actorId: SYSTEM_ACTOR,
|
|
201846
|
+
event: { kind: "review.timeout", workorderId: revMapping.workorderId, reviewId: revMapping.reviewId }
|
|
201847
|
+
});
|
|
201848
|
+
}
|
|
201849
|
+
} catch (err) {
|
|
201850
|
+
console.error(`[new-engine] \u670D\u52A1\u7AEF\u81EA\u5224\u6B7B\u6536\u53E3\u5931\u8D25 ${dispatchId}:`, err);
|
|
201851
|
+
}
|
|
201852
|
+
}
|
|
200625
201853
|
async function fallbackDispatchExitToWork(msg, bus) {
|
|
200626
201854
|
try {
|
|
200627
201855
|
const entry = journalRing.find(
|
|
@@ -200695,7 +201923,7 @@ async function startServe(opts) {
|
|
|
200695
201923
|
console.log(`[new-engine] dispatchWork ${workId} \u662F human work\u2014\u2014\u4E0D\u6D3E runtime\uFF0C\u7B49\u5F85\u4EBA\u5DE5\u5904\u7406`);
|
|
200696
201924
|
return;
|
|
200697
201925
|
}
|
|
200698
|
-
const ledgerId = `dispatch:${(0,
|
|
201926
|
+
const ledgerId = `dispatch:${(0, import_node_crypto48.randomUUID)()}`;
|
|
200699
201927
|
try {
|
|
200700
201928
|
await dispatchLedger.insertOpen({
|
|
200701
201929
|
id: ledgerId,
|
|
@@ -200771,7 +201999,7 @@ async function startServe(opts) {
|
|
|
200771
201999
|
const kernelModel = newKernel.model;
|
|
200772
202000
|
const art = kernelModel.artifacts.get(nodeId);
|
|
200773
202001
|
const revWid = art?.workspace ?? "";
|
|
200774
|
-
const ledgerId = `dispatch:${(0,
|
|
202002
|
+
const ledgerId = `dispatch:${(0, import_node_crypto48.randomUUID)()}`;
|
|
200775
202003
|
try {
|
|
200776
202004
|
await dispatchLedger.insertOpen({
|
|
200777
202005
|
id: ledgerId,
|
|
@@ -201281,8 +202509,8 @@ async function startServe(opts) {
|
|
|
201281
202509
|
const agentMs = opts.sla?.agentMs ?? 10 * 6e4;
|
|
201282
202510
|
const quotaStarvationMs = opts.sla?.quotaStarvationMs ?? 6 * 36e5;
|
|
201283
202511
|
const reviewStallMs = opts.sla?.reviewStallMs ?? 60 * 6e4;
|
|
201284
|
-
const fmtSince = (
|
|
201285
|
-
const min2 = Math.floor(Math.max(0, now - Date.parse(
|
|
202512
|
+
const fmtSince = (iso5, now) => {
|
|
202513
|
+
const min2 = Math.floor(Math.max(0, now - Date.parse(iso5)) / 6e4);
|
|
201286
202514
|
if (!Number.isFinite(min2)) return "\u521A\u624D";
|
|
201287
202515
|
if (min2 < 1) return "\u4E0D\u5230 1 \u5206\u949F\u524D";
|
|
201288
202516
|
if (min2 < 60) return `${min2} \u5206\u949F\u524D`;
|
|
@@ -202404,7 +203632,7 @@ var SessionProcessState = class {
|
|
|
202404
203632
|
// ../cli/src/daemon/ws-client.ts
|
|
202405
203633
|
init_wrapper();
|
|
202406
203634
|
var import_node_os9 = require("node:os");
|
|
202407
|
-
var
|
|
203635
|
+
var import_node_crypto49 = require("node:crypto");
|
|
202408
203636
|
init_src8();
|
|
202409
203637
|
init_src7();
|
|
202410
203638
|
|
|
@@ -202739,8 +203967,21 @@ var DaemonWsClient = class {
|
|
|
202739
203967
|
ws = null;
|
|
202740
203968
|
pingTimer = null;
|
|
202741
203969
|
stopped = false;
|
|
202742
|
-
/** 收到 update
|
|
203970
|
+
/** 收到 update 但本进程内还有活跃会话时置真:延后到全部结束再自更新,避免打断执行中的 agent。 */
|
|
202743
203971
|
pendingUpdate = false;
|
|
203972
|
+
/** 第一次延后这次更新的时刻。用于给「等空闲」封顶——否则长跑会话能把更新无限期挂住(ADR 0115 缺陷 3)。 */
|
|
203973
|
+
pendingUpdateSince = null;
|
|
203974
|
+
/** 「等空闲」的上限;到点就照做(会打断本进程内的会话)。env OASIS_UPDATE_DEFER_MAX_MS 可调。 */
|
|
203975
|
+
updateDeferMaxMs = (() => {
|
|
203976
|
+
const raw = Number(process.env["OASIS_UPDATE_DEFER_MAX_MS"]);
|
|
203977
|
+
return Number.isFinite(raw) && raw >= 0 ? raw : 30 * 6e4;
|
|
203978
|
+
})();
|
|
203979
|
+
/** 记下首次延后时刻并回答「还在上限内吗」。 */
|
|
203980
|
+
deferUpdateWithinLimit() {
|
|
203981
|
+
this.pendingUpdate = true;
|
|
203982
|
+
this.pendingUpdateSince ??= Date.now();
|
|
203983
|
+
return Date.now() - this.pendingUpdateSince < this.updateDeferMaxMs;
|
|
203984
|
+
}
|
|
202744
203985
|
/** 停机排空中(见 {@link drain}):不再接新派发、不再触发延后的自更新。 */
|
|
202745
203986
|
draining = false;
|
|
202746
203987
|
/** 已回 dispatch_received、尚未完成 runtime spawn 的派发;也随 hello 上报供重连对账。 */
|
|
@@ -203057,9 +204298,13 @@ var DaemonWsClient = class {
|
|
|
203057
204298
|
break;
|
|
203058
204299
|
}
|
|
203059
204300
|
const active = this.sessions.activeCount();
|
|
203060
|
-
if (active > 0) {
|
|
203061
|
-
this.
|
|
203062
|
-
|
|
204301
|
+
if (active > 0 && this.deferUpdateWithinLimit()) {
|
|
204302
|
+
log2("[node-cli]", `\u2190 update\uFF1A\u5F53\u524D\u6709 ${active} \u4E2A\u6267\u884C\u4E2D\u4F1A\u8BDD\uFF08\u672C\u8FDB\u7A0B\u5185\uFF09\uFF0C\u5EF6\u540E\u5230\u5168\u90E8\u7ED3\u675F\u6216 ${Math.round(this.updateDeferMaxMs / 6e4)} \u5206\u949F\u4E0A\u9650`);
|
|
204303
|
+
} else if (active > 0) {
|
|
204304
|
+
log2("[node-cli]", `\u2190 update\uFF1A\u5DF2\u5EF6\u540E ${Math.round((Date.now() - (this.pendingUpdateSince ?? Date.now())) / 6e4)} \u5206\u949F\u4ECD\u672A\u7A7A\u95F2\uFF0C\u8D85\u8FC7\u4E0A\u9650\uFF0C\u73B0\u5728\u5C31\u66F4\u65B0\uFF08\u4F1A\u6253\u65AD ${active} \u4E2A\u672C\u8FDB\u7A0B\u5185\u4F1A\u8BDD\uFF09`);
|
|
204305
|
+
this.pendingUpdate = false;
|
|
204306
|
+
this.pendingUpdateSince = null;
|
|
204307
|
+
this.onUpdate();
|
|
203063
204308
|
} else {
|
|
203064
204309
|
log2("[node-cli]", "\u2190 update\uFF1A\u7A7A\u95F2,\u7ACB\u5373\u62C9\u53D6\u6700\u65B0\u7248\u672C\u5E76\u91CD\u542F");
|
|
203065
204310
|
this.onUpdate();
|
|
@@ -203076,7 +204321,7 @@ var DaemonWsClient = class {
|
|
|
203076
204321
|
*/
|
|
203077
204322
|
async queryArtifactStates(artifactIds, timeoutMs = 15e3) {
|
|
203078
204323
|
if (artifactIds.length === 0) return {};
|
|
203079
|
-
const requestId = (0,
|
|
204324
|
+
const requestId = (0, import_node_crypto49.randomUUID)();
|
|
203080
204325
|
return new Promise((resolve10, reject) => {
|
|
203081
204326
|
const timer = setTimeout(() => {
|
|
203082
204327
|
this.gcPending.delete(requestId);
|
|
@@ -203143,9 +204388,11 @@ var DaemonWsClient = class {
|
|
|
203143
204388
|
}
|
|
203144
204389
|
/** 会话结束后调用:若之前收到过 update 但因忙延后了,且现已空闲,则触发自更新。 */
|
|
203145
204390
|
maybeRunPendingUpdate() {
|
|
204391
|
+
if (!this.pendingUpdate) return;
|
|
203146
204392
|
if (this.draining) return;
|
|
203147
204393
|
if (this.pendingUpdate && this.sessions.activeCount() === 0) {
|
|
203148
204394
|
this.pendingUpdate = false;
|
|
204395
|
+
this.pendingUpdateSince = null;
|
|
203149
204396
|
log2("[node-cli]", "\u6240\u6709\u4F1A\u8BDD\u5DF2\u7ED3\u675F,\u6267\u884C\u5EF6\u540E\u7684\u66F4\u65B0\uFF1A\u62C9\u53D6\u6700\u65B0\u7248\u672C\u5E76\u91CD\u542F");
|
|
203150
204397
|
this.onUpdate?.();
|
|
203151
204398
|
}
|
|
@@ -203420,7 +204667,7 @@ function forwardSignal(child, sig, killGroup = (pgid, signal) => {
|
|
|
203420
204667
|
// ../cli/src/daemon/machine-id.ts
|
|
203421
204668
|
var import_node_child_process18 = require("node:child_process");
|
|
203422
204669
|
var import_node_fs21 = require("node:fs");
|
|
203423
|
-
var
|
|
204670
|
+
var import_node_crypto50 = require("node:crypto");
|
|
203424
204671
|
var import_node_os12 = require("node:os");
|
|
203425
204672
|
function linuxMachineId() {
|
|
203426
204673
|
for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
@@ -203486,7 +204733,7 @@ var defaultSources = {
|
|
|
203486
204733
|
function resolveNodeId(sources = {}) {
|
|
203487
204734
|
const s2 = { ...defaultSources, ...sources };
|
|
203488
204735
|
const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
|
|
203489
|
-
const digest = (0,
|
|
204736
|
+
const digest = (0, import_node_crypto50.createHash)("sha256").update(material).digest("hex").slice(0, 12);
|
|
203490
204737
|
return `node-${digest}`;
|
|
203491
204738
|
}
|
|
203492
204739
|
|
|
@@ -203750,18 +204997,19 @@ var COMMAND_DECLS = {
|
|
|
203750
204997
|
"automation-get": {
|
|
203751
204998
|
group: "\u81EA\u52A8\u5316",
|
|
203752
204999
|
usage: "oasis automation-get <id>",
|
|
203753
|
-
description: "\u81EA\u52A8\u5316\u8BE6\u60C5\uFF1A\u89C4\u5219 + \u89E6\u53D1\u5668 + \u6700\u8FD1\u8FD0\u884C\u6295\u5F71\u3002",
|
|
205000
|
+
description: "\u81EA\u52A8\u5316\u8BE6\u60C5\uFF1A\u89C4\u5219 + \u89E6\u53D1\u5668 + \u6700\u8FD1\u8FD0\u884C\u6295\u5F71\u3002\u5BF9\u8BDD\u6267\u884C\u4F1A\u5E26 automation.chatTarget\uFF08\u76EE\u6807\u4F1A\u8BDD\u7B56\u7565\uFF09\u4E0E chatTargetView\uFF08\u56FA\u5B9A\u4F1A\u8BDD\u662F\u5426\u4ECD\u53EF\u6295\u9012\u3001\u6D88\u606F\u91CF\u3001\u6700\u8FD1\u6D3B\u52A8\uFF09\u3002",
|
|
203754
205001
|
positional: [{ name: "<id>", required: true, desc: "\u81EA\u52A8\u5316 id" }],
|
|
203755
205002
|
examples: ["oasis automation-get auto_abc123"]
|
|
203756
205003
|
},
|
|
203757
205004
|
"automation-create": {
|
|
203758
205005
|
group: "\u81EA\u52A8\u5316",
|
|
203759
|
-
usage: "oasis automation-create --name <\u540D> [--mode chat|workorder] [--agent <actorId>] [--playbook <ref>] [--payload '<JSON>'] [--cron '0 9 * * 1' --tz Asia/Shanghai] [--webhook generic|github] [--project <id>] [--title-template '\u6668\u62A5 {{date}}'] [--dispatch true] [--subscribers a,b]",
|
|
205006
|
+
usage: "oasis automation-create --name <\u540D> [--mode chat|workorder] [--agent <actorId>] [--chat-target new|session:<\u4F1A\u8BDDid>|create] [--playbook <ref>] [--payload '<JSON>'] [--cron '0 9 * * 1' --tz Asia/Shanghai] [--webhook generic|github] [--project <id>] [--title-template '\u6668\u62A5 {{date}}'] [--dispatch true] [--subscribers a,b]",
|
|
203760
205007
|
description: "\u65B0\u5EFA\u81EA\u52A8\u5316\u3002chat \u6A21\u5F0F\uFF08\u9ED8\u8BA4\u7ED9\u4E86 --agent \u5373\u662F\uFF09\uFF1A\u5F00\u4F1A\u8BDD\u628A\u4EFB\u52A1\u53D1\u7ED9\u6267\u884C\u4EBA\u3001\u56DE\u590D\u8FDB\u8FD0\u884C\u5386\u53F2\uFF1Bworkorder \u6A21\u5F0F\uFF1A\u6309\u5267\u672C\u5EFA\u5DE5\u5355\uFF08\u9ED8\u8BA4 dispatch-hold \u5F85\u4EBA\u653E\u884C\uFF09\u3002",
|
|
203761
205008
|
flags: [
|
|
203762
205009
|
{ name: "name", desc: "\u663E\u793A\u540D", required: true },
|
|
203763
205010
|
{ name: "mode", desc: "chat|workorder\uFF08\u7F3A\u7701\uFF1A\u7ED9\u4E86 --agent \u4E3A chat\uFF0C\u5426\u5219 workorder\uFF09" },
|
|
203764
205011
|
{ name: "agent", desc: "\u6267\u884C\u4EBA agent actor id\uFF08chat \u6A21\u5F0F\u5FC5\u586B\uFF09" },
|
|
205012
|
+
{ name: "chat-target", desc: "\u5BF9\u8BDD\u6267\u884C\u7684\u76EE\u6807\u4F1A\u8BDD\uFF1Anew=\u6BCF\u6B21\u65B0\u5F00\uFF08\u7F3A\u7701\uFF09\uFF5Csession:<\u4F1A\u8BDDid>=\u56FA\u5B9A\u53D1\u5230\u8BE5\u4F1A\u8BDD\uFF5Ccreate=\u73B0\u5EFA\u4E00\u4E2A\u957F\u671F\u76EE\u6807\u4F1A\u8BDD\u5E76\u7ED1\u4E0A" },
|
|
203765
205013
|
{ name: "playbook", desc: "\u5267\u672C ref\uFF08workorder \u6A21\u5F0F\u5FC5\u586B\uFF1Boasis playbooks \u53EF\u67E5\uFF09" },
|
|
203766
205014
|
{ name: "payload", desc: "\u5267\u672C\u5165\u53C2\uFF08JSON\uFF0C\u5BF9\u5E94\u5267\u672C inputs\uFF09" },
|
|
203767
205015
|
{ name: "cron", desc: "5 \u5B57\u6BB5 cron\uFF08\u7ED9\u4E86\u5373\u5EFA schedule \u89E6\u53D1\u5668\uFF09" },
|
|
@@ -203776,13 +205024,14 @@ var COMMAND_DECLS = {
|
|
|
203776
205024
|
},
|
|
203777
205025
|
"automation-update": {
|
|
203778
205026
|
group: "\u81EA\u52A8\u5316",
|
|
203779
|
-
usage: "oasis automation-update <id> [--name <\u540D>] [--mode chat|workorder] [--agent <actorId>] [--playbook <ref>] [--payload '<JSON>'] [--project <id>] [--title-template <t>] [--dispatch true|false] [--enabled true|false] [--subscribers a,b]",
|
|
205027
|
+
usage: "oasis automation-update <id> [--name <\u540D>] [--mode chat|workorder] [--agent <actorId>] [--chat-target new|session:<\u4F1A\u8BDDid>|create] [--playbook <ref>] [--payload '<JSON>'] [--project <id>] [--title-template <t>] [--dispatch true|false] [--enabled true|false] [--subscribers a,b]",
|
|
203780
205028
|
description: "\u66F4\u65B0\u81EA\u52A8\u5316\u3002\u5B9E\u8D28\u53D8\u66F4\uFF08\u5267\u672C/\u5165\u53C2/\u6A21\u677F/dispatch/\u542F\u505C\uFF09\u4F1A\u628A\u95EE\u8D23\u8F6C\u79FB\u7ED9\u7F16\u8F91\u8005\uFF08\u5F52\u56E0\uFF09\u3002",
|
|
203781
205029
|
positional: [{ name: "<id>", required: true, desc: "\u81EA\u52A8\u5316 id" }],
|
|
203782
205030
|
flags: [
|
|
203783
205031
|
{ name: "name", desc: "\u663E\u793A\u540D" },
|
|
203784
205032
|
{ name: "mode", desc: "chat|workorder" },
|
|
203785
205033
|
{ name: "agent", desc: "\u6267\u884C\u4EBA agent actor id" },
|
|
205034
|
+
{ name: "chat-target", desc: "\u5BF9\u8BDD\u6267\u884C\u7684\u76EE\u6807\u4F1A\u8BDD\uFF1Anew=\u6BCF\u6B21\u65B0\u5F00\uFF5Csession:<\u4F1A\u8BDDid>=\u56FA\u5B9A\u53D1\u5230\u8BE5\u4F1A\u8BDD\uFF5Ccreate=\u73B0\u5EFA\u4E00\u4E2A\u957F\u671F\u76EE\u6807\u4F1A\u8BDD\u5E76\u7ED1\u4E0A\uFF08\u4E0D\u7ED9=\u4E0D\u52A8\uFF09" },
|
|
203786
205035
|
{ name: "playbook", desc: "\u5267\u672C ref" },
|
|
203787
205036
|
{ name: "payload", desc: "\u5267\u672C\u5165\u53C2\uFF08JSON\uFF09" },
|
|
203788
205037
|
{ name: "project", desc: "\u76EE\u6807\u9879\u76EE id" },
|
|
@@ -204376,6 +205625,30 @@ var COMMAND_DECLS = {
|
|
|
204376
205625
|
description: "\u5B64\u513F blob \u56DE\u6536\uFF08mark-and-sweep\uFF1B\u64CD\u4F5C\u8005\u547D\u4EE4\uFF0CF1\uFF09\u3002",
|
|
204377
205626
|
examples: ["oasis gc"]
|
|
204378
205627
|
},
|
|
205628
|
+
"chat-turn": {
|
|
205629
|
+
group: "\u8FD0\u7EF4",
|
|
205630
|
+
usage: "oasis chat-turn <\u4F1A\u8BDDid>",
|
|
205631
|
+
description: "\u770B\u8FD9\u6761 chat \u4F1A\u8BDD\u5F53\u524D\u5360\u7740\u7684\u90A3\u4E00\u8F6E\uFF08\u8F6E\u6B21\u8D26\u672C\u7684 active \u884C\uFF09\u3002\u300C\u76EE\u6807\u4F1A\u8BDD\u6B63\u5FD9 / session_busy\u300D\u7684\u552F\u4E00\u53E3\u5F84\u5C31\u662F\u5B83\u2014\u2014\u6392\u67E5\u81EA\u52A8\u5316\u4E3A\u4EC0\u4E48\u4E00\u76F4\u88AB\u8DF3\u8FC7\u5148\u770B\u8FD9\u91CC\u3002",
|
|
205632
|
+
positional: [{ name: "<\u4F1A\u8BDDid>", required: true, desc: "chat \u4F1A\u8BDD id" }],
|
|
205633
|
+
examples: ["oasis chat-turn 84f48795-1c2d-4e5f-8a9b-0c1d2e3f4a5b"]
|
|
205634
|
+
},
|
|
205635
|
+
"chat-turn-settle": {
|
|
205636
|
+
group: "\u8FD0\u7EF4",
|
|
205637
|
+
usage: "oasis chat-turn-settle <\u4F1A\u8BDDid> <\u8F6E\u6B21id> [--force true] [--reason <\u8BF4\u660E>]",
|
|
205638
|
+
description: "\u628A\u5361\u6B7B\u7684\u4E00\u8F6E\u7F6E\u7EC8\u6001\u3001\u653E\u5F00\u4F1A\u8BDD\u69FD\uFF08\u8FDB\u7A0B\u88AB\u6740\u7559\u4E0B\u7684 running \u884C\u4F1A\u8BA9\u4F1A\u8BDD\u6C38\u4E45\u5224\u5FD9\uFF09\u3002\u9ED8\u8BA4\u5148\u5411 trace \u8D26\u672C\u6838\u5B9E\uFF1A\u8FD8\u5728\u8DD1\u5C31\u62D2\u7EDD\uFF1B--force true \u662F\u660E\u786E\u7684\u4EBA\u5DE5\u63A8\u7FFB\uFF0C\u843D cancelled \u5E76\u8BB0\u4E0B\u539F\u56E0\u3002",
|
|
205639
|
+
positional: [
|
|
205640
|
+
{ name: "<\u4F1A\u8BDDid>", required: true, desc: "chat \u4F1A\u8BDD id" },
|
|
205641
|
+
{ name: "<\u8F6E\u6B21id>", required: true, desc: "\u8F6E\u6B21 id\uFF08oasis chat-turn \u91CC\u7684 id\uFF0Crun.result.blockedByTurnId \u540C\u503C\uFF09" }
|
|
205642
|
+
],
|
|
205643
|
+
flags: [
|
|
205644
|
+
{ name: "force", desc: "true=\u4E0D\u6838\u5B9E\u76F4\u63A5\u7F6E cancelled\uFF08\u786E\u8BA4\u6267\u884C\u4EBA\u771F\u7684\u6B7B\u4E86\u518D\u7528\uFF09" },
|
|
205645
|
+
{ name: "reason", desc: "\u5F3A\u5236\u7F6E\u7EC8\u6001\u7684\u539F\u56E0\uFF08\u4F1A\u8BB0\u8FDB\u8F6E\u6B21\u7684 lastError\uFF09" }
|
|
205646
|
+
],
|
|
205647
|
+
examples: [
|
|
205648
|
+
"oasis chat-turn-settle 84f48795-\u2026 cturn_nbgv5c7g8u",
|
|
205649
|
+
'oasis chat-turn-settle 84f48795-\u2026 cturn_nbgv5c7g8u --force true --reason "\u8282\u70B9\u5DF2\u91CD\u88C5\uFF0C\u8FD9\u4E00\u8F6E\u7684\u8FDB\u7A0B\u4E0D\u5B58\u5728\u4E86"'
|
|
205650
|
+
]
|
|
205651
|
+
},
|
|
204379
205652
|
// —— 读产物 ——
|
|
204380
205653
|
status: {
|
|
204381
205654
|
group: "\u8BFB\u4EA7\u7269",
|
|
@@ -205103,13 +206376,13 @@ function ownFlagsFromDecl(command) {
|
|
|
205103
206376
|
}
|
|
205104
206377
|
|
|
205105
206378
|
// ../cli/src/connector-effect-runner.ts
|
|
205106
|
-
var
|
|
206379
|
+
var import_node_crypto51 = require("node:crypto");
|
|
205107
206380
|
var import_node_child_process19 = require("node:child_process");
|
|
205108
206381
|
init_src8();
|
|
205109
206382
|
function stableKey(effect) {
|
|
205110
206383
|
const keyFields = Object.fromEntries(Object.entries(effect.keyFields).sort(([a], [b2]) => a.localeCompare(b2)));
|
|
205111
206384
|
const canonical = JSON.stringify({ kind: effect.kind, target: effect.target, keyFields });
|
|
205112
|
-
return `sha256:${(0,
|
|
206385
|
+
return `sha256:${(0, import_node_crypto51.createHash)("sha256").update(canonical).digest("hex")}`;
|
|
205113
206386
|
}
|
|
205114
206387
|
async function runConnectorEffect(connector, toolArgs, deps) {
|
|
205115
206388
|
const effect = connector.describeExternalEffect?.(toolArgs) ?? null;
|
|
@@ -205236,6 +206509,18 @@ function need(flags, name) {
|
|
|
205236
206509
|
if (v2 === void 0) throw new Error(`\u7F3A\u5C11 --${name}\uFF08oasis \u4E0D\u5E26\u53C2\u6570\u53EF\u770B\u7528\u6CD5\uFF09`);
|
|
205237
206510
|
return v2;
|
|
205238
206511
|
}
|
|
206512
|
+
function parseChatTargetFlag(raw) {
|
|
206513
|
+
if (raw === void 0) return {};
|
|
206514
|
+
const v2 = raw.trim();
|
|
206515
|
+
if (v2 === "new") return { chatTarget: { mode: "new_session" } };
|
|
206516
|
+
if (v2 === "create") return { createChatTargetSession: true };
|
|
206517
|
+
if (v2.startsWith("session:")) {
|
|
206518
|
+
const sessionId = v2.slice("session:".length).trim();
|
|
206519
|
+
if (!sessionId) throw new Error("--chat-target session:<\u4F1A\u8BDDid> \u7F3A\u5C11\u4F1A\u8BDD id");
|
|
206520
|
+
return { chatTarget: { mode: "existing_session", sessionId } };
|
|
206521
|
+
}
|
|
206522
|
+
throw new Error(`--chat-target \u53EA\u80FD\u662F new | session:<\u4F1A\u8BDDid> | create\uFF08\u6536\u5230\uFF1A${raw}\uFF09`);
|
|
206523
|
+
}
|
|
205239
206524
|
function needPos(positional, i, usage) {
|
|
205240
206525
|
const v2 = positional[i];
|
|
205241
206526
|
if (v2 === void 0) throw new Error(`\u7528\u6CD5: ${usage}`);
|
|
@@ -205704,7 +206989,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
|
|
|
205704
206989
|
const store = createNodeTokenStore(path31.join(dir, "node-tokens.json"));
|
|
205705
206990
|
const sub = positional[0];
|
|
205706
206991
|
if (sub === "issue") {
|
|
205707
|
-
const id = flags.get("id") ?? `node-${(0,
|
|
206992
|
+
const id = flags.get("id") ?? `node-${(0, import_node_crypto52.randomUUID)()}`;
|
|
205708
206993
|
const token2 = store.issue(id);
|
|
205709
206994
|
println(token2);
|
|
205710
206995
|
process.stderr.write(
|
|
@@ -206260,10 +207545,12 @@ ${p2.ref} ${p2.name}`);
|
|
|
206260
207545
|
triggers.push({ kind: "webhook", webhook: { provider: flags.get("webhook") || "generic" } });
|
|
206261
207546
|
}
|
|
206262
207547
|
const mode = flags.get("mode") ?? (flags.has("agent") ? "chat" : "workorder");
|
|
207548
|
+
const chatTargetFlag = parseChatTargetFlag(flags.get("chat-target"));
|
|
206263
207549
|
const result = await api.post("/api/automations", {
|
|
206264
207550
|
name: need(flags, "name"),
|
|
206265
207551
|
executionMode: mode,
|
|
206266
207552
|
...flags.has("agent") ? { agentId: flags.get("agent") } : {},
|
|
207553
|
+
...chatTargetFlag,
|
|
206267
207554
|
...mode === "workorder" ? { playbookRef: need(flags, "playbook") } : {},
|
|
206268
207555
|
...flags.has("payload") ? { payload: JSON.parse(flags.get("payload")) } : {},
|
|
206269
207556
|
...flags.has("project") ? { projectId: flags.get("project") } : {},
|
|
@@ -206277,8 +207564,14 @@ ${p2.ref} ${p2.name}`);
|
|
|
206277
207564
|
}
|
|
206278
207565
|
case "automation-update": {
|
|
206279
207566
|
const id = needPos(positional, 0, "oasis automation-update <id> [--name ...] [--enabled true|false] ...");
|
|
207567
|
+
const chatTargetFlag = parseChatTargetFlag(flags.get("chat-target"));
|
|
207568
|
+
if ("createChatTargetSession" in chatTargetFlag) {
|
|
207569
|
+
println(JSON.stringify(await api.post(`/api/automations/${encodeURIComponent(id)}/chat-target-session`, {}), null, 2));
|
|
207570
|
+
break;
|
|
207571
|
+
}
|
|
206280
207572
|
const result = await api.request("PATCH", `/api/automations/${encodeURIComponent(id)}`, {
|
|
206281
207573
|
...flags.has("name") ? { name: flags.get("name") } : {},
|
|
207574
|
+
...chatTargetFlag,
|
|
206282
207575
|
...flags.has("mode") ? { executionMode: flags.get("mode") } : {},
|
|
206283
207576
|
...flags.has("agent") ? { agentId: flags.get("agent") } : {},
|
|
206284
207577
|
...flags.has("playbook") ? { playbookRef: flags.get("playbook") } : {},
|
|
@@ -207622,6 +208915,34 @@ ${res.warning}`);
|
|
|
207622
208915
|
println(message);
|
|
207623
208916
|
break;
|
|
207624
208917
|
}
|
|
208918
|
+
case "chat-turn": {
|
|
208919
|
+
const sid = needPos(positional, 0, "oasis chat-turn <\u4F1A\u8BDDid>");
|
|
208920
|
+
const { turn } = await api.request(
|
|
208921
|
+
"GET",
|
|
208922
|
+
`/api/chat-sessions/${encodeURIComponent(sid)}/turns/active`
|
|
208923
|
+
);
|
|
208924
|
+
if (!turn) {
|
|
208925
|
+
println("\u8FD9\u6761\u4F1A\u8BDD\u5F53\u524D\u7A7A\u95F2\uFF08\u6CA1\u6709 active \u8F6E\u6B21\uFF09\u3002");
|
|
208926
|
+
break;
|
|
208927
|
+
}
|
|
208928
|
+
println(JSON.stringify(turn, null, 2));
|
|
208929
|
+
println("");
|
|
208930
|
+
println(`\u5361\u4F4F\u4E86\uFF1F\u5148\u6838\u5B9E\u6267\u884C\u4EBA\u6B7B\u6CA1\u6B7B\uFF0C\u518D \`oasis chat-turn-settle ${sid} ${String(turn["id"])}\`\u3002`);
|
|
208931
|
+
break;
|
|
208932
|
+
}
|
|
208933
|
+
case "chat-turn-settle": {
|
|
208934
|
+
const sid = needPos(positional, 0, "oasis chat-turn-settle <\u4F1A\u8BDDid> <\u8F6E\u6B21id>");
|
|
208935
|
+
const turnId = needPos(positional, 1, "oasis chat-turn-settle <\u4F1A\u8BDDid> <\u8F6E\u6B21id>");
|
|
208936
|
+
const res = await api.post(
|
|
208937
|
+
`/api/chat-sessions/${encodeURIComponent(sid)}/turns/${encodeURIComponent(turnId)}/settle`,
|
|
208938
|
+
{
|
|
208939
|
+
...flags.get("force") === "true" ? { force: true } : {},
|
|
208940
|
+
...flags.has("reason") ? { reason: flags.get("reason") } : {}
|
|
208941
|
+
}
|
|
208942
|
+
);
|
|
208943
|
+
println(res.settled ? `\u5DF2\u7F6E\u7EC8\u6001\uFF1A${res.status}${res.reason ? `\uFF08${res.reason}\uFF09` : ""}\u2014\u2014\u4F1A\u8BDD\u69FD\u5DF2\u653E\u5F00\u3002` : `\u672A\u5904\u7F6E\uFF1A${res.reason ?? "\u8FD9\u4E00\u8F6E\u5DF2\u7ECF\u662F\u7EC8\u6001"}\u3002`);
|
|
208944
|
+
break;
|
|
208945
|
+
}
|
|
207625
208946
|
case "queue": {
|
|
207626
208947
|
const artifactId = needPos(positional, 0, "oasis queue <artifactId>");
|
|
207627
208948
|
const { head, queue } = await api.view("queue", artifactId);
|
|
@@ -208250,12 +209571,12 @@ var LEGACY_SYSTEMD_UNIT = "oasis-node.service";
|
|
|
208250
209571
|
var LEGACY_LAUNCHD_LABEL = "com.oasis.node";
|
|
208251
209572
|
|
|
208252
209573
|
// src/install.ts
|
|
208253
|
-
var
|
|
209574
|
+
var import_node_crypto53 = require("node:crypto");
|
|
208254
209575
|
var fs41 = __toESM(require("node:fs"));
|
|
208255
209576
|
var path35 = __toESM(require("node:path"));
|
|
208256
209577
|
function versionLabel(sourceFile, pkgVersion, npmPrefixDir) {
|
|
208257
209578
|
if (isFromNpmPrefix(sourceFile, npmPrefixDir)) return pkgVersion;
|
|
208258
|
-
const digest = (0,
|
|
209579
|
+
const digest = (0, import_node_crypto53.createHash)("sha256").update(fs41.readFileSync(sourceFile)).digest("hex").slice(0, 8);
|
|
208259
209580
|
return `${pkgVersion}+local.${digest}`;
|
|
208260
209581
|
}
|
|
208261
209582
|
function isFromNpmPrefix(sourceFile, npmPrefixDir) {
|
|
@@ -208378,7 +209699,7 @@ function shimScript() {
|
|
|
208378
209699
|
}
|
|
208379
209700
|
|
|
208380
209701
|
// src/index.ts
|
|
208381
|
-
var PKG_VERSION = true ? "0.1.
|
|
209702
|
+
var PKG_VERSION = true ? "0.1.122" : "dev";
|
|
208382
209703
|
var LOCAL_BIN = localBin();
|
|
208383
209704
|
var NPM_PREFIX = npmPrefix();
|
|
208384
209705
|
var INSTANCE = DEFAULT_INSTANCE;
|
|
@@ -208638,7 +209959,7 @@ function newInstanceName() {
|
|
|
208638
209959
|
const existing = new Set(listInstances());
|
|
208639
209960
|
if (!existing.has(DEFAULT_INSTANCE)) return DEFAULT_INSTANCE;
|
|
208640
209961
|
for (; ; ) {
|
|
208641
|
-
const n = `inst-${(0,
|
|
209962
|
+
const n = `inst-${(0, import_node_crypto54.randomBytes)(3).toString("hex")}`;
|
|
208642
209963
|
if (!existing.has(n)) return n;
|
|
208643
209964
|
}
|
|
208644
209965
|
}
|