dsh-lark-bot 0.9.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -7
- package/SECURITY.md +3 -2
- package/dist/cli.js +431 -92
- package/dist/cli.js.map +1 -1
- package/dist/plugin.d.ts +2 -0
- package/dist/plugin.js +87 -38
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -667,7 +667,7 @@ var init_acp_adapter = __esm({
|
|
|
667
667
|
});
|
|
668
668
|
|
|
669
669
|
// src/cli.ts
|
|
670
|
-
import { readFileSync as
|
|
670
|
+
import { readFileSync as readFileSync5, realpathSync as realpathSync4 } from "fs";
|
|
671
671
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
672
672
|
import { Command } from "commander";
|
|
673
673
|
|
|
@@ -1277,6 +1277,7 @@ var SDK_SERVER_PACKAGE = "@deepseek-ai/dsh-sdk-jsonrpc-server";
|
|
|
1277
1277
|
var SDK_SERVER_VERSION = DSH_COMPATIBILITY.sdkServer;
|
|
1278
1278
|
var SDK_BASE_BUNDLE = "@deepseek-ai/dsh-base";
|
|
1279
1279
|
var DEFAULT_SDK_PROFILE = "dsh-lark-sdk";
|
|
1280
|
+
var DEFAULT_SAFE_SDK_PROFILE = "dsh-lark-safe-sdk";
|
|
1280
1281
|
function sdkProfileRoot(home, profile, env) {
|
|
1281
1282
|
return join3(resolveDshHome(home, env), "profiles", profile);
|
|
1282
1283
|
}
|
|
@@ -1301,9 +1302,10 @@ function packageJsonFor(profile) {
|
|
|
1301
1302
|
)}
|
|
1302
1303
|
`;
|
|
1303
1304
|
}
|
|
1304
|
-
function patchYamlFor() {
|
|
1305
|
+
function patchYamlFor(options) {
|
|
1305
1306
|
const own = ownPackageInfo();
|
|
1306
|
-
|
|
1307
|
+
const bridgeTools = options?.bridgeTools ?? true;
|
|
1308
|
+
const lines = [
|
|
1307
1309
|
"# dsh-lark SDK JSON-RPC runtime overlay (managed by dsh-lark-bot).",
|
|
1308
1310
|
"# stdout is reserved for SDK JSON-RPC frames; no console logger may load.",
|
|
1309
1311
|
"- insert:",
|
|
@@ -1324,26 +1326,31 @@ function patchYamlFor() {
|
|
|
1324
1326
|
"",
|
|
1325
1327
|
"- id: hmr",
|
|
1326
1328
|
" disabled: true",
|
|
1327
|
-
"",
|
|
1328
|
-
// In-process bridge callback tool: lets the agent mention users and push
|
|
1329
|
-
// messages to other chats/topics through the running bridge process.
|
|
1330
|
-
"- insert:",
|
|
1331
|
-
" - id: lark-notify",
|
|
1332
|
-
` name: '${own.name}/notify'`,
|
|
1333
|
-
" config:",
|
|
1334
|
-
" endpoint: !!js process.env.DSH_LARK_NOTIFY_URL",
|
|
1335
|
-
" token: !!js process.env.DSH_LARK_NOTIFY_TOKEN",
|
|
1336
|
-
"",
|
|
1337
|
-
// Question-card tool: the agent asks the user for decisions / missing
|
|
1338
|
-
// information; the bridge shows a card and returns the answer.
|
|
1339
|
-
"- insert:",
|
|
1340
|
-
" - id: lark-ask",
|
|
1341
|
-
` name: '${own.name}/ask'`,
|
|
1342
|
-
" config:",
|
|
1343
|
-
" endpoint: !!js process.env.DSH_LARK_ASK_URL",
|
|
1344
|
-
" token: !!js process.env.DSH_LARK_NOTIFY_TOKEN",
|
|
1345
1329
|
""
|
|
1346
|
-
]
|
|
1330
|
+
];
|
|
1331
|
+
if (bridgeTools) {
|
|
1332
|
+
lines.push(
|
|
1333
|
+
// In-process bridge callback tool: lets the agent mention users and push
|
|
1334
|
+
// messages to other chats/topics through the running bridge process.
|
|
1335
|
+
"- insert:",
|
|
1336
|
+
" - id: lark-notify",
|
|
1337
|
+
` name: '${own.name}/notify'`,
|
|
1338
|
+
" config:",
|
|
1339
|
+
" endpoint: !!js process.env.DSH_LARK_NOTIFY_URL",
|
|
1340
|
+
" token: !!js process.env.DSH_LARK_NOTIFY_TOKEN",
|
|
1341
|
+
"",
|
|
1342
|
+
// Question-card tool: the agent asks the user for decisions / missing
|
|
1343
|
+
// information; the bridge shows a card and returns the answer.
|
|
1344
|
+
"- insert:",
|
|
1345
|
+
" - id: lark-ask",
|
|
1346
|
+
` name: '${own.name}/ask'`,
|
|
1347
|
+
" config:",
|
|
1348
|
+
" endpoint: !!js process.env.DSH_LARK_ASK_URL",
|
|
1349
|
+
" token: !!js process.env.DSH_LARK_NOTIFY_TOKEN",
|
|
1350
|
+
""
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
return lines.join("\n");
|
|
1347
1354
|
}
|
|
1348
1355
|
function sdkServerInstalled(profileRoot) {
|
|
1349
1356
|
const candidates = [
|
|
@@ -1401,7 +1408,13 @@ async function ensureSdkProfile(options) {
|
|
|
1401
1408
|
await mkdir(root, { recursive: true });
|
|
1402
1409
|
await writeFile(join3(root, "package.json"), packageJsonFor(profile), "utf8");
|
|
1403
1410
|
await writeFile(join3(root, "cordis.yml"), "[]\n", "utf8");
|
|
1404
|
-
await writeFile(
|
|
1411
|
+
await writeFile(
|
|
1412
|
+
join3(root, "cordis.patch.yml"),
|
|
1413
|
+
patchYamlFor(
|
|
1414
|
+
options.bridgeTools === void 0 ? {} : { bridgeTools: options.bridgeTools }
|
|
1415
|
+
),
|
|
1416
|
+
"utf8"
|
|
1417
|
+
);
|
|
1405
1418
|
const install = options.install ?? runPnpmInstall;
|
|
1406
1419
|
if (!isSdkProfileReady(root)) {
|
|
1407
1420
|
await install(root);
|
|
@@ -2179,6 +2192,10 @@ var PendingQueue = class {
|
|
|
2179
2192
|
hasPending(scope) {
|
|
2180
2193
|
return (this.pending.get(scope)?.length ?? 0) > 0;
|
|
2181
2194
|
}
|
|
2195
|
+
/** Number of messages waiting in the queue for a scope (not yet flushing). */
|
|
2196
|
+
size(scope) {
|
|
2197
|
+
return this.pending.get(scope)?.length ?? 0;
|
|
2198
|
+
}
|
|
2182
2199
|
isBlocked(scope) {
|
|
2183
2200
|
return this.blocked.has(scope);
|
|
2184
2201
|
}
|
|
@@ -2442,7 +2459,9 @@ var initialState = {
|
|
|
2442
2459
|
footer: "thinking",
|
|
2443
2460
|
terminal: "running",
|
|
2444
2461
|
errorMsg: void 0,
|
|
2445
|
-
idleTimeoutMinutes: void 0
|
|
2462
|
+
idleTimeoutMinutes: void 0,
|
|
2463
|
+
startedAtMs: void 0,
|
|
2464
|
+
lastActivityMs: void 0
|
|
2446
2465
|
};
|
|
2447
2466
|
function closeStreamingText(blocks) {
|
|
2448
2467
|
return blocks.map(
|
|
@@ -2588,8 +2607,16 @@ function markdown(content) {
|
|
|
2588
2607
|
function noteMd(content) {
|
|
2589
2608
|
return { tag: "markdown", content, text_size: "notation" };
|
|
2590
2609
|
}
|
|
2591
|
-
function footerStatus(status) {
|
|
2592
|
-
|
|
2610
|
+
function footerStatus(status, state, now) {
|
|
2611
|
+
let text = status === "thinking" ? "\u{1F9E0} \u6B63\u5728\u601D\u8003" : status === "tool_running" ? "\u{1F9F0} \u6B63\u5728\u8C03\u7528\u5DE5\u5177" : "\u270D\uFE0F \u6B63\u5728\u8F93\u51FA";
|
|
2612
|
+
if (state.startedAtMs !== void 0) {
|
|
2613
|
+
const elapsed = Math.max(0, Math.round((now - state.startedAtMs) / 1e3));
|
|
2614
|
+
text += ` \u23F1 ${elapsed}s`;
|
|
2615
|
+
}
|
|
2616
|
+
if (state.lastActivityMs !== void 0) {
|
|
2617
|
+
const idle = Math.max(0, Math.round((now - state.lastActivityMs) / 1e3));
|
|
2618
|
+
if (idle >= 60) text += ` \xB7 \u23F8 \u65E0\u54CD\u5E94 ${idle}s`;
|
|
2619
|
+
}
|
|
2593
2620
|
return noteMd(text);
|
|
2594
2621
|
}
|
|
2595
2622
|
function summaryText(state) {
|
|
@@ -2623,7 +2650,7 @@ function usageLine(state) {
|
|
|
2623
2650
|
if (state.usage.outputTokens !== void 0) parts.push(`out ${state.usage.outputTokens}`);
|
|
2624
2651
|
return parts.length ? `\uFF08tokens ${parts.join(" \xB7 ")}\uFF09` : "";
|
|
2625
2652
|
}
|
|
2626
|
-
function renderStandard(state) {
|
|
2653
|
+
function renderStandard(state, now) {
|
|
2627
2654
|
const elements = [];
|
|
2628
2655
|
if (state.reasoning.content) {
|
|
2629
2656
|
elements.push(
|
|
@@ -2652,7 +2679,7 @@ function renderStandard(state) {
|
|
|
2652
2679
|
if (usage) elements.push(noteMd(usage));
|
|
2653
2680
|
}
|
|
2654
2681
|
if (state.terminal === "running") {
|
|
2655
|
-
if (state.footer) elements.push(footerStatus(state.footer));
|
|
2682
|
+
if (state.footer) elements.push(footerStatus(state.footer, state, now));
|
|
2656
2683
|
elements.push(stopButton());
|
|
2657
2684
|
}
|
|
2658
2685
|
return {
|
|
@@ -2664,10 +2691,10 @@ function renderStandard(state) {
|
|
|
2664
2691
|
body: { elements }
|
|
2665
2692
|
};
|
|
2666
2693
|
}
|
|
2667
|
-
function renderCompact(state) {
|
|
2694
|
+
function renderCompact(state, now) {
|
|
2668
2695
|
const elements = [noteMd(summaryText(state))];
|
|
2669
2696
|
if (state.terminal === "running" && state.footer) {
|
|
2670
|
-
elements.push(footerStatus(state.footer));
|
|
2697
|
+
elements.push(footerStatus(state.footer, state, now));
|
|
2671
2698
|
}
|
|
2672
2699
|
if (state.terminal === "running") {
|
|
2673
2700
|
elements.push(stopButton());
|
|
@@ -2681,7 +2708,7 @@ function renderCompact(state) {
|
|
|
2681
2708
|
body: { elements }
|
|
2682
2709
|
};
|
|
2683
2710
|
}
|
|
2684
|
-
function renderDetailed(state) {
|
|
2711
|
+
function renderDetailed(state, now) {
|
|
2685
2712
|
const elements = [];
|
|
2686
2713
|
if (state.reasoning.content) {
|
|
2687
2714
|
elements.push(
|
|
@@ -2720,7 +2747,7 @@ ${safeJsonPreview(tool.input)}
|
|
|
2720
2747
|
if (usage) elements.push(noteMd(usage));
|
|
2721
2748
|
}
|
|
2722
2749
|
if (state.terminal === "running") {
|
|
2723
|
-
if (state.footer) elements.push(footerStatus(state.footer));
|
|
2750
|
+
if (state.footer) elements.push(footerStatus(state.footer, state, now));
|
|
2724
2751
|
elements.push(stopButton());
|
|
2725
2752
|
}
|
|
2726
2753
|
return {
|
|
@@ -2740,10 +2767,10 @@ function safeJsonPreview(value) {
|
|
|
2740
2767
|
return String(value).slice(0, 300);
|
|
2741
2768
|
}
|
|
2742
2769
|
}
|
|
2743
|
-
function renderCard(state, density = "standard") {
|
|
2744
|
-
if (density === "compact") return renderCompact(state);
|
|
2745
|
-
if (density === "detailed") return renderDetailed(state);
|
|
2746
|
-
return renderStandard(state);
|
|
2770
|
+
function renderCard(state, density = "standard", now = Date.now()) {
|
|
2771
|
+
if (density === "compact") return renderCompact(state, now);
|
|
2772
|
+
if (density === "detailed") return renderDetailed(state, now);
|
|
2773
|
+
return renderStandard(state, now);
|
|
2747
2774
|
}
|
|
2748
2775
|
|
|
2749
2776
|
// src/card/approval-card.ts
|
|
@@ -2895,7 +2922,12 @@ async function runAgentBatch(input) {
|
|
|
2895
2922
|
} : {}
|
|
2896
2923
|
});
|
|
2897
2924
|
input.activeRuns.set(input.scope, { runId, stop: run.stop });
|
|
2898
|
-
|
|
2925
|
+
const now = Date.now();
|
|
2926
|
+
let state = {
|
|
2927
|
+
...initialState,
|
|
2928
|
+
startedAtMs: now,
|
|
2929
|
+
lastActivityMs: now
|
|
2930
|
+
};
|
|
2899
2931
|
const stopRequested = { value: false };
|
|
2900
2932
|
const timeoutMs = input.runPolicies?.get(input.scope) ?? input.runTimeoutMs ?? 0;
|
|
2901
2933
|
let timedOut = false;
|
|
@@ -2906,10 +2938,16 @@ async function runAgentBatch(input) {
|
|
|
2906
2938
|
input.chatId,
|
|
2907
2939
|
renderCard(state, density),
|
|
2908
2940
|
async (controller) => {
|
|
2941
|
+
const ticker = setInterval(() => {
|
|
2942
|
+
void controller.update(renderCard(state, density, Date.now())).catch(() => {
|
|
2943
|
+
});
|
|
2944
|
+
}, 5e3);
|
|
2945
|
+
ticker.unref?.();
|
|
2909
2946
|
const consume = async () => {
|
|
2910
2947
|
for await (const event of run.events) {
|
|
2911
2948
|
if (timedOut) return;
|
|
2912
2949
|
state = applyEvent(state, event, stopRequested);
|
|
2950
|
+
state = { ...state, lastActivityMs: Date.now() };
|
|
2913
2951
|
if (event.type === "final_text") {
|
|
2914
2952
|
assistantOutput = event.content;
|
|
2915
2953
|
} else if (event.type === "text") {
|
|
@@ -2950,8 +2988,9 @@ async function runAgentBatch(input) {
|
|
|
2950
2988
|
await consume();
|
|
2951
2989
|
}
|
|
2952
2990
|
state = timedOut ? markIdleTimeout(state, timeoutMs / 6e4) : finalizeIfRunning(state);
|
|
2953
|
-
await controller.update(renderCard(state, density));
|
|
2991
|
+
await controller.update(renderCard(state, density, Date.now()));
|
|
2954
2992
|
} finally {
|
|
2993
|
+
clearInterval(ticker);
|
|
2955
2994
|
if (timeoutTimer !== void 0) clearTimeout(timeoutTimer);
|
|
2956
2995
|
unsubscribeSettled?.();
|
|
2957
2996
|
}
|
|
@@ -4578,7 +4617,18 @@ async function startChannel(deps) {
|
|
|
4578
4617
|
log.fail("channel-command", error, { scope });
|
|
4579
4618
|
return false;
|
|
4580
4619
|
});
|
|
4581
|
-
if (!handled)
|
|
4620
|
+
if (!handled) {
|
|
4621
|
+
const queued = deps.pending.size(scope);
|
|
4622
|
+
const busy = queued > 0 || deps.pending.isFlushing(scope) || deps.pending.isBlocked(scope);
|
|
4623
|
+
if (busy) {
|
|
4624
|
+
await commandChannel.sendMarkdown(
|
|
4625
|
+
msg.chatId,
|
|
4626
|
+
`\u23F3 \u5DF2\u6536\u5230\uFF0C\u5F53\u524D\u6392\u961F\u4E2D\uFF08\u961F\u5217 ${queued + 1} \u6761\uFF09\u3002\u4EFB\u52A1\u5F00\u59CB\u540E\u4F1A\u5728\u8FD9\u91CC\u5B9E\u65F6\u663E\u793A\u8FDB\u5EA6\u3002`,
|
|
4627
|
+
{ replyTo: msg.messageId }
|
|
4628
|
+
);
|
|
4629
|
+
}
|
|
4630
|
+
deps.pending.push(scope, msg);
|
|
4631
|
+
}
|
|
4582
4632
|
},
|
|
4583
4633
|
cardAction: async (event) => {
|
|
4584
4634
|
const value = event.action.value && typeof event.action.value === "object" ? event.action.value : void 0;
|
|
@@ -6383,9 +6433,13 @@ import { join as join16 } from "path";
|
|
|
6383
6433
|
|
|
6384
6434
|
// src/guardian/service.ts
|
|
6385
6435
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
6436
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
6386
6437
|
import { homedir as homedir8 } from "os";
|
|
6387
6438
|
import { join as join15 } from "path";
|
|
6388
|
-
import {
|
|
6439
|
+
import {
|
|
6440
|
+
createLarkChannel as createLarkChannel2
|
|
6441
|
+
} from "@larksuite/channel";
|
|
6442
|
+
import { parse } from "yaml";
|
|
6389
6443
|
init_dsh_runtime();
|
|
6390
6444
|
|
|
6391
6445
|
// src/guardian/control.ts
|
|
@@ -6410,6 +6464,11 @@ function parseGuardianCommand(text) {
|
|
|
6410
6464
|
case "leave":
|
|
6411
6465
|
case "restore":
|
|
6412
6466
|
return { kind: "safemode-exit", argument };
|
|
6467
|
+
case "stop":
|
|
6468
|
+
case "cancel":
|
|
6469
|
+
case "abort":
|
|
6470
|
+
case "kill":
|
|
6471
|
+
return { kind: "safemode-stop", argument };
|
|
6413
6472
|
case "help":
|
|
6414
6473
|
case "?":
|
|
6415
6474
|
return { kind: "safemode-help", argument };
|
|
@@ -6422,6 +6481,7 @@ var SAFEMODE_HELP = [
|
|
|
6422
6481
|
"/safemode status \u2014 \u67E5\u770B\u5B88\u62A4\u72B6\u6001",
|
|
6423
6482
|
"/safemode plugins \u2014 \u5217\u51FA\u6545\u969C profile \u5DF2\u5B89\u88C5\u7684\u63D2\u4EF6",
|
|
6424
6483
|
"/safemode exit \u2014 \u9000\u51FA\u5B89\u5168\u6A21\u5F0F\uFF0C\u91CD\u542F\u5B8C\u6574 profile \u5E76\u4EA4\u8FD8\u98DE\u4E66\u901A\u9053",
|
|
6484
|
+
"/safemode stop \u2014 \u7EC8\u6B62\u5F53\u524D\u6B63\u5728\u8FD0\u884C\u7684\u5B89\u5168\u6A21\u5F0F\u4EFB\u52A1",
|
|
6425
6485
|
"",
|
|
6426
6486
|
"\u5B89\u5168\u6A21\u5F0F\u4E0B\u53D1\u9001\u666E\u901A\u6D88\u606F\u5373\u53EF\u4E0E dsh \u6838\u5FC3\u5BF9\u8BDD\uFF0C\u8FDB\u884C\u5B9A\u4F4D / \u4FEE\u590D / \u7981\u7528\u635F\u574F\u63D2\u4EF6\u7684\u81EA\u6108\u64CD\u4F5C\u3002"
|
|
6427
6487
|
].join("\n");
|
|
@@ -6430,6 +6490,7 @@ var SAFEMODE_HELP_EN = [
|
|
|
6430
6490
|
"/safemode status \u2014 show guardian state",
|
|
6431
6491
|
"/safemode plugins \u2014 list plugins installed into the broken profile",
|
|
6432
6492
|
"/safemode exit \u2014 leave safe mode, relaunch the full profile and hand the channel back",
|
|
6493
|
+
"/safemode stop \u2014 interrupt the currently running safe-mode task",
|
|
6433
6494
|
"",
|
|
6434
6495
|
"In safe mode, send normal messages to converse with the dsh core for self-healing."
|
|
6435
6496
|
].join("\n");
|
|
@@ -6555,11 +6616,15 @@ async function probeSafeProfile(options) {
|
|
|
6555
6616
|
// src/guardian/service.ts
|
|
6556
6617
|
var MAX_TRANSCRIPT_ENTRIES = 30;
|
|
6557
6618
|
var SAFE_RUN_TIMEOUT_MS = 10 * 6e4;
|
|
6619
|
+
var SAFE_SDK_PROVISION_TIMEOUT_MS = 3 * 6e4;
|
|
6620
|
+
var SAFE_CARD_TICK_MS = 5e3;
|
|
6558
6621
|
var GuardianService = class {
|
|
6559
6622
|
options;
|
|
6560
6623
|
state;
|
|
6561
6624
|
channel;
|
|
6562
|
-
|
|
6625
|
+
safeEngine;
|
|
6626
|
+
safeRuns = /* @__PURE__ */ new Map();
|
|
6627
|
+
sessionIds = /* @__PURE__ */ new Map();
|
|
6563
6628
|
transcripts = /* @__PURE__ */ new Map();
|
|
6564
6629
|
downStreak = 0;
|
|
6565
6630
|
lastHeartbeatFreshAt;
|
|
@@ -6577,6 +6642,9 @@ var GuardianService = class {
|
|
|
6577
6642
|
engineDeadMs: options.engineDeadMs ?? 12e4,
|
|
6578
6643
|
takeoverGracePolls: options.takeoverGracePolls ?? 2,
|
|
6579
6644
|
sendDelayMs: options.sendDelayMs ?? 600,
|
|
6645
|
+
safeAdapterMode: options.safeAdapterMode ?? "auto",
|
|
6646
|
+
safeTimeoutMs: options.safeTimeoutMs ?? SAFE_RUN_TIMEOUT_MS,
|
|
6647
|
+
safeDensity: options.safeDensity ?? "detailed",
|
|
6580
6648
|
stateFile: options.stateFile,
|
|
6581
6649
|
configFile: options.configFile,
|
|
6582
6650
|
heartbeatFile: options.heartbeatFile,
|
|
@@ -6591,6 +6659,7 @@ var GuardianService = class {
|
|
|
6591
6659
|
findProcess: options.findProcess,
|
|
6592
6660
|
spawnDetachedFn: options.spawnDetachedFn,
|
|
6593
6661
|
probeSafeProfileFn: options.probeSafeProfileFn,
|
|
6662
|
+
ensureSdkProfile: options.ensureSdkProfile,
|
|
6594
6663
|
runPluginList: options.runPluginList,
|
|
6595
6664
|
dshBin: options.dshBin,
|
|
6596
6665
|
saveState: options.saveState,
|
|
@@ -6633,9 +6702,11 @@ var GuardianService = class {
|
|
|
6633
6702
|
this.stopped = true;
|
|
6634
6703
|
if (this.timer) clearInterval(this.timer);
|
|
6635
6704
|
this.timer = void 0;
|
|
6705
|
+
await this.stopAllSafeRuns();
|
|
6706
|
+
this.sessionIds.clear();
|
|
6636
6707
|
await Promise.allSettled([...this.activeMessages]);
|
|
6637
6708
|
await this.disconnectChannel();
|
|
6638
|
-
await this.
|
|
6709
|
+
await this.disposeSafeEngine();
|
|
6639
6710
|
this.log().info("guardian", "stopped", {});
|
|
6640
6711
|
}
|
|
6641
6712
|
snapshot() {
|
|
@@ -6648,6 +6719,8 @@ var GuardianService = class {
|
|
|
6648
6719
|
dshUp: this.dshUp,
|
|
6649
6720
|
heartbeatAgeMs: this.lastHeartbeatAgeMs,
|
|
6650
6721
|
channelConnected: this.channel !== void 0,
|
|
6722
|
+
safeEngine: this.safeEngine?.kind,
|
|
6723
|
+
safeRuns: this.safeRuns.size,
|
|
6651
6724
|
pid: process.pid,
|
|
6652
6725
|
dshBin: this.dshBin,
|
|
6653
6726
|
relaunchedPid: this.state.relaunchedPid,
|
|
@@ -6702,8 +6775,11 @@ var GuardianService = class {
|
|
|
6702
6775
|
this.downStreak = 0;
|
|
6703
6776
|
await this.setSeenUp();
|
|
6704
6777
|
if (this.state.mode !== "standby" || this.channel !== void 0) {
|
|
6778
|
+
await this.stopAllSafeRuns();
|
|
6779
|
+
this.sessionIds.clear();
|
|
6705
6780
|
await this.disconnectChannel();
|
|
6706
6781
|
this.transcripts.clear();
|
|
6782
|
+
await this.disposeSafeEngine();
|
|
6707
6783
|
await this.setMode("standby");
|
|
6708
6784
|
}
|
|
6709
6785
|
return;
|
|
@@ -6754,6 +6830,7 @@ var GuardianService = class {
|
|
|
6754
6830
|
});
|
|
6755
6831
|
channel.on({
|
|
6756
6832
|
message: (msg) => this.track(this.handleMessage(msg)),
|
|
6833
|
+
cardAction: (event) => this.track(this.handleCardAction(event)),
|
|
6757
6834
|
error: (error) => {
|
|
6758
6835
|
this.log().fail("guardian-channel", error);
|
|
6759
6836
|
},
|
|
@@ -6870,13 +6947,16 @@ var GuardianService = class {
|
|
|
6870
6947
|
case "safemode-exit":
|
|
6871
6948
|
await this.exitSafeMode(msg);
|
|
6872
6949
|
return;
|
|
6950
|
+
case "safemode-stop":
|
|
6951
|
+
await this.handleStop(msg);
|
|
6952
|
+
return;
|
|
6873
6953
|
case "safemode-help":
|
|
6874
6954
|
await this.sendMarkdown(msg.chatId, safemodeHelpText(), msg.messageId);
|
|
6875
6955
|
return;
|
|
6876
6956
|
}
|
|
6877
6957
|
}
|
|
6878
6958
|
async enterSafeMode(msg) {
|
|
6879
|
-
if (this.state.mode === "safe") {
|
|
6959
|
+
if (this.state.mode === "safe" && this.safeEngine) {
|
|
6880
6960
|
await this.sendMarkdown(
|
|
6881
6961
|
msg.chatId,
|
|
6882
6962
|
"\u5DF2\u5728\u5B89\u5168\u6A21\u5F0F\u4E2D\u3002\u53D1\u9001\u666E\u901A\u6D88\u606F\u4E0E dsh \u6838\u5FC3\u5BF9\u8BDD\uFF1B`/safemode exit` \u9000\u51FA\u3002",
|
|
@@ -6924,16 +7004,26 @@ var GuardianService = class {
|
|
|
6924
7004
|
);
|
|
6925
7005
|
return;
|
|
6926
7006
|
}
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
7007
|
+
const engine = await this.resolveSafeEngine();
|
|
7008
|
+
if (!engine) {
|
|
7009
|
+
await this.sendMarkdown(
|
|
7010
|
+
msg.chatId,
|
|
7011
|
+
[
|
|
7012
|
+
"\u5B89\u5168\u6A21\u5F0F\u5F15\u64CE\u4E0D\u53EF\u7528\uFF1ASDK runtime \u672A\u5C31\u7EEA\u4E14 headless \u4E5F\u65E0\u6CD5\u542F\u52A8\u3002",
|
|
7013
|
+
"\u8BF7\u68C0\u67E5\u672C\u673A dsh \u5B89\u88C5\u4E0E pnpm \u53EF\u7528\u6027\u540E\u91CD\u8BD5\u3002"
|
|
7014
|
+
].join("\n"),
|
|
7015
|
+
msg.messageId
|
|
7016
|
+
);
|
|
7017
|
+
return;
|
|
7018
|
+
}
|
|
7019
|
+
this.safeEngine = engine;
|
|
6932
7020
|
await this.setMode("safe");
|
|
7021
|
+
const engineLabel = engine.kind === "sdk" ? "SDK \u6D41\u5F0F\u5F15\u64CE\uFF08\u5B9E\u65F6\u601D\u8003 / \u5DE5\u5177\u8C03\u7528 / \u6587\u5B57\u8F93\u51FA\uFF09" : engine.kind === "headless" ? "headless \u56DE\u9000\u5F15\u64CE\uFF08\u5B8C\u6210\u540E\u4E00\u6B21\u6027\u8F93\u51FA\uFF0C\u4EFB\u52A1\u671F\u95F4\u5361\u7247\u5B9E\u65F6\u663E\u793A\u6D3B\u52A8\u72B6\u6001\uFF09" : "\u6D4B\u8BD5\u5F15\u64CE";
|
|
6933
7022
|
await this.sendMarkdown(
|
|
6934
7023
|
msg.chatId,
|
|
6935
7024
|
[
|
|
6936
|
-
|
|
7025
|
+
`\u5B89\u5168\u6A21\u5F0F\u5DF2\u5C31\u7EEA\uFF1Adsh \u4E3B\u6838\u5FC3\u8FD0\u884C\u4E2D\uFF0C\u7B2C\u4E09\u65B9\u63D2\u4EF6\u672A\u52A0\u8F7D\u3002`,
|
|
7026
|
+
`\u5F15\u64CE\uFF1A${engineLabel}`,
|
|
6937
7027
|
"",
|
|
6938
7028
|
"\u73B0\u5728\u53EF\u4EE5\u76F4\u63A5\u5BF9\u8BDD\u8FDB\u884C\u81EA\u6108\uFF08\u5B9A\u4F4D / \u4FEE\u590D / \u7981\u7528\u635F\u574F\u63D2\u4EF6\uFF09\uFF0C\u4F8B\u5982\uFF1A",
|
|
6939
7029
|
"- \u201C\u5217\u51FA\u5F53\u524D profile \u5B89\u88C5\u7684\u63D2\u4EF6\u5E76\u68C0\u67E5\u54EA\u4E2A\u6700\u8FD1\u53D8\u574F\u201D",
|
|
@@ -6961,6 +7051,8 @@ var GuardianService = class {
|
|
|
6961
7051
|
`dsh \u662F\u5426\u5728\u7EBF\uFF1A${snapshot.dshUp ? "\u662F" : "\u5426"}`,
|
|
6962
7052
|
`\u5FC3\u8DF3\u9F84\uFF1A${snapshot.heartbeatAgeMs === void 0 ? "\u65E0" : `${snapshot.heartbeatAgeMs}ms`}`,
|
|
6963
7053
|
`\u98DE\u4E66\u901A\u9053\uFF1A${snapshot.channelConnected ? "\u5B88\u62A4\u5DF2\u63A5\u7BA1" : "\u672A\u8FDE\u63A5"}`,
|
|
7054
|
+
`\u5B89\u5168\u5F15\u64CE\uFF1A${snapshot.safeEngine ?? "\u672A\u5C31\u7EEA"}`,
|
|
7055
|
+
`\u5B89\u5168\u6A21\u5F0F\u8FD0\u884C\u4E2D\u4EFB\u52A1\uFF1A${snapshot.safeRuns}`,
|
|
6964
7056
|
`dsh bin\uFF1A${snapshot.dshBin ?? "\u672A\u53D1\u73B0"}`,
|
|
6965
7057
|
`\u5B88\u62A4 pid\uFF1A${snapshot.pid}`,
|
|
6966
7058
|
`\u5DF2\u89C2\u5BDF\u8FC7 dsh \u8FD0\u884C\uFF1A${snapshot.profileSeenUp ? "\u662F" : "\u5426"}`
|
|
@@ -7024,12 +7116,15 @@ var GuardianService = class {
|
|
|
7024
7116
|
msg.messageId
|
|
7025
7117
|
);
|
|
7026
7118
|
await delay(this.options.sendDelayMs);
|
|
7119
|
+
await this.stopAllSafeRuns();
|
|
7120
|
+
this.sessionIds.clear();
|
|
7027
7121
|
this.transcripts.clear();
|
|
7122
|
+
await this.disposeSafeEngine();
|
|
7028
7123
|
await this.disconnectChannel();
|
|
7029
7124
|
}
|
|
7030
7125
|
async runSafeTask(scope, msg) {
|
|
7031
|
-
const
|
|
7032
|
-
if (!
|
|
7126
|
+
const engine = this.safeEngine;
|
|
7127
|
+
if (!engine) {
|
|
7033
7128
|
await this.sendMarkdown(
|
|
7034
7129
|
msg.chatId,
|
|
7035
7130
|
"\u5B89\u5168\u6A21\u5F0F\u672A\u5C31\u7EEA\uFF0C\u8BF7\u5148\u53D1\u9001 `/safemode`\u3002",
|
|
@@ -7037,67 +7132,259 @@ var GuardianService = class {
|
|
|
7037
7132
|
);
|
|
7038
7133
|
return;
|
|
7039
7134
|
}
|
|
7135
|
+
const active = this.safeRuns.get(scope);
|
|
7136
|
+
if (active) {
|
|
7137
|
+
const elapsed = Math.round((Date.now() - active.startedAt) / 1e3);
|
|
7138
|
+
await this.sendMarkdown(
|
|
7139
|
+
msg.chatId,
|
|
7140
|
+
`\uFF08\u5B89\u5168\u6A21\u5F0F\uFF09\u4E0A\u4E00\u6761\u4EFB\u52A1\u4ECD\u5728\u5904\u7406\u4E2D\uFF0C\u5DF2\u8FD0\u884C ${elapsed}s\u3002\u53D1\u9001 \`/safemode stop\` \u6216\u70B9\u51FB\u5361\u7247 \u23F9 \u6309\u94AE\u53EF\u7EC8\u6B62\u3002`,
|
|
7141
|
+
msg.messageId
|
|
7142
|
+
);
|
|
7143
|
+
return;
|
|
7144
|
+
}
|
|
7040
7145
|
const transcript = this.transcripts.get(scope) ?? [];
|
|
7041
7146
|
const prompt = buildSafePrompt(transcript, msg.content);
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7147
|
+
const runId = randomUUID5();
|
|
7148
|
+
const density = this.options.safeDensity;
|
|
7149
|
+
const timeoutMs = this.options.safeTimeoutMs;
|
|
7150
|
+
const now = Date.now();
|
|
7151
|
+
let state = {
|
|
7152
|
+
...initialState,
|
|
7153
|
+
startedAtMs: now,
|
|
7154
|
+
lastActivityMs: now
|
|
7155
|
+
};
|
|
7156
|
+
let assistantOutput = "";
|
|
7157
|
+
let finalText;
|
|
7158
|
+
let errorText;
|
|
7159
|
+
let timedOut = false;
|
|
7160
|
+
let events = 0;
|
|
7161
|
+
const run = engine.adapter.run({
|
|
7162
|
+
runId,
|
|
7049
7163
|
prompt,
|
|
7050
7164
|
cwd: this.config?.workspaces.default,
|
|
7051
|
-
sessionId:
|
|
7165
|
+
sessionId: this.sessionIds.get(scope),
|
|
7052
7166
|
model: void 0,
|
|
7053
7167
|
images: void 0,
|
|
7054
7168
|
stopGraceMs: 5e3
|
|
7055
7169
|
});
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7170
|
+
this.safeRuns.set(scope, { stop: () => run.stop(), startedAt: now });
|
|
7171
|
+
this.log().info("guardian-safe", "task-start", {
|
|
7172
|
+
runId,
|
|
7173
|
+
scope,
|
|
7174
|
+
engine: engine.kind,
|
|
7175
|
+
timeoutMs
|
|
7176
|
+
});
|
|
7060
7177
|
try {
|
|
7061
|
-
|
|
7062
|
-
if (event.type === "text" && event.delta) textParts.push(event.delta);
|
|
7063
|
-
if (event.type === "final_text") finalText = event.content;
|
|
7064
|
-
if (event.type === "error") {
|
|
7065
|
-
errorText = event.message;
|
|
7066
|
-
terminal = true;
|
|
7067
|
-
}
|
|
7068
|
-
if (event.type === "done") terminal = true;
|
|
7069
|
-
}
|
|
7070
|
-
} catch (error) {
|
|
7071
|
-
errorText = error instanceof Error ? error.message : String(error);
|
|
7072
|
-
terminal = true;
|
|
7073
|
-
}
|
|
7074
|
-
if (!terminal) {
|
|
7075
|
-
await run.waitForExit(SAFE_RUN_TIMEOUT_MS);
|
|
7076
|
-
}
|
|
7077
|
-
if (errorText) {
|
|
7078
|
-
await this.sendMarkdown(
|
|
7178
|
+
await this.streamCard(
|
|
7079
7179
|
msg.chatId,
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7180
|
+
renderCard(state, density, Date.now()),
|
|
7181
|
+
async (controller) => {
|
|
7182
|
+
const ticker = setInterval(() => {
|
|
7183
|
+
void controller.update(renderCard(state, density, Date.now())).catch(() => {
|
|
7184
|
+
});
|
|
7185
|
+
}, SAFE_CARD_TICK_MS);
|
|
7186
|
+
ticker.unref?.();
|
|
7187
|
+
let timeoutTimer;
|
|
7188
|
+
try {
|
|
7189
|
+
const consume = async () => {
|
|
7190
|
+
for await (const event of run.events) {
|
|
7191
|
+
if (timedOut) return;
|
|
7192
|
+
events += 1;
|
|
7193
|
+
state = reduce(state, event);
|
|
7194
|
+
state = { ...state, lastActivityMs: Date.now() };
|
|
7195
|
+
if (event.type === "final_text") {
|
|
7196
|
+
finalText = event.content;
|
|
7197
|
+
} else if (event.type === "text") {
|
|
7198
|
+
assistantOutput += event.delta;
|
|
7199
|
+
}
|
|
7200
|
+
if (event.type === "system" && event.sessionId) {
|
|
7201
|
+
this.sessionIds.set(scope, event.sessionId);
|
|
7202
|
+
}
|
|
7203
|
+
if (event.type === "error") errorText = event.message;
|
|
7204
|
+
await controller.update(renderCard(state, density, Date.now()));
|
|
7205
|
+
}
|
|
7206
|
+
};
|
|
7207
|
+
const timeoutPromise = timeoutMs > 0 ? new Promise((resolve5) => {
|
|
7208
|
+
timeoutTimer = setTimeout(() => {
|
|
7209
|
+
if (timedOut) return;
|
|
7210
|
+
timedOut = true;
|
|
7211
|
+
state = markIdleTimeout(
|
|
7212
|
+
state,
|
|
7213
|
+
Math.round(timeoutMs / 6e4)
|
|
7214
|
+
);
|
|
7215
|
+
void run.stop();
|
|
7216
|
+
resolve5();
|
|
7217
|
+
}, timeoutMs);
|
|
7218
|
+
}) : void 0;
|
|
7219
|
+
if (timeoutPromise) {
|
|
7220
|
+
await Promise.race([consume(), timeoutPromise]);
|
|
7221
|
+
} else {
|
|
7222
|
+
await consume();
|
|
7223
|
+
}
|
|
7224
|
+
if (!timedOut && state.terminal === "running") {
|
|
7225
|
+
state = finalizeIfRunning(state);
|
|
7226
|
+
}
|
|
7227
|
+
await controller.update(renderCard(state, density, Date.now()));
|
|
7228
|
+
} finally {
|
|
7229
|
+
clearInterval(ticker);
|
|
7230
|
+
if (timeoutTimer !== void 0) clearTimeout(timeoutTimer);
|
|
7231
|
+
}
|
|
7232
|
+
},
|
|
7233
|
+
{ replyTo: msg.messageId }
|
|
7083
7234
|
);
|
|
7235
|
+
} catch (error) {
|
|
7236
|
+
this.log().fail("guardian-safe", error, { runId, scope });
|
|
7237
|
+
state = markInterrupted(state);
|
|
7238
|
+
try {
|
|
7239
|
+
await this.sendMarkdown(
|
|
7240
|
+
msg.chatId,
|
|
7241
|
+
`\u26A0\uFE0F \u5B89\u5168\u6A21\u5F0F\u4EFB\u52A1\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`,
|
|
7242
|
+
msg.messageId
|
|
7243
|
+
);
|
|
7244
|
+
} catch {
|
|
7245
|
+
}
|
|
7084
7246
|
return;
|
|
7247
|
+
} finally {
|
|
7248
|
+
this.safeRuns.delete(scope);
|
|
7085
7249
|
}
|
|
7086
|
-
const
|
|
7250
|
+
const durationMs = Date.now() - now;
|
|
7251
|
+
const terminal = state.terminal;
|
|
7252
|
+
this.log().info("guardian-safe", "task-end", {
|
|
7253
|
+
runId,
|
|
7254
|
+
scope,
|
|
7255
|
+
engine: engine.kind,
|
|
7256
|
+
terminal,
|
|
7257
|
+
events,
|
|
7258
|
+
durationMs,
|
|
7259
|
+
...errorText === void 0 ? {} : { errorText },
|
|
7260
|
+
outputLength: (finalText ?? assistantOutput).trim().length
|
|
7261
|
+
});
|
|
7262
|
+
if (timedOut || terminal === "interrupted" || terminal === "error" || terminal === "idle_timeout") {
|
|
7263
|
+
return;
|
|
7264
|
+
}
|
|
7265
|
+
const answer = finalText ?? assistantOutput.trim();
|
|
7087
7266
|
if (!answer) {
|
|
7088
|
-
|
|
7089
|
-
msg.chatId,
|
|
7090
|
-
"\uFF08\u5B89\u5168\u6A21\u5F0F \xB7 dsh \u6838\u5FC3\u672A\u8FD4\u56DE\u5185\u5BB9\uFF09",
|
|
7091
|
-
msg.messageId
|
|
7092
|
-
);
|
|
7267
|
+
this.log().warn("guardian-safe", "task-empty", { runId, scope });
|
|
7093
7268
|
return;
|
|
7094
7269
|
}
|
|
7095
|
-
await this.sendMarkdown(msg.chatId, answer, msg.messageId);
|
|
7096
7270
|
this.transcripts.set(scope, pushTranscript(transcript, [
|
|
7097
7271
|
{ role: "user", content: msg.content },
|
|
7098
7272
|
{ role: "assistant", content: answer }
|
|
7099
7273
|
]));
|
|
7100
7274
|
}
|
|
7275
|
+
async streamCard(chatId, initial, producer, options) {
|
|
7276
|
+
if (!this.channel) return;
|
|
7277
|
+
await this.channel.stream(chatId, { card: { initial, producer } }, options);
|
|
7278
|
+
}
|
|
7279
|
+
async handleCardAction(event) {
|
|
7280
|
+
const value = isRecord4(event.action.value) ? event.action.value : void 0;
|
|
7281
|
+
if (value?.cmd !== "stop") return;
|
|
7282
|
+
const scope = safeScopeForAction(event);
|
|
7283
|
+
const run = this.safeRuns.get(scope);
|
|
7284
|
+
if (!run) return;
|
|
7285
|
+
this.log().info("guardian-safe", "stop-requested", { scope });
|
|
7286
|
+
await run.stop();
|
|
7287
|
+
}
|
|
7288
|
+
async handleStop(msg) {
|
|
7289
|
+
const scope = this.scopeFor(msg);
|
|
7290
|
+
const run = this.safeRuns.get(scope);
|
|
7291
|
+
if (!run) {
|
|
7292
|
+
await this.sendMarkdown(
|
|
7293
|
+
msg.chatId,
|
|
7294
|
+
"\u5F53\u524D\u6CA1\u6709\u6B63\u5728\u8FD0\u884C\u7684\u5B89\u5168\u6A21\u5F0F\u4EFB\u52A1\u3002",
|
|
7295
|
+
msg.messageId
|
|
7296
|
+
);
|
|
7297
|
+
return;
|
|
7298
|
+
}
|
|
7299
|
+
await this.sendMarkdown(
|
|
7300
|
+
msg.chatId,
|
|
7301
|
+
"\u5DF2\u8BF7\u6C42\u7EC8\u6B62\u5F53\u524D\u4EFB\u52A1\uFF0C\u6B63\u5728\u505C\u6B62 dsh \u8FDB\u7A0B\u2026",
|
|
7302
|
+
msg.messageId
|
|
7303
|
+
);
|
|
7304
|
+
await run.stop();
|
|
7305
|
+
}
|
|
7306
|
+
async resolveSafeEngine() {
|
|
7307
|
+
if (this.options.adapter) {
|
|
7308
|
+
return { adapter: this.options.adapter, kind: "test" };
|
|
7309
|
+
}
|
|
7310
|
+
const mode = this.options.safeAdapterMode;
|
|
7311
|
+
if (mode === "sdk" || mode === "auto") {
|
|
7312
|
+
const launch = await this.provisionSafeSdk();
|
|
7313
|
+
if (launch) {
|
|
7314
|
+
this.log().info("guardian-safe", "engine-selected", { engine: "sdk" });
|
|
7315
|
+
return {
|
|
7316
|
+
adapter: new SdkDshAdapter({
|
|
7317
|
+
launch,
|
|
7318
|
+
provider: this.options.env?.DSH_LARK_PROVIDER ?? "deepseek-official",
|
|
7319
|
+
model: this.safeModel()
|
|
7320
|
+
}),
|
|
7321
|
+
kind: "sdk"
|
|
7322
|
+
};
|
|
7323
|
+
}
|
|
7324
|
+
if (mode === "sdk") return void 0;
|
|
7325
|
+
}
|
|
7326
|
+
if (!this.dshBin) return void 0;
|
|
7327
|
+
this.log().info("guardian-safe", "engine-selected", { engine: "headless" });
|
|
7328
|
+
return {
|
|
7329
|
+
adapter: new DshAdapter({
|
|
7330
|
+
command: "node",
|
|
7331
|
+
args: [this.dshBin, "--profile", this.state.safeProfile],
|
|
7332
|
+
stopGraceMs: 5e3
|
|
7333
|
+
}),
|
|
7334
|
+
kind: "headless"
|
|
7335
|
+
};
|
|
7336
|
+
}
|
|
7337
|
+
async provisionSafeSdk() {
|
|
7338
|
+
if (!this.dshBin) return void 0;
|
|
7339
|
+
const ensure = this.options.ensureSdkProfile ?? ensureSdkProfile;
|
|
7340
|
+
const result = await withTimeout2(
|
|
7341
|
+
ensure({
|
|
7342
|
+
home: this.options.home,
|
|
7343
|
+
env: this.options.env ?? process.env,
|
|
7344
|
+
profile: DEFAULT_SAFE_SDK_PROFILE,
|
|
7345
|
+
bridgeTools: false
|
|
7346
|
+
}),
|
|
7347
|
+
SAFE_SDK_PROVISION_TIMEOUT_MS
|
|
7348
|
+
);
|
|
7349
|
+
if (!result) {
|
|
7350
|
+
this.log().warn("guardian-safe", "sdk-provision-timeout", {
|
|
7351
|
+
profile: DEFAULT_SAFE_SDK_PROFILE
|
|
7352
|
+
});
|
|
7353
|
+
return void 0;
|
|
7354
|
+
}
|
|
7355
|
+
if (!result.ok) {
|
|
7356
|
+
this.log().warn("guardian-safe", "sdk-provision-failed", {
|
|
7357
|
+
profile: DEFAULT_SAFE_SDK_PROFILE,
|
|
7358
|
+
error: result.error
|
|
7359
|
+
});
|
|
7360
|
+
return void 0;
|
|
7361
|
+
}
|
|
7362
|
+
return resolveSdkLaunch({
|
|
7363
|
+
home: this.options.home,
|
|
7364
|
+
env: this.options.env ?? process.env,
|
|
7365
|
+
profile: DEFAULT_SAFE_SDK_PROFILE
|
|
7366
|
+
});
|
|
7367
|
+
}
|
|
7368
|
+
safeModel() {
|
|
7369
|
+
const explicit = this.options.env?.DSH_LARK_MODEL;
|
|
7370
|
+
if (explicit) return explicit;
|
|
7371
|
+
return readDshDefaultModel(this.options.home, this.options.env ?? process.env) ?? "deepseek-v4-flash";
|
|
7372
|
+
}
|
|
7373
|
+
async stopAllSafeRuns() {
|
|
7374
|
+
const runs = [...this.safeRuns.values()];
|
|
7375
|
+
this.safeRuns.clear();
|
|
7376
|
+
await Promise.allSettled(runs.map((run) => run.stop()));
|
|
7377
|
+
}
|
|
7378
|
+
async disposeSafeEngine() {
|
|
7379
|
+
const engine = this.safeEngine;
|
|
7380
|
+
this.safeEngine = void 0;
|
|
7381
|
+
if (!engine) return;
|
|
7382
|
+
try {
|
|
7383
|
+
await engine.adapter.dispose?.();
|
|
7384
|
+
} catch (error) {
|
|
7385
|
+
this.log().fail("guardian-safe", error);
|
|
7386
|
+
}
|
|
7387
|
+
}
|
|
7101
7388
|
};
|
|
7102
7389
|
function buildSafePrompt(transcript, current) {
|
|
7103
7390
|
if (transcript.length === 0) return current;
|
|
@@ -7119,12 +7406,58 @@ async function defaultRunPluginList(bin, dshProfile) {
|
|
|
7119
7406
|
function delay(ms) {
|
|
7120
7407
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
7121
7408
|
}
|
|
7409
|
+
function withTimeout2(promise, ms) {
|
|
7410
|
+
return new Promise((resolve5) => {
|
|
7411
|
+
const timer = setTimeout(() => resolve5(void 0), ms);
|
|
7412
|
+
timer.unref?.();
|
|
7413
|
+
promise.then(
|
|
7414
|
+
(value) => {
|
|
7415
|
+
clearTimeout(timer);
|
|
7416
|
+
resolve5(value);
|
|
7417
|
+
},
|
|
7418
|
+
() => {
|
|
7419
|
+
clearTimeout(timer);
|
|
7420
|
+
resolve5(void 0);
|
|
7421
|
+
}
|
|
7422
|
+
);
|
|
7423
|
+
});
|
|
7424
|
+
}
|
|
7425
|
+
function isRecord4(value) {
|
|
7426
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7427
|
+
}
|
|
7428
|
+
function safeScopeForAction(event) {
|
|
7429
|
+
const raw = isRecord4(event.raw) ? event.raw : void 0;
|
|
7430
|
+
const message = isRecord4(raw?.message) ? raw.message : void 0;
|
|
7431
|
+
const threadId = typeof message?.thread_id === "string" ? message.thread_id : void 0;
|
|
7432
|
+
return threadId ? `${event.chatId}:${threadId}` : event.chatId;
|
|
7433
|
+
}
|
|
7434
|
+
function readDshDefaultModel(home, env) {
|
|
7435
|
+
try {
|
|
7436
|
+
const file = join15(resolveDshHome(home, env), "settings.yaml");
|
|
7437
|
+
const doc = parse(readFileSync4(file, "utf8"));
|
|
7438
|
+
const value = doc?.["agent-default-model"];
|
|
7439
|
+
return typeof value === "string" && value ? value : void 0;
|
|
7440
|
+
} catch {
|
|
7441
|
+
return void 0;
|
|
7442
|
+
}
|
|
7443
|
+
}
|
|
7122
7444
|
function parseFreshness2(value) {
|
|
7123
7445
|
const raw = value?.trim();
|
|
7124
7446
|
if (!raw) return 6e5;
|
|
7125
7447
|
const parsed = Number(raw);
|
|
7126
7448
|
return Number.isInteger(parsed) && parsed >= 0 ? parsed : 6e5;
|
|
7127
7449
|
}
|
|
7450
|
+
function parseSafeAdapterMode(value) {
|
|
7451
|
+
const normalized = value?.trim().toLowerCase();
|
|
7452
|
+
if (normalized === "sdk" || normalized === "headless") return normalized;
|
|
7453
|
+
return "auto";
|
|
7454
|
+
}
|
|
7455
|
+
function parsePositiveInt2(value, fallback) {
|
|
7456
|
+
const raw = value?.trim();
|
|
7457
|
+
if (!raw) return fallback;
|
|
7458
|
+
const parsed = Number(raw);
|
|
7459
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
7460
|
+
}
|
|
7128
7461
|
function defined(input) {
|
|
7129
7462
|
const output = {};
|
|
7130
7463
|
for (const [key, value] of Object.entries(input)) {
|
|
@@ -7161,6 +7494,12 @@ async function buildGuardianService(env, overrides = {}) {
|
|
|
7161
7494
|
pollMs: env.guardianPollMs,
|
|
7162
7495
|
staleMs: env.guardianStaleMs,
|
|
7163
7496
|
engineDeadMs: env.guardianEngineDeadMs,
|
|
7497
|
+
safeAdapterMode: parseSafeAdapterMode(process.env.DSH_LARK_GUARDIAN_SAFE_ADAPTER),
|
|
7498
|
+
safeTimeoutMs: parsePositiveInt2(
|
|
7499
|
+
process.env.DSH_LARK_GUARDIAN_SAFE_TIMEOUT_MS,
|
|
7500
|
+
SAFE_RUN_TIMEOUT_MS
|
|
7501
|
+
),
|
|
7502
|
+
safeDensity: parseCardDensity(process.env.DSH_LARK_GUARDIAN_CARD_DENSITY) ?? "detailed",
|
|
7164
7503
|
...overrides
|
|
7165
7504
|
});
|
|
7166
7505
|
}
|
|
@@ -7252,7 +7591,7 @@ function waitForShutdown2() {
|
|
|
7252
7591
|
|
|
7253
7592
|
// src/cli.ts
|
|
7254
7593
|
function packageVersion() {
|
|
7255
|
-
const raw =
|
|
7594
|
+
const raw = readFileSync5(new URL("../package.json", import.meta.url), "utf8");
|
|
7256
7595
|
const pkg = JSON.parse(raw);
|
|
7257
7596
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
7258
7597
|
}
|