dominds 1.4.2 → 1.5.2
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 +24 -0
- package/README.zh.md +24 -0
- package/dist/apps/app-json.js +38 -3
- package/dist/apps/dialog-run-controls.js +4 -0
- package/dist/apps/enabled-apps.js +8 -1
- package/dist/apps/installed-file.js +207 -0
- package/dist/apps/run-app-json.js +6 -6
- package/dist/apps/runtime-port.js +91 -0
- package/dist/apps/runtime.js +316 -68
- package/dist/apps-host/client.js +153 -3
- package/dist/apps-host/host.js +339 -2
- package/dist/apps-host/ipc-types.js +215 -30
- package/dist/cli/install.js +21 -1
- package/dist/dialog-fork.js +609 -0
- package/dist/dialog.js +2 -2
- package/dist/docs/agent-priming.md +38 -0
- package/dist/docs/agent-priming.zh.md +34 -0
- package/dist/docs/app-constitution.md +153 -2
- package/dist/docs/app-constitution.zh.md +153 -2
- package/dist/docs/dialog-persistence.md +31 -0
- package/dist/docs/dialog-persistence.zh.md +31 -0
- package/dist/docs/dialog-system.md +29 -0
- package/dist/docs/dialog-system.zh.md +29 -0
- package/dist/docs/kernel-app-architecture.md +286 -0
- package/dist/docs/kernel-app-architecture.zh.md +285 -0
- package/dist/llm/defaults.yaml +16 -0
- package/dist/llm/driver-entry.js +28 -0
- package/dist/llm/driver-v2/context-health.js +121 -0
- package/dist/llm/driver-v2/context.js +56 -0
- package/dist/llm/driver-v2/core.js +1545 -0
- package/dist/llm/driver-v2/index.js +26 -0
- package/dist/llm/driver-v2/orchestrator.js +158 -0
- package/dist/llm/driver-v2/policy.js +129 -0
- package/dist/llm/driver-v2/restore-dialog-hierarchy.js +73 -0
- package/dist/llm/driver-v2/round.js +366 -0
- package/dist/llm/driver-v2/runtime-utils.js +365 -0
- package/dist/llm/driver-v2/saying-events.js +20 -0
- package/dist/llm/driver-v2/subdialog-txn.js +42 -0
- package/dist/llm/driver-v2/supdialog-response.js +400 -0
- package/dist/llm/driver-v2/tellask-bridge.js +1148 -0
- package/dist/llm/driver-v2/types.js +10 -0
- package/dist/llm/driver-v2-ref-only/context-health.js +121 -0
- package/dist/llm/driver-v2-ref-only/context.js +17 -0
- package/dist/llm/driver-v2-ref-only/core.js +1710 -0
- package/dist/llm/driver-v2-ref-only/index.js +26 -0
- package/dist/llm/driver-v2-ref-only/orchestrator.js +158 -0
- package/dist/llm/driver-v2-ref-only/policy.js +129 -0
- package/dist/llm/driver-v2-ref-only/restore-dialog-hierarchy.js +73 -0
- package/dist/llm/driver-v2-ref-only/round.js +366 -0
- package/dist/llm/driver-v2-ref-only/runtime-utils.js +473 -0
- package/dist/llm/driver-v2-ref-only/saying-events.js +18 -0
- package/dist/llm/driver-v2-ref-only/subdialog-txn.js +42 -0
- package/dist/llm/driver-v2-ref-only/supdialog-response.js +453 -0
- package/dist/llm/driver-v2-ref-only/tellask-bridge.js +1178 -0
- package/dist/llm/driver-v2-ref-only/types.js +10 -0
- package/dist/llm/gen/anthropic.js +68 -15
- package/dist/llm/gen/codex.js +59 -10
- package/dist/llm/gen/openai-compatible.js +38 -9
- package/dist/llm/gen/openai.js +58 -11
- package/dist/llm/gen/tool-output-limit.js +50 -0
- package/dist/llm/kernel-driver/subdialog.js +23 -12
- package/dist/llm/kernel-driver/tellask-special.js +20 -4
- package/dist/minds/load.js +7 -0
- package/dist/persistence.js +216 -30
- package/dist/priming.js +171 -18
- package/dist/server/api-routes.js +82 -0
- package/dist/server/setup-routes.js +15 -0
- package/dist/shared/types/storage.js +77 -0
- package/dist/static/assets/{_basePickBy-B2o4z1Hf.js → _basePickBy-B-A5XrWM.js} +3 -3
- package/dist/static/assets/{_basePickBy-B2o4z1Hf.js.map → _basePickBy-B-A5XrWM.js.map} +1 -1
- package/dist/static/assets/{_baseUniq-CLmcxjdl.js → _baseUniq-BANLb0cu.js} +2 -2
- package/dist/static/assets/{_baseUniq-CLmcxjdl.js.map → _baseUniq-BANLb0cu.js.map} +1 -1
- package/dist/static/assets/{arc-CymD_KN7.js → arc-CYZYnojf.js} +2 -2
- package/dist/static/assets/{arc-CymD_KN7.js.map → arc-CYZYnojf.js.map} +1 -1
- package/dist/static/assets/{architectureDiagram-VXUJARFQ-DJQfSJUH.js → architectureDiagram-VXUJARFQ-Cxf4pmYG.js} +7 -7
- package/dist/static/assets/{architectureDiagram-VXUJARFQ-DJQfSJUH.js.map → architectureDiagram-VXUJARFQ-Cxf4pmYG.js.map} +1 -1
- package/dist/static/assets/{blockDiagram-VD42YOAC-pHVz60D0.js → blockDiagram-VD42YOAC-wvs0G30c.js} +7 -7
- package/dist/static/assets/{blockDiagram-VD42YOAC-pHVz60D0.js.map → blockDiagram-VD42YOAC-wvs0G30c.js.map} +1 -1
- package/dist/static/assets/{c4Diagram-YG6GDRKO-B0WnCfAT.js → c4Diagram-YG6GDRKO-BKFNexn4.js} +3 -3
- package/dist/static/assets/{c4Diagram-YG6GDRKO-B0WnCfAT.js.map → c4Diagram-YG6GDRKO-BKFNexn4.js.map} +1 -1
- package/dist/static/assets/{channel-CX9BlKil.js → channel-_1qpxJWy.js} +2 -2
- package/dist/static/assets/{channel-CX9BlKil.js.map → channel-_1qpxJWy.js.map} +1 -1
- package/dist/static/assets/{chunk-4BX2VUAB-lXArRj3o.js → chunk-4BX2VUAB-BIdC0phm.js} +2 -2
- package/dist/static/assets/{chunk-4BX2VUAB-lXArRj3o.js.map → chunk-4BX2VUAB-BIdC0phm.js.map} +1 -1
- package/dist/static/assets/{chunk-55IACEB6-CdqwynH9.js → chunk-55IACEB6-BNvGenQ9.js} +2 -2
- package/dist/static/assets/{chunk-55IACEB6-CdqwynH9.js.map → chunk-55IACEB6-BNvGenQ9.js.map} +1 -1
- package/dist/static/assets/{chunk-B4BG7PRW-Y-uXcJst.js → chunk-B4BG7PRW-jmf-1Wv7.js} +5 -5
- package/dist/static/assets/{chunk-B4BG7PRW-Y-uXcJst.js.map → chunk-B4BG7PRW-jmf-1Wv7.js.map} +1 -1
- package/dist/static/assets/{chunk-DI55MBZ5-C5xSbRST.js → chunk-DI55MBZ5-nmEmcikR.js} +4 -4
- package/dist/static/assets/{chunk-DI55MBZ5-C5xSbRST.js.map → chunk-DI55MBZ5-nmEmcikR.js.map} +1 -1
- package/dist/static/assets/{chunk-FMBD7UC4-5uefwCjI.js → chunk-FMBD7UC4-kGysaq_j.js} +2 -2
- package/dist/static/assets/{chunk-FMBD7UC4-5uefwCjI.js.map → chunk-FMBD7UC4-kGysaq_j.js.map} +1 -1
- package/dist/static/assets/{chunk-QN33PNHL-DzWVcvpI.js → chunk-QN33PNHL-8JwMLFIJ.js} +2 -2
- package/dist/static/assets/{chunk-QN33PNHL-DzWVcvpI.js.map → chunk-QN33PNHL-8JwMLFIJ.js.map} +1 -1
- package/dist/static/assets/{chunk-QZHKN3VN-BrrvAZdP.js → chunk-QZHKN3VN-DZleEj00.js} +2 -2
- package/dist/static/assets/{chunk-QZHKN3VN-BrrvAZdP.js.map → chunk-QZHKN3VN-DZleEj00.js.map} +1 -1
- package/dist/static/assets/{chunk-TZMSLE5B-DyKOlPTY.js → chunk-TZMSLE5B-CXxl_uqH.js} +2 -2
- package/dist/static/assets/{chunk-TZMSLE5B-DyKOlPTY.js.map → chunk-TZMSLE5B-CXxl_uqH.js.map} +1 -1
- package/dist/static/assets/{classDiagram-2ON5EDUG-FCrnlCWC.js → classDiagram-2ON5EDUG-C-7R0QB6.js} +6 -6
- package/dist/static/assets/{classDiagram-2ON5EDUG-FCrnlCWC.js.map → classDiagram-2ON5EDUG-C-7R0QB6.js.map} +1 -1
- package/dist/static/assets/{classDiagram-v2-WZHVMYZB-FCrnlCWC.js → classDiagram-v2-WZHVMYZB-C-7R0QB6.js} +6 -6
- package/dist/static/assets/{classDiagram-v2-WZHVMYZB-FCrnlCWC.js.map → classDiagram-v2-WZHVMYZB-C-7R0QB6.js.map} +1 -1
- package/dist/static/assets/{clone-BlI81KqZ.js → clone-BwOKYSj8.js} +2 -2
- package/dist/static/assets/{clone-BlI81KqZ.js.map → clone-BwOKYSj8.js.map} +1 -1
- package/dist/static/assets/{cose-bilkent-S5V4N54A-yM7S2atz.js → cose-bilkent-S5V4N54A-BCBalM7p.js} +2 -2
- package/dist/static/assets/{cose-bilkent-S5V4N54A-yM7S2atz.js.map → cose-bilkent-S5V4N54A-BCBalM7p.js.map} +1 -1
- package/dist/static/assets/{dagre-6UL2VRFP-BcweuZHt.js → dagre-6UL2VRFP-uV2ekQoj.js} +7 -7
- package/dist/static/assets/{dagre-6UL2VRFP-BcweuZHt.js.map → dagre-6UL2VRFP-uV2ekQoj.js.map} +1 -1
- package/dist/static/assets/{diagram-PSM6KHXK-D4-QwLW1.js → diagram-PSM6KHXK-D-ZMog1-.js} +8 -8
- package/dist/static/assets/{diagram-PSM6KHXK-D4-QwLW1.js.map → diagram-PSM6KHXK-D-ZMog1-.js.map} +1 -1
- package/dist/static/assets/{diagram-QEK2KX5R-BVbuejJn.js → diagram-QEK2KX5R-BThSELUH.js} +7 -7
- package/dist/static/assets/{diagram-QEK2KX5R-BVbuejJn.js.map → diagram-QEK2KX5R-BThSELUH.js.map} +1 -1
- package/dist/static/assets/{diagram-S2PKOQOG-pB6N6Tq_.js → diagram-S2PKOQOG-Di-YN5cd.js} +7 -7
- package/dist/static/assets/{diagram-S2PKOQOG-pB6N6Tq_.js.map → diagram-S2PKOQOG-Di-YN5cd.js.map} +1 -1
- package/dist/static/assets/{erDiagram-Q2GNP2WA-DLKmthuw.js → erDiagram-Q2GNP2WA-lBZ9DITn.js} +5 -5
- package/dist/static/assets/{erDiagram-Q2GNP2WA-DLKmthuw.js.map → erDiagram-Q2GNP2WA-lBZ9DITn.js.map} +1 -1
- package/dist/static/assets/{flowDiagram-NV44I4VS-BsBhWukh.js → flowDiagram-NV44I4VS-C_60PNQR.js} +6 -6
- package/dist/static/assets/{flowDiagram-NV44I4VS-BsBhWukh.js.map → flowDiagram-NV44I4VS-C_60PNQR.js.map} +1 -1
- package/dist/static/assets/{ganttDiagram-JELNMOA3-Debz-J-C.js → ganttDiagram-JELNMOA3-Dvqq-VHJ.js} +3 -3
- package/dist/static/assets/{ganttDiagram-JELNMOA3-Debz-J-C.js.map → ganttDiagram-JELNMOA3-Dvqq-VHJ.js.map} +1 -1
- package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-BnAPFBGR.js → gitGraphDiagram-V2S2FVAM-BTj8orRe.js} +8 -8
- package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-BnAPFBGR.js.map → gitGraphDiagram-V2S2FVAM-BTj8orRe.js.map} +1 -1
- package/dist/static/assets/{graph-DbzWiBNK.js → graph-BqCzR2Nl.js} +3 -3
- package/dist/static/assets/{graph-DbzWiBNK.js.map → graph-BqCzR2Nl.js.map} +1 -1
- package/dist/static/assets/{index-B-8J28g7.js → index-DrTqAfFy.js} +386 -201
- package/dist/static/assets/index-DrTqAfFy.js.map +1 -0
- package/dist/static/assets/{infoDiagram-HS3SLOUP-CZ5hWoxV.js → infoDiagram-HS3SLOUP-DlC6wsrv.js} +6 -6
- package/dist/static/assets/{infoDiagram-HS3SLOUP-CZ5hWoxV.js.map → infoDiagram-HS3SLOUP-DlC6wsrv.js.map} +1 -1
- package/dist/static/assets/{journeyDiagram-XKPGCS4Q-CKN3oSxk.js → journeyDiagram-XKPGCS4Q-Dg_RgtQX.js} +5 -5
- package/dist/static/assets/{journeyDiagram-XKPGCS4Q-CKN3oSxk.js.map → journeyDiagram-XKPGCS4Q-Dg_RgtQX.js.map} +1 -1
- package/dist/static/assets/{kanban-definition-3W4ZIXB7-BQCMklfJ.js → kanban-definition-3W4ZIXB7-DuGS3lId.js} +3 -3
- package/dist/static/assets/{kanban-definition-3W4ZIXB7-BQCMklfJ.js.map → kanban-definition-3W4ZIXB7-DuGS3lId.js.map} +1 -1
- package/dist/static/assets/{layout-C5B58szc.js → layout-FDz2bstZ.js} +5 -5
- package/dist/static/assets/{layout-C5B58szc.js.map → layout-FDz2bstZ.js.map} +1 -1
- package/dist/static/assets/{linear-_32fut6G.js → linear-CzsdvPGb.js} +2 -2
- package/dist/static/assets/{linear-_32fut6G.js.map → linear-CzsdvPGb.js.map} +1 -1
- package/dist/static/assets/{mindmap-definition-VGOIOE7T-C_goMzjx.js → mindmap-definition-VGOIOE7T-WsAF5UNp.js} +4 -4
- package/dist/static/assets/{mindmap-definition-VGOIOE7T-C_goMzjx.js.map → mindmap-definition-VGOIOE7T-WsAF5UNp.js.map} +1 -1
- package/dist/static/assets/{pieDiagram-ADFJNKIX-BQ2n0cOB.js → pieDiagram-ADFJNKIX-DJpRJ5ei.js} +8 -8
- package/dist/static/assets/{pieDiagram-ADFJNKIX-BQ2n0cOB.js.map → pieDiagram-ADFJNKIX-DJpRJ5ei.js.map} +1 -1
- package/dist/static/assets/{quadrantDiagram-AYHSOK5B-BLg7_neg.js → quadrantDiagram-AYHSOK5B-CMyIzTkY.js} +3 -3
- package/dist/static/assets/{quadrantDiagram-AYHSOK5B-BLg7_neg.js.map → quadrantDiagram-AYHSOK5B-CMyIzTkY.js.map} +1 -1
- package/dist/static/assets/{requirementDiagram-UZGBJVZJ-DwkJt0zi.js → requirementDiagram-UZGBJVZJ-D_yqVXGu.js} +4 -4
- package/dist/static/assets/{requirementDiagram-UZGBJVZJ-DwkJt0zi.js.map → requirementDiagram-UZGBJVZJ-D_yqVXGu.js.map} +1 -1
- package/dist/static/assets/{sankeyDiagram-TZEHDZUN-DmxmatUB.js → sankeyDiagram-TZEHDZUN-D4-cF724.js} +2 -2
- package/dist/static/assets/{sankeyDiagram-TZEHDZUN-DmxmatUB.js.map → sankeyDiagram-TZEHDZUN-D4-cF724.js.map} +1 -1
- package/dist/static/assets/{sequenceDiagram-WL72ISMW-KHU_eApU.js → sequenceDiagram-WL72ISMW-B7J3gWYN.js} +4 -4
- package/dist/static/assets/{sequenceDiagram-WL72ISMW-KHU_eApU.js.map → sequenceDiagram-WL72ISMW-B7J3gWYN.js.map} +1 -1
- package/dist/static/assets/{stateDiagram-FKZM4ZOC-B3DBCxAL.js → stateDiagram-FKZM4ZOC-DwEYYCcu.js} +9 -9
- package/dist/static/assets/{stateDiagram-FKZM4ZOC-B3DBCxAL.js.map → stateDiagram-FKZM4ZOC-DwEYYCcu.js.map} +1 -1
- package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-C-uIk7gh.js → stateDiagram-v2-4FDKWEC3-D4LOOQV5.js} +5 -5
- package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-C-uIk7gh.js.map → stateDiagram-v2-4FDKWEC3-D4LOOQV5.js.map} +1 -1
- package/dist/static/assets/{timeline-definition-IT6M3QCI-SysEcQCC.js → timeline-definition-IT6M3QCI-CyG-TJ_A.js} +3 -3
- package/dist/static/assets/{timeline-definition-IT6M3QCI-SysEcQCC.js.map → timeline-definition-IT6M3QCI-CyG-TJ_A.js.map} +1 -1
- package/dist/static/assets/{treemap-GDKQZRPO-d0AbKEc4.js → treemap-GDKQZRPO-yY4GiKmU.js} +5 -5
- package/dist/static/assets/{treemap-GDKQZRPO-d0AbKEc4.js.map → treemap-GDKQZRPO-yY4GiKmU.js.map} +1 -1
- package/dist/static/assets/{xychartDiagram-PRI3JC2R-CmSQMxUh.js → xychartDiagram-PRI3JC2R-5TYN_q15.js} +3 -3
- package/dist/static/assets/{xychartDiagram-PRI3JC2R-CmSQMxUh.js.map → xychartDiagram-PRI3JC2R-5TYN_q15.js.map} +1 -1
- package/dist/static/index.html +1 -1
- package/dist/team.js +33 -4
- package/dist/tools/app-reminders.js +280 -0
- package/dist/tools/prompts/memory/en/errors.md +155 -0
- package/dist/tools/prompts/memory/en/index.md +47 -0
- package/dist/tools/prompts/memory/en/principles.md +79 -0
- package/dist/tools/prompts/memory/en/scenarios.md +174 -0
- package/dist/tools/prompts/memory/en/tools.md +154 -0
- package/dist/tools/prompts/memory/zh/errors.md +155 -0
- package/dist/tools/prompts/memory/zh/index.md +47 -0
- package/dist/tools/prompts/memory/zh/principles.md +79 -0
- package/dist/tools/prompts/memory/zh/scenarios.md +174 -0
- package/dist/tools/prompts/memory/zh/tools.md +154 -0
- package/dist/tools/ripgrep.js +197 -63
- package/package.json +2 -2
- package/dist/static/assets/index-B-8J28g7.js.map +0 -1
|
@@ -0,0 +1,1710 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.driveDialogStreamCoreV2 = driveDialogStreamCoreV2;
|
|
4
|
+
const dialog_1 = require("../../dialog");
|
|
5
|
+
const dialog_run_state_1 = require("../../dialog-run-state");
|
|
6
|
+
const evt_registry_1 = require("../../evt-registry");
|
|
7
|
+
const log_1 = require("../../log");
|
|
8
|
+
const load_1 = require("../../minds/load");
|
|
9
|
+
const persistence_1 = require("../../persistence");
|
|
10
|
+
const diligence_1 = require("../../shared/diligence");
|
|
11
|
+
const driver_messages_1 = require("../../shared/i18n/driver-messages");
|
|
12
|
+
const runtime_language_1 = require("../../shared/runtime-language");
|
|
13
|
+
const id_1 = require("../../shared/utils/id");
|
|
14
|
+
const time_1 = require("../../shared/utils/time");
|
|
15
|
+
const taskdoc_1 = require("../../utils/taskdoc");
|
|
16
|
+
const client_1 = require("../client");
|
|
17
|
+
const registry_1 = require("../gen/registry");
|
|
18
|
+
const tools_projection_1 = require("../tools-projection");
|
|
19
|
+
const context_1 = require("./context");
|
|
20
|
+
const context_health_1 = require("./context-health");
|
|
21
|
+
const policy_1 = require("./policy");
|
|
22
|
+
const runtime_utils_1 = require("./runtime-utils");
|
|
23
|
+
const saying_events_1 = require("./saying-events");
|
|
24
|
+
const tellask_bridge_1 = require("./tellask-bridge");
|
|
25
|
+
class DialogInterruptedError extends Error {
|
|
26
|
+
constructor(reason) {
|
|
27
|
+
super('Dialog interrupted');
|
|
28
|
+
this.reason = reason;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function throwIfAborted(abortSignal, dialog) {
|
|
32
|
+
if (!abortSignal?.aborted) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const stopRequested = (0, dialog_run_state_1.getStopRequestedReason)(dialog.id);
|
|
36
|
+
if (stopRequested === 'emergency_stop') {
|
|
37
|
+
throw new DialogInterruptedError({ kind: 'emergency_stop' });
|
|
38
|
+
}
|
|
39
|
+
if (stopRequested === 'user_stop') {
|
|
40
|
+
throw new DialogInterruptedError({ kind: 'user_stop' });
|
|
41
|
+
}
|
|
42
|
+
throw new DialogInterruptedError({ kind: 'system_stop', detail: 'Aborted.' });
|
|
43
|
+
}
|
|
44
|
+
function resolveMemberDiligencePushMax(team, agentId) {
|
|
45
|
+
const member = team.getMember(agentId);
|
|
46
|
+
if (member && member.diligence_push_max !== undefined) {
|
|
47
|
+
return member.diligence_push_max;
|
|
48
|
+
}
|
|
49
|
+
return diligence_1.DEFAULT_DILIGENCE_PUSH_MAX;
|
|
50
|
+
}
|
|
51
|
+
function emitDiligenceBudgetEvent(dlg, options) {
|
|
52
|
+
const maxInjectCount = Math.max(0, Math.floor(options.maxInjectCount));
|
|
53
|
+
const remainingCount = Math.max(0, Math.floor(options.nextRemainingBudget));
|
|
54
|
+
(0, evt_registry_1.postDialogEvent)(dlg, {
|
|
55
|
+
type: 'diligence_budget_evt',
|
|
56
|
+
maxInjectCount,
|
|
57
|
+
injectedCount: Math.max(0, maxInjectCount - remainingCount),
|
|
58
|
+
remainingCount,
|
|
59
|
+
disableDiligencePush: dlg.disableDiligencePush,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function resolveUpNextPrompt(dlg) {
|
|
63
|
+
const upNext = dlg.takeUpNext();
|
|
64
|
+
if (!upNext) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
content: upNext.prompt,
|
|
69
|
+
msgId: upNext.msgId,
|
|
70
|
+
grammar: upNext.grammar ?? 'markdown',
|
|
71
|
+
userLanguageCode: upNext.userLanguageCode,
|
|
72
|
+
q4hAnswerCallIds: upNext.q4hAnswerCallIds,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function isUserOriginPrompt(prompt) {
|
|
76
|
+
if (!prompt) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return (prompt.origin ?? 'user') === 'user';
|
|
80
|
+
}
|
|
81
|
+
function normalizeQ4HAnswerCallIds(raw) {
|
|
82
|
+
if (!raw || raw.length === 0)
|
|
83
|
+
return undefined;
|
|
84
|
+
const seen = new Set();
|
|
85
|
+
const normalized = [];
|
|
86
|
+
for (const value of raw) {
|
|
87
|
+
const callId = value.trim();
|
|
88
|
+
if (callId === '' || seen.has(callId))
|
|
89
|
+
continue;
|
|
90
|
+
seen.add(callId);
|
|
91
|
+
normalized.push(callId);
|
|
92
|
+
}
|
|
93
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
94
|
+
}
|
|
95
|
+
async function emitUserMarkdown(dlg, content) {
|
|
96
|
+
if (!content.trim()) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
await dlg.markdownStart();
|
|
100
|
+
await dlg.markdownChunk(content);
|
|
101
|
+
await dlg.markdownFinish();
|
|
102
|
+
}
|
|
103
|
+
function resolveModelInfo(providerCfg, model) {
|
|
104
|
+
return providerCfg.models[model];
|
|
105
|
+
}
|
|
106
|
+
const DRIVER_V2_DEFAULT_RETRY_POLICY = {
|
|
107
|
+
maxRetries: 5,
|
|
108
|
+
initialDelayMs: 1000,
|
|
109
|
+
backoffMultiplier: 2,
|
|
110
|
+
maxDelayMs: 30000,
|
|
111
|
+
};
|
|
112
|
+
const DRIVER_V2_EMPTY_LLM_RESPONSE_ERROR_CODE = 'DOMINDS_LLM_EMPTY_RESPONSE';
|
|
113
|
+
function resolveRetryMaxRetries(raw) {
|
|
114
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
|
|
115
|
+
return DRIVER_V2_DEFAULT_RETRY_POLICY.maxRetries;
|
|
116
|
+
}
|
|
117
|
+
const normalized = Math.floor(raw);
|
|
118
|
+
if (normalized < 0) {
|
|
119
|
+
return DRIVER_V2_DEFAULT_RETRY_POLICY.maxRetries;
|
|
120
|
+
}
|
|
121
|
+
return normalized;
|
|
122
|
+
}
|
|
123
|
+
function resolveRetryInitialDelayMs(raw) {
|
|
124
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
|
|
125
|
+
return DRIVER_V2_DEFAULT_RETRY_POLICY.initialDelayMs;
|
|
126
|
+
}
|
|
127
|
+
const normalized = Math.floor(raw);
|
|
128
|
+
if (normalized < 0) {
|
|
129
|
+
return DRIVER_V2_DEFAULT_RETRY_POLICY.initialDelayMs;
|
|
130
|
+
}
|
|
131
|
+
return normalized;
|
|
132
|
+
}
|
|
133
|
+
function resolveRetryBackoffMultiplier(raw) {
|
|
134
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
|
|
135
|
+
return DRIVER_V2_DEFAULT_RETRY_POLICY.backoffMultiplier;
|
|
136
|
+
}
|
|
137
|
+
if (raw < 1) {
|
|
138
|
+
return DRIVER_V2_DEFAULT_RETRY_POLICY.backoffMultiplier;
|
|
139
|
+
}
|
|
140
|
+
return raw;
|
|
141
|
+
}
|
|
142
|
+
function resolveRetryMaxDelayMs(raw) {
|
|
143
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw)) {
|
|
144
|
+
return DRIVER_V2_DEFAULT_RETRY_POLICY.maxDelayMs;
|
|
145
|
+
}
|
|
146
|
+
const normalized = Math.floor(raw);
|
|
147
|
+
if (normalized < 0) {
|
|
148
|
+
return DRIVER_V2_DEFAULT_RETRY_POLICY.maxDelayMs;
|
|
149
|
+
}
|
|
150
|
+
return normalized;
|
|
151
|
+
}
|
|
152
|
+
function resolveDriverV2RetryPolicy(providerCfg) {
|
|
153
|
+
const maxRetries = resolveRetryMaxRetries(providerCfg.llm_retry_max_retries);
|
|
154
|
+
const initialDelayMs = resolveRetryInitialDelayMs(providerCfg.llm_retry_initial_delay_ms);
|
|
155
|
+
const backoffMultiplier = resolveRetryBackoffMultiplier(providerCfg.llm_retry_backoff_multiplier);
|
|
156
|
+
const maxDelayMs = resolveRetryMaxDelayMs(providerCfg.llm_retry_max_delay_ms);
|
|
157
|
+
return {
|
|
158
|
+
maxRetries,
|
|
159
|
+
initialDelayMs,
|
|
160
|
+
backoffMultiplier,
|
|
161
|
+
maxDelayMs: Math.max(initialDelayMs, maxDelayMs),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function hasMeaningfulBatchOutput(messages) {
|
|
165
|
+
for (const msg of messages) {
|
|
166
|
+
if (msg.type === 'func_call_msg') {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
if ((msg.type === 'saying_msg' || msg.type === 'thinking_msg') && msg.content.trim() !== '') {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
function resolveModelContextLimitTokens(modelInfo) {
|
|
176
|
+
if (modelInfo &&
|
|
177
|
+
typeof modelInfo.context_length === 'number' &&
|
|
178
|
+
Number.isFinite(modelInfo.context_length)) {
|
|
179
|
+
const n = Math.floor(modelInfo.context_length);
|
|
180
|
+
return n > 0 ? n : null;
|
|
181
|
+
}
|
|
182
|
+
if (modelInfo &&
|
|
183
|
+
typeof modelInfo.input_length === 'number' &&
|
|
184
|
+
Number.isFinite(modelInfo.input_length)) {
|
|
185
|
+
const n = Math.floor(modelInfo.input_length);
|
|
186
|
+
return n > 0 ? n : null;
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
function resolveEffectiveOptimalMaxTokens(args) {
|
|
191
|
+
const configuredOptimal = args.modelInfo &&
|
|
192
|
+
typeof args.modelInfo.optimal_max_tokens === 'number' &&
|
|
193
|
+
Number.isFinite(args.modelInfo.optimal_max_tokens)
|
|
194
|
+
? Math.floor(args.modelInfo.optimal_max_tokens)
|
|
195
|
+
: undefined;
|
|
196
|
+
const optimalMaxTokensConfigured = configuredOptimal !== undefined && configuredOptimal > 0 ? configuredOptimal : undefined;
|
|
197
|
+
const configuredCritical = args.modelInfo &&
|
|
198
|
+
typeof args.modelInfo.critical_max_tokens === 'number' &&
|
|
199
|
+
Number.isFinite(args.modelInfo.critical_max_tokens)
|
|
200
|
+
? Math.floor(args.modelInfo.critical_max_tokens)
|
|
201
|
+
: undefined;
|
|
202
|
+
const criticalMaxTokensConfigured = configuredCritical !== undefined && configuredCritical > 0 ? configuredCritical : undefined;
|
|
203
|
+
const defaultOptimal = 100000;
|
|
204
|
+
const effectiveOptimalMaxTokens = optimalMaxTokensConfigured !== undefined ? optimalMaxTokensConfigured : defaultOptimal;
|
|
205
|
+
const defaultCritical = Math.max(1, Math.floor(args.modelContextLimitTokens * 0.9));
|
|
206
|
+
const effectiveCriticalMaxTokens = criticalMaxTokensConfigured !== undefined ? criticalMaxTokensConfigured : defaultCritical;
|
|
207
|
+
return {
|
|
208
|
+
effectiveOptimalMaxTokens,
|
|
209
|
+
optimalMaxTokensConfigured,
|
|
210
|
+
effectiveCriticalMaxTokens,
|
|
211
|
+
criticalMaxTokensConfigured,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function resolveFbrEffortDefaultForTool(member) {
|
|
215
|
+
const raw = member.fbr_effort;
|
|
216
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw))
|
|
217
|
+
return 0;
|
|
218
|
+
if (!Number.isInteger(raw))
|
|
219
|
+
return 0;
|
|
220
|
+
if (raw < 0)
|
|
221
|
+
return 0;
|
|
222
|
+
if (raw > 100)
|
|
223
|
+
return 0;
|
|
224
|
+
return raw;
|
|
225
|
+
}
|
|
226
|
+
function createFreshBootsReasoningTool(args) {
|
|
227
|
+
const fbrDefault = args.fbrEffortDefault;
|
|
228
|
+
const fbrDefaultHint = fbrDefault > 0
|
|
229
|
+
? `Runtime default for \`effort\` is current member \`fbr_effort=${fbrDefault}\` when omitted.`
|
|
230
|
+
: 'Runtime default for `effort` is current member `fbr_effort=0` (FBR disabled unless reconfigured).';
|
|
231
|
+
const codexAuthHint = args.providerApiType === 'codex'
|
|
232
|
+
? ` Codex-auth note: function arguments are often emitted with all fields present; if user did not specify intensity, pass \`effort: ${fbrDefault}\` explicitly.`
|
|
233
|
+
: '';
|
|
234
|
+
return {
|
|
235
|
+
type: 'func',
|
|
236
|
+
name: 'freshBootsReasoning',
|
|
237
|
+
description: 'Start an FBR sideline dialog for tool-less fresh-boots reasoning. tellaskContent MUST stay neutral and fact-oriented (Goal/Facts/Constraints/Evidence[/Unknowns]); do not issue analysis directives (for example “from the following dimensions”, “analyze in steps 1..N”, or “N rounds per dimension”). ' +
|
|
238
|
+
fbrDefaultHint +
|
|
239
|
+
codexAuthHint,
|
|
240
|
+
parameters: {
|
|
241
|
+
type: 'object',
|
|
242
|
+
properties: {
|
|
243
|
+
tellaskContent: {
|
|
244
|
+
type: 'string',
|
|
245
|
+
description: 'Use a neutral factual body: Goal/Facts/Constraints/Evidence (optional Unknowns). Avoid dimension checklists and stepwise directives (e.g. “from the following dimensions/aspects”, “analyze in steps 1..N”, “N rounds per dimension”).',
|
|
246
|
+
},
|
|
247
|
+
effort: {
|
|
248
|
+
type: 'integer',
|
|
249
|
+
description: `Optional FBR intensity override (0..100 integer). Runtime maps intensity N to N serial FBR passes in one sideline window. When omitted, runtime defaults to current member fbr_effort=${fbrDefault}.`,
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
required: ['tellaskContent'],
|
|
253
|
+
additionalProperties: false,
|
|
254
|
+
},
|
|
255
|
+
call: async () => {
|
|
256
|
+
throw new Error('freshBootsReasoning is handled by driver-v2 tellask-special channel');
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const TELLASK_SPECIAL_VIRTUAL_TOOLS = [
|
|
261
|
+
{
|
|
262
|
+
type: 'func',
|
|
263
|
+
name: 'tellaskBack',
|
|
264
|
+
description: 'Ask back to the requester dialog in sideline context.',
|
|
265
|
+
parameters: {
|
|
266
|
+
type: 'object',
|
|
267
|
+
properties: {
|
|
268
|
+
tellaskContent: { type: 'string' },
|
|
269
|
+
},
|
|
270
|
+
required: ['tellaskContent'],
|
|
271
|
+
additionalProperties: false,
|
|
272
|
+
},
|
|
273
|
+
call: async () => {
|
|
274
|
+
throw new Error('tellaskBack is handled by driver-v2 tellask-special channel');
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
type: 'func',
|
|
279
|
+
name: 'tellask',
|
|
280
|
+
description: 'Create or resume a teammate sideline dialog with sessionSlug.',
|
|
281
|
+
parameters: {
|
|
282
|
+
type: 'object',
|
|
283
|
+
properties: {
|
|
284
|
+
targetAgentId: { type: 'string' },
|
|
285
|
+
sessionSlug: { type: 'string' },
|
|
286
|
+
tellaskContent: { type: 'string' },
|
|
287
|
+
},
|
|
288
|
+
required: ['targetAgentId', 'sessionSlug', 'tellaskContent'],
|
|
289
|
+
additionalProperties: false,
|
|
290
|
+
},
|
|
291
|
+
call: async () => {
|
|
292
|
+
throw new Error('tellask is handled by driver-v2 tellask-special channel');
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
type: 'func',
|
|
297
|
+
name: 'tellaskSessionless',
|
|
298
|
+
description: 'Create a one-shot teammate sideline dialog.',
|
|
299
|
+
parameters: {
|
|
300
|
+
type: 'object',
|
|
301
|
+
properties: {
|
|
302
|
+
targetAgentId: { type: 'string' },
|
|
303
|
+
tellaskContent: { type: 'string' },
|
|
304
|
+
},
|
|
305
|
+
required: ['targetAgentId', 'tellaskContent'],
|
|
306
|
+
additionalProperties: false,
|
|
307
|
+
},
|
|
308
|
+
call: async () => {
|
|
309
|
+
throw new Error('tellaskSessionless is handled by driver-v2 tellask-special channel');
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
type: 'func',
|
|
314
|
+
name: 'askHuman',
|
|
315
|
+
description: 'Ask for required clarification/decision from human.',
|
|
316
|
+
parameters: {
|
|
317
|
+
type: 'object',
|
|
318
|
+
properties: {
|
|
319
|
+
tellaskContent: { type: 'string' },
|
|
320
|
+
},
|
|
321
|
+
required: ['tellaskContent'],
|
|
322
|
+
additionalProperties: false,
|
|
323
|
+
},
|
|
324
|
+
call: async () => {
|
|
325
|
+
throw new Error('askHuman is handled by driver-v2 tellask-special channel');
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
];
|
|
329
|
+
function mergeTellaskSpecialVirtualTools(baseTools, options) {
|
|
330
|
+
const merged = [...baseTools];
|
|
331
|
+
const seen = new Set(merged.map((tool) => tool.name));
|
|
332
|
+
const freshBootsReasoning = createFreshBootsReasoningTool({
|
|
333
|
+
fbrEffortDefault: options.fbrEffortDefault,
|
|
334
|
+
providerApiType: options.providerApiType,
|
|
335
|
+
});
|
|
336
|
+
const specialTools = options.includeTellaskBack
|
|
337
|
+
? [...TELLASK_SPECIAL_VIRTUAL_TOOLS, freshBootsReasoning]
|
|
338
|
+
: [
|
|
339
|
+
...TELLASK_SPECIAL_VIRTUAL_TOOLS.filter((tool) => tool.name !== 'tellaskBack'),
|
|
340
|
+
freshBootsReasoning,
|
|
341
|
+
];
|
|
342
|
+
for (const virtualTool of specialTools) {
|
|
343
|
+
if (seen.has(virtualTool.name)) {
|
|
344
|
+
throw new Error(`driver-v2 tool invariant violation: function tool name '${virtualTool.name}' collides with tellask-special virtual tool`);
|
|
345
|
+
}
|
|
346
|
+
merged.push(virtualTool);
|
|
347
|
+
seen.add(virtualTool.name);
|
|
348
|
+
}
|
|
349
|
+
return merged;
|
|
350
|
+
}
|
|
351
|
+
function computeContextHealthSnapshot(args) {
|
|
352
|
+
const modelInfo = args.providerCfg.models[args.model];
|
|
353
|
+
const modelContextWindowText = modelInfo && typeof modelInfo.context_window === 'string'
|
|
354
|
+
? modelInfo.context_window
|
|
355
|
+
: undefined;
|
|
356
|
+
const modelContextLimitTokens = resolveModelContextLimitTokens(modelInfo);
|
|
357
|
+
if (modelContextLimitTokens === null) {
|
|
358
|
+
return { kind: 'unavailable', reason: 'model_limit_unavailable', modelContextWindowText };
|
|
359
|
+
}
|
|
360
|
+
const { effectiveOptimalMaxTokens, optimalMaxTokensConfigured, effectiveCriticalMaxTokens, criticalMaxTokensConfigured, } = resolveEffectiveOptimalMaxTokens({
|
|
361
|
+
modelInfo,
|
|
362
|
+
modelContextLimitTokens,
|
|
363
|
+
});
|
|
364
|
+
if (args.usage.kind !== 'available') {
|
|
365
|
+
return {
|
|
366
|
+
kind: 'unavailable',
|
|
367
|
+
reason: 'usage_unavailable',
|
|
368
|
+
modelContextWindowText,
|
|
369
|
+
modelContextLimitTokens,
|
|
370
|
+
effectiveOptimalMaxTokens,
|
|
371
|
+
optimalMaxTokensConfigured,
|
|
372
|
+
effectiveCriticalMaxTokens,
|
|
373
|
+
criticalMaxTokensConfigured,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
const hardUtil = args.usage.promptTokens / modelContextLimitTokens;
|
|
377
|
+
const optimalUtil = args.usage.promptTokens / effectiveOptimalMaxTokens;
|
|
378
|
+
const level = args.usage.promptTokens > effectiveCriticalMaxTokens
|
|
379
|
+
? 'critical'
|
|
380
|
+
: args.usage.promptTokens > effectiveOptimalMaxTokens
|
|
381
|
+
? 'caution'
|
|
382
|
+
: 'healthy';
|
|
383
|
+
return {
|
|
384
|
+
kind: 'available',
|
|
385
|
+
promptTokens: args.usage.promptTokens,
|
|
386
|
+
completionTokens: args.usage.completionTokens,
|
|
387
|
+
totalTokens: args.usage.totalTokens,
|
|
388
|
+
modelContextWindowText,
|
|
389
|
+
modelContextLimitTokens,
|
|
390
|
+
effectiveOptimalMaxTokens,
|
|
391
|
+
optimalMaxTokensConfigured,
|
|
392
|
+
effectiveCriticalMaxTokens,
|
|
393
|
+
criticalMaxTokensConfigured,
|
|
394
|
+
hardUtil,
|
|
395
|
+
optimalUtil,
|
|
396
|
+
level,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
async function buildProviderContext(args) {
|
|
400
|
+
const provider = args.agent.provider ?? args.team.memberDefaults.provider;
|
|
401
|
+
const model = args.agent.model ?? args.team.memberDefaults.model;
|
|
402
|
+
if (!provider) {
|
|
403
|
+
throw new Error(`Configuration Error: No provider configured for agent '${args.dialog.agentId}'. Please specify a provider in the agent's configuration or in member_defaults section of .minds/team.yaml.`);
|
|
404
|
+
}
|
|
405
|
+
if (!model) {
|
|
406
|
+
throw new Error(`Configuration Error: No model configured for agent '${args.dialog.agentId}'. Please specify a model in the agent's configuration or in member_defaults section of .minds/team.yaml.`);
|
|
407
|
+
}
|
|
408
|
+
const llmCfg = await client_1.LlmConfig.load();
|
|
409
|
+
const providerCfg = llmCfg.getProvider(provider);
|
|
410
|
+
if (!providerCfg) {
|
|
411
|
+
throw new Error(`Provider configuration error: Provider '${provider}' not found for agent '${args.dialog.agentId}'. Please check .minds/llm.yaml and .minds/team.yaml configuration.`);
|
|
412
|
+
}
|
|
413
|
+
const modelInfo = resolveModelInfo(providerCfg, model);
|
|
414
|
+
if (!modelInfo) {
|
|
415
|
+
const uiLanguage = args.dialog.getUiLanguage();
|
|
416
|
+
const msg = uiLanguage === 'zh'
|
|
417
|
+
? [
|
|
418
|
+
'配置错误:当前成员的模型配置无效。',
|
|
419
|
+
'',
|
|
420
|
+
`- member: ${args.agent.name} (${args.dialog.agentId})`,
|
|
421
|
+
`- provider: ${provider}`,
|
|
422
|
+
`- model: ${model}(这是 model key;在该 provider 的 models 列表中不存在,或该 provider 缺少 models 配置)`,
|
|
423
|
+
'',
|
|
424
|
+
'请联系团队管理者修复:',
|
|
425
|
+
`- 在 .minds/team.yaml 中把该成员的 provider/model 改成有效 key;或`,
|
|
426
|
+
`- 在 .minds/llm.yaml 的 providers.${provider}.models 下补齐该 model key。`,
|
|
427
|
+
'',
|
|
428
|
+
'提示:你也可以打开 WebUI 的 `/setup` 查看当前 rtws(运行时工作区)可用的 provider/model 列表。',
|
|
429
|
+
'',
|
|
430
|
+
'团队管理者修复后建议运行:`team_mgmt_validate_team_cfg({})`。',
|
|
431
|
+
].join('\n')
|
|
432
|
+
: [
|
|
433
|
+
'Configuration error: invalid model selection for this member.',
|
|
434
|
+
'',
|
|
435
|
+
`- member: ${args.agent.name} (${args.dialog.agentId})`,
|
|
436
|
+
`- provider: ${provider}`,
|
|
437
|
+
`- model: ${model} (this is a model key; not found under this provider's models list, or the provider has no models configured)`,
|
|
438
|
+
'',
|
|
439
|
+
'Please contact your team manager to fix:',
|
|
440
|
+
`- Update the member\'s provider/model keys in .minds/team.yaml, or`,
|
|
441
|
+
`- Add the model key under .minds/llm.yaml providers.${provider}.models.`,
|
|
442
|
+
'',
|
|
443
|
+
'Tip: you can also open the WebUI `/setup` page to see available provider/model keys for this rtws (runtime workspace).',
|
|
444
|
+
'',
|
|
445
|
+
'After the fix, the team manager should run: `team_mgmt_validate_team_cfg({})`.',
|
|
446
|
+
].join('\n');
|
|
447
|
+
throw new Error(msg);
|
|
448
|
+
}
|
|
449
|
+
return { provider, model, providerCfg };
|
|
450
|
+
}
|
|
451
|
+
async function executeFunctionCalls(args) {
|
|
452
|
+
const { dialog, agent, agentTools, funcCalls, abortSignal } = args;
|
|
453
|
+
const functionPromises = funcCalls.map(async (func) => {
|
|
454
|
+
throwIfAborted(abortSignal, dialog);
|
|
455
|
+
const callGenseq = func.genseq;
|
|
456
|
+
const argsStr = typeof func.arguments === 'string' ? func.arguments : JSON.stringify(func.arguments ?? {});
|
|
457
|
+
const tool = agentTools.find((t) => t.type === 'func' && t.name === func.name);
|
|
458
|
+
if (!tool) {
|
|
459
|
+
const errorResult = {
|
|
460
|
+
type: 'func_result_msg',
|
|
461
|
+
id: func.id,
|
|
462
|
+
name: func.name,
|
|
463
|
+
content: `Tool '${func.name}' not found`,
|
|
464
|
+
role: 'tool',
|
|
465
|
+
genseq: callGenseq,
|
|
466
|
+
};
|
|
467
|
+
await dialog.receiveFuncResult(errorResult);
|
|
468
|
+
return errorResult;
|
|
469
|
+
}
|
|
470
|
+
let rawArgs = {};
|
|
471
|
+
if (typeof func.arguments === 'string' && func.arguments.trim()) {
|
|
472
|
+
try {
|
|
473
|
+
rawArgs = JSON.parse(func.arguments);
|
|
474
|
+
}
|
|
475
|
+
catch (parseErr) {
|
|
476
|
+
rawArgs = null;
|
|
477
|
+
log_1.log.warn('driver-v2 failed to parse function arguments as JSON', undefined, {
|
|
478
|
+
funcName: func.name,
|
|
479
|
+
arguments: func.arguments,
|
|
480
|
+
error: parseErr,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
let result;
|
|
485
|
+
const argsValidation = (0, runtime_utils_1.validateFuncToolArguments)(tool, rawArgs);
|
|
486
|
+
if (argsValidation.ok) {
|
|
487
|
+
const argsObj = argsValidation.args;
|
|
488
|
+
await dialog.funcCallRequested(func.id, func.name, argsStr);
|
|
489
|
+
await dialog.persistFunctionCall(func.id, func.name, argsObj, callGenseq);
|
|
490
|
+
try {
|
|
491
|
+
throwIfAborted(abortSignal, dialog);
|
|
492
|
+
const output = await tool.call(dialog, agent, argsObj);
|
|
493
|
+
throwIfAborted(abortSignal, dialog);
|
|
494
|
+
const normalized = typeof output === 'string'
|
|
495
|
+
? { content: output, contentItems: undefined }
|
|
496
|
+
: {
|
|
497
|
+
content: typeof output.content === 'string' ? output.content : String(output),
|
|
498
|
+
contentItems: Array.isArray(output.contentItems) ? output.contentItems : undefined,
|
|
499
|
+
};
|
|
500
|
+
result = {
|
|
501
|
+
type: 'func_result_msg',
|
|
502
|
+
id: func.id,
|
|
503
|
+
name: func.name,
|
|
504
|
+
content: String(normalized.content),
|
|
505
|
+
contentItems: normalized.contentItems,
|
|
506
|
+
role: 'tool',
|
|
507
|
+
genseq: callGenseq,
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
catch (err) {
|
|
511
|
+
const errText = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
|
|
512
|
+
result = {
|
|
513
|
+
type: 'func_result_msg',
|
|
514
|
+
id: func.id,
|
|
515
|
+
name: func.name,
|
|
516
|
+
content: `Function '${func.name}' execution failed: ${errText}`,
|
|
517
|
+
role: 'tool',
|
|
518
|
+
genseq: callGenseq,
|
|
519
|
+
};
|
|
520
|
+
if (abortSignal.aborted || err instanceof DialogInterruptedError) {
|
|
521
|
+
throw err;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
result = {
|
|
527
|
+
type: 'func_result_msg',
|
|
528
|
+
id: func.id,
|
|
529
|
+
name: func.name,
|
|
530
|
+
content: `Invalid arguments: ${argsValidation.error}`,
|
|
531
|
+
role: 'tool',
|
|
532
|
+
genseq: callGenseq,
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
await dialog.receiveFuncResult(result);
|
|
536
|
+
return result;
|
|
537
|
+
});
|
|
538
|
+
return await Promise.all(functionPromises);
|
|
539
|
+
}
|
|
540
|
+
async function executeRoutedFunctionCalls(args) {
|
|
541
|
+
const { dialog, agent, agentTools, funcCalls, callbacks, abortSignal } = args;
|
|
542
|
+
if (funcCalls.length === 0) {
|
|
543
|
+
return { suspendForHuman: false, pairedMessages: [], tellaskToolOutputs: [] };
|
|
544
|
+
}
|
|
545
|
+
throwIfAborted(abortSignal, dialog);
|
|
546
|
+
const allowTellaskBack = dialog.id.rootId !== dialog.id.selfId;
|
|
547
|
+
const allowedSpecials = new Set([
|
|
548
|
+
'tellask',
|
|
549
|
+
'tellaskSessionless',
|
|
550
|
+
'askHuman',
|
|
551
|
+
'freshBootsReasoning',
|
|
552
|
+
...(allowTellaskBack ? ['tellaskBack'] : []),
|
|
553
|
+
]);
|
|
554
|
+
const classified = (0, tellask_bridge_1.classifyTellaskSpecialFunctionCalls)(funcCalls, { allowedSpecials });
|
|
555
|
+
const specialCallById = new Map(classified.specialCalls.map((call) => [call.callId, call]));
|
|
556
|
+
const toPersistedSpecialCallArgs = (call) => {
|
|
557
|
+
switch (call.callName) {
|
|
558
|
+
case 'tellaskBack':
|
|
559
|
+
return { tellaskContent: call.tellaskContent };
|
|
560
|
+
case 'askHuman':
|
|
561
|
+
return { tellaskContent: call.tellaskContent };
|
|
562
|
+
case 'freshBootsReasoning':
|
|
563
|
+
return {
|
|
564
|
+
tellaskContent: call.tellaskContent,
|
|
565
|
+
...(call.effort !== undefined ? { effort: call.effort } : {}),
|
|
566
|
+
};
|
|
567
|
+
case 'tellask':
|
|
568
|
+
return {
|
|
569
|
+
targetAgentId: call.targetAgentId,
|
|
570
|
+
sessionSlug: call.sessionSlug,
|
|
571
|
+
tellaskContent: call.tellaskContent,
|
|
572
|
+
};
|
|
573
|
+
case 'tellaskSessionless':
|
|
574
|
+
return {
|
|
575
|
+
targetAgentId: call.targetAgentId,
|
|
576
|
+
tellaskContent: call.tellaskContent,
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
for (const callMsg of funcCalls) {
|
|
581
|
+
throwIfAborted(abortSignal, dialog);
|
|
582
|
+
const special = specialCallById.get(callMsg.id);
|
|
583
|
+
if (!special) {
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
await dialog.persistFunctionCall(callMsg.id, callMsg.name, toPersistedSpecialCallArgs(special), callMsg.genseq);
|
|
587
|
+
}
|
|
588
|
+
const issueResults = [];
|
|
589
|
+
for (const issue of classified.parseIssues) {
|
|
590
|
+
const result = {
|
|
591
|
+
type: 'func_result_msg',
|
|
592
|
+
id: issue.call.id,
|
|
593
|
+
name: issue.call.name,
|
|
594
|
+
content: `Invalid arguments for tellask special function '${issue.call.name}': ${issue.error}`,
|
|
595
|
+
role: 'tool',
|
|
596
|
+
genseq: issue.call.genseq,
|
|
597
|
+
};
|
|
598
|
+
await dialog.receiveFuncResult(result);
|
|
599
|
+
issueResults.push(result);
|
|
600
|
+
}
|
|
601
|
+
throwIfAborted(abortSignal, dialog);
|
|
602
|
+
const specialResult = await (0, tellask_bridge_1.executeTellaskSpecialCalls)({
|
|
603
|
+
dlg: dialog,
|
|
604
|
+
agent,
|
|
605
|
+
calls: classified.specialCalls,
|
|
606
|
+
callbacks,
|
|
607
|
+
});
|
|
608
|
+
throwIfAborted(abortSignal, dialog);
|
|
609
|
+
const specialCallIds = new Set(classified.specialCalls.map((call) => call.callId));
|
|
610
|
+
const genericResults = await executeFunctionCalls({
|
|
611
|
+
dialog,
|
|
612
|
+
agent,
|
|
613
|
+
agentTools,
|
|
614
|
+
funcCalls: classified.normalCalls,
|
|
615
|
+
abortSignal,
|
|
616
|
+
});
|
|
617
|
+
const resultByCallId = new Map();
|
|
618
|
+
const register = (result) => {
|
|
619
|
+
const existing = resultByCallId.get(result.id);
|
|
620
|
+
if (existing) {
|
|
621
|
+
throw new Error(`driver-v2 function result invariant violation: duplicate call id '${result.id}'`);
|
|
622
|
+
}
|
|
623
|
+
resultByCallId.set(result.id, result);
|
|
624
|
+
};
|
|
625
|
+
for (const result of issueResults) {
|
|
626
|
+
register(result);
|
|
627
|
+
}
|
|
628
|
+
for (const result of genericResults) {
|
|
629
|
+
register(result);
|
|
630
|
+
}
|
|
631
|
+
const pairedMessages = [];
|
|
632
|
+
for (const call of funcCalls) {
|
|
633
|
+
pairedMessages.push(call);
|
|
634
|
+
const result = resultByCallId.get(call.id);
|
|
635
|
+
if (result) {
|
|
636
|
+
pairedMessages.push(result);
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
if (specialCallIds.has(call.id)) {
|
|
640
|
+
// Tellask-special calls get func_result via dynamic context projection instead of persisted records.
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
if (!result) {
|
|
644
|
+
throw new Error(`driver-v2 function result invariant violation: missing result for call id '${call.id}' (${call.name})`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return {
|
|
648
|
+
suspendForHuman: specialResult.suspend,
|
|
649
|
+
pairedMessages,
|
|
650
|
+
tellaskToolOutputs: specialResult.toolOutputs,
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function parseUnifiedTimestampMs(ts) {
|
|
654
|
+
const normalized = ts.trim();
|
|
655
|
+
if (normalized === '') {
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
const parsed = Date.parse(normalized.replace(' ', 'T'));
|
|
659
|
+
if (!Number.isFinite(parsed)) {
|
|
660
|
+
return null;
|
|
661
|
+
}
|
|
662
|
+
return parsed;
|
|
663
|
+
}
|
|
664
|
+
function formatElapsedSecondsText(startedAtMs) {
|
|
665
|
+
const language = (0, runtime_language_1.getWorkLanguage)();
|
|
666
|
+
if (startedAtMs === null) {
|
|
667
|
+
return language === 'zh' ? '未知时长' : 'unknown elapsed time';
|
|
668
|
+
}
|
|
669
|
+
const elapsedMs = Math.max(0, Date.now() - startedAtMs);
|
|
670
|
+
const elapsedSec = Math.floor(elapsedMs / 1000);
|
|
671
|
+
return language === 'zh' ? `${elapsedSec} 秒` : `${elapsedSec}s`;
|
|
672
|
+
}
|
|
673
|
+
function formatPendingSpecialFuncResult(name, startedAtMs) {
|
|
674
|
+
const language = (0, runtime_language_1.getWorkLanguage)();
|
|
675
|
+
const elapsed = formatElapsedSecondsText(startedAtMs);
|
|
676
|
+
if (name === 'askHuman') {
|
|
677
|
+
return language === 'zh'
|
|
678
|
+
? `Q4H 仍在等待人类回复,已持续 ${elapsed}。`
|
|
679
|
+
: `Q4H is still waiting for human reply (elapsed ${elapsed}).`;
|
|
680
|
+
}
|
|
681
|
+
return language === 'zh'
|
|
682
|
+
? `支线对话仍在进行中,已持续 ${elapsed}。`
|
|
683
|
+
: `Sideline dialog is still running (elapsed ${elapsed}).`;
|
|
684
|
+
}
|
|
685
|
+
function formatResolvedAskHumanResult() {
|
|
686
|
+
return (0, runtime_language_1.getWorkLanguage)() === 'zh'
|
|
687
|
+
? 'Q4H 已结束等待状态,请参考后续用户消息。'
|
|
688
|
+
: 'Q4H wait is resolved; refer to subsequent user messages.';
|
|
689
|
+
}
|
|
690
|
+
async function projectTellaskSpecialFuncResultsForContext(args) {
|
|
691
|
+
const hasSpecialFuncCall = args.dialogMsgsForContext.some((msg) => msg.type === 'func_call_msg' && (0, tellask_bridge_1.isTellaskSpecialFunctionName)(msg.name));
|
|
692
|
+
if (!hasSpecialFuncCall) {
|
|
693
|
+
return [...args.dialogMsgsForContext];
|
|
694
|
+
}
|
|
695
|
+
const pendingSubdialogs = await persistence_1.DialogPersistence.loadPendingSubdialogs(args.dialog.id, args.dialog.status);
|
|
696
|
+
const pendingSubByCallId = new Map();
|
|
697
|
+
for (const pending of pendingSubdialogs) {
|
|
698
|
+
const callId = pending.callId.trim();
|
|
699
|
+
if (callId === '') {
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
pendingSubByCallId.set(callId, { createdAt: pending.createdAt });
|
|
703
|
+
}
|
|
704
|
+
const pendingQ4H = await persistence_1.DialogPersistence.loadQuestions4HumanState(args.dialog.id, args.dialog.status);
|
|
705
|
+
const pendingQ4HByCallId = new Map();
|
|
706
|
+
for (const question of pendingQ4H) {
|
|
707
|
+
if (typeof question.callId !== 'string') {
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
const callId = question.callId.trim();
|
|
711
|
+
if (callId === '') {
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
pendingQ4HByCallId.set(callId, { askedAt: question.askedAt });
|
|
715
|
+
}
|
|
716
|
+
const settledByCallId = new Map();
|
|
717
|
+
const existingSpecialFuncResults = new Map();
|
|
718
|
+
for (const msg of args.dialogMsgsForContext) {
|
|
719
|
+
if (msg.type === 'tellask_result_msg') {
|
|
720
|
+
const callId = typeof msg.callId === 'string' ? msg.callId.trim() : '';
|
|
721
|
+
if (callId !== '') {
|
|
722
|
+
settledByCallId.set(callId, msg.content);
|
|
723
|
+
}
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
if (msg.type === 'func_result_msg' && (0, tellask_bridge_1.isTellaskSpecialFunctionName)(msg.name)) {
|
|
727
|
+
existingSpecialFuncResults.set(msg.id, msg);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
const projected = [];
|
|
731
|
+
const specialCallIds = new Set();
|
|
732
|
+
for (const msg of args.dialogMsgsForContext) {
|
|
733
|
+
if (msg.type === 'func_result_msg' && specialCallIds.has(msg.id)) {
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
projected.push(msg);
|
|
737
|
+
if (msg.type !== 'func_call_msg') {
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
if (!(0, tellask_bridge_1.isTellaskSpecialFunctionName)(msg.name)) {
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
specialCallIds.add(msg.id);
|
|
744
|
+
const settled = settledByCallId.get(msg.id);
|
|
745
|
+
if (settled !== undefined) {
|
|
746
|
+
projected.push({
|
|
747
|
+
type: 'func_result_msg',
|
|
748
|
+
role: 'tool',
|
|
749
|
+
genseq: msg.genseq,
|
|
750
|
+
id: msg.id,
|
|
751
|
+
name: msg.name,
|
|
752
|
+
content: settled,
|
|
753
|
+
});
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
const existingResult = existingSpecialFuncResults.get(msg.id);
|
|
757
|
+
if (existingResult) {
|
|
758
|
+
projected.push(existingResult);
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
if (msg.name === 'askHuman') {
|
|
762
|
+
const pendingQ4HState = pendingQ4HByCallId.get(msg.id);
|
|
763
|
+
const content = pendingQ4HState
|
|
764
|
+
? formatPendingSpecialFuncResult(msg.name, parseUnifiedTimestampMs(pendingQ4HState.askedAt))
|
|
765
|
+
: formatResolvedAskHumanResult();
|
|
766
|
+
projected.push({
|
|
767
|
+
type: 'func_result_msg',
|
|
768
|
+
role: 'tool',
|
|
769
|
+
genseq: msg.genseq,
|
|
770
|
+
id: msg.id,
|
|
771
|
+
name: msg.name,
|
|
772
|
+
content,
|
|
773
|
+
});
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
const pendingSubState = pendingSubByCallId.get(msg.id);
|
|
777
|
+
projected.push({
|
|
778
|
+
type: 'func_result_msg',
|
|
779
|
+
role: 'tool',
|
|
780
|
+
genseq: msg.genseq,
|
|
781
|
+
id: msg.id,
|
|
782
|
+
name: msg.name,
|
|
783
|
+
content: formatPendingSpecialFuncResult(msg.name, pendingSubState ? parseUnifiedTimestampMs(pendingSubState.createdAt) : null),
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
return projected;
|
|
787
|
+
}
|
|
788
|
+
async function resetDiligenceBudgetAfterQ4H(dlg, team) {
|
|
789
|
+
try {
|
|
790
|
+
if (!(await dlg.hasPendingQ4H())) {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const configuredMax = resolveMemberDiligencePushMax(team, dlg.agentId);
|
|
794
|
+
if (typeof configuredMax === 'number' && Number.isFinite(configuredMax)) {
|
|
795
|
+
const next = Math.floor(configuredMax);
|
|
796
|
+
dlg.diligencePushRemainingBudget =
|
|
797
|
+
next > 0 ? next : Math.max(0, Math.floor(dlg.diligencePushRemainingBudget));
|
|
798
|
+
}
|
|
799
|
+
else {
|
|
800
|
+
dlg.diligencePushRemainingBudget = Math.max(0, Math.floor(dlg.diligencePushRemainingBudget));
|
|
801
|
+
}
|
|
802
|
+
void persistence_1.DialogPersistence.mutateDialogLatest(dlg.id, () => ({
|
|
803
|
+
kind: 'patch',
|
|
804
|
+
patch: { diligencePushRemainingBudget: dlg.diligencePushRemainingBudget },
|
|
805
|
+
}));
|
|
806
|
+
}
|
|
807
|
+
catch (err) {
|
|
808
|
+
log_1.log.error('driver-v2 failed to reset Diligence Push budget after Q4H', err, {
|
|
809
|
+
dialogId: dlg.id.valueOf(),
|
|
810
|
+
});
|
|
811
|
+
throw err;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
async function maybeContinueWithDiligencePrompt(args) {
|
|
815
|
+
const { dlg, team, suppressDiligencePushForDrive } = args;
|
|
816
|
+
if (!(dlg instanceof dialog_1.RootDialog)) {
|
|
817
|
+
return { kind: 'break' };
|
|
818
|
+
}
|
|
819
|
+
const suspension = await dlg.getSuspensionStatus();
|
|
820
|
+
if (!suspension.canDrive) {
|
|
821
|
+
if (suspension.q4h) {
|
|
822
|
+
await resetDiligenceBudgetAfterQ4H(dlg, team);
|
|
823
|
+
}
|
|
824
|
+
return { kind: 'break' };
|
|
825
|
+
}
|
|
826
|
+
const prepared = await (0, runtime_utils_1.maybePrepareDiligenceAutoContinuePrompt)({
|
|
827
|
+
dlg,
|
|
828
|
+
isRootDialog: true,
|
|
829
|
+
remainingBudget: dlg.diligencePushRemainingBudget,
|
|
830
|
+
diligencePushMax: resolveMemberDiligencePushMax(team, dlg.agentId),
|
|
831
|
+
suppressDiligencePush: suppressDiligencePushForDrive,
|
|
832
|
+
});
|
|
833
|
+
dlg.diligencePushRemainingBudget = prepared.nextRemainingBudget;
|
|
834
|
+
void persistence_1.DialogPersistence.mutateDialogLatest(dlg.id, () => ({
|
|
835
|
+
kind: 'patch',
|
|
836
|
+
patch: { diligencePushRemainingBudget: dlg.diligencePushRemainingBudget },
|
|
837
|
+
}));
|
|
838
|
+
if (prepared.kind !== 'disabled') {
|
|
839
|
+
emitDiligenceBudgetEvent(dlg, {
|
|
840
|
+
maxInjectCount: prepared.maxInjectCount,
|
|
841
|
+
nextRemainingBudget: prepared.nextRemainingBudget,
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
if (prepared.kind === 'budget_exhausted') {
|
|
845
|
+
await (0, runtime_utils_1.suspendForKeepGoingBudgetExhausted)({
|
|
846
|
+
dlg,
|
|
847
|
+
maxInjectCount: prepared.maxInjectCount,
|
|
848
|
+
});
|
|
849
|
+
dlg.diligencePushRemainingBudget = 0;
|
|
850
|
+
return { kind: 'break' };
|
|
851
|
+
}
|
|
852
|
+
if (prepared.kind === 'prompt') {
|
|
853
|
+
return { kind: 'continue', prompt: prepared.prompt };
|
|
854
|
+
}
|
|
855
|
+
return { kind: 'break' };
|
|
856
|
+
}
|
|
857
|
+
async function maybeContinueWithHealthPromptBeforeDiligence(args) {
|
|
858
|
+
const { dlg, providerCfg, model } = args;
|
|
859
|
+
// This path is only used as a higher-priority alternative to Diligence Push.
|
|
860
|
+
if (!(dlg instanceof dialog_1.RootDialog)) {
|
|
861
|
+
return { kind: 'no_health_prompt' };
|
|
862
|
+
}
|
|
863
|
+
const snapshot = dlg.getLastContextHealth();
|
|
864
|
+
const modelInfoForRemediation = resolveModelInfo(providerCfg, model);
|
|
865
|
+
const cautionRemediationCadenceGenerations = (0, context_health_1.resolveCautionRemediationCadenceGenerations)(modelInfoForRemediation?.caution_remediation_cadence_generations);
|
|
866
|
+
const criticalCountdownRemaining = (0, context_health_1.resolveCriticalCountdownRemaining)(dlg.id.key(), snapshot);
|
|
867
|
+
const healthDecision = (0, context_health_1.decideDriverV2ContextHealth)({
|
|
868
|
+
dialogKey: dlg.id.key(),
|
|
869
|
+
snapshot,
|
|
870
|
+
hadUserPromptThisGen: false,
|
|
871
|
+
canInjectPromptThisGen: true,
|
|
872
|
+
cautionRemediationCadenceGenerations,
|
|
873
|
+
criticalCountdownRemaining,
|
|
874
|
+
});
|
|
875
|
+
if (healthDecision.kind === 'suspend') {
|
|
876
|
+
return { kind: 'health_suspend' };
|
|
877
|
+
}
|
|
878
|
+
if (healthDecision.kind !== 'continue') {
|
|
879
|
+
return { kind: 'no_health_prompt' };
|
|
880
|
+
}
|
|
881
|
+
if (healthDecision.reason === 'critical_force_new_course') {
|
|
882
|
+
const language = (0, runtime_language_1.getWorkLanguage)();
|
|
883
|
+
const newCoursePrompt = language === 'zh'
|
|
884
|
+
? '系统因上下文已告急(critical)而自动开启新一程对话,请继续推进任务。'
|
|
885
|
+
: 'System auto-started a new dialog course because context health is critical. Please continue the task.';
|
|
886
|
+
await dlg.startNewCourse(newCoursePrompt);
|
|
887
|
+
dlg.setLastContextHealth({ kind: 'unavailable', reason: 'usage_unavailable' });
|
|
888
|
+
(0, context_health_1.resetContextHealthRoundState)(dlg.id.key());
|
|
889
|
+
const nextPrompt = resolveUpNextPrompt(dlg);
|
|
890
|
+
if (!nextPrompt) {
|
|
891
|
+
throw new Error(`driver-v2 critical force-new-course invariant violation: missing upNext prompt after startNewCourse for dialog=${dlg.id.valueOf()}`);
|
|
892
|
+
}
|
|
893
|
+
return { kind: 'health_continue', prompt: nextPrompt, resetTaskdoc: true };
|
|
894
|
+
}
|
|
895
|
+
const language = (0, runtime_language_1.getWorkLanguage)();
|
|
896
|
+
const guideText = healthDecision.reason === 'caution_soft_remediation'
|
|
897
|
+
? (0, driver_messages_1.formatAgentFacingContextHealthV3RemediationGuide)(language, {
|
|
898
|
+
kind: 'caution',
|
|
899
|
+
mode: 'soft',
|
|
900
|
+
})
|
|
901
|
+
: (0, driver_messages_1.formatAgentFacingContextHealthV3RemediationGuide)(language, {
|
|
902
|
+
kind: 'critical',
|
|
903
|
+
mode: 'countdown',
|
|
904
|
+
promptsRemainingAfterThis: (0, context_health_1.consumeCriticalCountdown)(dlg.id.key()),
|
|
905
|
+
promptsTotal: context_health_1.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS,
|
|
906
|
+
});
|
|
907
|
+
return {
|
|
908
|
+
kind: 'health_continue',
|
|
909
|
+
prompt: {
|
|
910
|
+
content: guideText,
|
|
911
|
+
msgId: (0, id_1.generateShortId)(),
|
|
912
|
+
grammar: 'markdown',
|
|
913
|
+
userLanguageCode: language,
|
|
914
|
+
},
|
|
915
|
+
resetTaskdoc: false,
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
async function driveDialogStreamCoreV2(dlg, humanPrompt, driveOptions, callbacks) {
|
|
919
|
+
const suppressDiligencePushForDrive = driveOptions?.suppressDiligencePush === true;
|
|
920
|
+
const abortSignal = (0, dialog_run_state_1.createActiveRun)(dlg.id);
|
|
921
|
+
let finalRunState;
|
|
922
|
+
let finalResult;
|
|
923
|
+
let shouldEmitResumedMarker = false;
|
|
924
|
+
if (!humanPrompt) {
|
|
925
|
+
try {
|
|
926
|
+
const latest = await persistence_1.DialogPersistence.loadDialogLatest(dlg.id, 'running');
|
|
927
|
+
shouldEmitResumedMarker =
|
|
928
|
+
latest !== null &&
|
|
929
|
+
latest !== undefined &&
|
|
930
|
+
latest.runState !== undefined &&
|
|
931
|
+
latest.runState.kind === 'interrupted';
|
|
932
|
+
}
|
|
933
|
+
catch (err) {
|
|
934
|
+
log_1.log.warn('driver-v2 failed to load latest.yaml for resumption marker', err, {
|
|
935
|
+
dialogId: dlg.id.valueOf(),
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if (shouldEmitResumedMarker) {
|
|
940
|
+
(0, dialog_run_state_1.broadcastRunStateMarker)(dlg.id, { kind: 'resumed' });
|
|
941
|
+
}
|
|
942
|
+
await (0, dialog_run_state_1.setDialogRunState)(dlg.id, { kind: 'proceeding' });
|
|
943
|
+
let pubRemindersVer = dlg.remindersVer;
|
|
944
|
+
let lastAssistantSayingContent = null;
|
|
945
|
+
let lastAssistantSayingGenseq = null;
|
|
946
|
+
let lastFunctionCallGenseq = null;
|
|
947
|
+
let genIterNo = 0;
|
|
948
|
+
let pendingPrompt = humanPrompt;
|
|
949
|
+
let skipTaskdocForThisDrive = humanPrompt?.skipTaskdoc === true;
|
|
950
|
+
try {
|
|
951
|
+
while (true) {
|
|
952
|
+
genIterNo += 1;
|
|
953
|
+
throwIfAborted(abortSignal, dlg);
|
|
954
|
+
const minds = await (0, load_1.loadAgentMinds)(dlg.agentId, dlg);
|
|
955
|
+
const team = minds.team;
|
|
956
|
+
const policy = (0, policy_1.buildDriverV2Policy)({
|
|
957
|
+
dlg,
|
|
958
|
+
agent: minds.agent,
|
|
959
|
+
systemPrompt: minds.systemPrompt,
|
|
960
|
+
agentTools: minds.agentTools,
|
|
961
|
+
language: (0, runtime_language_1.getWorkLanguage)(),
|
|
962
|
+
});
|
|
963
|
+
const policyValidation = (0, policy_1.validateDriverV2PolicyInvariants)(policy, (0, runtime_language_1.getWorkLanguage)());
|
|
964
|
+
if (!policyValidation.ok) {
|
|
965
|
+
throw new Error(`driver-v2 policy invariant violation: ${policyValidation.detail}`);
|
|
966
|
+
}
|
|
967
|
+
let agent = policy.effectiveAgent;
|
|
968
|
+
let systemPrompt = policy.effectiveSystemPrompt;
|
|
969
|
+
const memories = minds.memories;
|
|
970
|
+
const agentTools = policy.effectiveAgentTools;
|
|
971
|
+
const { provider, model, providerCfg } = await buildProviderContext({
|
|
972
|
+
dialog: dlg,
|
|
973
|
+
team,
|
|
974
|
+
agent,
|
|
975
|
+
});
|
|
976
|
+
const retryPolicy = resolveDriverV2RetryPolicy(providerCfg);
|
|
977
|
+
const llmGen = (0, registry_1.getLlmGenerator)(providerCfg.apiType);
|
|
978
|
+
if (!llmGen) {
|
|
979
|
+
throw new Error(`LLM generator not found: API type '${providerCfg.apiType}' for provider '${provider}' in agent '${dlg.agentId}'. Please check .minds/llm.yaml configuration.`);
|
|
980
|
+
}
|
|
981
|
+
const canonicalFuncTools = agentTools.filter((t) => t.type === 'func');
|
|
982
|
+
const isSubdialog = dlg.id.rootId !== dlg.id.selfId;
|
|
983
|
+
const fbrEffortDefault = resolveFbrEffortDefaultForTool(agent);
|
|
984
|
+
const effectiveFuncTools = policy.allowFunctionCalls
|
|
985
|
+
? mergeTellaskSpecialVirtualTools(canonicalFuncTools, {
|
|
986
|
+
includeTellaskBack: isSubdialog,
|
|
987
|
+
fbrEffortDefault,
|
|
988
|
+
providerApiType: providerCfg.apiType,
|
|
989
|
+
})
|
|
990
|
+
: canonicalFuncTools;
|
|
991
|
+
const projected = (0, tools_projection_1.projectFuncToolsForProvider)(providerCfg.apiType, effectiveFuncTools);
|
|
992
|
+
const funcTools = projected.tools;
|
|
993
|
+
if (genIterNo > 1) {
|
|
994
|
+
const snapshot = dlg.getLastContextHealth();
|
|
995
|
+
const hasQueuedUpNext = dlg.hasUpNext() || pendingPrompt !== undefined;
|
|
996
|
+
const modelInfoForRemediation = resolveModelInfo(providerCfg, model);
|
|
997
|
+
const cautionRemediationCadenceGenerations = (0, context_health_1.resolveCautionRemediationCadenceGenerations)(modelInfoForRemediation?.caution_remediation_cadence_generations);
|
|
998
|
+
const criticalCountdownRemaining = (0, context_health_1.resolveCriticalCountdownRemaining)(dlg.id.key(), snapshot);
|
|
999
|
+
const healthDecision = (0, context_health_1.decideDriverV2ContextHealth)({
|
|
1000
|
+
dialogKey: dlg.id.key(),
|
|
1001
|
+
snapshot,
|
|
1002
|
+
hadUserPromptThisGen: isUserOriginPrompt(pendingPrompt),
|
|
1003
|
+
canInjectPromptThisGen: !hasQueuedUpNext,
|
|
1004
|
+
cautionRemediationCadenceGenerations,
|
|
1005
|
+
criticalCountdownRemaining,
|
|
1006
|
+
});
|
|
1007
|
+
if (healthDecision.kind === 'suspend') {
|
|
1008
|
+
log_1.log.debug('driver-v2 suspend iterative generation due to critical context while waiting for human prompt', undefined, {
|
|
1009
|
+
dialogId: dlg.id.valueOf(),
|
|
1010
|
+
rootId: dlg.id.rootId,
|
|
1011
|
+
selfId: dlg.id.selfId,
|
|
1012
|
+
genIterNo,
|
|
1013
|
+
pendingPromptOrigin: pendingPrompt?.origin ?? null,
|
|
1014
|
+
});
|
|
1015
|
+
break;
|
|
1016
|
+
}
|
|
1017
|
+
if (healthDecision.kind === 'continue') {
|
|
1018
|
+
if (healthDecision.reason === 'critical_force_new_course') {
|
|
1019
|
+
const language = (0, runtime_language_1.getWorkLanguage)();
|
|
1020
|
+
const newCoursePrompt = language === 'zh'
|
|
1021
|
+
? '系统因上下文已告急(critical)而自动开启新一程对话,请继续推进任务。'
|
|
1022
|
+
: 'System auto-started a new dialog course because context health is critical. Please continue the task.';
|
|
1023
|
+
await dlg.startNewCourse(newCoursePrompt);
|
|
1024
|
+
dlg.setLastContextHealth({ kind: 'unavailable', reason: 'usage_unavailable' });
|
|
1025
|
+
(0, context_health_1.resetContextHealthRoundState)(dlg.id.key());
|
|
1026
|
+
const nextPrompt = resolveUpNextPrompt(dlg);
|
|
1027
|
+
if (!nextPrompt) {
|
|
1028
|
+
throw new Error(`driver-v2 critical force-new-course invariant violation: missing upNext prompt after startNewCourse for dialog=${dlg.id.valueOf()}`);
|
|
1029
|
+
}
|
|
1030
|
+
pendingPrompt = nextPrompt;
|
|
1031
|
+
skipTaskdocForThisDrive = false;
|
|
1032
|
+
}
|
|
1033
|
+
else if (!hasQueuedUpNext) {
|
|
1034
|
+
const language = (0, runtime_language_1.getWorkLanguage)();
|
|
1035
|
+
const guideText = healthDecision.reason === 'caution_soft_remediation'
|
|
1036
|
+
? (0, driver_messages_1.formatAgentFacingContextHealthV3RemediationGuide)(language, {
|
|
1037
|
+
kind: 'caution',
|
|
1038
|
+
mode: 'soft',
|
|
1039
|
+
})
|
|
1040
|
+
: (0, driver_messages_1.formatAgentFacingContextHealthV3RemediationGuide)(language, {
|
|
1041
|
+
kind: 'critical',
|
|
1042
|
+
mode: 'countdown',
|
|
1043
|
+
promptsRemainingAfterThis: (0, context_health_1.consumeCriticalCountdown)(dlg.id.key()),
|
|
1044
|
+
promptsTotal: context_health_1.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS,
|
|
1045
|
+
});
|
|
1046
|
+
pendingPrompt = {
|
|
1047
|
+
content: guideText,
|
|
1048
|
+
msgId: (0, id_1.generateShortId)(),
|
|
1049
|
+
grammar: 'markdown',
|
|
1050
|
+
userLanguageCode: language,
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
let suspendForHuman = false;
|
|
1056
|
+
let llmGenModelForGen = model;
|
|
1057
|
+
let contextHealthForGen;
|
|
1058
|
+
await dlg.notifyGeneratingStart();
|
|
1059
|
+
try {
|
|
1060
|
+
const currentPrompt = pendingPrompt;
|
|
1061
|
+
pendingPrompt = undefined;
|
|
1062
|
+
if (currentPrompt) {
|
|
1063
|
+
const promptOrigin = currentPrompt.origin ?? 'user';
|
|
1064
|
+
const isDiligencePrompt = promptOrigin === 'diligence_push';
|
|
1065
|
+
if (isDiligencePrompt && (dlg.disableDiligencePush || suppressDiligencePushForDrive)) {
|
|
1066
|
+
log_1.log.debug('driver-v2 skip diligence prompt after disable toggle', undefined, {
|
|
1067
|
+
dialogId: dlg.id.valueOf(),
|
|
1068
|
+
msgId: currentPrompt.msgId,
|
|
1069
|
+
});
|
|
1070
|
+
break;
|
|
1071
|
+
}
|
|
1072
|
+
if (currentPrompt.skipTaskdoc === true) {
|
|
1073
|
+
skipTaskdocForThisDrive = true;
|
|
1074
|
+
}
|
|
1075
|
+
const promptContent = currentPrompt.content;
|
|
1076
|
+
const msgId = currentPrompt.msgId;
|
|
1077
|
+
const promptGrammar = currentPrompt.grammar;
|
|
1078
|
+
const persistedUserLanguageCode = currentPrompt.userLanguageCode ?? dlg.getLastUserLanguageCode();
|
|
1079
|
+
const q4hAnswerCallIds = normalizeQ4HAnswerCallIds(currentPrompt.q4hAnswerCallIds);
|
|
1080
|
+
await dlg.addChatMessages({
|
|
1081
|
+
type: 'prompting_msg',
|
|
1082
|
+
role: 'user',
|
|
1083
|
+
genseq: dlg.activeGenSeq,
|
|
1084
|
+
content: promptContent,
|
|
1085
|
+
msgId,
|
|
1086
|
+
grammar: promptGrammar,
|
|
1087
|
+
});
|
|
1088
|
+
await dlg.persistUserMessage(promptContent, msgId, promptGrammar, persistedUserLanguageCode, q4hAnswerCallIds);
|
|
1089
|
+
if (currentPrompt.subdialogReplyTarget) {
|
|
1090
|
+
const normalizedCallId = currentPrompt.subdialogReplyTarget.callId.trim();
|
|
1091
|
+
if (normalizedCallId === '') {
|
|
1092
|
+
throw new Error(`driver-v2 assignment anchor invariant violation: empty callId for subdialogReplyTarget (dialog=${dlg.id.valueOf()})`);
|
|
1093
|
+
}
|
|
1094
|
+
const rawCourse = dlg.activeGenCourseOrUndefined ?? dlg.currentCourse;
|
|
1095
|
+
if (!Number.isFinite(rawCourse) || rawCourse <= 0) {
|
|
1096
|
+
throw new Error(`driver-v2 assignment anchor invariant violation: invalid course=${String(rawCourse)} (dialog=${dlg.id.valueOf()})`);
|
|
1097
|
+
}
|
|
1098
|
+
const rawGenseq = dlg.activeGenSeq;
|
|
1099
|
+
if (!Number.isFinite(rawGenseq) || rawGenseq <= 0) {
|
|
1100
|
+
throw new Error(`driver-v2 assignment anchor invariant violation: invalid genseq=${String(rawGenseq)} (dialog=${dlg.id.valueOf()})`);
|
|
1101
|
+
}
|
|
1102
|
+
const assignmentAnchor = {
|
|
1103
|
+
ts: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
1104
|
+
type: 'teammate_call_anchor_record',
|
|
1105
|
+
anchorRole: 'assignment',
|
|
1106
|
+
callId: normalizedCallId,
|
|
1107
|
+
genseq: Math.floor(rawGenseq),
|
|
1108
|
+
};
|
|
1109
|
+
await persistence_1.DialogPersistence.appendEvent(dlg.id, Math.floor(rawCourse), assignmentAnchor);
|
|
1110
|
+
}
|
|
1111
|
+
await emitUserMarkdown(dlg, promptContent);
|
|
1112
|
+
(0, evt_registry_1.postDialogEvent)(dlg, {
|
|
1113
|
+
type: 'end_of_user_saying_evt',
|
|
1114
|
+
course: dlg.currentCourse,
|
|
1115
|
+
genseq: dlg.activeGenSeq,
|
|
1116
|
+
msgId,
|
|
1117
|
+
content: promptContent,
|
|
1118
|
+
grammar: promptGrammar,
|
|
1119
|
+
userLanguageCode: persistedUserLanguageCode,
|
|
1120
|
+
q4hAnswerCallIds,
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
if (suspendForHuman) {
|
|
1124
|
+
await resetDiligenceBudgetAfterQ4H(dlg, team);
|
|
1125
|
+
break;
|
|
1126
|
+
}
|
|
1127
|
+
const taskDocMsg = dlg.taskDocPath && !skipTaskdocForThisDrive ? await (0, taskdoc_1.formatTaskDocContent)(dlg) : undefined;
|
|
1128
|
+
const coursePrefixMsgs = (() => {
|
|
1129
|
+
const msgs = dlg.getCoursePrefixMsgs();
|
|
1130
|
+
return msgs.length > 0 ? [...msgs] : [];
|
|
1131
|
+
})();
|
|
1132
|
+
const rawDialogMsgsForContext = dlg.msgs.filter((m) => {
|
|
1133
|
+
if (!m)
|
|
1134
|
+
return false;
|
|
1135
|
+
if (m.type === 'ui_only_markdown_msg')
|
|
1136
|
+
return false;
|
|
1137
|
+
return true;
|
|
1138
|
+
});
|
|
1139
|
+
const dialogMsgsForContext = await projectTellaskSpecialFuncResultsForContext({
|
|
1140
|
+
dialog: dlg,
|
|
1141
|
+
dialogMsgsForContext: rawDialogMsgsForContext,
|
|
1142
|
+
});
|
|
1143
|
+
await dlg.processReminderUpdates();
|
|
1144
|
+
const renderedReminders = dlg.reminders.length > 0
|
|
1145
|
+
? await Promise.all(dlg.reminders.map(async (reminder, index) => {
|
|
1146
|
+
if (reminder.owner) {
|
|
1147
|
+
return await reminder.owner.renderReminder(dlg, reminder, index);
|
|
1148
|
+
}
|
|
1149
|
+
return {
|
|
1150
|
+
type: 'environment_msg',
|
|
1151
|
+
role: 'user',
|
|
1152
|
+
content: (0, driver_messages_1.formatReminderItemGuide)((0, runtime_language_1.getWorkLanguage)(), index + 1, reminder.content, {
|
|
1153
|
+
meta: reminder.meta,
|
|
1154
|
+
}),
|
|
1155
|
+
};
|
|
1156
|
+
}))
|
|
1157
|
+
: [];
|
|
1158
|
+
const uiLanguage = dlg.getLastUserLanguageCode();
|
|
1159
|
+
const workingLanguage = (0, runtime_language_1.getWorkLanguage)();
|
|
1160
|
+
const guideMsg = {
|
|
1161
|
+
type: 'transient_guide_msg',
|
|
1162
|
+
role: 'assistant',
|
|
1163
|
+
content: (0, driver_messages_1.formatCurrentUserLanguagePreference)(workingLanguage, uiLanguage),
|
|
1164
|
+
};
|
|
1165
|
+
const ctxMsgs = (0, context_1.assembleDriveContextMessages)({
|
|
1166
|
+
base: {
|
|
1167
|
+
prependedContextMessages: policy.prependedContextMessages,
|
|
1168
|
+
memories,
|
|
1169
|
+
taskDocMsg,
|
|
1170
|
+
coursePrefixMsgs,
|
|
1171
|
+
dialogMsgsForContext,
|
|
1172
|
+
},
|
|
1173
|
+
ephemeral: {},
|
|
1174
|
+
tail: {
|
|
1175
|
+
renderedReminders,
|
|
1176
|
+
languageGuideMsg: guideMsg,
|
|
1177
|
+
},
|
|
1178
|
+
});
|
|
1179
|
+
if (agent.streaming === false) {
|
|
1180
|
+
const nonStreamResult = await (0, runtime_utils_1.runLlmRequestWithRetry)({
|
|
1181
|
+
dlg,
|
|
1182
|
+
provider,
|
|
1183
|
+
abortSignal,
|
|
1184
|
+
maxRetries: retryPolicy.maxRetries,
|
|
1185
|
+
retryInitialDelayMs: retryPolicy.initialDelayMs,
|
|
1186
|
+
retryBackoffMultiplier: retryPolicy.backoffMultiplier,
|
|
1187
|
+
retryMaxDelayMs: retryPolicy.maxDelayMs,
|
|
1188
|
+
canRetry: () => true,
|
|
1189
|
+
doRequest: async () => {
|
|
1190
|
+
const batchResult = await llmGen.genMoreMessages(providerCfg, agent, systemPrompt, funcTools, ctxMsgs, dlg.activeGenSeq, abortSignal);
|
|
1191
|
+
if (!hasMeaningfulBatchOutput(batchResult.messages)) {
|
|
1192
|
+
throw {
|
|
1193
|
+
status: 503,
|
|
1194
|
+
code: DRIVER_V2_EMPTY_LLM_RESPONSE_ERROR_CODE,
|
|
1195
|
+
message: `LLM returned empty response (provider=${provider}, model=${model}, streaming=false).`,
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
return batchResult;
|
|
1199
|
+
},
|
|
1200
|
+
});
|
|
1201
|
+
if (typeof nonStreamResult.llmGenModel === 'string' &&
|
|
1202
|
+
nonStreamResult.llmGenModel.trim() !== '') {
|
|
1203
|
+
llmGenModelForGen = nonStreamResult.llmGenModel.trim();
|
|
1204
|
+
}
|
|
1205
|
+
contextHealthForGen = computeContextHealthSnapshot({
|
|
1206
|
+
providerCfg,
|
|
1207
|
+
model,
|
|
1208
|
+
usage: nonStreamResult.usage,
|
|
1209
|
+
});
|
|
1210
|
+
dlg.setLastContextHealth(contextHealthForGen);
|
|
1211
|
+
const nonStreamMsgs = nonStreamResult.messages;
|
|
1212
|
+
const assistantMsgs = nonStreamMsgs.filter((m) => m.type === 'saying_msg' || m.type === 'thinking_msg');
|
|
1213
|
+
if (assistantMsgs.length > 0) {
|
|
1214
|
+
await dlg.addChatMessages(...assistantMsgs);
|
|
1215
|
+
for (const msg of assistantMsgs) {
|
|
1216
|
+
if (msg.role === 'assistant' &&
|
|
1217
|
+
msg.genseq !== undefined &&
|
|
1218
|
+
(msg.type === 'thinking_msg' || msg.type === 'saying_msg')) {
|
|
1219
|
+
if (msg.type === 'saying_msg') {
|
|
1220
|
+
lastAssistantSayingContent = msg.content;
|
|
1221
|
+
lastAssistantSayingGenseq = msg.genseq;
|
|
1222
|
+
await dlg.persistAgentMessage(msg.content, msg.genseq, 'saying_msg');
|
|
1223
|
+
await emitUserMarkdown(dlg, msg.content);
|
|
1224
|
+
}
|
|
1225
|
+
if (msg.type === 'thinking_msg') {
|
|
1226
|
+
await (0, saying_events_1.emitThinkingEvents)(dlg, msg.content);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
const funcCalls = nonStreamMsgs.filter((m) => m.type === 'func_call_msg');
|
|
1232
|
+
for (const call of funcCalls) {
|
|
1233
|
+
const rawCallGenseq = call.genseq;
|
|
1234
|
+
if (!Number.isFinite(rawCallGenseq) || rawCallGenseq <= 0) {
|
|
1235
|
+
continue;
|
|
1236
|
+
}
|
|
1237
|
+
const callGenseq = Math.floor(rawCallGenseq);
|
|
1238
|
+
if (lastFunctionCallGenseq === null || callGenseq > lastFunctionCallGenseq) {
|
|
1239
|
+
lastFunctionCallGenseq = callGenseq;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
const toolPolicyViolation = (0, policy_1.resolveDriverV2PolicyViolationKind)({
|
|
1243
|
+
policy,
|
|
1244
|
+
tellaskCallCount: 0,
|
|
1245
|
+
functionCallCount: funcCalls.length,
|
|
1246
|
+
});
|
|
1247
|
+
if (toolPolicyViolation === 'tool') {
|
|
1248
|
+
const violationText = (0, driver_messages_1.formatDomindsNoteFbrToollessViolation)((0, runtime_language_1.getWorkLanguage)(), {
|
|
1249
|
+
kind: 'tool',
|
|
1250
|
+
});
|
|
1251
|
+
const genseq = dlg.activeGenSeq ?? 0;
|
|
1252
|
+
await dlg.addChatMessages({
|
|
1253
|
+
type: 'saying_msg',
|
|
1254
|
+
role: 'assistant',
|
|
1255
|
+
genseq,
|
|
1256
|
+
content: violationText,
|
|
1257
|
+
});
|
|
1258
|
+
lastAssistantSayingContent = violationText;
|
|
1259
|
+
lastAssistantSayingGenseq = genseq;
|
|
1260
|
+
await dlg.persistAgentMessage(violationText, genseq, 'saying_msg');
|
|
1261
|
+
return {
|
|
1262
|
+
lastAssistantSayingContent,
|
|
1263
|
+
lastAssistantSayingGenseq,
|
|
1264
|
+
lastFunctionCallGenseq,
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
const routedFunctionResult = await executeRoutedFunctionCalls({
|
|
1268
|
+
dialog: dlg,
|
|
1269
|
+
agent,
|
|
1270
|
+
agentTools,
|
|
1271
|
+
funcCalls,
|
|
1272
|
+
callbacks,
|
|
1273
|
+
abortSignal,
|
|
1274
|
+
});
|
|
1275
|
+
if (routedFunctionResult.tellaskToolOutputs.length > 0) {
|
|
1276
|
+
await dlg.addChatMessages(...routedFunctionResult.tellaskToolOutputs);
|
|
1277
|
+
}
|
|
1278
|
+
if (routedFunctionResult.pairedMessages.length > 0) {
|
|
1279
|
+
await dlg.addChatMessages(...routedFunctionResult.pairedMessages);
|
|
1280
|
+
}
|
|
1281
|
+
if (routedFunctionResult.suspendForHuman) {
|
|
1282
|
+
suspendForHuman = true;
|
|
1283
|
+
}
|
|
1284
|
+
if (dlg.hasUpNext()) {
|
|
1285
|
+
pendingPrompt = resolveUpNextPrompt(dlg);
|
|
1286
|
+
continue;
|
|
1287
|
+
}
|
|
1288
|
+
if (suspendForHuman) {
|
|
1289
|
+
await resetDiligenceBudgetAfterQ4H(dlg, team);
|
|
1290
|
+
break;
|
|
1291
|
+
}
|
|
1292
|
+
const shouldContinue = funcCalls.length > 0 ||
|
|
1293
|
+
routedFunctionResult.pairedMessages.length > 0 ||
|
|
1294
|
+
routedFunctionResult.tellaskToolOutputs.length > 0;
|
|
1295
|
+
if (!shouldContinue) {
|
|
1296
|
+
const healthFirst = await maybeContinueWithHealthPromptBeforeDiligence({
|
|
1297
|
+
dlg,
|
|
1298
|
+
providerCfg,
|
|
1299
|
+
model,
|
|
1300
|
+
});
|
|
1301
|
+
if (healthFirst.kind === 'health_continue') {
|
|
1302
|
+
pendingPrompt = healthFirst.prompt;
|
|
1303
|
+
if (healthFirst.resetTaskdoc) {
|
|
1304
|
+
skipTaskdocForThisDrive = false;
|
|
1305
|
+
}
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
if (healthFirst.kind === 'health_suspend') {
|
|
1309
|
+
break;
|
|
1310
|
+
}
|
|
1311
|
+
const next = await maybeContinueWithDiligencePrompt({
|
|
1312
|
+
dlg,
|
|
1313
|
+
team,
|
|
1314
|
+
suppressDiligencePushForDrive,
|
|
1315
|
+
});
|
|
1316
|
+
if (next.kind === 'continue') {
|
|
1317
|
+
pendingPrompt = next.prompt;
|
|
1318
|
+
continue;
|
|
1319
|
+
}
|
|
1320
|
+
break;
|
|
1321
|
+
}
|
|
1322
|
+
continue;
|
|
1323
|
+
}
|
|
1324
|
+
const newMsgs = [];
|
|
1325
|
+
const streamedFuncCalls = [];
|
|
1326
|
+
let currentThinkingContent = '';
|
|
1327
|
+
let currentThinkingSignature = '';
|
|
1328
|
+
let currentSayingContent = '';
|
|
1329
|
+
let streamAttemptCourse;
|
|
1330
|
+
let streamAttemptCheckpointOffset;
|
|
1331
|
+
let streamAttemptSayingContent;
|
|
1332
|
+
let streamAttemptSayingGenseq;
|
|
1333
|
+
let streamSawWebSearchCall = false;
|
|
1334
|
+
let streamActive = { kind: 'idle' };
|
|
1335
|
+
const rollbackStreamAttempt = async () => {
|
|
1336
|
+
if (streamAttemptCourse === undefined || streamAttemptCheckpointOffset === undefined) {
|
|
1337
|
+
throw new Error(`driver-v2 stream retry invariant violation: missing checkpoint (dialog=${dlg.id.valueOf()})`);
|
|
1338
|
+
}
|
|
1339
|
+
await persistence_1.DialogPersistence.rollbackCourseFileToOffset(dlg.id, streamAttemptCourse, streamAttemptCheckpointOffset, dlg.status);
|
|
1340
|
+
(0, evt_registry_1.postDialogEvent)(dlg, {
|
|
1341
|
+
type: 'genseq_discard_evt',
|
|
1342
|
+
course: streamAttemptCourse,
|
|
1343
|
+
genseq: dlg.activeGenSeq,
|
|
1344
|
+
reason: 'retry',
|
|
1345
|
+
});
|
|
1346
|
+
streamActive = { kind: 'idle' };
|
|
1347
|
+
currentThinkingContent = '';
|
|
1348
|
+
currentThinkingSignature = '';
|
|
1349
|
+
currentSayingContent = '';
|
|
1350
|
+
streamAttemptSayingContent = undefined;
|
|
1351
|
+
streamAttemptSayingGenseq = undefined;
|
|
1352
|
+
streamSawWebSearchCall = false;
|
|
1353
|
+
streamedFuncCalls.length = 0;
|
|
1354
|
+
newMsgs.length = 0;
|
|
1355
|
+
};
|
|
1356
|
+
const streamResult = await (0, runtime_utils_1.runLlmRequestWithRetry)({
|
|
1357
|
+
dlg,
|
|
1358
|
+
provider,
|
|
1359
|
+
abortSignal,
|
|
1360
|
+
maxRetries: retryPolicy.maxRetries,
|
|
1361
|
+
retryInitialDelayMs: retryPolicy.initialDelayMs,
|
|
1362
|
+
retryBackoffMultiplier: retryPolicy.backoffMultiplier,
|
|
1363
|
+
retryMaxDelayMs: retryPolicy.maxDelayMs,
|
|
1364
|
+
canRetry: () => true,
|
|
1365
|
+
onRetry: rollbackStreamAttempt,
|
|
1366
|
+
onGiveUp: rollbackStreamAttempt,
|
|
1367
|
+
doRequest: async () => {
|
|
1368
|
+
streamAttemptCourse = dlg.activeGenCourseOrUndefined ?? dlg.currentCourse;
|
|
1369
|
+
streamAttemptCheckpointOffset = await persistence_1.DialogPersistence.captureCourseFileOffset(dlg.id, streamAttemptCourse, dlg.status);
|
|
1370
|
+
streamActive = { kind: 'idle' };
|
|
1371
|
+
currentThinkingContent = '';
|
|
1372
|
+
currentThinkingSignature = '';
|
|
1373
|
+
currentSayingContent = '';
|
|
1374
|
+
streamAttemptSayingContent = undefined;
|
|
1375
|
+
streamAttemptSayingGenseq = undefined;
|
|
1376
|
+
streamSawWebSearchCall = false;
|
|
1377
|
+
streamedFuncCalls.length = 0;
|
|
1378
|
+
newMsgs.length = 0;
|
|
1379
|
+
const streamResult = await llmGen.genToReceiver(providerCfg, agent, systemPrompt, funcTools, ctxMsgs, {
|
|
1380
|
+
streamError: async (detail) => {
|
|
1381
|
+
await dlg.streamError(detail);
|
|
1382
|
+
},
|
|
1383
|
+
thinkingStart: async () => {
|
|
1384
|
+
throwIfAborted(abortSignal, dlg);
|
|
1385
|
+
if (streamActive.kind !== 'idle') {
|
|
1386
|
+
const detail = `Protocol violation: thinkingStart while ${streamActive.kind} is active`;
|
|
1387
|
+
await dlg.streamError(detail);
|
|
1388
|
+
throw new Error(detail);
|
|
1389
|
+
}
|
|
1390
|
+
streamActive = { kind: 'thinking' };
|
|
1391
|
+
currentThinkingContent = '';
|
|
1392
|
+
currentThinkingSignature = '';
|
|
1393
|
+
await dlg.thinkingStart();
|
|
1394
|
+
},
|
|
1395
|
+
thinkingChunk: async (chunk) => {
|
|
1396
|
+
throwIfAborted(abortSignal, dlg);
|
|
1397
|
+
currentThinkingContent += chunk;
|
|
1398
|
+
const signatureMatch = currentThinkingContent.match(/<thinking[^>]*>(.*?)<\/thinking>/s);
|
|
1399
|
+
if (signatureMatch && signatureMatch[1]) {
|
|
1400
|
+
currentThinkingSignature = signatureMatch[1].trim();
|
|
1401
|
+
}
|
|
1402
|
+
await dlg.thinkingChunk(chunk);
|
|
1403
|
+
},
|
|
1404
|
+
thinkingFinish: async () => {
|
|
1405
|
+
throwIfAborted(abortSignal, dlg);
|
|
1406
|
+
if (streamActive.kind !== 'thinking') {
|
|
1407
|
+
const detail = `Protocol violation: thinkingFinish while ${streamActive.kind} is active`;
|
|
1408
|
+
await dlg.streamError(detail);
|
|
1409
|
+
throw new Error(detail);
|
|
1410
|
+
}
|
|
1411
|
+
streamActive = { kind: 'idle' };
|
|
1412
|
+
const genseq = dlg.activeGenSeq;
|
|
1413
|
+
if (genseq) {
|
|
1414
|
+
const thinkingMessage = {
|
|
1415
|
+
type: 'thinking_msg',
|
|
1416
|
+
role: 'assistant',
|
|
1417
|
+
genseq,
|
|
1418
|
+
content: currentThinkingContent,
|
|
1419
|
+
provider_data: currentThinkingSignature
|
|
1420
|
+
? { signature: currentThinkingSignature }
|
|
1421
|
+
: undefined,
|
|
1422
|
+
};
|
|
1423
|
+
newMsgs.push(thinkingMessage);
|
|
1424
|
+
}
|
|
1425
|
+
await dlg.thinkingFinish();
|
|
1426
|
+
},
|
|
1427
|
+
sayingStart: async () => {
|
|
1428
|
+
throwIfAborted(abortSignal, dlg);
|
|
1429
|
+
if (streamActive.kind !== 'idle') {
|
|
1430
|
+
const detail = `Protocol violation: sayingStart while ${streamActive.kind} is active`;
|
|
1431
|
+
await dlg.streamError(detail);
|
|
1432
|
+
throw new Error(detail);
|
|
1433
|
+
}
|
|
1434
|
+
streamActive = { kind: 'saying' };
|
|
1435
|
+
currentSayingContent = '';
|
|
1436
|
+
await dlg.sayingStart();
|
|
1437
|
+
},
|
|
1438
|
+
sayingChunk: async (chunk) => {
|
|
1439
|
+
throwIfAborted(abortSignal, dlg);
|
|
1440
|
+
currentSayingContent += chunk;
|
|
1441
|
+
await dlg.sayingChunk(chunk);
|
|
1442
|
+
},
|
|
1443
|
+
sayingFinish: async () => {
|
|
1444
|
+
throwIfAborted(abortSignal, dlg);
|
|
1445
|
+
if (streamActive.kind !== 'saying') {
|
|
1446
|
+
const detail = `Protocol violation: sayingFinish while ${streamActive.kind} is active`;
|
|
1447
|
+
await dlg.streamError(detail);
|
|
1448
|
+
throw new Error(detail);
|
|
1449
|
+
}
|
|
1450
|
+
streamActive = { kind: 'idle' };
|
|
1451
|
+
const sayingMessage = {
|
|
1452
|
+
type: 'saying_msg',
|
|
1453
|
+
role: 'assistant',
|
|
1454
|
+
genseq: dlg.activeGenSeq,
|
|
1455
|
+
content: currentSayingContent,
|
|
1456
|
+
};
|
|
1457
|
+
newMsgs.push(sayingMessage);
|
|
1458
|
+
streamAttemptSayingContent = currentSayingContent;
|
|
1459
|
+
streamAttemptSayingGenseq = sayingMessage.genseq;
|
|
1460
|
+
await dlg.sayingFinish();
|
|
1461
|
+
},
|
|
1462
|
+
funcCall: async (callId, name, args) => {
|
|
1463
|
+
throwIfAborted(abortSignal, dlg);
|
|
1464
|
+
const genseq = dlg.activeGenSeq;
|
|
1465
|
+
if (genseq === undefined) {
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
streamedFuncCalls.push({
|
|
1469
|
+
type: 'func_call_msg',
|
|
1470
|
+
role: 'assistant',
|
|
1471
|
+
genseq,
|
|
1472
|
+
id: callId,
|
|
1473
|
+
name,
|
|
1474
|
+
arguments: args,
|
|
1475
|
+
});
|
|
1476
|
+
},
|
|
1477
|
+
webSearchCall: async (call) => {
|
|
1478
|
+
throwIfAborted(abortSignal, dlg);
|
|
1479
|
+
streamSawWebSearchCall = true;
|
|
1480
|
+
await dlg.webSearchCall(call);
|
|
1481
|
+
},
|
|
1482
|
+
}, dlg.activeGenSeq, abortSignal);
|
|
1483
|
+
const hasThinkingContent = currentThinkingContent.trim() !== '';
|
|
1484
|
+
const hasSayingContent = (streamAttemptSayingContent ?? '').trim() !== '';
|
|
1485
|
+
const hasFunctionCall = streamedFuncCalls.length > 0;
|
|
1486
|
+
if (!hasThinkingContent &&
|
|
1487
|
+
!hasSayingContent &&
|
|
1488
|
+
!hasFunctionCall &&
|
|
1489
|
+
!streamSawWebSearchCall) {
|
|
1490
|
+
throw {
|
|
1491
|
+
status: 503,
|
|
1492
|
+
code: DRIVER_V2_EMPTY_LLM_RESPONSE_ERROR_CODE,
|
|
1493
|
+
message: `LLM returned empty response (provider=${provider}, model=${model}, streaming=true).`,
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
return streamResult;
|
|
1497
|
+
},
|
|
1498
|
+
});
|
|
1499
|
+
if (typeof streamResult.llmGenModel === 'string' &&
|
|
1500
|
+
streamResult.llmGenModel.trim() !== '') {
|
|
1501
|
+
llmGenModelForGen = streamResult.llmGenModel.trim();
|
|
1502
|
+
}
|
|
1503
|
+
contextHealthForGen = computeContextHealthSnapshot({
|
|
1504
|
+
providerCfg,
|
|
1505
|
+
model,
|
|
1506
|
+
usage: streamResult.usage,
|
|
1507
|
+
});
|
|
1508
|
+
dlg.setLastContextHealth(contextHealthForGen);
|
|
1509
|
+
const policyViolation = (0, policy_1.resolveDriverV2PolicyViolationKind)({
|
|
1510
|
+
policy,
|
|
1511
|
+
tellaskCallCount: 0,
|
|
1512
|
+
functionCallCount: streamedFuncCalls.length,
|
|
1513
|
+
});
|
|
1514
|
+
for (const call of streamedFuncCalls) {
|
|
1515
|
+
const rawCallGenseq = call.genseq;
|
|
1516
|
+
if (!Number.isFinite(rawCallGenseq) || rawCallGenseq <= 0) {
|
|
1517
|
+
continue;
|
|
1518
|
+
}
|
|
1519
|
+
const callGenseq = Math.floor(rawCallGenseq);
|
|
1520
|
+
if (lastFunctionCallGenseq === null || callGenseq > lastFunctionCallGenseq) {
|
|
1521
|
+
lastFunctionCallGenseq = callGenseq;
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
if (policyViolation) {
|
|
1525
|
+
const violationText = (0, driver_messages_1.formatDomindsNoteFbrToollessViolation)((0, runtime_language_1.getWorkLanguage)(), {
|
|
1526
|
+
kind: policyViolation,
|
|
1527
|
+
});
|
|
1528
|
+
const genseq = dlg.activeGenSeq ?? 0;
|
|
1529
|
+
newMsgs.push({
|
|
1530
|
+
type: 'saying_msg',
|
|
1531
|
+
role: 'assistant',
|
|
1532
|
+
genseq,
|
|
1533
|
+
content: violationText,
|
|
1534
|
+
});
|
|
1535
|
+
lastAssistantSayingContent = violationText;
|
|
1536
|
+
lastAssistantSayingGenseq = genseq;
|
|
1537
|
+
await dlg.addChatMessages(...newMsgs);
|
|
1538
|
+
await dlg.persistAgentMessage(violationText, genseq, 'saying_msg');
|
|
1539
|
+
return {
|
|
1540
|
+
lastAssistantSayingContent,
|
|
1541
|
+
lastAssistantSayingGenseq,
|
|
1542
|
+
lastFunctionCallGenseq,
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1545
|
+
if (streamAttemptSayingContent !== undefined) {
|
|
1546
|
+
lastAssistantSayingContent = streamAttemptSayingContent;
|
|
1547
|
+
lastAssistantSayingGenseq =
|
|
1548
|
+
streamAttemptSayingGenseq === undefined ? null : streamAttemptSayingGenseq;
|
|
1549
|
+
}
|
|
1550
|
+
const routedFunctionResult = await executeRoutedFunctionCalls({
|
|
1551
|
+
dialog: dlg,
|
|
1552
|
+
agent,
|
|
1553
|
+
agentTools,
|
|
1554
|
+
funcCalls: streamedFuncCalls,
|
|
1555
|
+
callbacks,
|
|
1556
|
+
abortSignal,
|
|
1557
|
+
});
|
|
1558
|
+
if (routedFunctionResult.tellaskToolOutputs.length > 0) {
|
|
1559
|
+
newMsgs.push(...routedFunctionResult.tellaskToolOutputs);
|
|
1560
|
+
}
|
|
1561
|
+
if (routedFunctionResult.pairedMessages.length > 0) {
|
|
1562
|
+
newMsgs.push(...routedFunctionResult.pairedMessages);
|
|
1563
|
+
}
|
|
1564
|
+
if (routedFunctionResult.suspendForHuman) {
|
|
1565
|
+
suspendForHuman = true;
|
|
1566
|
+
}
|
|
1567
|
+
await dlg.addChatMessages(...newMsgs);
|
|
1568
|
+
if (dlg.hasUpNext()) {
|
|
1569
|
+
pendingPrompt = resolveUpNextPrompt(dlg);
|
|
1570
|
+
continue;
|
|
1571
|
+
}
|
|
1572
|
+
if (dlg.remindersVer > pubRemindersVer) {
|
|
1573
|
+
await dlg.processReminderUpdates();
|
|
1574
|
+
pubRemindersVer = dlg.remindersVer;
|
|
1575
|
+
}
|
|
1576
|
+
if (suspendForHuman) {
|
|
1577
|
+
await resetDiligenceBudgetAfterQ4H(dlg, team);
|
|
1578
|
+
break;
|
|
1579
|
+
}
|
|
1580
|
+
const shouldContinue = streamedFuncCalls.length > 0 ||
|
|
1581
|
+
routedFunctionResult.pairedMessages.length > 0 ||
|
|
1582
|
+
routedFunctionResult.tellaskToolOutputs.length > 0;
|
|
1583
|
+
if (!shouldContinue) {
|
|
1584
|
+
const healthFirst = await maybeContinueWithHealthPromptBeforeDiligence({
|
|
1585
|
+
dlg,
|
|
1586
|
+
providerCfg,
|
|
1587
|
+
model,
|
|
1588
|
+
});
|
|
1589
|
+
if (healthFirst.kind === 'health_continue') {
|
|
1590
|
+
pendingPrompt = healthFirst.prompt;
|
|
1591
|
+
if (healthFirst.resetTaskdoc) {
|
|
1592
|
+
skipTaskdocForThisDrive = false;
|
|
1593
|
+
}
|
|
1594
|
+
continue;
|
|
1595
|
+
}
|
|
1596
|
+
if (healthFirst.kind === 'health_suspend') {
|
|
1597
|
+
break;
|
|
1598
|
+
}
|
|
1599
|
+
const next = await maybeContinueWithDiligencePrompt({
|
|
1600
|
+
dlg,
|
|
1601
|
+
team,
|
|
1602
|
+
suppressDiligencePushForDrive,
|
|
1603
|
+
});
|
|
1604
|
+
if (next.kind === 'continue') {
|
|
1605
|
+
pendingPrompt = next.prompt;
|
|
1606
|
+
continue;
|
|
1607
|
+
}
|
|
1608
|
+
break;
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
finally {
|
|
1612
|
+
await dlg.notifyGeneratingFinish(contextHealthForGen, llmGenModelForGen);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
throwIfAborted(abortSignal, dlg);
|
|
1616
|
+
finalRunState = await (0, dialog_run_state_1.computeIdleRunState)(dlg);
|
|
1617
|
+
throwIfAborted(abortSignal, dlg);
|
|
1618
|
+
finalResult = {
|
|
1619
|
+
lastAssistantSayingContent,
|
|
1620
|
+
lastAssistantSayingGenseq,
|
|
1621
|
+
lastFunctionCallGenseq,
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
catch (err) {
|
|
1625
|
+
const stopRequested = (0, dialog_run_state_1.getStopRequestedReason)(dlg.id);
|
|
1626
|
+
const interruptedReason = err instanceof DialogInterruptedError
|
|
1627
|
+
? err.reason
|
|
1628
|
+
: abortSignal.aborted
|
|
1629
|
+
? stopRequested === 'emergency_stop'
|
|
1630
|
+
? { kind: 'emergency_stop' }
|
|
1631
|
+
: stopRequested === 'user_stop'
|
|
1632
|
+
? { kind: 'user_stop' }
|
|
1633
|
+
: { kind: 'system_stop', detail: 'Aborted.' }
|
|
1634
|
+
: undefined;
|
|
1635
|
+
if (interruptedReason) {
|
|
1636
|
+
finalRunState = { kind: 'interrupted', reason: interruptedReason };
|
|
1637
|
+
(0, dialog_run_state_1.broadcastRunStateMarker)(dlg.id, { kind: 'interrupted', reason: interruptedReason });
|
|
1638
|
+
finalResult = {
|
|
1639
|
+
lastAssistantSayingContent,
|
|
1640
|
+
lastAssistantSayingGenseq,
|
|
1641
|
+
lastFunctionCallGenseq,
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
else {
|
|
1645
|
+
const errText = (0, log_1.extractErrorDetails)(err).message;
|
|
1646
|
+
try {
|
|
1647
|
+
await dlg.streamError(errText);
|
|
1648
|
+
}
|
|
1649
|
+
catch {
|
|
1650
|
+
// best-effort
|
|
1651
|
+
}
|
|
1652
|
+
finalRunState = { kind: 'interrupted', reason: { kind: 'system_stop', detail: errText } };
|
|
1653
|
+
(0, dialog_run_state_1.broadcastRunStateMarker)(dlg.id, {
|
|
1654
|
+
kind: 'interrupted',
|
|
1655
|
+
reason: { kind: 'system_stop', detail: errText },
|
|
1656
|
+
});
|
|
1657
|
+
finalResult = {
|
|
1658
|
+
lastAssistantSayingContent,
|
|
1659
|
+
lastAssistantSayingGenseq,
|
|
1660
|
+
lastFunctionCallGenseq,
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
finally {
|
|
1665
|
+
if (!finalRunState) {
|
|
1666
|
+
try {
|
|
1667
|
+
finalRunState = await (0, dialog_run_state_1.computeIdleRunState)(dlg);
|
|
1668
|
+
}
|
|
1669
|
+
catch (stateErr) {
|
|
1670
|
+
log_1.log.warn('driver-v2 failed to compute final run state; falling back to idle', stateErr, {
|
|
1671
|
+
dialogId: dlg.id.valueOf(),
|
|
1672
|
+
});
|
|
1673
|
+
finalRunState = { kind: 'idle_waiting_user' };
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
if (abortSignal.aborted &&
|
|
1677
|
+
finalRunState.kind !== 'interrupted' &&
|
|
1678
|
+
finalRunState.kind !== 'dead') {
|
|
1679
|
+
const stopRequested = (0, dialog_run_state_1.getStopRequestedReason)(dlg.id);
|
|
1680
|
+
const lateInterruptedReason = stopRequested === 'emergency_stop'
|
|
1681
|
+
? { kind: 'emergency_stop' }
|
|
1682
|
+
: stopRequested === 'user_stop'
|
|
1683
|
+
? { kind: 'user_stop' }
|
|
1684
|
+
: { kind: 'system_stop', detail: 'Aborted.' };
|
|
1685
|
+
finalRunState = { kind: 'interrupted', reason: lateInterruptedReason };
|
|
1686
|
+
if (finalResult) {
|
|
1687
|
+
(0, dialog_run_state_1.broadcastRunStateMarker)(dlg.id, { kind: 'interrupted', reason: lateInterruptedReason });
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
try {
|
|
1691
|
+
const latest = await persistence_1.DialogPersistence.loadDialogLatest(dlg.id, 'running');
|
|
1692
|
+
if (dlg.id.selfId !== dlg.id.rootId &&
|
|
1693
|
+
latest &&
|
|
1694
|
+
latest.runState &&
|
|
1695
|
+
latest.runState.kind === 'dead') {
|
|
1696
|
+
finalRunState = latest.runState;
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
catch (err) {
|
|
1700
|
+
log_1.log.warn('driver-v2 failed to re-check runState before finalizing', err, {
|
|
1701
|
+
dialogId: dlg.id.valueOf(),
|
|
1702
|
+
});
|
|
1703
|
+
}
|
|
1704
|
+
await (0, dialog_run_state_1.setDialogRunState)(dlg.id, finalRunState);
|
|
1705
|
+
}
|
|
1706
|
+
if (!finalResult) {
|
|
1707
|
+
throw new Error(`driver-v2 core invariant violation: missing final result (dialog=${dlg.id.valueOf()})`);
|
|
1708
|
+
}
|
|
1709
|
+
return finalResult;
|
|
1710
|
+
}
|