dominds 1.13.2 → 1.15.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/dist/bootstrap/global-dialog-event-broadcaster.d.ts +18 -0
- package/dist/bootstrap/global-dialog-event-broadcaster.js +81 -0
- package/dist/dialog-fork.js +13 -12
- package/dist/dialog.d.ts +61 -50
- package/dist/dialog.js +284 -78
- package/dist/docs/dialog-system.md +12 -0
- package/dist/docs/dialog-system.zh.md +12 -0
- package/dist/docs/dominds-terminology.md +17 -0
- package/dist/docs/issues/global-dialog-event-broadcaster-missing.md +128 -0
- package/dist/docs/llm-provider-isolation.md +35 -0
- package/dist/docs/llm-provider-isolation.zh.md +35 -0
- package/dist/llm/client.d.ts +2 -1
- package/dist/llm/defaults.yaml +118 -4
- package/dist/llm/gen/anthropic.js +2 -4
- package/dist/llm/gen/codex.d.ts +11 -0
- package/dist/llm/gen/codex.js +41 -31
- package/dist/llm/gen/failure-classifier.js +17 -0
- package/dist/llm/gen/mock.js +45 -21
- package/dist/llm/gen/openai-compatible.d.ts +2 -0
- package/dist/llm/gen/openai-compatible.js +43 -38
- package/dist/llm/gen/openai.d.ts +3 -1
- package/dist/llm/gen/openai.js +888 -71
- package/dist/llm/gen/tool-call-context.d.ts +7 -2
- package/dist/llm/gen/tool-call-context.js +55 -13
- package/dist/llm/gen.d.ts +60 -3
- package/dist/llm/kernel-driver/context.js +1 -1
- package/dist/llm/kernel-driver/drive.js +374 -348
- package/dist/llm/kernel-driver/flow.js +3 -3
- package/dist/llm/kernel-driver/guardrails.d.ts +1 -1
- package/dist/llm/kernel-driver/guardrails.js +4 -4
- package/dist/llm/kernel-driver/runtime.js +11 -29
- package/dist/llm/kernel-driver/subdialog.js +56 -5
- package/dist/llm/kernel-driver/tellask-special.d.ts +38 -12
- package/dist/llm/kernel-driver/tellask-special.js +489 -180
- package/dist/llm/kernel-driver/types.d.ts +1 -1
- package/dist/persistence.d.ts +30 -62
- package/dist/persistence.js +978 -986
- package/dist/priming.js +398 -365
- package/dist/recovery/reply-special.js +3 -3
- package/dist/runtime/inter-dialog-format.d.ts +1 -1
- package/dist/runtime/inter-dialog-format.js +1 -1
- package/dist/runtime/reply-prompt-copy.js +4 -4
- package/dist/server/setup-routes.js +26 -5
- package/dist/server/snippets-routes.d.ts +1 -0
- package/dist/server/snippets-routes.js +20 -9
- package/dist/server/websocket-handler.js +58 -25
- package/dist/shared/utils/fbr.js +12 -8
- package/dist/shared/utils/inter-dialog-format.js +6 -4
- package/dist/team.d.ts +24 -13
- package/dist/team.js +123 -32
- package/dist/tool.d.ts +26 -0
- package/dist/tool.js +97 -0
- package/dist/tools/team_mgmt.js +18 -0
- package/package.json +2 -2
- package/webapp/dist/assets/{_basePickBy-CBOtd63g.js → _basePickBy-DsirmCgI.js} +3 -3
- package/webapp/dist/assets/_basePickBy-DsirmCgI.js.map +1 -0
- package/webapp/dist/assets/{_baseUniq-mfoKz4Wm.js → _baseUniq-tR6G8loB.js} +2 -2
- package/webapp/dist/assets/_baseUniq-tR6G8loB.js.map +1 -0
- package/webapp/dist/assets/{arc-Dq0WZLyu.js → arc-CzxpASkZ.js} +2 -2
- package/webapp/dist/assets/arc-CzxpASkZ.js.map +1 -0
- package/webapp/dist/assets/{architectureDiagram-VXUJARFQ-CNmygmp3.js → architectureDiagram-2XIMDMQ5-BSH7H5oI.js} +26 -8
- package/webapp/dist/assets/architectureDiagram-2XIMDMQ5-BSH7H5oI.js.map +1 -0
- package/webapp/dist/assets/{blockDiagram-VD42YOAC-DvE0lybt.js → blockDiagram-WCTKOSBZ-DpLIr7yO.js} +187 -170
- package/webapp/dist/assets/blockDiagram-WCTKOSBZ-DpLIr7yO.js.map +1 -0
- package/webapp/dist/assets/{c4Diagram-YG6GDRKO-CR7zJ2_u.js → c4Diagram-IC4MRINW-WuYKgWfY.js} +4 -4
- package/webapp/dist/assets/c4Diagram-IC4MRINW-WuYKgWfY.js.map +1 -0
- package/webapp/dist/assets/{channel-DrTrnYx4.js → channel-B-v9dqLN.js} +2 -2
- package/webapp/dist/assets/channel-B-v9dqLN.js.map +1 -0
- package/webapp/dist/assets/{chunk-4BX2VUAB-CVuJEIeN.js → chunk-4BX2VUAB-MtFUfKZy.js} +2 -2
- package/webapp/dist/assets/chunk-4BX2VUAB-MtFUfKZy.js.map +1 -0
- package/webapp/dist/assets/{chunk-55IACEB6-BxUoXApB.js → chunk-55IACEB6-rY9AJdzj.js} +2 -2
- package/webapp/dist/assets/chunk-55IACEB6-rY9AJdzj.js.map +1 -0
- package/webapp/dist/assets/{chunk-FMBD7UC4-TX-LVAaV.js → chunk-FMBD7UC4-B-RtOs7e.js} +2 -2
- package/webapp/dist/assets/chunk-FMBD7UC4-B-RtOs7e.js.map +1 -0
- package/webapp/dist/assets/{chunk-TZMSLE5B-Cw689yRl.js → chunk-JSJVCQXG-Da1d3uS4.js} +14 -6
- package/webapp/dist/assets/chunk-JSJVCQXG-Da1d3uS4.js.map +1 -0
- package/webapp/dist/assets/{chunk-QN33PNHL-D1uiKlOO.js → chunk-KX2RTZJC-DH9UrpuG.js} +2 -2
- package/webapp/dist/assets/chunk-KX2RTZJC-DH9UrpuG.js.map +1 -0
- package/webapp/dist/assets/{chunk-DI55MBZ5-SAhxUTqQ.js → chunk-NQ4KR5QH-CK365lrr.js} +9 -7
- package/webapp/dist/assets/chunk-NQ4KR5QH-CK365lrr.js.map +1 -0
- package/webapp/dist/assets/{chunk-QZHKN3VN-BxuV0Oba.js → chunk-QZHKN3VN-BCaWPGDm.js} +2 -2
- package/webapp/dist/assets/chunk-QZHKN3VN-BCaWPGDm.js.map +1 -0
- package/webapp/dist/assets/{chunk-B4BG7PRW-DpMa3-9L.js → chunk-WL4C6EOR-DDCnEwft.js} +171 -121
- package/webapp/dist/assets/chunk-WL4C6EOR-DDCnEwft.js.map +1 -0
- package/webapp/dist/assets/{classDiagram-2ON5EDUG-BTTGianr.js → classDiagram-VBA2DB6C-CvMBU4WA.js} +7 -6
- package/webapp/dist/assets/classDiagram-VBA2DB6C-CvMBU4WA.js.map +1 -0
- package/webapp/dist/assets/{classDiagram-v2-WZHVMYZB-BTTGianr.js → classDiagram-v2-RAHNMMFH-CvMBU4WA.js} +7 -6
- package/webapp/dist/assets/classDiagram-v2-RAHNMMFH-CvMBU4WA.js.map +1 -0
- package/webapp/dist/assets/{clone-Dk8cAI3I.js → clone-r98jR0MC.js} +2 -2
- package/webapp/dist/assets/clone-r98jR0MC.js.map +1 -0
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-BjJnzB2N.js → cose-bilkent-S5V4N54A-t6J60Ogk.js} +2 -2
- package/webapp/dist/assets/cose-bilkent-S5V4N54A-t6J60Ogk.js.map +1 -0
- package/webapp/dist/assets/cytoscape.esm-Bm8DJGmZ.js.map +1 -1
- package/webapp/dist/assets/{dagre-6UL2VRFP-VF-xGhAf.js → dagre-KLK3FWXG-BlqmY2DV.js} +7 -7
- package/webapp/dist/assets/dagre-KLK3FWXG-BlqmY2DV.js.map +1 -0
- package/webapp/dist/assets/defaultLocale-B2RvLBDe.js.map +1 -1
- package/webapp/dist/assets/{diagram-PSM6KHXK-Ba5U0oRY.js → diagram-E7M64L7V-FwCHeIUD.js} +10 -10
- package/webapp/dist/assets/diagram-E7M64L7V-FwCHeIUD.js.map +1 -0
- package/webapp/dist/assets/{diagram-QEK2KX5R-DoYCnEw_.js → diagram-IFDJBPK2-NhtmkuZG.js} +9 -8
- package/webapp/dist/assets/diagram-IFDJBPK2-NhtmkuZG.js.map +1 -0
- package/webapp/dist/assets/{diagram-S2PKOQOG-CkK4SRyE.js → diagram-P4PSJMXO-B9FcmokX.js} +8 -8
- package/webapp/dist/assets/diagram-P4PSJMXO-B9FcmokX.js.map +1 -0
- package/webapp/dist/assets/{erDiagram-Q2GNP2WA-DkI5eYww.js → erDiagram-INFDFZHY-DHKmWvtB.js} +96 -75
- package/webapp/dist/assets/erDiagram-INFDFZHY-DHKmWvtB.js.map +1 -0
- package/webapp/dist/assets/{flowDiagram-NV44I4VS-wOdPUQ7Y.js → flowDiagram-PKNHOUZH-C7Zi8I7T.js} +98 -81
- package/webapp/dist/assets/flowDiagram-PKNHOUZH-C7Zi8I7T.js.map +1 -0
- package/webapp/dist/assets/{ganttDiagram-JELNMOA3-BtRWgkUH.js → ganttDiagram-A5KZAMGK-Cv2T8tz_.js} +28 -3
- package/webapp/dist/assets/ganttDiagram-A5KZAMGK-Cv2T8tz_.js.map +1 -0
- package/webapp/dist/assets/{gitGraphDiagram-V2S2FVAM-Bsz7u1vi.js → gitGraphDiagram-K3NZZRJ6-DztaipJU.js} +38 -46
- package/webapp/dist/assets/gitGraphDiagram-K3NZZRJ6-DztaipJU.js.map +1 -0
- package/webapp/dist/assets/graph-C5yf62Vs.js +782 -0
- package/webapp/dist/assets/graph-C5yf62Vs.js.map +1 -0
- package/webapp/dist/assets/{index-xvYYeHuy.css → index-YaxF76or.css} +1 -1
- package/webapp/dist/assets/{index-rYmIohM_.js → index-hve5MWPs.js} +1603 -1415
- package/webapp/dist/assets/index-hve5MWPs.js.map +1 -0
- package/webapp/dist/assets/{infoDiagram-HS3SLOUP-BMaxCvH5.js → infoDiagram-LFFYTUFH-VgsbBPZP.js} +7 -7
- package/webapp/dist/assets/infoDiagram-LFFYTUFH-VgsbBPZP.js.map +1 -0
- package/webapp/dist/assets/init-ZxktEp_H.js.map +1 -1
- package/webapp/dist/assets/ishikawaDiagram-PHBUUO56-C7j3YWdw.js +966 -0
- package/webapp/dist/assets/ishikawaDiagram-PHBUUO56-C7j3YWdw.js.map +1 -0
- package/webapp/dist/assets/{journeyDiagram-XKPGCS4Q-ejyerzmG.js → journeyDiagram-4ABVD52K-OO8sev-Y.js} +5 -5
- package/webapp/dist/assets/journeyDiagram-4ABVD52K-OO8sev-Y.js.map +1 -0
- package/webapp/dist/assets/{kanban-definition-3W4ZIXB7-CYj35TEs.js → kanban-definition-K7BYSVSG-DiYCC1Ig.js} +5 -3
- package/webapp/dist/assets/kanban-definition-K7BYSVSG-DiYCC1Ig.js.map +1 -0
- package/webapp/dist/assets/{layout-7Ql4zmuL.js → layout-DdZSgGdu.js} +5 -5
- package/webapp/dist/assets/layout-DdZSgGdu.js.map +1 -0
- package/webapp/dist/assets/{linear-CVmgVPuZ.js → linear-7-aHtaFi.js} +2 -2
- package/webapp/dist/assets/linear-7-aHtaFi.js.map +1 -0
- package/webapp/dist/assets/{mindmap-definition-VGOIOE7T-DOpxjGVo.js → mindmap-definition-YRQLILUH-IG3I-RdD.js} +7 -5
- package/webapp/dist/assets/mindmap-definition-YRQLILUH-IG3I-RdD.js.map +1 -0
- package/webapp/dist/assets/ordinal-CxptdPJm.js.map +1 -1
- package/webapp/dist/assets/{pieDiagram-ADFJNKIX-CLQjpmAG.js → pieDiagram-SKSYHLDU-z68KJT5r.js} +8 -8
- package/webapp/dist/assets/pieDiagram-SKSYHLDU-z68KJT5r.js.map +1 -0
- package/webapp/dist/assets/{quadrantDiagram-AYHSOK5B-ClD_bz7z.js → quadrantDiagram-337W2JSQ-DaENWdO6.js} +3 -3
- package/webapp/dist/assets/quadrantDiagram-337W2JSQ-DaENWdO6.js.map +1 -0
- package/webapp/dist/assets/{requirementDiagram-UZGBJVZJ-DOpb-TWH.js → requirementDiagram-Z7DCOOCP-ROTFv4sa.js} +16 -6
- package/webapp/dist/assets/requirementDiagram-Z7DCOOCP-ROTFv4sa.js.map +1 -0
- package/webapp/dist/assets/{sankeyDiagram-TZEHDZUN-D8Hsj3yx.js → sankeyDiagram-WA2Y5GQK-CK7qtpzw.js} +2 -2
- package/webapp/dist/assets/sankeyDiagram-WA2Y5GQK-CK7qtpzw.js.map +1 -0
- package/webapp/dist/assets/{sequenceDiagram-WL72ISMW-CFMNjBER.js → sequenceDiagram-2WXFIKYE-R5lDySeI.js} +601 -201
- package/webapp/dist/assets/sequenceDiagram-2WXFIKYE-R5lDySeI.js.map +1 -0
- package/webapp/dist/assets/{stateDiagram-FKZM4ZOC-BQeDlw0P.js → stateDiagram-RAJIS63D-sr7msF5U.js} +9 -9
- package/webapp/dist/assets/stateDiagram-RAJIS63D-sr7msF5U.js.map +1 -0
- package/webapp/dist/assets/{stateDiagram-v2-4FDKWEC3-DscX61Rs.js → stateDiagram-v2-FVOUBMTO-X663liwS.js} +5 -5
- package/webapp/dist/assets/stateDiagram-v2-FVOUBMTO-X663liwS.js.map +1 -0
- package/webapp/dist/assets/{timeline-definition-IT6M3QCI-BcXPSTiw.js → timeline-definition-YZTLITO2-Bw0TdG26.js} +3 -3
- package/webapp/dist/assets/timeline-definition-YZTLITO2-Bw0TdG26.js.map +1 -0
- package/webapp/dist/assets/{treemap-GDKQZRPO-BBr4UV0Z.js → treemap-KZPCXAKY-D_sjKwI7.js} +37 -24
- package/webapp/dist/assets/treemap-KZPCXAKY-D_sjKwI7.js.map +1 -0
- package/webapp/dist/assets/vennDiagram-LZ73GAT5-DhlHIHid.js +2487 -0
- package/webapp/dist/assets/vennDiagram-LZ73GAT5-DhlHIHid.js.map +1 -0
- package/webapp/dist/assets/{xychartDiagram-PRI3JC2R-CS5RAtQE.js → xychartDiagram-JWTSCODW-C65ESjTc.js} +4 -4
- package/webapp/dist/assets/xychartDiagram-JWTSCODW-C65ESjTc.js.map +1 -0
- package/webapp/dist/index.html +2 -2
- package/webapp/dist/assets/_basePickBy-CBOtd63g.js.map +0 -1
- package/webapp/dist/assets/_baseUniq-mfoKz4Wm.js.map +0 -1
- package/webapp/dist/assets/arc-Dq0WZLyu.js.map +0 -1
- package/webapp/dist/assets/architectureDiagram-VXUJARFQ-CNmygmp3.js.map +0 -1
- package/webapp/dist/assets/blockDiagram-VD42YOAC-DvE0lybt.js.map +0 -1
- package/webapp/dist/assets/c4Diagram-YG6GDRKO-CR7zJ2_u.js.map +0 -1
- package/webapp/dist/assets/channel-DrTrnYx4.js.map +0 -1
- package/webapp/dist/assets/chunk-4BX2VUAB-CVuJEIeN.js.map +0 -1
- package/webapp/dist/assets/chunk-55IACEB6-BxUoXApB.js.map +0 -1
- package/webapp/dist/assets/chunk-B4BG7PRW-DpMa3-9L.js.map +0 -1
- package/webapp/dist/assets/chunk-DI55MBZ5-SAhxUTqQ.js.map +0 -1
- package/webapp/dist/assets/chunk-FMBD7UC4-TX-LVAaV.js.map +0 -1
- package/webapp/dist/assets/chunk-QN33PNHL-D1uiKlOO.js.map +0 -1
- package/webapp/dist/assets/chunk-QZHKN3VN-BxuV0Oba.js.map +0 -1
- package/webapp/dist/assets/chunk-TZMSLE5B-Cw689yRl.js.map +0 -1
- package/webapp/dist/assets/classDiagram-2ON5EDUG-BTTGianr.js.map +0 -1
- package/webapp/dist/assets/classDiagram-v2-WZHVMYZB-BTTGianr.js.map +0 -1
- package/webapp/dist/assets/clone-Dk8cAI3I.js.map +0 -1
- package/webapp/dist/assets/cose-bilkent-S5V4N54A-BjJnzB2N.js.map +0 -1
- package/webapp/dist/assets/dagre-6UL2VRFP-VF-xGhAf.js.map +0 -1
- package/webapp/dist/assets/diagram-PSM6KHXK-Ba5U0oRY.js.map +0 -1
- package/webapp/dist/assets/diagram-QEK2KX5R-DoYCnEw_.js.map +0 -1
- package/webapp/dist/assets/diagram-S2PKOQOG-CkK4SRyE.js.map +0 -1
- package/webapp/dist/assets/erDiagram-Q2GNP2WA-DkI5eYww.js.map +0 -1
- package/webapp/dist/assets/flowDiagram-NV44I4VS-wOdPUQ7Y.js.map +0 -1
- package/webapp/dist/assets/ganttDiagram-JELNMOA3-BtRWgkUH.js.map +0 -1
- package/webapp/dist/assets/gitGraphDiagram-V2S2FVAM-Bsz7u1vi.js.map +0 -1
- package/webapp/dist/assets/graph-DAMkuTbn.js +0 -425
- package/webapp/dist/assets/graph-DAMkuTbn.js.map +0 -1
- package/webapp/dist/assets/index-rYmIohM_.js.map +0 -1
- package/webapp/dist/assets/infoDiagram-HS3SLOUP-BMaxCvH5.js.map +0 -1
- package/webapp/dist/assets/journeyDiagram-XKPGCS4Q-ejyerzmG.js.map +0 -1
- package/webapp/dist/assets/kanban-definition-3W4ZIXB7-CYj35TEs.js.map +0 -1
- package/webapp/dist/assets/layout-7Ql4zmuL.js.map +0 -1
- package/webapp/dist/assets/linear-CVmgVPuZ.js.map +0 -1
- package/webapp/dist/assets/mindmap-definition-VGOIOE7T-DOpxjGVo.js.map +0 -1
- package/webapp/dist/assets/pieDiagram-ADFJNKIX-CLQjpmAG.js.map +0 -1
- package/webapp/dist/assets/quadrantDiagram-AYHSOK5B-ClD_bz7z.js.map +0 -1
- package/webapp/dist/assets/requirementDiagram-UZGBJVZJ-DOpb-TWH.js.map +0 -1
- package/webapp/dist/assets/sankeyDiagram-TZEHDZUN-D8Hsj3yx.js.map +0 -1
- package/webapp/dist/assets/sequenceDiagram-WL72ISMW-CFMNjBER.js.map +0 -1
- package/webapp/dist/assets/stateDiagram-FKZM4ZOC-BQeDlw0P.js.map +0 -1
- package/webapp/dist/assets/stateDiagram-v2-4FDKWEC3-DscX61Rs.js.map +0 -1
- package/webapp/dist/assets/timeline-definition-IT6M3QCI-BcXPSTiw.js.map +0 -1
- package/webapp/dist/assets/treemap-GDKQZRPO-BBr4UV0Z.js.map +0 -1
- package/webapp/dist/assets/xychartDiagram-PRI3JC2R-CS5RAtQE.js.map +0 -1
|
@@ -18,6 +18,7 @@ const tool_1 = require("../../tool");
|
|
|
18
18
|
const taskdoc_1 = require("../../utils/taskdoc");
|
|
19
19
|
const client_1 = require("../client");
|
|
20
20
|
const registry_1 = require("../gen/registry");
|
|
21
|
+
const tool_call_context_1 = require("../gen/tool-call-context");
|
|
21
22
|
const tools_projection_1 = require("../tools-projection");
|
|
22
23
|
const context_1 = require("./context");
|
|
23
24
|
const context_health_1 = require("./context-health");
|
|
@@ -35,6 +36,57 @@ const KERNEL_DRIVER_DEFAULT_RETRY_POLICY = {
|
|
|
35
36
|
maxDelayMs: 30 * 60 * 1000, // 30 minutes
|
|
36
37
|
};
|
|
37
38
|
const KERNEL_DRIVER_EMPTY_LLM_RESPONSE_ERROR_CODE = 'DOMINDS_LLM_EMPTY_RESPONSE';
|
|
39
|
+
// Wrapper isolation boundary:
|
|
40
|
+
// - Wrappers emit provider-native web-search events.
|
|
41
|
+
// - The driver is the first place allowed to project them into a narrower shared dialog shape.
|
|
42
|
+
function projectLlmWebSearchCall(call) {
|
|
43
|
+
if (call.source === 'codex') {
|
|
44
|
+
return call;
|
|
45
|
+
}
|
|
46
|
+
const action = call.action;
|
|
47
|
+
if (!action) {
|
|
48
|
+
return {
|
|
49
|
+
source: call.source,
|
|
50
|
+
phase: call.phase,
|
|
51
|
+
itemId: call.itemId,
|
|
52
|
+
status: call.status,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (action.type === 'search') {
|
|
56
|
+
const query = typeof action.query === 'string' && action.query.trim().length > 0
|
|
57
|
+
? action.query
|
|
58
|
+
: Array.isArray(action.queries)
|
|
59
|
+
? action.queries.find((entry) => entry.trim().length > 0)
|
|
60
|
+
: undefined;
|
|
61
|
+
return {
|
|
62
|
+
source: call.source,
|
|
63
|
+
phase: call.phase,
|
|
64
|
+
itemId: call.itemId,
|
|
65
|
+
status: call.status,
|
|
66
|
+
action: query !== undefined ? { type: 'search', query } : { type: 'search' },
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (action.type === 'open_page') {
|
|
70
|
+
return {
|
|
71
|
+
source: call.source,
|
|
72
|
+
phase: call.phase,
|
|
73
|
+
itemId: call.itemId,
|
|
74
|
+
status: call.status,
|
|
75
|
+
action: typeof action.url === 'string' ? { type: 'open_page', url: action.url } : action,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
source: call.source,
|
|
80
|
+
phase: call.phase,
|
|
81
|
+
itemId: call.itemId,
|
|
82
|
+
status: call.status,
|
|
83
|
+
action: {
|
|
84
|
+
type: 'find_in_page',
|
|
85
|
+
...(typeof action.url === 'string' ? { url: action.url } : {}),
|
|
86
|
+
...(typeof action.pattern === 'string' ? { pattern: action.pattern } : {}),
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
38
90
|
class KernelDriverInterruptedError extends Error {
|
|
39
91
|
constructor(reason) {
|
|
40
92
|
super('Dialog interrupted');
|
|
@@ -86,19 +138,11 @@ function buildKernelDriverFbrPrompt(dlg, state) {
|
|
|
86
138
|
origin: 'runtime',
|
|
87
139
|
};
|
|
88
140
|
}
|
|
89
|
-
function
|
|
90
|
-
if (
|
|
141
|
+
function normalizeQ4HAnswerCallId(raw) {
|
|
142
|
+
if (typeof raw !== 'string')
|
|
91
143
|
return undefined;
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
for (const value of raw) {
|
|
95
|
-
const callId = value.trim();
|
|
96
|
-
if (callId === '' || seen.has(callId))
|
|
97
|
-
continue;
|
|
98
|
-
seen.add(callId);
|
|
99
|
-
normalized.push(callId);
|
|
100
|
-
}
|
|
101
|
-
return normalized.length > 0 ? normalized : undefined;
|
|
144
|
+
const callId = raw.trim();
|
|
145
|
+
return callId !== '' ? callId : undefined;
|
|
102
146
|
}
|
|
103
147
|
function isUserOriginPrompt(prompt) {
|
|
104
148
|
if (!prompt)
|
|
@@ -171,8 +215,23 @@ function resolveKernelDriverRetryPolicy(providerCfg) {
|
|
|
171
215
|
maxDelayMs: Math.max(initialDelayMs, conservativeDelayMs, maxDelayMs),
|
|
172
216
|
};
|
|
173
217
|
}
|
|
174
|
-
function hasMeaningfulBatchOutput(
|
|
175
|
-
|
|
218
|
+
function hasMeaningfulBatchOutput(batch) {
|
|
219
|
+
if (Array.isArray(batch.outputs) && batch.outputs.length > 0) {
|
|
220
|
+
for (const output of batch.outputs) {
|
|
221
|
+
if (output.kind !== 'message') {
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
const msg = output.message;
|
|
225
|
+
if (msg.type === 'func_call_msg') {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
if ((msg.type === 'saying_msg' || msg.type === 'thinking_msg') && msg.content.trim() !== '') {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
for (const msg of batch.messages) {
|
|
176
235
|
if (msg.type === 'func_call_msg') {
|
|
177
236
|
return true;
|
|
178
237
|
}
|
|
@@ -380,7 +439,7 @@ const TELLASK_SPECIAL_VIRTUAL_TOOLS = [
|
|
|
380
439
|
},
|
|
381
440
|
},
|
|
382
441
|
];
|
|
383
|
-
function
|
|
442
|
+
function mergeTellaskVirtualTools(baseTools, options) {
|
|
384
443
|
const merged = [...baseTools];
|
|
385
444
|
const seen = new Set(merged.map((tool) => tool.name));
|
|
386
445
|
const freshBootsReasoning = createFreshBootsReasoningTool({
|
|
@@ -492,7 +551,7 @@ function resolveUpNextPrompt(dlg) {
|
|
|
492
551
|
grammar: upNext.grammar ?? 'markdown',
|
|
493
552
|
origin: upNext.origin,
|
|
494
553
|
userLanguageCode: upNext.userLanguageCode,
|
|
495
|
-
|
|
554
|
+
q4hAnswerCallId: upNext.q4hAnswerCallId,
|
|
496
555
|
tellaskReplyDirective: upNext.tellaskReplyDirective,
|
|
497
556
|
skipTaskdoc: upNext.skipTaskdoc,
|
|
498
557
|
subdialogReplyTarget: upNext.subdialogReplyTarget,
|
|
@@ -551,48 +610,30 @@ function hasSameReplyDirective(left, right) {
|
|
|
551
610
|
}
|
|
552
611
|
return true;
|
|
553
612
|
}
|
|
554
|
-
function
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
}
|
|
563
|
-
function formatPendingSpecialFuncResult(name, startedAtMs) {
|
|
564
|
-
const language = (0, work_language_1.getWorkLanguage)();
|
|
565
|
-
const elapsed = formatElapsedSecondsText(startedAtMs);
|
|
566
|
-
if (name === 'askHuman') {
|
|
567
|
-
return language === 'zh'
|
|
568
|
-
? `Q4H 仍在等待人类回复,已持续 ${elapsed}。`
|
|
569
|
-
: `Q4H is still waiting for human reply (elapsed ${elapsed}).`;
|
|
570
|
-
}
|
|
571
|
-
return language === 'zh'
|
|
572
|
-
? `支线对话仍在进行中,已持续 ${elapsed}。`
|
|
573
|
-
: `Sideline dialog is still running (elapsed ${elapsed}).`;
|
|
574
|
-
}
|
|
575
|
-
function formatResolvedAskHumanResult() {
|
|
576
|
-
return (0, work_language_1.getWorkLanguage)() === 'zh'
|
|
577
|
-
? 'Q4H 已结束等待状态,请参考后续用户消息。'
|
|
578
|
-
: 'Q4H wait is resolved; refer to subsequent user messages.';
|
|
613
|
+
function buildPendingTellaskFuncResult(args) {
|
|
614
|
+
return {
|
|
615
|
+
type: 'func_result_msg',
|
|
616
|
+
role: 'tool',
|
|
617
|
+
genseq: args.genseq,
|
|
618
|
+
id: args.callId,
|
|
619
|
+
name: args.callName,
|
|
620
|
+
content: (0, tellask_special_1.formatPendingTellaskFuncResultContent)(args.callName, null),
|
|
621
|
+
};
|
|
579
622
|
}
|
|
580
|
-
async function
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
return [...args.dialogMsgsForContext];
|
|
584
|
-
}
|
|
585
|
-
const pendingSubdialogs = await persistence_1.DialogPersistence.loadPendingSubdialogs(args.dialog.id, args.dialog.status);
|
|
586
|
-
const pendingSubByCallId = new Map();
|
|
623
|
+
async function loadPendingTellaskSpecialStates(dialog) {
|
|
624
|
+
const pendingByCallId = new Map();
|
|
625
|
+
const pendingSubdialogs = await persistence_1.DialogPersistence.loadPendingSubdialogs(dialog.id, dialog.status);
|
|
587
626
|
for (const pending of pendingSubdialogs) {
|
|
588
627
|
const callId = pending.callId.trim();
|
|
589
628
|
if (callId === '') {
|
|
590
629
|
continue;
|
|
591
630
|
}
|
|
592
|
-
|
|
631
|
+
pendingByCallId.set(callId, {
|
|
632
|
+
callName: pending.callName,
|
|
633
|
+
startedAtMs: parseUnifiedTimestampMs(pending.createdAt),
|
|
634
|
+
});
|
|
593
635
|
}
|
|
594
|
-
const pendingQ4H = await persistence_1.DialogPersistence.loadQuestions4HumanState(
|
|
595
|
-
const pendingQ4HByCallId = new Map();
|
|
636
|
+
const pendingQ4H = await persistence_1.DialogPersistence.loadQuestions4HumanState(dialog.id, dialog.status);
|
|
596
637
|
for (const question of pendingQ4H) {
|
|
597
638
|
if (typeof question.callId !== 'string') {
|
|
598
639
|
continue;
|
|
@@ -601,23 +642,42 @@ async function projectTellaskSpecialFuncResultsForContext(args) {
|
|
|
601
642
|
if (callId === '') {
|
|
602
643
|
continue;
|
|
603
644
|
}
|
|
604
|
-
|
|
645
|
+
pendingByCallId.set(callId, {
|
|
646
|
+
callName: 'askHuman',
|
|
647
|
+
startedAtMs: parseUnifiedTimestampMs(question.askedAt),
|
|
648
|
+
});
|
|
605
649
|
}
|
|
606
|
-
|
|
650
|
+
return pendingByCallId;
|
|
651
|
+
}
|
|
652
|
+
async function projectTellaskFuncResultsForContext(args) {
|
|
653
|
+
const hasSpecialFuncCall = args.dialogMsgsForContext.some((msg) => msg.type === 'func_call_msg' && (0, tellask_special_1.isTellaskCallFunctionName)(msg.name));
|
|
654
|
+
if (!hasSpecialFuncCall) {
|
|
655
|
+
return {
|
|
656
|
+
messages: [...args.dialogMsgsForContext],
|
|
657
|
+
projectedResultCallIds: new Set(),
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
const pendingSpecialByCallId = await loadPendingTellaskSpecialStates(args.dialog);
|
|
661
|
+
// Only technical tool-result-shaped messages can satisfy provider tool-call adjacency. A
|
|
662
|
+
// carryover message is different: it is already the canonical latest-course business context and
|
|
663
|
+
// intentionally does not act as a tool-result surrogate for an older-course call that is no
|
|
664
|
+
// longer present in current context.
|
|
665
|
+
const pairedToolResultContentByCallId = new Map();
|
|
607
666
|
const existingSpecialFuncResults = new Map();
|
|
608
667
|
for (const msg of args.dialogMsgsForContext) {
|
|
609
668
|
if (msg.type === 'tellask_result_msg') {
|
|
610
669
|
const callId = typeof msg.callId === 'string' ? msg.callId.trim() : '';
|
|
611
670
|
if (callId !== '') {
|
|
612
|
-
|
|
671
|
+
pairedToolResultContentByCallId.set(callId, msg.content);
|
|
613
672
|
}
|
|
614
673
|
continue;
|
|
615
674
|
}
|
|
616
|
-
if (msg.type === 'func_result_msg' && (0, tellask_special_1.
|
|
675
|
+
if (msg.type === 'func_result_msg' && (0, tellask_special_1.isTellaskCallFunctionName)(msg.name)) {
|
|
617
676
|
existingSpecialFuncResults.set(msg.id, msg);
|
|
618
677
|
}
|
|
619
678
|
}
|
|
620
679
|
const projected = [];
|
|
680
|
+
const projectedResultCallIds = new Set();
|
|
621
681
|
const specialCallIds = new Set();
|
|
622
682
|
for (const msg of args.dialogMsgsForContext) {
|
|
623
683
|
if (msg.type === 'func_result_msg' && specialCallIds.has(msg.id)) {
|
|
@@ -627,67 +687,98 @@ async function projectTellaskSpecialFuncResultsForContext(args) {
|
|
|
627
687
|
if (msg.type !== 'func_call_msg') {
|
|
628
688
|
continue;
|
|
629
689
|
}
|
|
630
|
-
if (!(0, tellask_special_1.
|
|
690
|
+
if (!(0, tellask_special_1.isTellaskCallFunctionName)(msg.name)) {
|
|
631
691
|
continue;
|
|
632
692
|
}
|
|
633
693
|
specialCallIds.add(msg.id);
|
|
634
|
-
const
|
|
635
|
-
if (
|
|
694
|
+
const pairedToolResultContent = pairedToolResultContentByCallId.get(msg.id);
|
|
695
|
+
if (pairedToolResultContent !== undefined) {
|
|
696
|
+
projectedResultCallIds.add(msg.id);
|
|
636
697
|
projected.push({
|
|
637
698
|
type: 'func_result_msg',
|
|
638
699
|
role: 'tool',
|
|
639
700
|
genseq: msg.genseq,
|
|
640
701
|
id: msg.id,
|
|
641
702
|
name: msg.name,
|
|
642
|
-
content:
|
|
703
|
+
content: pairedToolResultContent,
|
|
643
704
|
});
|
|
644
705
|
continue;
|
|
645
706
|
}
|
|
646
707
|
const existingResult = existingSpecialFuncResults.get(msg.id);
|
|
647
708
|
if (existingResult) {
|
|
709
|
+
projectedResultCallIds.add(msg.id);
|
|
648
710
|
projected.push(existingResult);
|
|
649
711
|
continue;
|
|
650
712
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
? formatPendingSpecialFuncResult(msg.name, parseUnifiedTimestampMs(pendingQ4HState.askedAt))
|
|
655
|
-
: formatResolvedAskHumanResult();
|
|
713
|
+
const pendingSpecialState = pendingSpecialByCallId.get(msg.id);
|
|
714
|
+
if (pendingSpecialState?.callName === msg.name) {
|
|
715
|
+
projectedResultCallIds.add(msg.id);
|
|
656
716
|
projected.push({
|
|
657
717
|
type: 'func_result_msg',
|
|
658
718
|
role: 'tool',
|
|
659
719
|
genseq: msg.genseq,
|
|
660
720
|
id: msg.id,
|
|
661
721
|
name: msg.name,
|
|
662
|
-
content,
|
|
722
|
+
content: (0, tellask_special_1.formatPendingTellaskFuncResultContent)(msg.name, pendingSpecialState.startedAtMs),
|
|
663
723
|
});
|
|
664
724
|
continue;
|
|
665
725
|
}
|
|
666
|
-
|
|
667
|
-
projected.push({
|
|
668
|
-
|
|
669
|
-
|
|
726
|
+
projectedResultCallIds.add(msg.id);
|
|
727
|
+
projected.push(buildPendingTellaskFuncResult({
|
|
728
|
+
callId: msg.id,
|
|
729
|
+
callName: msg.name,
|
|
670
730
|
genseq: msg.genseq,
|
|
671
|
-
|
|
672
|
-
name: msg.name,
|
|
673
|
-
content: formatPendingSpecialFuncResult(msg.name, pendingSubState ? parseUnifiedTimestampMs(pendingSubState.createdAt) : null),
|
|
674
|
-
});
|
|
731
|
+
}));
|
|
675
732
|
}
|
|
676
|
-
return
|
|
733
|
+
return {
|
|
734
|
+
messages: projected,
|
|
735
|
+
projectedResultCallIds,
|
|
736
|
+
};
|
|
677
737
|
}
|
|
678
738
|
async function buildDialogMsgsForContext(dlg) {
|
|
679
|
-
const rawDialogMsgsForContext = dlg.msgs.filter((m) =>
|
|
680
|
-
|
|
681
|
-
return false;
|
|
682
|
-
if (m.type === 'ui_only_markdown_msg')
|
|
683
|
-
return false;
|
|
684
|
-
return true;
|
|
685
|
-
});
|
|
686
|
-
const projected = await projectTellaskSpecialFuncResultsForContext({
|
|
739
|
+
const rawDialogMsgsForContext = dlg.msgs.filter((m) => !!m);
|
|
740
|
+
const projected = await projectTellaskFuncResultsForContext({
|
|
687
741
|
dialog: dlg,
|
|
688
742
|
dialogMsgsForContext: rawDialogMsgsForContext,
|
|
689
743
|
});
|
|
690
|
-
|
|
744
|
+
const businessFiltered = projected.messages.filter((msg) => {
|
|
745
|
+
if (msg.type !== 'tellask_result_msg') {
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
// Business tellask result bubbles stay in storage/UI, but when the same latest-course call is
|
|
749
|
+
// also projected into an adjacent technical tool result for provider context we omit the
|
|
750
|
+
// duplicate bubble form here. Carryover messages are intentionally not filtered by this branch:
|
|
751
|
+
// they are already the canonical latest-course context, not a tool-pair surrogate.
|
|
752
|
+
return !projected.projectedResultCallIds.has(msg.callId);
|
|
753
|
+
});
|
|
754
|
+
const sanitized = (0, tool_call_context_1.sanitizeToolContextForProvider)(businessFiltered);
|
|
755
|
+
if (sanitized.droppedViolations.length > 0) {
|
|
756
|
+
const details = sanitized.droppedViolations.map((violation) => (0, tool_call_context_1.formatToolCallAdjacencyViolation)(violation, 'kernel-driver provider context sanitization'));
|
|
757
|
+
const summary = `kernel-driver dropped ${sanitized.droppedViolations.length} unpaired persisted tool ` +
|
|
758
|
+
`message(s) before provider projection for dialog=${dlg.id.valueOf()}; see logs for details.`;
|
|
759
|
+
log_1.log.error(summary, new Error('kernel_driver_provider_context_sanitized_unpaired_tool_msgs'), {
|
|
760
|
+
rootId: dlg.id.rootId,
|
|
761
|
+
selfId: dlg.id.selfId,
|
|
762
|
+
droppedViolationCount: sanitized.droppedViolations.length,
|
|
763
|
+
droppedViolations: sanitized.droppedViolations.map((violation) => ({
|
|
764
|
+
kind: violation.kind,
|
|
765
|
+
callId: violation.callId,
|
|
766
|
+
toolName: violation.toolName,
|
|
767
|
+
index: violation.index,
|
|
768
|
+
})),
|
|
769
|
+
detailPreview: details.slice(0, 3),
|
|
770
|
+
});
|
|
771
|
+
try {
|
|
772
|
+
await dlg.streamError(`${summary} ${details.slice(0, 3).join(' ')}`);
|
|
773
|
+
}
|
|
774
|
+
catch (error) {
|
|
775
|
+
log_1.log.warn('kernel-driver failed to emit stream_error_evt for sanitized tool context', error, {
|
|
776
|
+
rootId: dlg.id.rootId,
|
|
777
|
+
selfId: dlg.id.selfId,
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return sanitized.messages;
|
|
691
782
|
}
|
|
692
783
|
async function emitAssistantSaying(dlg, content) {
|
|
693
784
|
if (content.trim() === '')
|
|
@@ -696,146 +787,94 @@ async function emitAssistantSaying(dlg, content) {
|
|
|
696
787
|
await dlg.sayingChunk(content);
|
|
697
788
|
await dlg.sayingFinish();
|
|
698
789
|
}
|
|
699
|
-
function isReplyTellaskCallName(name) {
|
|
700
|
-
return (name === 'replyTellask' || name === 'replyTellaskSessionless' || name === 'replyTellaskBack');
|
|
701
|
-
}
|
|
702
|
-
function isToolArgumentsObject(value) {
|
|
703
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
704
|
-
}
|
|
705
|
-
function prepareFuncCallArguments(argumentsStr) {
|
|
706
|
-
if (argumentsStr.trim() === '') {
|
|
707
|
-
return {
|
|
708
|
-
ok: true,
|
|
709
|
-
raw: {},
|
|
710
|
-
contextArguments: '{}',
|
|
711
|
-
};
|
|
712
|
-
}
|
|
713
|
-
let parsed;
|
|
714
|
-
try {
|
|
715
|
-
parsed = JSON.parse(argumentsStr);
|
|
716
|
-
}
|
|
717
|
-
catch (err) {
|
|
718
|
-
return {
|
|
719
|
-
ok: false,
|
|
720
|
-
error: `Arguments must be valid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
721
|
-
contextArguments: '{}',
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
if (!isToolArgumentsObject(parsed)) {
|
|
725
|
-
return {
|
|
726
|
-
ok: false,
|
|
727
|
-
error: 'Arguments must be an object',
|
|
728
|
-
contextArguments: '{}',
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
return {
|
|
732
|
-
ok: true,
|
|
733
|
-
raw: parsed,
|
|
734
|
-
contextArguments: argumentsStr,
|
|
735
|
-
};
|
|
736
|
-
}
|
|
737
790
|
async function executeFunctionCalls(args) {
|
|
738
791
|
const functionPromises = args.funcCalls.map(async (func) => {
|
|
739
792
|
throwIfAborted(args.abortSignal, args.dlg);
|
|
740
793
|
const callGenseq = func.genseq;
|
|
741
794
|
const argsStr = typeof func.arguments === 'string' ? func.arguments : JSON.stringify(func.arguments ?? {});
|
|
742
|
-
const preparedArgs = prepareFuncCallArguments(argsStr);
|
|
743
|
-
const persistedArguments = preparedArgs.ok ? preparedArgs.raw : {};
|
|
744
|
-
await args.dlg.funcCallRequested(func.id, func.name, preparedArgs.contextArguments);
|
|
745
|
-
await args.dlg.persistFunctionCall(func.id, func.name, persistedArguments, callGenseq);
|
|
746
795
|
const tool = args.agentTools.find((t) => t.type === 'func' && t.name === func.name);
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
type: 'func_result_msg',
|
|
750
|
-
id: func.id,
|
|
751
|
-
name: func.name,
|
|
752
|
-
content: `Tool '${func.name}' not found`,
|
|
753
|
-
role: 'tool',
|
|
754
|
-
genseq: callGenseq,
|
|
755
|
-
};
|
|
756
|
-
await args.dlg.receiveFuncResult(errorResult);
|
|
757
|
-
return errorResult;
|
|
758
|
-
}
|
|
796
|
+
const preparedInvocationArgs = tool !== undefined ? (0, tool_1.resolveFuncToolInvocationArguments)(tool, argsStr) : null;
|
|
797
|
+
await args.dlg.funcCallRequested(func.id, func.name, argsStr);
|
|
759
798
|
let result;
|
|
760
|
-
let
|
|
761
|
-
if (!
|
|
762
|
-
log_1.log.warn('kernel-driver rejected function call arguments before execution', undefined, {
|
|
763
|
-
funcName: func.name,
|
|
764
|
-
arguments: argsStr,
|
|
765
|
-
error: preparedArgs.error,
|
|
766
|
-
});
|
|
799
|
+
let rethrowError;
|
|
800
|
+
if (!tool) {
|
|
767
801
|
result = {
|
|
768
802
|
type: 'func_result_msg',
|
|
769
803
|
id: func.id,
|
|
770
804
|
name: func.name,
|
|
771
|
-
content: `
|
|
805
|
+
content: `Tool '${func.name}' not found`,
|
|
772
806
|
role: 'tool',
|
|
773
807
|
genseq: callGenseq,
|
|
774
808
|
};
|
|
775
809
|
}
|
|
776
810
|
else {
|
|
777
|
-
|
|
778
|
-
|
|
811
|
+
if (!preparedInvocationArgs || !preparedInvocationArgs.ok) {
|
|
812
|
+
const errorText = preparedInvocationArgs?.error ?? 'Arguments could not be prepared for tool invocation';
|
|
813
|
+
log_1.log.warn('kernel-driver rejected function call arguments before execution', undefined, {
|
|
814
|
+
funcName: func.name,
|
|
815
|
+
arguments: argsStr,
|
|
816
|
+
error: errorText,
|
|
817
|
+
});
|
|
779
818
|
result = {
|
|
780
819
|
type: 'func_result_msg',
|
|
781
820
|
id: func.id,
|
|
782
821
|
name: func.name,
|
|
783
|
-
content: `Invalid arguments: ${
|
|
822
|
+
content: `Invalid arguments: ${errorText}`,
|
|
784
823
|
role: 'tool',
|
|
785
824
|
genseq: callGenseq,
|
|
786
825
|
};
|
|
787
|
-
await args.dlg.receiveFuncResult(result);
|
|
788
|
-
return result;
|
|
789
826
|
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
827
|
+
else {
|
|
828
|
+
try {
|
|
829
|
+
throwIfAborted(args.abortSignal, args.dlg);
|
|
830
|
+
const output = await tool.call(args.dlg, args.agent, preparedInvocationArgs.args);
|
|
831
|
+
throwIfAborted(args.abortSignal, args.dlg);
|
|
832
|
+
const normalized = typeof output === 'string'
|
|
833
|
+
? { content: output, contentItems: undefined }
|
|
834
|
+
: {
|
|
835
|
+
content: typeof output.content === 'string' ? output.content : String(output),
|
|
836
|
+
contentItems: Array.isArray(output.contentItems)
|
|
837
|
+
? output.contentItems
|
|
838
|
+
: undefined,
|
|
839
|
+
};
|
|
840
|
+
result = {
|
|
841
|
+
type: 'func_result_msg',
|
|
842
|
+
id: func.id,
|
|
843
|
+
name: func.name,
|
|
844
|
+
content: String(normalized.content),
|
|
845
|
+
contentItems: normalized.contentItems,
|
|
846
|
+
role: 'tool',
|
|
847
|
+
genseq: callGenseq,
|
|
800
848
|
};
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
type: 'func_result_msg',
|
|
815
|
-
id: func.id,
|
|
816
|
-
name: func.name,
|
|
817
|
-
content: `Function '${func.name}' execution failed: ${errText}`,
|
|
818
|
-
role: 'tool',
|
|
819
|
-
genseq: callGenseq,
|
|
820
|
-
};
|
|
821
|
-
if (args.abortSignal?.aborted || err instanceof KernelDriverInterruptedError) {
|
|
822
|
-
if (!resultPersisted) {
|
|
823
|
-
await args.dlg.receiveFuncResult({
|
|
849
|
+
}
|
|
850
|
+
catch (err) {
|
|
851
|
+
const errText = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
|
|
852
|
+
result = {
|
|
853
|
+
type: 'func_result_msg',
|
|
854
|
+
id: func.id,
|
|
855
|
+
name: func.name,
|
|
856
|
+
content: `Function '${func.name}' execution failed: ${errText}`,
|
|
857
|
+
role: 'tool',
|
|
858
|
+
genseq: callGenseq,
|
|
859
|
+
};
|
|
860
|
+
if (args.abortSignal?.aborted || err instanceof KernelDriverInterruptedError) {
|
|
861
|
+
result = {
|
|
824
862
|
type: 'func_result_msg',
|
|
825
863
|
id: func.id,
|
|
826
864
|
name: func.name,
|
|
827
|
-
content: `Function '${func.name}' interrupted
|
|
865
|
+
content: `Function '${func.name}' interrupted before completion: ${errText}`,
|
|
828
866
|
role: 'tool',
|
|
829
867
|
genseq: callGenseq,
|
|
830
|
-
}
|
|
831
|
-
|
|
868
|
+
};
|
|
869
|
+
rethrowError = err;
|
|
832
870
|
}
|
|
833
|
-
throw err;
|
|
834
871
|
}
|
|
835
872
|
}
|
|
836
873
|
}
|
|
837
|
-
await args.dlg.
|
|
838
|
-
|
|
874
|
+
await args.dlg.persistFunctionCallResultPair(func.id, func.name, argsStr, callGenseq, result);
|
|
875
|
+
if (rethrowError !== undefined) {
|
|
876
|
+
throw rethrowError;
|
|
877
|
+
}
|
|
839
878
|
return result;
|
|
840
879
|
});
|
|
841
880
|
return await Promise.all(functionPromises);
|
|
@@ -850,8 +889,8 @@ async function executeFunctionRound(args) {
|
|
|
850
889
|
};
|
|
851
890
|
}
|
|
852
891
|
throwIfAborted(args.abortSignal, args.dlg);
|
|
853
|
-
const allowTellaskBack = args.
|
|
854
|
-
const allowedSpecials = args.
|
|
892
|
+
const allowTellaskBack = args.allowTellaskFunctions && args.dlg.id.rootId !== args.dlg.id.selfId;
|
|
893
|
+
const allowedSpecials = args.allowTellaskFunctions
|
|
855
894
|
? new Set([
|
|
856
895
|
'tellask',
|
|
857
896
|
'tellaskSessionless',
|
|
@@ -863,114 +902,19 @@ async function executeFunctionRound(args) {
|
|
|
863
902
|
...(allowTellaskBack ? ['tellaskBack'] : []),
|
|
864
903
|
])
|
|
865
904
|
: new Set();
|
|
866
|
-
const classified = (0, tellask_special_1.classifyTellaskSpecialFunctionCalls)(args.funcCalls, { allowedSpecials });
|
|
867
|
-
const specialCallById = new Map(classified.specialCalls.map((call) => [call.callId, call]));
|
|
868
|
-
const originalCallById = new Map(args.funcCalls.map((call) => [call.id, call]));
|
|
869
|
-
const toPersistedSpecialCallArgs = (call) => {
|
|
870
|
-
switch (call.callName) {
|
|
871
|
-
case 'tellaskBack':
|
|
872
|
-
return { tellaskContent: call.tellaskContent };
|
|
873
|
-
case 'askHuman':
|
|
874
|
-
return { tellaskContent: call.tellaskContent };
|
|
875
|
-
case 'freshBootsReasoning':
|
|
876
|
-
return {
|
|
877
|
-
tellaskContent: call.tellaskContent,
|
|
878
|
-
...(call.effort !== undefined ? { effort: call.effort } : {}),
|
|
879
|
-
};
|
|
880
|
-
case 'tellask':
|
|
881
|
-
return {
|
|
882
|
-
targetAgentId: call.targetAgentId,
|
|
883
|
-
sessionSlug: call.sessionSlug,
|
|
884
|
-
tellaskContent: call.tellaskContent,
|
|
885
|
-
};
|
|
886
|
-
case 'tellaskSessionless':
|
|
887
|
-
return {
|
|
888
|
-
targetAgentId: call.targetAgentId,
|
|
889
|
-
tellaskContent: call.tellaskContent,
|
|
890
|
-
};
|
|
891
|
-
case 'replyTellask':
|
|
892
|
-
case 'replyTellaskSessionless':
|
|
893
|
-
case 'replyTellaskBack':
|
|
894
|
-
return { replyContent: call.replyContent };
|
|
895
|
-
}
|
|
896
|
-
};
|
|
897
|
-
for (const callMsg of args.funcCalls) {
|
|
898
|
-
throwIfAborted(args.abortSignal, args.dlg);
|
|
899
|
-
const special = specialCallById.get(callMsg.id);
|
|
900
|
-
if (!special) {
|
|
901
|
-
continue;
|
|
902
|
-
}
|
|
903
|
-
const argumentsStr = typeof callMsg.arguments === 'string'
|
|
904
|
-
? callMsg.arguments
|
|
905
|
-
: JSON.stringify(callMsg.arguments ?? {});
|
|
906
|
-
if (isReplyTellaskCallName(callMsg.name)) {
|
|
907
|
-
await args.dlg.funcCallRequested(callMsg.id, callMsg.name, argumentsStr);
|
|
908
|
-
}
|
|
909
|
-
await args.dlg.persistTellaskSpecialCall(callMsg.id, special.callName, toPersistedSpecialCallArgs(special), callMsg.genseq);
|
|
910
|
-
}
|
|
911
|
-
const issueResults = [];
|
|
912
|
-
for (const issue of classified.parseIssues) {
|
|
913
|
-
const result = {
|
|
914
|
-
type: 'func_result_msg',
|
|
915
|
-
id: issue.call.id,
|
|
916
|
-
name: issue.call.name,
|
|
917
|
-
content: `Invalid arguments for tellask special function '${issue.call.name}': ${issue.error}`,
|
|
918
|
-
role: 'tool',
|
|
919
|
-
genseq: issue.call.genseq,
|
|
920
|
-
};
|
|
921
|
-
await args.dlg.receiveFuncResult(result);
|
|
922
|
-
issueResults.push(result);
|
|
923
|
-
}
|
|
924
905
|
throwIfAborted(args.abortSignal, args.dlg);
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
});
|
|
932
|
-
}
|
|
933
|
-
catch (err) {
|
|
934
|
-
const errText = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
|
|
935
|
-
for (const call of classified.specialCalls) {
|
|
936
|
-
if (issueResults.some((result) => result.id === call.callId)) {
|
|
937
|
-
continue;
|
|
938
|
-
}
|
|
939
|
-
const originalCall = originalCallById.get(call.callId);
|
|
940
|
-
if (!originalCall) {
|
|
941
|
-
throw new Error(`kernel-driver tellask special call invariant violation: missing original call for '${call.callId}'`);
|
|
942
|
-
}
|
|
943
|
-
await args.dlg.receiveFuncResult({
|
|
944
|
-
type: 'func_result_msg',
|
|
945
|
-
id: call.callId,
|
|
946
|
-
name: call.callName,
|
|
947
|
-
content: args.abortSignal?.aborted || err instanceof KernelDriverInterruptedError
|
|
948
|
-
? `Special function '${call.callName}' interrupted after call was persisted: ${errText}`
|
|
949
|
-
: `Special function '${call.callName}' execution failed after call was persisted: ${errText}`,
|
|
950
|
-
role: 'tool',
|
|
951
|
-
genseq: originalCall.genseq,
|
|
952
|
-
});
|
|
953
|
-
}
|
|
954
|
-
throw err;
|
|
955
|
-
}
|
|
956
|
-
const tellaskFuncResults = [];
|
|
957
|
-
const tellaskToolOutputs = [];
|
|
958
|
-
for (const output of tellaskExecution.toolOutputs) {
|
|
959
|
-
if (output.type === 'func_result_msg') {
|
|
960
|
-
await args.dlg.receiveFuncResult(output);
|
|
961
|
-
tellaskFuncResults.push(output);
|
|
962
|
-
continue;
|
|
963
|
-
}
|
|
964
|
-
tellaskToolOutputs.push(output);
|
|
965
|
-
}
|
|
966
|
-
const shouldStopAfterReplyTool = tellaskExecution.successfulReplyCallIds.length > 0;
|
|
906
|
+
const tellaskRound = await (0, tellask_special_1.processTellaskFunctionRound)({
|
|
907
|
+
dlg: args.dlg,
|
|
908
|
+
funcCalls: args.funcCalls,
|
|
909
|
+
allowedSpecials,
|
|
910
|
+
callbacks: args.callbacks,
|
|
911
|
+
});
|
|
967
912
|
throwIfAborted(args.abortSignal, args.dlg);
|
|
968
|
-
const specialCallIds = new Set(classified.specialCalls.map((call) => call.callId));
|
|
969
913
|
const genericResults = await executeFunctionCalls({
|
|
970
914
|
dlg: args.dlg,
|
|
971
915
|
agent: args.agent,
|
|
972
916
|
agentTools: args.agentTools,
|
|
973
|
-
funcCalls:
|
|
917
|
+
funcCalls: tellaskRound.normalCalls,
|
|
974
918
|
abortSignal: args.abortSignal,
|
|
975
919
|
});
|
|
976
920
|
const resultByCallId = new Map();
|
|
@@ -981,42 +925,46 @@ async function executeFunctionRound(args) {
|
|
|
981
925
|
}
|
|
982
926
|
resultByCallId.set(result.id, result);
|
|
983
927
|
};
|
|
984
|
-
for (const result of
|
|
985
|
-
register(result);
|
|
986
|
-
}
|
|
987
|
-
for (const result of tellaskFuncResults) {
|
|
928
|
+
for (const result of tellaskRound.tellaskResults) {
|
|
988
929
|
register(result);
|
|
989
930
|
}
|
|
990
931
|
for (const result of genericResults) {
|
|
991
932
|
register(result);
|
|
992
933
|
}
|
|
993
934
|
const pairedMessages = [];
|
|
935
|
+
const tellaskCallMsgById = new Map(tellaskRound.tellaskCallMessages.map((msg) => [msg.id, msg]));
|
|
936
|
+
const specialCallIds = new Set(tellaskRound.handledCallIds);
|
|
994
937
|
for (const call of args.funcCalls) {
|
|
995
|
-
const
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
938
|
+
const tellaskCallMsg = tellaskCallMsgById.get(call.id);
|
|
939
|
+
if (tellaskCallMsg) {
|
|
940
|
+
pairedMessages.push(tellaskCallMsg);
|
|
941
|
+
}
|
|
942
|
+
else {
|
|
943
|
+
const originalArgsStr = typeof call.arguments === 'string' ? call.arguments : JSON.stringify(call.arguments ?? {});
|
|
944
|
+
pairedMessages.push({
|
|
945
|
+
type: 'func_call_msg',
|
|
946
|
+
role: 'assistant',
|
|
947
|
+
genseq: call.genseq,
|
|
948
|
+
id: call.id,
|
|
949
|
+
name: call.name,
|
|
950
|
+
arguments: originalArgsStr,
|
|
951
|
+
});
|
|
952
|
+
}
|
|
1005
953
|
const result = resultByCallId.get(call.id);
|
|
1006
954
|
if (result) {
|
|
1007
955
|
pairedMessages.push(result);
|
|
1008
956
|
continue;
|
|
1009
957
|
}
|
|
1010
958
|
if (specialCallIds.has(call.id)) {
|
|
1011
|
-
|
|
959
|
+
throw new Error(`kernel-driver tellask result invariant violation: missing tellask result for call id '${call.id}' (${call.name})`);
|
|
1012
960
|
}
|
|
1013
961
|
throw new Error(`kernel-driver function result invariant violation: missing result for call id '${call.id}' (${call.name})`);
|
|
1014
962
|
}
|
|
1015
963
|
return {
|
|
1016
|
-
hadNormalToolCalls:
|
|
1017
|
-
shouldStopAfterReplyTool,
|
|
964
|
+
hadNormalToolCalls: tellaskRound.normalCalls.length > 0,
|
|
965
|
+
shouldStopAfterReplyTool: tellaskRound.shouldStopAfterReplyTool,
|
|
1018
966
|
pairedMessages,
|
|
1019
|
-
tellaskToolOutputs,
|
|
967
|
+
tellaskToolOutputs: [...tellaskRound.toolOutputs],
|
|
1020
968
|
};
|
|
1021
969
|
}
|
|
1022
970
|
async function resetDiligenceBudgetAfterQ4H(dlg, team) {
|
|
@@ -1233,7 +1181,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1233
1181
|
const isSubdialog = dlg.id.rootId !== dlg.id.selfId;
|
|
1234
1182
|
const fbrEffortDefault = resolveFbrEffortDefaultForTool(agent);
|
|
1235
1183
|
const effectiveFuncTools = policy.mode === 'default'
|
|
1236
|
-
?
|
|
1184
|
+
? mergeTellaskVirtualTools(canonicalFuncTools, {
|
|
1237
1185
|
includeTellaskBack: isSubdialog,
|
|
1238
1186
|
fbrEffortDefault,
|
|
1239
1187
|
})
|
|
@@ -1330,7 +1278,10 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1330
1278
|
skipTaskdocForThisDrive = true;
|
|
1331
1279
|
}
|
|
1332
1280
|
const persistedUserLanguageCode = currentPrompt.userLanguageCode ?? dlg.getLastUserLanguageCode();
|
|
1333
|
-
const
|
|
1281
|
+
const q4hAnswerCallId = normalizeQ4HAnswerCallId(currentPrompt.q4hAnswerCallId);
|
|
1282
|
+
// `q4hAnswerCallId` marks a continuation input for an already-materialized askHuman
|
|
1283
|
+
// answer. It is not a second business-level user prompt that should re-enter transcript.
|
|
1284
|
+
const isQ4HAnswerPrompt = q4hAnswerCallId !== undefined;
|
|
1334
1285
|
const promptLanguage = persistedUserLanguageCode === 'zh' || persistedUserLanguageCode === 'en'
|
|
1335
1286
|
? persistedUserLanguageCode
|
|
1336
1287
|
: (0, work_language_1.getWorkLanguage)();
|
|
@@ -1390,15 +1341,26 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1390
1341
|
});
|
|
1391
1342
|
currentRuntimeGuideMsg = undefined;
|
|
1392
1343
|
}
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1344
|
+
if (isQ4HAnswerPrompt) {
|
|
1345
|
+
// Record only the answered call correlation / user language for the resumed round.
|
|
1346
|
+
// The actual human answer fact was already persisted via askHuman tellask result flow.
|
|
1347
|
+
await dlg.receiveHumanReply({
|
|
1348
|
+
content: replyGuidance.promptContent,
|
|
1349
|
+
userLanguageCode: persistedUserLanguageCode,
|
|
1350
|
+
q4hAnswerCallId,
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
else {
|
|
1354
|
+
await dlg.addChatMessages({
|
|
1355
|
+
type: 'prompting_msg',
|
|
1356
|
+
role: 'user',
|
|
1357
|
+
genseq: dlg.activeGenSeq,
|
|
1358
|
+
msgId: currentPrompt.msgId,
|
|
1359
|
+
grammar: 'markdown',
|
|
1360
|
+
content: replyGuidance.promptContent,
|
|
1361
|
+
});
|
|
1362
|
+
await dlg.persistUserMessage(replyGuidance.promptContent, currentPrompt.msgId, 'markdown', origin, persistedUserLanguageCode, q4hAnswerCallId, replyGuidance.persistedTellaskReplyDirective);
|
|
1363
|
+
}
|
|
1402
1364
|
if (renderPromptAsRuntimeGuideBubble) {
|
|
1403
1365
|
(0, evt_registry_1.postDialogEvent)(dlg, {
|
|
1404
1366
|
type: 'runtime_guide_evt',
|
|
@@ -1407,10 +1369,9 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1407
1369
|
content: replyGuidance.promptContent,
|
|
1408
1370
|
});
|
|
1409
1371
|
}
|
|
1410
|
-
else {
|
|
1372
|
+
else if (!isQ4HAnswerPrompt) {
|
|
1411
1373
|
// Emit the live user-side boundary event for UI generation bubbles.
|
|
1412
|
-
// Without this, realtime turns can miss user content + divider (<hr/>)
|
|
1413
|
-
// while replay (from persisted human_text_record) still looks correct.
|
|
1374
|
+
// Without this, realtime turns can miss user content + divider (<hr/>).
|
|
1414
1375
|
(0, evt_registry_1.postDialogEvent)(dlg, {
|
|
1415
1376
|
type: 'end_of_user_saying_evt',
|
|
1416
1377
|
course: dlg.currentCourse,
|
|
@@ -1420,7 +1381,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1420
1381
|
grammar: 'markdown',
|
|
1421
1382
|
origin,
|
|
1422
1383
|
userLanguageCode: persistedUserLanguageCode,
|
|
1423
|
-
|
|
1384
|
+
q4hAnswerCallId,
|
|
1424
1385
|
});
|
|
1425
1386
|
}
|
|
1426
1387
|
if (currentPromptFromFbrState && currentFbrState) {
|
|
@@ -1469,7 +1430,27 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1469
1430
|
});
|
|
1470
1431
|
const newMsgs = [];
|
|
1471
1432
|
const streamedFuncCalls = [];
|
|
1433
|
+
let sawWebSearchSideChannelOutput = false;
|
|
1434
|
+
let sawNativeToolSideChannelOutput = false;
|
|
1472
1435
|
const streamOrBatch = async () => {
|
|
1436
|
+
let batchAttemptCourse;
|
|
1437
|
+
let batchAttemptCheckpointOffset;
|
|
1438
|
+
const rollbackBatchAttempt = async () => {
|
|
1439
|
+
if (batchAttemptCourse === undefined || batchAttemptCheckpointOffset === undefined) {
|
|
1440
|
+
throw new Error(`kernel-driver batch retry invariant violation: missing checkpoint (dialog=${dlg.id.valueOf()})`);
|
|
1441
|
+
}
|
|
1442
|
+
await persistence_1.DialogPersistence.rollbackCourseFileToOffset(dlg.id, batchAttemptCourse, batchAttemptCheckpointOffset, dlg.status);
|
|
1443
|
+
(0, evt_registry_1.postDialogEvent)(dlg, {
|
|
1444
|
+
type: 'genseq_discard_evt',
|
|
1445
|
+
course: batchAttemptCourse,
|
|
1446
|
+
genseq: dlg.activeGenSeq,
|
|
1447
|
+
reason: 'retry',
|
|
1448
|
+
});
|
|
1449
|
+
sawWebSearchSideChannelOutput = false;
|
|
1450
|
+
sawNativeToolSideChannelOutput = false;
|
|
1451
|
+
streamedFuncCalls.length = 0;
|
|
1452
|
+
newMsgs.length = 0;
|
|
1453
|
+
};
|
|
1473
1454
|
if (agent.streaming === false) {
|
|
1474
1455
|
const batch = await (0, runtime_1.runLlmRequestWithRetry)({
|
|
1475
1456
|
dlg,
|
|
@@ -1482,13 +1463,21 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1482
1463
|
retryMaxDelayMs: retryPolicy.maxDelayMs,
|
|
1483
1464
|
classifyFailure: llmGen.classifyFailure?.bind(llmGen),
|
|
1484
1465
|
canRetry: () => true,
|
|
1466
|
+
onRetry: rollbackBatchAttempt,
|
|
1467
|
+
onGiveUp: rollbackBatchAttempt,
|
|
1485
1468
|
doRequest: async () => {
|
|
1469
|
+
batchAttemptCourse = dlg.activeGenCourseOrUndefined ?? dlg.currentCourse;
|
|
1470
|
+
batchAttemptCheckpointOffset = await persistence_1.DialogPersistence.captureCourseFileOffset(dlg.id, batchAttemptCourse, dlg.status);
|
|
1471
|
+
sawWebSearchSideChannelOutput = false;
|
|
1472
|
+
sawNativeToolSideChannelOutput = false;
|
|
1473
|
+
streamedFuncCalls.length = 0;
|
|
1474
|
+
newMsgs.length = 0;
|
|
1486
1475
|
const batchResult = await llmGen.genMoreMessages(providerCfg, agent, systemPrompt, funcTools, {
|
|
1487
1476
|
dialogSelfId: dlg.id.selfId,
|
|
1488
1477
|
dialogRootId: dlg.id.rootId,
|
|
1489
1478
|
promptCacheKey: `${dlg.id.selfId}:c${String(dlg.currentCourse)}`,
|
|
1490
1479
|
}, ctxMsgs, dlg.activeGenSeq, abortSignal);
|
|
1491
|
-
if (!hasMeaningfulBatchOutput(batchResult
|
|
1480
|
+
if (!hasMeaningfulBatchOutput(batchResult)) {
|
|
1492
1481
|
throw {
|
|
1493
1482
|
status: 503,
|
|
1494
1483
|
code: KERNEL_DRIVER_EMPTY_LLM_RESPONSE_ERROR_CODE,
|
|
@@ -1502,6 +1491,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1502
1491
|
usage: batch.usage,
|
|
1503
1492
|
llmGenModel: batch.llmGenModel,
|
|
1504
1493
|
batchMessages: batch.messages,
|
|
1494
|
+
batchOutputs: batch.outputs,
|
|
1505
1495
|
};
|
|
1506
1496
|
}
|
|
1507
1497
|
let currentSayingContent = '';
|
|
@@ -1511,7 +1501,6 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1511
1501
|
let streamAttemptCheckpointOffset;
|
|
1512
1502
|
let streamAttemptSayingContent;
|
|
1513
1503
|
let streamAttemptSayingGenseq;
|
|
1514
|
-
let streamSawWebSearchCall = false;
|
|
1515
1504
|
let streamActive = { kind: 'idle' };
|
|
1516
1505
|
const rollbackStreamAttempt = async () => {
|
|
1517
1506
|
if (streamAttemptCourse === undefined || streamAttemptCheckpointOffset === undefined) {
|
|
@@ -1530,7 +1519,8 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1530
1519
|
currentSayingContent = '';
|
|
1531
1520
|
streamAttemptSayingContent = undefined;
|
|
1532
1521
|
streamAttemptSayingGenseq = undefined;
|
|
1533
|
-
|
|
1522
|
+
sawWebSearchSideChannelOutput = false;
|
|
1523
|
+
sawNativeToolSideChannelOutput = false;
|
|
1534
1524
|
streamedFuncCalls.length = 0;
|
|
1535
1525
|
newMsgs.length = 0;
|
|
1536
1526
|
};
|
|
@@ -1626,8 +1616,13 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1626
1616
|
},
|
|
1627
1617
|
webSearchCall: async (call) => {
|
|
1628
1618
|
throwIfAborted(abortSignal, dlg);
|
|
1629
|
-
|
|
1630
|
-
await dlg.webSearchCall(call);
|
|
1619
|
+
sawWebSearchSideChannelOutput = true;
|
|
1620
|
+
await dlg.webSearchCall(projectLlmWebSearchCall(call));
|
|
1621
|
+
},
|
|
1622
|
+
nativeToolCall: async (call) => {
|
|
1623
|
+
throwIfAborted(abortSignal, dlg);
|
|
1624
|
+
sawNativeToolSideChannelOutput = true;
|
|
1625
|
+
await dlg.nativeToolCall(call);
|
|
1631
1626
|
},
|
|
1632
1627
|
};
|
|
1633
1628
|
const res = await (0, runtime_1.runLlmRequestWithRetry)({
|
|
@@ -1652,7 +1647,8 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1652
1647
|
currentSayingContent = '';
|
|
1653
1648
|
streamAttemptSayingContent = undefined;
|
|
1654
1649
|
streamAttemptSayingGenseq = undefined;
|
|
1655
|
-
|
|
1650
|
+
sawWebSearchSideChannelOutput = false;
|
|
1651
|
+
sawNativeToolSideChannelOutput = false;
|
|
1656
1652
|
streamedFuncCalls.length = 0;
|
|
1657
1653
|
newMsgs.length = 0;
|
|
1658
1654
|
const streamResult = await llmGen.genToReceiver(providerCfg, agent, systemPrompt, funcTools, {
|
|
@@ -1666,7 +1662,8 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1666
1662
|
if (!hasThinkingContent &&
|
|
1667
1663
|
!hasSayingContent &&
|
|
1668
1664
|
!hasFunctionCall &&
|
|
1669
|
-
!
|
|
1665
|
+
!sawWebSearchSideChannelOutput &&
|
|
1666
|
+
!sawNativeToolSideChannelOutput) {
|
|
1670
1667
|
throw {
|
|
1671
1668
|
status: 503,
|
|
1672
1669
|
code: KERNEL_DRIVER_EMPTY_LLM_RESPONSE_ERROR_CODE,
|
|
@@ -1694,24 +1691,50 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1694
1691
|
usage: llmOutput.usage,
|
|
1695
1692
|
});
|
|
1696
1693
|
dlg.setLastContextHealth(contextHealthForGen);
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1694
|
+
const batchOutputs = Array.isArray(llmOutput.batchOutputs) && llmOutput.batchOutputs.length > 0
|
|
1695
|
+
? llmOutput.batchOutputs
|
|
1696
|
+
: Array.isArray(llmOutput.batchMessages)
|
|
1697
|
+
? llmOutput.batchMessages.map((message) => ({ kind: 'message', message }))
|
|
1698
|
+
: [];
|
|
1699
|
+
for (const output of batchOutputs) {
|
|
1700
|
+
switch (output.kind) {
|
|
1701
|
+
case 'message': {
|
|
1702
|
+
const msg = output.message;
|
|
1703
|
+
if (msg.type === 'thinking_msg' || msg.type === 'saying_msg') {
|
|
1704
|
+
newMsgs.push(msg);
|
|
1705
|
+
if (msg.type === 'thinking_msg') {
|
|
1706
|
+
await (0, events_1.emitThinkingEvents)(dlg, msg.content, msg.reasoning);
|
|
1707
|
+
}
|
|
1708
|
+
else {
|
|
1709
|
+
lastAssistantSayingContent = msg.content;
|
|
1710
|
+
lastAssistantSayingGenseq = msg.genseq;
|
|
1711
|
+
lastAssistantReplyTarget = currentReplyTarget;
|
|
1712
|
+
await emitAssistantSaying(dlg, msg.content);
|
|
1713
|
+
}
|
|
1714
|
+
break;
|
|
1715
|
+
}
|
|
1716
|
+
if (msg.type === 'func_call_msg') {
|
|
1717
|
+
streamedFuncCalls.push(msg);
|
|
1718
|
+
}
|
|
1719
|
+
break;
|
|
1720
|
+
}
|
|
1721
|
+
case 'web_search_call': {
|
|
1722
|
+
sawWebSearchSideChannelOutput = true;
|
|
1723
|
+
await dlg.webSearchCall(projectLlmWebSearchCall(output.call));
|
|
1724
|
+
break;
|
|
1725
|
+
}
|
|
1726
|
+
case 'native_tool_call': {
|
|
1727
|
+
sawNativeToolSideChannelOutput = true;
|
|
1728
|
+
await dlg.nativeToolCall(output.call);
|
|
1729
|
+
break;
|
|
1703
1730
|
}
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
lastAssistantReplyTarget = currentReplyTarget;
|
|
1708
|
-
await emitAssistantSaying(dlg, msg.content);
|
|
1731
|
+
default: {
|
|
1732
|
+
const _exhaustive = output;
|
|
1733
|
+
throw new Error(`Unhandled batch output kind: ${String(_exhaustive)}`);
|
|
1709
1734
|
}
|
|
1710
1735
|
}
|
|
1711
|
-
const funcCalls = llmOutput.batchMessages.filter((m) => m.type === 'func_call_msg');
|
|
1712
|
-
streamedFuncCalls.push(...funcCalls);
|
|
1713
1736
|
}
|
|
1714
|
-
const tellaskCallCount = policy.
|
|
1737
|
+
const tellaskCallCount = policy.allowTellaskFunctions
|
|
1715
1738
|
? streamedFuncCalls.filter((c) => c.name === 'tellask' ||
|
|
1716
1739
|
c.name === 'tellaskSessionless' ||
|
|
1717
1740
|
c.name === 'tellaskBack' ||
|
|
@@ -1789,7 +1812,7 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1789
1812
|
funcCalls: streamedFuncCalls,
|
|
1790
1813
|
callbacks,
|
|
1791
1814
|
abortSignal,
|
|
1792
|
-
|
|
1815
|
+
allowTellaskFunctions: policy.allowTellaskFunctions,
|
|
1793
1816
|
});
|
|
1794
1817
|
if (routed.tellaskToolOutputs.length > 0) {
|
|
1795
1818
|
newMsgs.push(...routed.tellaskToolOutputs);
|
|
@@ -1883,6 +1906,9 @@ async function driveDialogStreamCore(dlg, callbacks, humanPrompt, driveOptions)
|
|
|
1883
1906
|
await resetDiligenceBudgetAfterQ4H(dlg, team);
|
|
1884
1907
|
break;
|
|
1885
1908
|
}
|
|
1909
|
+
// Continue only when this round produced new context that must be fed back into the next
|
|
1910
|
+
// LLM turn. Provider-native side-channel UI events are meaningful output, but they are not
|
|
1911
|
+
// transcript/context inputs and therefore must not trigger another generation round.
|
|
1886
1912
|
const shouldContinue = streamedFuncCalls.length > 0 ||
|
|
1887
1913
|
routed.pairedMessages.length > 0 ||
|
|
1888
1914
|
routed.tellaskToolOutputs.length > 0;
|