dominds 1.23.2 → 1.23.4
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/dialog-display-state.js +112 -9
- package/dist/dialog.js +4 -0
- package/dist/docs/dialog-system.md +6 -2
- package/dist/docs/dialog-system.zh.md +5 -1
- package/dist/docs/diligence-push.md +27 -6
- package/dist/docs/diligence-push.zh.md +13 -6
- package/dist/docs/llm-provider-isolation.md +1 -1
- package/dist/docs/llm-provider-isolation.zh.md +1 -1
- package/dist/docs/tellask-revive-context-refactor.zh.md +13 -1
- package/dist/docs/volcengine-coding-plan-openai-compatible.zh.md +3 -2
- package/dist/llm/api-quirks.d.ts +1 -0
- package/dist/llm/api-quirks.js +35 -1
- package/dist/llm/defaults.yaml +6 -0
- package/dist/llm/gen/anthropic.js +6 -2
- package/dist/llm/gen/mock.js +44 -11
- package/dist/llm/gen/openai-compatible.d.ts +2 -1
- package/dist/llm/gen/openai-compatible.js +88 -20
- package/dist/llm/gen.d.ts +12 -0
- package/dist/llm/kernel-driver/context-health.d.ts +3 -4
- package/dist/llm/kernel-driver/context-health.js +5 -2
- package/dist/llm/kernel-driver/context.d.ts +4 -8
- package/dist/llm/kernel-driver/context.js +5 -25
- package/dist/llm/kernel-driver/drive.js +263 -59
- package/dist/llm/kernel-driver/engine.d.ts +1 -1
- package/dist/llm/kernel-driver/engine.js +5 -3
- package/dist/llm/kernel-driver/flow.js +162 -45
- package/dist/llm/kernel-driver/runtime.d.ts +12 -11
- package/dist/llm/kernel-driver/runtime.js +106 -18
- package/dist/llm/kernel-driver/sideDialog.d.ts +3 -0
- package/dist/llm/kernel-driver/sideDialog.js +4 -1
- package/dist/llm/kernel-driver/tellask-special.d.ts +1 -0
- package/dist/llm/kernel-driver/tellask-special.js +30 -30
- package/dist/llm/kernel-driver/types.d.ts +7 -3
- package/dist/log.js +35 -2
- package/dist/persistence.js +12 -1
- package/dist/recovery/reply-special.js +1 -1
- package/dist/runtime/driver-messages.d.ts +14 -1
- package/dist/runtime/driver-messages.js +116 -6
- package/dist/runtime/inter-dialog-format.d.ts +1 -0
- package/dist/runtime/inter-dialog-format.js +7 -3
- package/dist/server/websocket-handler.js +0 -1
- package/dist/tools/team_mgmt-manual.js +2 -2
- package/package.json +2 -2
- package/webapp/dist/assets/{_basePickBy-C3SVVywm.js → _basePickBy-DMD1UhXs.js} +3 -3
- package/webapp/dist/assets/{_basePickBy-C3SVVywm.js.map → _basePickBy-DMD1UhXs.js.map} +1 -1
- package/webapp/dist/assets/{_baseUniq-egNq6cCa.js → _baseUniq-CsE8Qvwt.js} +2 -2
- package/webapp/dist/assets/{_baseUniq-egNq6cCa.js.map → _baseUniq-CsE8Qvwt.js.map} +1 -1
- package/webapp/dist/assets/{arc-CASAlRvm.js → arc-0h8sV6e1.js} +2 -2
- package/webapp/dist/assets/{arc-CASAlRvm.js.map → arc-0h8sV6e1.js.map} +1 -1
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-B6n5FQmS.js → architectureDiagram-2XIMDMQ5-BbMESECO.js} +7 -7
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-B6n5FQmS.js.map → architectureDiagram-2XIMDMQ5-BbMESECO.js.map} +1 -1
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-D2UGGjic.js → blockDiagram-WCTKOSBZ-DwkN-9a4.js} +7 -7
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-D2UGGjic.js.map → blockDiagram-WCTKOSBZ-DwkN-9a4.js.map} +1 -1
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-BOY_bQFP.js → c4Diagram-IC4MRINW-CGYONEh1.js} +3 -3
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-BOY_bQFP.js.map → c4Diagram-IC4MRINW-CGYONEh1.js.map} +1 -1
- package/webapp/dist/assets/{channel-CZ_X09H1.js → channel-DbSJhm5-.js} +2 -2
- package/webapp/dist/assets/{channel-CZ_X09H1.js.map → channel-DbSJhm5-.js.map} +1 -1
- package/webapp/dist/assets/{chunk-4BX2VUAB-BIwyAzZQ.js → chunk-4BX2VUAB-D1inRfgf.js} +2 -2
- package/webapp/dist/assets/{chunk-4BX2VUAB-BIwyAzZQ.js.map → chunk-4BX2VUAB-D1inRfgf.js.map} +1 -1
- package/webapp/dist/assets/{chunk-55IACEB6-zSjTFoCX.js → chunk-55IACEB6-DL1IDg_h.js} +2 -2
- package/webapp/dist/assets/{chunk-55IACEB6-zSjTFoCX.js.map → chunk-55IACEB6-DL1IDg_h.js.map} +1 -1
- package/webapp/dist/assets/{chunk-FMBD7UC4-CTpuRfdB.js → chunk-FMBD7UC4-CugIlRDV.js} +2 -2
- package/webapp/dist/assets/{chunk-FMBD7UC4-CTpuRfdB.js.map → chunk-FMBD7UC4-CugIlRDV.js.map} +1 -1
- package/webapp/dist/assets/{chunk-JSJVCQXG-CJ3DM4in.js → chunk-JSJVCQXG-DKHSdeu1.js} +2 -2
- package/webapp/dist/assets/{chunk-JSJVCQXG-CJ3DM4in.js.map → chunk-JSJVCQXG-DKHSdeu1.js.map} +1 -1
- package/webapp/dist/assets/{chunk-KX2RTZJC-B97EakhO.js → chunk-KX2RTZJC-DCU9tkq6.js} +2 -2
- package/webapp/dist/assets/{chunk-KX2RTZJC-B97EakhO.js.map → chunk-KX2RTZJC-DCU9tkq6.js.map} +1 -1
- package/webapp/dist/assets/{chunk-NQ4KR5QH-5o1o5x0z.js → chunk-NQ4KR5QH-DN3O2s2M.js} +4 -4
- package/webapp/dist/assets/{chunk-NQ4KR5QH-5o1o5x0z.js.map → chunk-NQ4KR5QH-DN3O2s2M.js.map} +1 -1
- package/webapp/dist/assets/{chunk-QZHKN3VN-D33FSIEb.js → chunk-QZHKN3VN-e3ztIJg0.js} +2 -2
- package/webapp/dist/assets/{chunk-QZHKN3VN-D33FSIEb.js.map → chunk-QZHKN3VN-e3ztIJg0.js.map} +1 -1
- package/webapp/dist/assets/{chunk-WL4C6EOR-C2InqFin.js → chunk-WL4C6EOR-Dv907NPM.js} +6 -6
- package/webapp/dist/assets/{chunk-WL4C6EOR-C2InqFin.js.map → chunk-WL4C6EOR-Dv907NPM.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-BfLZmK48.js → classDiagram-VBA2DB6C-DOTXtxYZ.js} +7 -7
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-BfLZmK48.js.map → classDiagram-VBA2DB6C-DOTXtxYZ.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-BfLZmK48.js → classDiagram-v2-RAHNMMFH-DOTXtxYZ.js} +7 -7
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-BfLZmK48.js.map → classDiagram-v2-RAHNMMFH-DOTXtxYZ.js.map} +1 -1
- package/webapp/dist/assets/{clone-BSCHnHfl.js → clone-6lYQMWpu.js} +2 -2
- package/webapp/dist/assets/{clone-BSCHnHfl.js.map → clone-6lYQMWpu.js.map} +1 -1
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-CeQ1jAJJ.js → cose-bilkent-S5V4N54A-DoJeDXV0.js} +2 -2
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-CeQ1jAJJ.js.map → cose-bilkent-S5V4N54A-DoJeDXV0.js.map} +1 -1
- package/webapp/dist/assets/{dagre-KLK3FWXG-WUuNYzcK.js → dagre-KLK3FWXG-F_n_vhV9.js} +7 -7
- package/webapp/dist/assets/{dagre-KLK3FWXG-WUuNYzcK.js.map → dagre-KLK3FWXG-F_n_vhV9.js.map} +1 -1
- package/webapp/dist/assets/{diagram-E7M64L7V-jOVCIExP.js → diagram-E7M64L7V-Crwhgyjv.js} +8 -8
- package/webapp/dist/assets/{diagram-E7M64L7V-jOVCIExP.js.map → diagram-E7M64L7V-Crwhgyjv.js.map} +1 -1
- package/webapp/dist/assets/{diagram-IFDJBPK2-cCeQqotA.js → diagram-IFDJBPK2-CIt1nnn5.js} +7 -7
- package/webapp/dist/assets/{diagram-IFDJBPK2-cCeQqotA.js.map → diagram-IFDJBPK2-CIt1nnn5.js.map} +1 -1
- package/webapp/dist/assets/{diagram-P4PSJMXO-DjAYFRLv.js → diagram-P4PSJMXO-qowipEfV.js} +7 -7
- package/webapp/dist/assets/{diagram-P4PSJMXO-DjAYFRLv.js.map → diagram-P4PSJMXO-qowipEfV.js.map} +1 -1
- package/webapp/dist/assets/{erDiagram-INFDFZHY-Dl_6U5fV.js → erDiagram-INFDFZHY-DV2BcYNa.js} +5 -5
- package/webapp/dist/assets/{erDiagram-INFDFZHY-Dl_6U5fV.js.map → erDiagram-INFDFZHY-DV2BcYNa.js.map} +1 -1
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-D80nrZ3S.js → flowDiagram-PKNHOUZH-CAbWV161.js} +7 -7
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-D80nrZ3S.js.map → flowDiagram-PKNHOUZH-CAbWV161.js.map} +1 -1
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-T3WdMrgj.js → ganttDiagram-A5KZAMGK-CfdR7FRr.js} +3 -3
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-T3WdMrgj.js.map → ganttDiagram-A5KZAMGK-CfdR7FRr.js.map} +1 -1
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-ifV-jkKL.js → gitGraphDiagram-K3NZZRJ6-DuJFTELz.js} +8 -8
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-ifV-jkKL.js.map → gitGraphDiagram-K3NZZRJ6-DuJFTELz.js.map} +1 -1
- package/webapp/dist/assets/{graph-D5jmnb35.js → graph-cjRyzujT.js} +3 -3
- package/webapp/dist/assets/{graph-D5jmnb35.js.map → graph-cjRyzujT.js.map} +1 -1
- package/webapp/dist/assets/{index-CGbZlct2.js → index-DgfF56L4.js} +36 -36
- package/webapp/dist/assets/{index-CGbZlct2.js.map → index-DgfF56L4.js.map} +1 -1
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-C340CY5x.js → infoDiagram-LFFYTUFH-3wx-7AdD.js} +6 -6
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-C340CY5x.js.map → infoDiagram-LFFYTUFH-3wx-7AdD.js.map} +1 -1
- package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-Bu4RsELK.js → ishikawaDiagram-PHBUUO56-g6CMb1Qc.js} +2 -2
- package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-Bu4RsELK.js.map → ishikawaDiagram-PHBUUO56-g6CMb1Qc.js.map} +1 -1
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-Dvv3ypKA.js → journeyDiagram-4ABVD52K-DdCcmOBO.js} +5 -5
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-Dvv3ypKA.js.map → journeyDiagram-4ABVD52K-DdCcmOBO.js.map} +1 -1
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-D_rsetjW.js → kanban-definition-K7BYSVSG-BFw2emGl.js} +3 -3
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-D_rsetjW.js.map → kanban-definition-K7BYSVSG-BFw2emGl.js.map} +1 -1
- package/webapp/dist/assets/{layout-CLmOfwnS.js → layout-Clazq06r.js} +5 -5
- package/webapp/dist/assets/{layout-CLmOfwnS.js.map → layout-Clazq06r.js.map} +1 -1
- package/webapp/dist/assets/{linear-DFAmViqi.js → linear-jdsBGgvD.js} +2 -2
- package/webapp/dist/assets/{linear-DFAmViqi.js.map → linear-jdsBGgvD.js.map} +1 -1
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-Ce3_czeS.js → mindmap-definition-YRQLILUH-DLSZrW6l.js} +4 -4
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-Ce3_czeS.js.map → mindmap-definition-YRQLILUH-DLSZrW6l.js.map} +1 -1
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-U6_un5Sc.js → pieDiagram-SKSYHLDU-Uj-Zpci6.js} +8 -8
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-U6_un5Sc.js.map → pieDiagram-SKSYHLDU-Uj-Zpci6.js.map} +1 -1
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-DmVJQItS.js → quadrantDiagram-337W2JSQ-DO7Sl1nV.js} +3 -3
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-DmVJQItS.js.map → quadrantDiagram-337W2JSQ-DO7Sl1nV.js.map} +1 -1
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-BkNhSY-g.js → requirementDiagram-Z7DCOOCP-WrurrDKQ.js} +4 -4
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-BkNhSY-g.js.map → requirementDiagram-Z7DCOOCP-WrurrDKQ.js.map} +1 -1
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-E3UEy5SX.js → sankeyDiagram-WA2Y5GQK-gcxbxuZB.js} +2 -2
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-E3UEy5SX.js.map → sankeyDiagram-WA2Y5GQK-gcxbxuZB.js.map} +1 -1
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-k0w9WKAO.js → sequenceDiagram-2WXFIKYE-B98U2Npa.js} +4 -4
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-k0w9WKAO.js.map → sequenceDiagram-2WXFIKYE-B98U2Npa.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-DRgdJrlx.js → stateDiagram-RAJIS63D-BUgfHMbd.js} +9 -9
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-DRgdJrlx.js.map → stateDiagram-RAJIS63D-BUgfHMbd.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-edtkX9x6.js → stateDiagram-v2-FVOUBMTO-C8gH0rSW.js} +5 -5
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-edtkX9x6.js.map → stateDiagram-v2-FVOUBMTO-C8gH0rSW.js.map} +1 -1
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-D0zyXyNL.js → timeline-definition-YZTLITO2-DnVikX3B.js} +3 -3
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-D0zyXyNL.js.map → timeline-definition-YZTLITO2-DnVikX3B.js.map} +1 -1
- package/webapp/dist/assets/{treemap-KZPCXAKY-CglsYqbQ.js → treemap-KZPCXAKY-BjhjT1IM.js} +5 -5
- package/webapp/dist/assets/{treemap-KZPCXAKY-CglsYqbQ.js.map → treemap-KZPCXAKY-BjhjT1IM.js.map} +1 -1
- package/webapp/dist/assets/{vennDiagram-LZ73GAT5-DsUizzvt.js → vennDiagram-LZ73GAT5-CXjPMxrl.js} +2 -2
- package/webapp/dist/assets/{vennDiagram-LZ73GAT5-DsUizzvt.js.map → vennDiagram-LZ73GAT5-CXjPMxrl.js.map} +1 -1
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-DvYQ4zKY.js → xychartDiagram-JWTSCODW-ByKmk3Cb.js} +3 -3
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-DvYQ4zKY.js.map → xychartDiagram-JWTSCODW-ByKmk3Cb.js.map} +1 -1
- package/webapp/dist/index.html +1 -1
|
@@ -90,6 +90,27 @@ function isDialogLatestResumable(latest) {
|
|
|
90
90
|
function isSameDisplayState(left, right) {
|
|
91
91
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
92
92
|
}
|
|
93
|
+
function isSideDialogResponseAnchor(record) {
|
|
94
|
+
return record?.type === 'tellask_anchor_record' && record.anchorRole === 'response';
|
|
95
|
+
}
|
|
96
|
+
function isNonIdleDisplayProjection(state) {
|
|
97
|
+
return state !== undefined && state.kind !== 'idle_waiting_user';
|
|
98
|
+
}
|
|
99
|
+
async function hasSideDialogFinalResponseAnchor(dialogId, latest) {
|
|
100
|
+
if (dialogId.selfId === dialogId.rootId) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const rawCourse = latest.currentCourse;
|
|
104
|
+
const currentCourse = Number.isFinite(rawCourse) && rawCourse > 0 ? Math.floor(rawCourse) : 1;
|
|
105
|
+
const courseEvents = await persistence_1.DialogPersistence.loadCourseEvents(dialogId, currentCourse, 'running');
|
|
106
|
+
for (let index = courseEvents.length - 1; index >= 0; index -= 1) {
|
|
107
|
+
const event = courseEvents[index];
|
|
108
|
+
if (event.type === 'tellask_anchor_record') {
|
|
109
|
+
return isSideDialogResponseAnchor(event);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
93
114
|
function classifyRunControlBucket(state) {
|
|
94
115
|
if (!state)
|
|
95
116
|
return 'none';
|
|
@@ -124,7 +145,16 @@ async function getRunControlCountsSnapshot() {
|
|
|
124
145
|
proceeding++;
|
|
125
146
|
continue;
|
|
126
147
|
}
|
|
127
|
-
|
|
148
|
+
let latest = await persistence_1.DialogPersistence.loadDialogLatest(dialogId, 'running');
|
|
149
|
+
if (!latest) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const healedLatest = await healStaleSideDialogRunControlAfterFinalResponse({
|
|
153
|
+
dialogId,
|
|
154
|
+
latest,
|
|
155
|
+
trigger: 'run_control_snapshot',
|
|
156
|
+
});
|
|
157
|
+
latest = healedLatest;
|
|
128
158
|
if (latest?.generating === true) {
|
|
129
159
|
proceeding++;
|
|
130
160
|
}
|
|
@@ -464,6 +494,9 @@ async function computeIdleDisplayStateFromPersistence(dialogId) {
|
|
|
464
494
|
continueEnabled: true,
|
|
465
495
|
};
|
|
466
496
|
}
|
|
497
|
+
if (latest && (await hasSideDialogFinalResponseAnchor(dialogId, latest))) {
|
|
498
|
+
return { kind: 'idle_waiting_user' };
|
|
499
|
+
}
|
|
467
500
|
const q4h = await persistence_1.DialogPersistence.loadQuestions4HumanState(dialogId, 'running');
|
|
468
501
|
const pendingSideDialogs = await persistence_1.DialogPersistence.loadPendingSideDialogs(dialogId, 'running');
|
|
469
502
|
const hasQ4H = q4h.length > 0;
|
|
@@ -479,15 +512,60 @@ async function computeIdleDisplayStateFromPersistence(dialogId) {
|
|
|
479
512
|
}
|
|
480
513
|
return { kind: 'idle_waiting_user' };
|
|
481
514
|
}
|
|
515
|
+
async function healStaleSideDialogRunControlAfterFinalResponse(args) {
|
|
516
|
+
if (args.dialogId.selfId === args.dialogId.rootId ||
|
|
517
|
+
(args.latest.needsDrive !== true &&
|
|
518
|
+
args.latest.generating !== true &&
|
|
519
|
+
args.latest.executionMarker?.kind !== 'interrupted' &&
|
|
520
|
+
!isNonIdleDisplayProjection(args.latest.displayState))) {
|
|
521
|
+
return args.latest;
|
|
522
|
+
}
|
|
523
|
+
if (args.latest.executionMarker?.kind === 'dead') {
|
|
524
|
+
return args.latest;
|
|
525
|
+
}
|
|
526
|
+
if (args.latest.pendingCourseStartPrompt) {
|
|
527
|
+
return args.latest;
|
|
528
|
+
}
|
|
529
|
+
if (!(await hasSideDialogFinalResponseAnchor(args.dialogId, args.latest))) {
|
|
530
|
+
return args.latest;
|
|
531
|
+
}
|
|
532
|
+
log.warn('Healing stale sideDialog run-control flags after final response anchor', undefined, {
|
|
533
|
+
dialogId: args.dialogId.valueOf(),
|
|
534
|
+
trigger: args.trigger,
|
|
535
|
+
previousGenerating: args.latest.generating ?? null,
|
|
536
|
+
previousNeedsDrive: args.latest.needsDrive ?? null,
|
|
537
|
+
previousDisplayState: args.latest.displayState ?? null,
|
|
538
|
+
previousExecutionMarker: args.latest.executionMarker ?? null,
|
|
539
|
+
});
|
|
540
|
+
await persistence_1.DialogPersistence.mutateDialogLatest(args.dialogId, () => ({
|
|
541
|
+
kind: 'patch',
|
|
542
|
+
patch: {
|
|
543
|
+
generating: false,
|
|
544
|
+
needsDrive: false,
|
|
545
|
+
displayState: { kind: 'idle_waiting_user' },
|
|
546
|
+
executionMarker: undefined,
|
|
547
|
+
},
|
|
548
|
+
}));
|
|
549
|
+
return await persistence_1.DialogPersistence.loadDialogLatest(args.dialogId, 'running');
|
|
550
|
+
}
|
|
482
551
|
async function refreshRunControlProjectionFromPersistenceFacts(dialogId, trigger) {
|
|
483
|
-
|
|
552
|
+
let latest = await persistence_1.DialogPersistence.loadDialogLatest(dialogId, 'running');
|
|
484
553
|
if (!latest) {
|
|
485
554
|
return null;
|
|
486
555
|
}
|
|
487
|
-
if (
|
|
556
|
+
if (hasActiveRun(dialogId)) {
|
|
488
557
|
return latest;
|
|
489
558
|
}
|
|
490
|
-
|
|
559
|
+
const healedStaleSideDialogRunControl = await healStaleSideDialogRunControlAfterFinalResponse({
|
|
560
|
+
dialogId,
|
|
561
|
+
latest,
|
|
562
|
+
trigger,
|
|
563
|
+
});
|
|
564
|
+
if (!healedStaleSideDialogRunControl) {
|
|
565
|
+
return null;
|
|
566
|
+
}
|
|
567
|
+
latest = healedStaleSideDialogRunControl;
|
|
568
|
+
if (latest.generating === true) {
|
|
491
569
|
return latest;
|
|
492
570
|
}
|
|
493
571
|
const desired = await (async () => {
|
|
@@ -524,6 +602,9 @@ async function refreshRunControlProjectionFromPersistenceFacts(dialogId, trigger
|
|
|
524
602
|
continueEnabled: true,
|
|
525
603
|
};
|
|
526
604
|
}
|
|
605
|
+
if (await hasSideDialogFinalResponseAnchor(dialogId, latest)) {
|
|
606
|
+
return { kind: 'idle_waiting_user' };
|
|
607
|
+
}
|
|
527
608
|
const q4h = await persistence_1.DialogPersistence.loadQuestions4HumanState(dialogId, 'running');
|
|
528
609
|
const pendingSideDialogs = await persistence_1.DialogPersistence.loadPendingSideDialogs(dialogId, 'running');
|
|
529
610
|
const hasQ4H = q4h.length > 0;
|
|
@@ -610,16 +691,20 @@ async function reconcileDisplayStatesAfterRestart() {
|
|
|
610
691
|
});
|
|
611
692
|
continue;
|
|
612
693
|
}
|
|
613
|
-
|
|
614
|
-
|
|
694
|
+
if (!latest) {
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
const existing = latest.displayState;
|
|
698
|
+
const existingMarker = latest.executionMarker;
|
|
615
699
|
if (existingMarker && existingMarker.kind === 'dead' && dialogId.selfId !== dialogId.rootId) {
|
|
616
|
-
if (latest
|
|
700
|
+
if (latest.generating === true) {
|
|
701
|
+
const displayState = latest.displayState ?? { kind: 'dead', reason: existingMarker.reason };
|
|
617
702
|
try {
|
|
618
703
|
await persistence_1.DialogPersistence.mutateDialogLatest(dialogId, () => ({
|
|
619
704
|
kind: 'patch',
|
|
620
705
|
patch: {
|
|
621
706
|
generating: false,
|
|
622
|
-
displayState
|
|
707
|
+
displayState,
|
|
623
708
|
executionMarker: existingMarker,
|
|
624
709
|
},
|
|
625
710
|
}));
|
|
@@ -632,6 +717,24 @@ async function reconcileDisplayStatesAfterRestart() {
|
|
|
632
717
|
}
|
|
633
718
|
continue;
|
|
634
719
|
}
|
|
720
|
+
if (dialogId.selfId !== dialogId.rootId &&
|
|
721
|
+
(latest.generating === true ||
|
|
722
|
+
latest.needsDrive === true ||
|
|
723
|
+
latest.executionMarker?.kind === 'interrupted' ||
|
|
724
|
+
isNonIdleDisplayProjection(latest.displayState))) {
|
|
725
|
+
const healedStaleSideDialogRunControl = await healStaleSideDialogRunControlAfterFinalResponse({
|
|
726
|
+
dialogId,
|
|
727
|
+
latest,
|
|
728
|
+
trigger: 'restart_reconciliation',
|
|
729
|
+
});
|
|
730
|
+
if (!healedStaleSideDialogRunControl) {
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
latest = healedStaleSideDialogRunControl;
|
|
734
|
+
if (latest.generating !== true && latest.needsDrive !== true) {
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
635
738
|
if (isRecoverableGeneratingLatest(latest)) {
|
|
636
739
|
try {
|
|
637
740
|
await persistence_1.DialogPersistence.mutateDialogLatest(dialogId, () => ({
|
|
@@ -653,7 +756,7 @@ async function reconcileDisplayStatesAfterRestart() {
|
|
|
653
756
|
}
|
|
654
757
|
continue;
|
|
655
758
|
}
|
|
656
|
-
if (latest
|
|
759
|
+
if (latest.generating === true || latest.needsDrive === true) {
|
|
657
760
|
const nextIdle = await computeIdleDisplayStateForReconciliation(dialogId);
|
|
658
761
|
if (!nextIdle) {
|
|
659
762
|
continue;
|
package/dist/dialog.js
CHANGED
|
@@ -983,6 +983,10 @@ class Dialog {
|
|
|
983
983
|
if (!trimmed) {
|
|
984
984
|
throw new Error('Prompt is required to queue registered assignment update');
|
|
985
985
|
}
|
|
986
|
+
// This is runtime scheduling state, not a durable redo log. Persisted business facts already
|
|
987
|
+
// record the latest assignment in the asker stack and pending records; if the process dies
|
|
988
|
+
// before this prompt is consumed, recovery should surface those facts loudly for the LLM to
|
|
989
|
+
// decide the next action. Do not add persistence here just to make the queued bubble replayable.
|
|
986
990
|
if (existing?.kind !== 'registered_assignment_update') {
|
|
987
991
|
const created = {
|
|
988
992
|
kind: 'registered_assignment_update',
|
|
@@ -327,9 +327,11 @@ This makes Type B sideDialogs reusable across multiple Tellask sites without los
|
|
|
327
327
|
**Updated Tellask While an Earlier Round Is Still Waiting (normative)**:
|
|
328
328
|
|
|
329
329
|
- For a registered Side Dialog (`same agentId!sessionSlug`), runtime maintains one current waiting tellasker round.
|
|
330
|
-
- If a newer TYPE B Tellask arrives before the earlier round replies, runtime
|
|
330
|
+
- If a newer TYPE B Tellask arrives before the earlier round replies, runtime updates pending state and the sideDialog asker stack to the newer round. The earlier call-site still needs a same-`callId` correspondence point, but UI/LLM wording must not claim the target Side Dialog has already received the update until the Side Dialog actually consumes the update prompt.
|
|
331
331
|
- The tellaskee is not force-stopped. Instead, its next runtime prompt explains that the work request has been updated, explicitly says not to send a standalone acknowledgement, and includes the latest full assignment.
|
|
332
332
|
- Delivery of that updated assignment prompt is queued in-order at the next safe turn boundary. Runtime must not reject the update merely because another normal queued prompt already exists; queued prompts are ordered work, not a single overwrite slot.
|
|
333
|
+
- The `registered_assignment_update` up-next item is runtime scheduling state, not a durable redo log. Do not make this queue a new persistence protocol merely to make the update bubble immediately replayable.
|
|
334
|
+
- Business self-healing after a backend restart comes from loud facts and sufficient context: pending reminders, asker-stack assignment state, missing old-call terminal facts, and missing assignment anchors should let the LLM decide whether to resend, correct, or wait. It is not a goal to guarantee that every in-memory queued update survives process death.
|
|
333
335
|
- A Side Dialog reply produced before that updated assignment prompt is rendered locally MUST NOT be delivered to the tellasker as the newer round's result.
|
|
334
336
|
|
|
335
337
|
**Key Characteristics**:
|
|
@@ -1291,8 +1293,10 @@ sequenceDiagram
|
|
|
1291
1293
|
alt registry hit
|
|
1292
1294
|
Reg-->>Driver: existing sideDialog selfId
|
|
1293
1295
|
opt earlier round still waiting
|
|
1294
|
-
Driver-->>Tellasker: close earlier waiting round with system-generated business notice
|
|
1295
1296
|
Driver->>Side: queue update notice + latest full assignment
|
|
1297
|
+
Driver-->>Tellasker: report earlier round superseded and update registered
|
|
1298
|
+
Side-->>Driver: later consumes update prompt and writes assignment anchor
|
|
1299
|
+
Driver-->>Tellasker: upgrade call-site link to the concrete assignment bubble
|
|
1296
1300
|
end
|
|
1297
1301
|
Driver->>Side: restore + drive
|
|
1298
1302
|
else registry miss
|
|
@@ -452,6 +452,8 @@ flowchart TD
|
|
|
452
452
|
|
|
453
453
|
5. **支线对话响应供应**:支线对话通过持久化将响应写入*当前诉请者*的上下文(不是回调)。对于 TYPE B,每次诉请都会用最新的诉请者 + tellaskInfo 更新支线对话的 `assignmentFromAsker`,因此响应被路由到最近的诉请者(主线或支线对话)。这支持分离操作、复用和崩溃恢复。
|
|
454
454
|
|
|
455
|
+
TYPE B 长线诉请更新的确认边界必须谨慎区分:pending 状态与 `asker-stack.jsonl` 更新,只表示运行时已接受/登记新要求;只有支线 driver 实际消费 `registered_assignment_update` up-next、写入可见更新气泡和 assignment anchor 后,才表示目标支线已收到并开始处理更新。`registered_assignment_update` up-next 是运行态调度状态,不是持久化 redo log;不要为了“更新气泡”即时可重放而新增严格持久队列。后端进程重启后的业务自愈依赖 loud facts 与足够上下文(pending reminder、asker stack 最新 assignment、旧 call 是否缺少终态、目标支线是否缺少 assignment anchor),让 LLM 自主决定重发、修正或等待,而不是追求技术层面绝不丢内存队列。
|
|
456
|
+
|
|
455
457
|
6. **支线对话注册表**:已注册的支线对话(TYPE B 长线诉请)在主线对话作用域的注册表中跟踪。注册表在 `clear_mind` 操作中持续存在,并在主线加载时重建。
|
|
456
458
|
|
|
457
459
|
7. **状态保留契约**:
|
|
@@ -1290,7 +1292,9 @@ sequenceDiagram
|
|
|
1290
1292
|
|
|
1291
1293
|
call-site 呼应不变量:每个 `tellask` 发起点的 `callId`,后续都必须在诉请者对话历史里留下同
|
|
1292
1294
|
`callId` 的呼应点。正常支线回复、跨程 carryover、已注册会话被更新后的替代通知都可以结束这次
|
|
1293
|
-
call;不能静默删除或覆盖 pending
|
|
1295
|
+
call;不能静默删除或覆盖 pending 轮次。已注册会话被更新时,替代通知的文案不能在目标支线实际消费
|
|
1296
|
+
更新前宣称“更新已送达/目标支线正在按新要求处理”;在此之前只能表达“旧轮已被新要求登记替换,等待
|
|
1297
|
+
目标支线在安全边界消费更新”。
|
|
1294
1298
|
|
|
1295
1299
|
WebUI 外链不变量:生成 `/dl/*` URL 时必须在业务现场显式写出目标语义,避免复用泛化 deep-link
|
|
1296
1300
|
helper。`/dl/callsite` 只表示诉请者对话里的发起气泡:`selfId/course` 是诉请者对话坐标,`callId`
|
|
@@ -15,6 +15,10 @@ This document specifies two related runtime controls:
|
|
|
15
15
|
- **Auto-continue injection**: for **main dialogs only**, whenever the driver would otherwise stop,
|
|
16
16
|
runtime auto-sends a short diligence prompt (rendered as a normal user bubble) and continues
|
|
17
17
|
generation, except when the dialog is legitimately suspended (Q4H or pending Side Dialogs).
|
|
18
|
+
- **Side Dialog quirk recovery push**: when a provider/API quirk explicitly requests a one-time
|
|
19
|
+
`diligence_push_once` recovery, a Side Dialog may receive a built-in runtime template, but only
|
|
20
|
+
when it currently has an active reply obligation; the template must name the one `replyTellask*`
|
|
21
|
+
tool confirmed by runtime.
|
|
18
22
|
- **Required tool-use control**: for ordinary main and side dialog rounds, the Diligence Push
|
|
19
23
|
checkbox controls whether the provider request must end through a Dominds tool call. When checked,
|
|
20
24
|
the model is expected to call a tool such as `askHuman`, `tellask*`, `replyTellask*`, or another
|
|
@@ -32,8 +36,9 @@ This document specifies two related runtime controls:
|
|
|
32
36
|
## Non-goals
|
|
33
37
|
|
|
34
38
|
- Auto-completing / auto-marking a dialog as done.
|
|
35
|
-
- Auto-injecting Diligence Push prompts into Side Dialogs (Side Dialogs remain scoped and
|
|
36
|
-
report back to their tellasker
|
|
39
|
+
- Auto-injecting ordinary Diligence Push prompts into Side Dialogs (Side Dialogs remain scoped and
|
|
40
|
+
should report back to their tellasker; only the provider-quirk recovery exception may use the Side
|
|
41
|
+
Dialog template).
|
|
37
42
|
|
|
38
43
|
## Definitions
|
|
39
44
|
|
|
@@ -57,7 +62,8 @@ This is the "controlled convergence" path. The diligence-push mechanism should *
|
|
|
57
62
|
|
|
58
63
|
### Trigger conditions (must all hold)
|
|
59
64
|
|
|
60
|
-
- Dialog is the **Main Dialog
|
|
65
|
+
- Dialog is the **Main Dialog**; Side Dialogs only use the provider deadlock recovery exception
|
|
66
|
+
below.
|
|
61
67
|
- Dialog is **not suspended**:
|
|
62
68
|
- no pending Q4H, and
|
|
63
69
|
- no pending Side Dialogs (waiting for backfill).
|
|
@@ -69,7 +75,15 @@ Some provider/API quirk handlers may request a one-time Diligence Push recovery
|
|
|
69
75
|
same-context retries for a known deadlock pattern. This is not the ordinary "dialog is about to go
|
|
70
76
|
idle" path. In that recovery-only case, pending sideDialogs do not veto the single Diligence Push
|
|
71
77
|
injection, because the deadlock may happen in a function-result-driven generation round right after
|
|
72
|
-
the main dialog has already registered an in-flight tellask/sideDialog.
|
|
78
|
+
the main dialog has already registered an in-flight tellask/sideDialog.
|
|
79
|
+
|
|
80
|
+
Side Dialogs may also use this recovery path, but only when an active reply obligation still exists.
|
|
81
|
+
If no active reply obligation exists, runtime does not inject a push and leaves the retry-stopped
|
|
82
|
+
state for a human to handle. The Side Dialog recovery template does not read rtws diligence files;
|
|
83
|
+
it uses a built-in bilingual template containing the current time, the current Tellask goal, and the
|
|
84
|
+
single runtime-confirmed `replyTellask*` tool (for example
|
|
85
|
+
`replyTellaskSessionless({ replyContent })`). The LLM must not guess the reply variant. Q4H remains
|
|
86
|
+
a hard blocker.
|
|
73
87
|
|
|
74
88
|
### Action
|
|
75
89
|
|
|
@@ -164,7 +178,10 @@ post-iteration check:
|
|
|
164
178
|
special case described above where one recovery-only Diligence Push may ignore pending
|
|
165
179
|
sideDialogs.
|
|
166
180
|
2. If there is any tool feedback, continue normally.
|
|
167
|
-
3. Otherwise
|
|
181
|
+
3. Otherwise, attempt diligence-push auto-continue:
|
|
182
|
+
- Main Dialog: resolve the rtws diligence file or built-in fallback text.
|
|
183
|
+
- Side Dialog: only for provider-quirk recovery with an active reply obligation; otherwise do
|
|
184
|
+
not inject.
|
|
168
185
|
- If disabled → stop normally.
|
|
169
186
|
- If budget exhausted → emit an informational UI notice and stop further automatic Diligence
|
|
170
187
|
Pushes for the current budget.
|
|
@@ -198,7 +215,11 @@ Regression tests should cover:
|
|
|
198
215
|
|
|
199
216
|
- Main dialog: tool-only output → diligence injection → continued response
|
|
200
217
|
- Main dialog: empty assistant output → diligence injection → continued response
|
|
201
|
-
- SideDialog: no diligence injection
|
|
218
|
+
- SideDialog: ordinary idle path has no diligence injection
|
|
219
|
+
- SideDialog: provider quirk recovery + active reply obligation → inject the Side Dialog template in
|
|
220
|
+
the work language, include the current Tellask goal, and name the exact active `replyTellask*`
|
|
221
|
+
- SideDialog: provider quirk recovery + no active reply obligation → no injection; leave the
|
|
222
|
+
stopped/give-up state for human handling
|
|
202
223
|
- rtws config:
|
|
203
224
|
- `.minds/diligence.md` is honored when lang-specific file is absent
|
|
204
225
|
- empty diligence file disables diligence-push
|
|
@@ -12,6 +12,7 @@ Dominds 主线对话旨在长期运行。主线对话"停止"(变为空闲)
|
|
|
12
12
|
本文档指定两个相关但不同的运行时控制:
|
|
13
13
|
|
|
14
14
|
- **自动续推注入**:仅针对**主线对话**,当驱动程序即将停止时,运行时会自动发送一个简短的鞭策语(渲染为正常的用户气泡)并继续生成,除非对话处于合法暂停状态(Q4H 或待处理的支线对话)。
|
|
15
|
+
- **支线 quirk 恢复续推**:当 provider/API quirk 明确给出一次性 `diligence_push_once` 恢复动作时,支线对话可使用运行时内置模板续推,但仅限当前存在活跃回贴义务(active reply obligation)的场景;模板必须点名运行时确认的唯一 `replyTellask*` 工具。
|
|
15
16
|
- **强制工具调用控制**:对于普通的主线/支线对话轮次,`鞭策` 勾选项控制本轮 provider 请求是否必须通过 Dominds 工具结束。勾选时,模型应通过 `askHuman`、`tellask*`、`replyTellask*` 或其他运行时函数完成这一轮,而不是用普通文本直接收尾。FBR 中间轮是刻意例外:它们可以处于无可调用工具状态;FBR 收口阶段则必须调用两个结论工具之一。
|
|
16
17
|
|
|
17
18
|
## 目标
|
|
@@ -24,7 +25,7 @@ Dominds 主线对话旨在长期运行。主线对话"停止"(变为空闲)
|
|
|
24
25
|
## 非目标
|
|
25
26
|
|
|
26
27
|
- 自动完成/自动将对话标记为完成。
|
|
27
|
-
-
|
|
28
|
+
- 将普通自动鞭策语注入应用于支线对话(支线对话保持范围,应向其诉请者报告;只有 provider quirk 恢复特例可使用支线模板)。
|
|
28
29
|
|
|
29
30
|
## 定义
|
|
30
31
|
|
|
@@ -48,18 +49,20 @@ Dominds 主线对话旨在长期运行。主线对话"停止"(变为空闲)
|
|
|
48
49
|
|
|
49
50
|
### 触发条件(必须全部满足)
|
|
50
51
|
|
|
51
|
-
-
|
|
52
|
+
- 对话是**主线对话**;支线对话只适用下文 provider 死锁恢复特例。
|
|
52
53
|
- 对话**未暂停**:
|
|
53
54
|
- 没有待处理的 Q4H,并且
|
|
54
55
|
- 没有待处理的支线对话(等待回填)。
|
|
55
56
|
- 驱动程序即将停止生成循环(即没有工具/函数输出需要另一次迭代)。
|
|
56
57
|
|
|
57
|
-
### 例外:provider
|
|
58
|
+
### 例外:provider 死锁恢复
|
|
58
59
|
|
|
59
60
|
某些 provider/API quirk 在识别到已知的 same-context deadlock,并停止沿用同一上下文自动重试后,
|
|
60
61
|
会请求一次性的鞭策恢复。这不是普通的“对话即将空转停止”路径。在这个仅用于恢复的特例里,
|
|
61
62
|
即使主线对话已经登记了在途诉请/支线对话,pending sideDialog 也不应否决这一次鞭策注入;因为卡死
|
|
62
|
-
可能正发生在函数结果驱动的生成轮次里。
|
|
63
|
+
可能正发生在函数结果驱动的生成轮次里。
|
|
64
|
+
|
|
65
|
+
支线对话也可使用这条恢复路径,但必须满足当前仍有活跃回贴义务(active reply obligation);否则不注入鞭策语,保留 retry stopped 状态交给人类处理。支线恢复模板不读取 rtws diligence 文件,而是使用内置双语模板,包含当前时间、当前诉请目标,并点名运行时已确认的唯一 `replyTellask*` 工具(例如 `replyTellaskSessionless({ replyContent })`),禁止让 LLM 自行猜测 reply 变体。Q4H 仍然是硬阻塞条件。
|
|
63
66
|
|
|
64
67
|
### 操作
|
|
65
68
|
|
|
@@ -138,7 +141,9 @@ members:
|
|
|
138
141
|
1. 如果对话处于暂停状态,则停止(Q4H / 支线对话待处理);但上文所述 deadlock-recovery 特例除外,
|
|
139
142
|
即那一次恢复专用的鞭策可忽略 pending sideDialog。
|
|
140
143
|
2. 如果有任何工具反馈,则正常继续。
|
|
141
|
-
3.
|
|
144
|
+
3. 否则尝试 diligence-push 自动继续:
|
|
145
|
+
- 主线对话:按 rtws diligence 文件 / 内置回退文本解析并续推。
|
|
146
|
+
- 支线对话:仅在 provider quirk 恢复且存在活跃回贴义务(active reply obligation)时,注入支线内置模板;没有活跃回贴义务时不注入。
|
|
142
147
|
- 如果禁用 → 正常停止。
|
|
143
148
|
- 如果预算耗尽 → 发出一条仅用于提示的 UI 信息,并停止继续自动鞭策当前预算。
|
|
144
149
|
- 否则 → 自动发送鞭策语并继续。
|
|
@@ -171,7 +176,9 @@ members:
|
|
|
171
176
|
|
|
172
177
|
- 主线对话:仅工具输出 → 鞭策语注入 → 继续响应
|
|
173
178
|
- 主线对话:空助手输出 → 鞭策语注入 → 继续响应
|
|
174
|
-
-
|
|
179
|
+
- 支线对话:普通 idle 无鞭策语注入
|
|
180
|
+
- 支线对话:provider quirk recovery + 活跃回贴义务(active reply obligation)→ 注入支线模板,文案使用工作语言,包含当前诉请目标,并准确点名运行时确认的 `replyTellask*`
|
|
181
|
+
- 支线对话:provider quirk recovery + 无活跃回贴义务 → 不注入,保留 stopped/giveup 给人类处理
|
|
175
182
|
- rtws 配置:
|
|
176
183
|
- 当语言特定文件缺失时,`.minds/diligence.md` 被遵守
|
|
177
184
|
- 空的鞭策语文件禁用 diligence-push
|
|
@@ -12,7 +12,7 @@ This means:
|
|
|
12
12
|
- `apiType: anthropic` owns official Anthropic Messages semantics, including object-shaped `model_params.anthropic.thinking`.
|
|
13
13
|
- `apiType: anthropic-compatible` owns Anthropic-compatible gateway semantics, including boolean `model_params.anthropic-compatible.thinking` mapped to provider `enabled` / `disabled` request objects.
|
|
14
14
|
|
|
15
|
-
Some providers expose OpenAI-compatible or Anthropic-compatible endpoints while still requiring explicit provider quirks. Volcano Engine Ark Coding Plan now uses the OpenAI-compatible Chat Completions shape with its dedicated `/api/coding/v3` endpoint; the historical Anthropic-compatible Volcano tool-call quirks have been removed. Kimi Code also uses the OpenAI-compatible Chat Completions shape, but must use the built-in `kimi-code` provider's dedicated `/coding/v1` endpoint,
|
|
15
|
+
Some providers expose OpenAI-compatible or Anthropic-compatible endpoints while still requiring explicit provider quirks. Volcano Engine Ark Coding Plan now uses the OpenAI-compatible Chat Completions shape with its dedicated `/api/coding/v3` endpoint; the historical Anthropic-compatible Volcano tool-call quirks have been removed. Kimi Code also uses the OpenAI-compatible Chat Completions shape, but must use the built-in `kimi-code` provider's dedicated `/coding/v1` endpoint, versioned `KimiCLI/Dominds/<version>` User-Agent, `prompt_cache_key`, and Kimi-specific `thinking`/`reasoning_effort` request shaping. See [`volcengine-coding-plan-openai-compatible.zh.md`](./volcengine-coding-plan-openai-compatible.zh.md) for the Volcano migration design record.
|
|
16
16
|
|
|
17
17
|
Similar field names across wrappers do not imply compatibility. For example, `reasoning_effort`, `verbosity`, `parallel_tool_calls`, and web search controls may look similar but can still differ in accepted values, payload shape, lifecycle events, validation rules, and runtime meaning.
|
|
18
18
|
|
|
@@ -12,7 +12,7 @@ Dominds 把每个 LLM provider wrapper 视为独立的协议适配器,而不
|
|
|
12
12
|
- `apiType: anthropic` 只负责 Anthropic 官方 Messages 语义,包括 object 形态的 `model_params.anthropic.thinking`。
|
|
13
13
|
- `apiType: anthropic-compatible` 负责 Anthropic 兼容网关语义,包括 boolean 形态的 `model_params.anthropic-compatible.thinking`,并映射为 provider 请求里的 `enabled` / `disabled` object。
|
|
14
14
|
|
|
15
|
-
某些 provider 虽然暴露 OpenAI-compatible 或 Anthropic-compatible endpoint,但仍可能需要明确的 provider quirk profile。火山方舟 Coding Plan 现在走 OpenAI-compatible Chat Completions 形态,并使用专属 `/api/coding/v3` endpoint;历史 Anthropic-compatible 火山工具调用 quirk 已取消。Kimi Code 也走 OpenAI-compatible Chat Completions 形态,但必须使用内置 `kimi-code` provider 的专属 `/coding/v1` endpoint
|
|
15
|
+
某些 provider 虽然暴露 OpenAI-compatible 或 Anthropic-compatible endpoint,但仍可能需要明确的 provider quirk profile。火山方舟 Coding Plan 现在走 OpenAI-compatible Chat Completions 形态,并使用专属 `/api/coding/v3` endpoint;历史 Anthropic-compatible 火山工具调用 quirk 已取消。Kimi Code 也走 OpenAI-compatible Chat Completions 形态,但必须使用内置 `kimi-code` provider 的专属 `/coding/v1` endpoint、带 Dominds 版本的 `KimiCLI/Dominds/<version>` User-Agent、`prompt_cache_key` 和 Kimi 专用 `thinking`/`reasoning_effort` 请求整形。火山迁移设计记录见 [`volcengine-coding-plan-openai-compatible.zh.md`](./volcengine-coding-plan-openai-compatible.zh.md)。
|
|
16
16
|
|
|
17
17
|
不同 wrapper 下看起来同名的字段,不代表它们可以互相兼容。比如 `reasoning_effort`、`verbosity`、`parallel_tool_calls`、web search 相关开关,名字可能相似,但可接受值、请求载荷形状、流事件生命周期、校验规则和运行时含义都可能不同。
|
|
18
18
|
|
|
@@ -418,6 +418,16 @@ replace pending 不是 silent overwrite,也不是 failed-result fallback。它
|
|
|
418
418
|
|
|
419
419
|
这样既保留“抽掉旧义务”的业务语义,也让持久层维持 append/truncate-only,不做 YAML 数组整体覆盖。
|
|
420
420
|
|
|
421
|
+
**更新投递确认边界(已定案)**:
|
|
422
|
+
|
|
423
|
+
- `registered_assignment_update` 的 up-next 队列是运行时调度状态,不是严格持久化 redo log。不要为了让“更新气泡”即时可重放,把这条队列升级成新的持久事务日志。
|
|
424
|
+
- 诉请者侧反馈必须区分两种事实:
|
|
425
|
+
- **更新已登记 / 已排队**:pending record 与 asker stack 已按新诉请更新,支线后续应按最新 assignment 推进;这只说明运行时接受了更新。
|
|
426
|
+
- **目标支线已实际收到并开始处理更新**:支线 driver 已消费 up-next,写入可见的更新 assignment 气泡与 assignment anchor;只有这个事实才能支撑“目标支线已经收到/正在按新要求处理”的主线反馈。
|
|
427
|
+
- 如果支线正忙,更新 prompt 可以留在内存 up-next 中等待安全边界异步消费。主线不应在消费前渲染“已送达目标支线”语义的气泡;最多表达“旧轮已被新诉请登记替换,目标支线尚待消费更新”。
|
|
428
|
+
- 后端进程意外退出时,不追求技术角度严格自愈不丢 up-next。业务自愈边界是:LLM 能看到足够事实(pending reminder、asker stack 最新 assignment、旧 call 是否缺少终态、目标支线是否缺少 assignment anchor),从而自主判断是否需要重发/修正/继续等待。
|
|
429
|
+
- 因此,维护者修复这类时序问题时,优先做真实状态反馈与 loud diagnostics,不要把 up-next 队列泛化成持久化 redo log。
|
|
430
|
+
|
|
421
431
|
### 7.3 Reply tool 与 direct fallback
|
|
422
432
|
|
|
423
433
|
`replyTellask*` 是精确回贴路径;direct fallback 是过渡兼容路径。
|
|
@@ -576,6 +586,7 @@ Dominds 不做同 course 内 context window 裁剪。上下文规则是:
|
|
|
576
586
|
- replace pending 从 stack 中抽调旧 frame,再把新 obligation 压栈顶;
|
|
577
587
|
- 原 call site 只出现 pointer,不出现真实回复正文;
|
|
578
588
|
- Type B registered update 压栈、先回复新诉请、再恢复旧诉请;
|
|
589
|
+
- Type B registered update 在支线消费更新前,主线不得宣称目标支线已收到/正在处理更新;
|
|
579
590
|
- 重启恢复后 pending 与 arrival fact 一致。
|
|
580
591
|
|
|
581
592
|
## 9. 已定案问题
|
|
@@ -589,4 +600,5 @@ Dominds 不做同 course 内 context window 裁剪。上下文规则是:
|
|
|
589
600
|
5. 旧 pending record 缺少 `callSiteCourse` / `callSiteGenseq` 不迁移、不隔离兼容、不 fallback。旧 `.dialogs/` 可丢弃;新 validator 直接要求必填,缺失即 loud fail / quarantine。
|
|
590
601
|
6. reply obligation 是栈,不是槽。root 与 side dialog 统一使用 `asker-stack.jsonl` 持久化 `AskerDialogStackFrame`,文件只允许 append/truncate。LLM context 从栈顶注入当前义务,而不是扫描历史 JSONL 对话。
|
|
591
602
|
7. replace pending 是特殊栈操作:抽调旧 frame,再把新 obligation 压到栈顶;找不到旧 frame 必须 loud fail,不能静默 fallback 成普通 push。
|
|
592
|
-
8.
|
|
603
|
+
8. Type B registered update 的 up-next 队列保持运行态内存调度,不升级为持久化 redo log;主线反馈必须等目标支线实际消费更新并写入 assignment anchor 后,才表达“目标支线已收到/开始处理更新”。
|
|
604
|
+
9. 实现术语升级为 `MainDialog` / `SideDialog` / `askerDialog` / `assignmentFromAsker` / `askerStack`。旧 `supdialog` 术语退出实现代码与文档;用户可见文案继续使用“主线对话 / 支线对话、诉请者 / 被诉请者”。
|
|
@@ -61,15 +61,16 @@ Dominds 现有火山方舟 Coding Plan 接入主要围绕 Anthropic-compatible
|
|
|
61
61
|
```yaml
|
|
62
62
|
providers:
|
|
63
63
|
volcano-engine-coding-plan:
|
|
64
|
-
name: Volcano
|
|
64
|
+
name: Volcano Ark Coding Plan
|
|
65
65
|
apiType: openai-compatible
|
|
66
66
|
apiQuirks:
|
|
67
67
|
- same-context-empty-response
|
|
68
|
+
- volcengine-invalid-parameter-aggressive-retry
|
|
68
69
|
baseUrl: https://ark.cn-beijing.volces.com/api/coding/v3
|
|
69
70
|
apiKeyEnvVar: ARK_API_KEY
|
|
70
71
|
```
|
|
71
72
|
|
|
72
|
-
`apiType: openai-compatible` 表示底层 HTTP endpoint、Chat Completions 请求形态和 SSE 基础形态接近 OpenAI Chat Completions。历史上用于火山 Anthropic-compatible 文本 tool_use / 空对象参数拼接的专项 quirks
|
|
73
|
+
`apiType: openai-compatible` 表示底层 HTTP endpoint、Chat Completions 请求形态和 SSE 基础形态接近 OpenAI Chat Completions。历史上用于火山 Anthropic-compatible 文本 tool_use / 空对象参数拼接的专项 quirks 已删除;当前内置保留 `same-context-empty-response` 这类通用 provider 重试/诊断 quirk,并增加 `volcengine-invalid-parameter-aggressive-retry`,用于火山方舟 Coding Plan 偶发 `400 InvalidParameter` 但同 payload 可重放成功的场景,将其归类为 aggressive 策略重试。
|
|
73
74
|
|
|
74
75
|
### 具体模型优先
|
|
75
76
|
|
package/dist/llm/api-quirks.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { ProviderConfig } from './client';
|
|
|
4
4
|
import type { LlmRetryStrategy } from './gen';
|
|
5
5
|
export type LlmFailureKind = 'retriable' | 'rejected' | 'fatal';
|
|
6
6
|
export declare const SAME_CONTEXT_EMPTY_RESPONSE_API_QUIRK = "same-context-empty-response";
|
|
7
|
+
export declare const VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_API_QUIRK = "volcengine-invalid-parameter-aggressive-retry";
|
|
7
8
|
export type LlmFailureSummary = {
|
|
8
9
|
kind: LlmFailureKind;
|
|
9
10
|
message: string;
|
package/dist/llm/api-quirks.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.XCODE_BEST_STREAM_INTERNAL_ERROR_CODE = exports.SAME_CONTEXT_EMPTY_RESPONSE_API_QUIRK = void 0;
|
|
3
|
+
exports.XCODE_BEST_STREAM_INTERNAL_ERROR_CODE = exports.VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_API_QUIRK = exports.SAME_CONTEXT_EMPTY_RESPONSE_API_QUIRK = void 0;
|
|
4
4
|
exports.normalizeProviderApiQuirks = normalizeProviderApiQuirks;
|
|
5
5
|
exports.createLlmFailureQuirkHandlerSession = createLlmFailureQuirkHandlerSession;
|
|
6
6
|
const persistence_errors_1 = require("../persistence-errors");
|
|
7
7
|
exports.SAME_CONTEXT_EMPTY_RESPONSE_API_QUIRK = 'same-context-empty-response';
|
|
8
|
+
exports.VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_API_QUIRK = 'volcengine-invalid-parameter-aggressive-retry';
|
|
8
9
|
const DOMINDS_LLM_EMPTY_RESPONSE_ERROR_CODE = 'DOMINDS_LLM_EMPTY_RESPONSE';
|
|
9
10
|
const XCODE_BEST_EMPTY_RESPONSE_SINGLE_RETRY_DELAY_MS = 3000;
|
|
10
11
|
const XCODE_BEST_EMPTY_RESPONSE_GIVE_UP_THRESHOLD = 5;
|
|
@@ -16,6 +17,8 @@ const XCODE_BEST_UNEXPECTED_EOF_RETRY_MESSAGE = 'xcode.best upstream stream ende
|
|
|
16
17
|
const XCODE_BEST_MISREPORTED_403_RETRY_MESSAGE = 'xcode.best returned 403 for a transient upstream failure; retrying aggressively.';
|
|
17
18
|
exports.XCODE_BEST_STREAM_INTERNAL_ERROR_CODE = 'XCODE_BEST_STREAM_INTERNAL_ERROR';
|
|
18
19
|
const XCODE_BEST_STREAM_INTERNAL_RETRY_MESSAGE = 'xcode.best upstream stream reported internal_error from peer; retrying aggressively.';
|
|
20
|
+
const VOLCENGINE_INVALID_PARAMETER_MESSAGE_FRAGMENT = 'a parameter specified in the request is not valid';
|
|
21
|
+
const VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_MESSAGE = 'Volcano Ark Coding Plan returned transient 400 InvalidParameter; retrying aggressively.';
|
|
19
22
|
const LOCAL_FILE_IO_ERROR_CODES = new Set(['ENOENT', 'ENOTDIR', 'EISDIR', 'EACCES', 'EPERM']);
|
|
20
23
|
const LOCAL_FILE_IO_SYSCALLS = new Set([
|
|
21
24
|
'open',
|
|
@@ -69,6 +72,18 @@ function isXcodeBestStreamInternalFailure(failure, error) {
|
|
|
69
72
|
const code = failure.code ?? readErrorCode(error);
|
|
70
73
|
return code === exports.XCODE_BEST_STREAM_INTERNAL_ERROR_CODE;
|
|
71
74
|
}
|
|
75
|
+
function isVolcengineTransientInvalidParameterFailure(args) {
|
|
76
|
+
const statuses = readFailureAndErrorStatuses(args);
|
|
77
|
+
if (!statuses.includes(400) || statuses.includes(429)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const code = (args.failure.code ?? readErrorCode(args.error))?.trim();
|
|
81
|
+
if (code !== 'InvalidParameter') {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return (args.failure.message.toLowerCase().includes(VOLCENGINE_INVALID_PARAMETER_MESSAGE_FRAGMENT) ||
|
|
85
|
+
errorChainIncludesMessageFragment(args.error, VOLCENGINE_INVALID_PARAMETER_MESSAGE_FRAGMENT));
|
|
86
|
+
}
|
|
72
87
|
const XCODE_BEST_RETRY_QUIRK_RULES = [
|
|
73
88
|
{
|
|
74
89
|
statusPolicy: { kind: 'only_status', status: 403 },
|
|
@@ -494,9 +509,28 @@ function createSameContextEmptyResponseFailureQuirkHandlerSession(providerConfig
|
|
|
494
509
|
},
|
|
495
510
|
};
|
|
496
511
|
}
|
|
512
|
+
function createVolcengineInvalidParameterAggressiveRetryQuirkHandlerSession() {
|
|
513
|
+
return {
|
|
514
|
+
quirkName: exports.VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_API_QUIRK,
|
|
515
|
+
onFailure(args) {
|
|
516
|
+
if (!isVolcengineTransientInvalidParameterFailure({
|
|
517
|
+
failure: args.failure,
|
|
518
|
+
error: args.error,
|
|
519
|
+
})) {
|
|
520
|
+
return { kind: 'default' };
|
|
521
|
+
}
|
|
522
|
+
return {
|
|
523
|
+
kind: 'retry_strategy',
|
|
524
|
+
retryStrategy: 'aggressive',
|
|
525
|
+
message: VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_MESSAGE,
|
|
526
|
+
};
|
|
527
|
+
},
|
|
528
|
+
};
|
|
529
|
+
}
|
|
497
530
|
const FAILURE_QUIRK_HANDLER_FACTORIES = {
|
|
498
531
|
'xcode.best': createXcodeBestFailureQuirkHandlerSession,
|
|
499
532
|
[exports.SAME_CONTEXT_EMPTY_RESPONSE_API_QUIRK]: createSameContextEmptyResponseFailureQuirkHandlerSession,
|
|
533
|
+
[exports.VOLCENGINE_INVALID_PARAMETER_AGGRESSIVE_RETRY_API_QUIRK]: createVolcengineInvalidParameterAggressiveRetryQuirkHandlerSession,
|
|
500
534
|
};
|
|
501
535
|
function normalizeProviderApiQuirks(providerConfig) {
|
|
502
536
|
const raw = providerConfig.apiQuirks;
|
package/dist/llm/defaults.yaml
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
# `500 auth_unavailable: no auth available` infrastructure failures.
|
|
15
15
|
# `apiQuirks: same-context-empty-response` detects repeated empty responses in the same
|
|
16
16
|
# dialog generation context and stops same-context retry loops with a deadlock-break prompt.
|
|
17
|
+
# `apiQuirks: volcengine-invalid-parameter-aggressive-retry` classifies Volcano Ark Coding Plan
|
|
18
|
+
# transient `400 InvalidParameter` failures as aggressive retry when the shape matches that
|
|
19
|
+
# provider's replay-successful instability.
|
|
17
20
|
# - tool_result_max_chars: optional transport-level cap for a single tool-result text payload
|
|
18
21
|
# before Dominds projects it into the provider request. Use this when a provider/gateway enforces
|
|
19
22
|
# a stricter per-item string limit than Dominds' built-in defaults.
|
|
@@ -498,6 +501,7 @@ providers:
|
|
|
498
501
|
apiType: openai-compatible
|
|
499
502
|
apiQuirks:
|
|
500
503
|
- same-context-empty-response
|
|
504
|
+
- volcengine-invalid-parameter-aggressive-retry
|
|
501
505
|
baseUrl: https://ark.cn-beijing.volces.com/api/coding/v3
|
|
502
506
|
apiKeyEnvVar: ARK_API_KEY
|
|
503
507
|
tech_spec_url: https://www.volcengine.com/docs/82379/1928261
|
|
@@ -577,6 +581,7 @@ providers:
|
|
|
577
581
|
context_window: '204K'
|
|
578
582
|
glm-5.1:
|
|
579
583
|
name: GLM-5.1
|
|
584
|
+
optimal_max_tokens: 180000
|
|
580
585
|
supports_thinking: true
|
|
581
586
|
default_thinking: true
|
|
582
587
|
supports_image_input: false
|
|
@@ -586,6 +591,7 @@ providers:
|
|
|
586
591
|
context_window: '256K'
|
|
587
592
|
glm-4.7:
|
|
588
593
|
name: GLM-4.7
|
|
594
|
+
optimal_max_tokens: 180000
|
|
589
595
|
supports_thinking: true
|
|
590
596
|
default_thinking: false
|
|
591
597
|
supports_image_input: false
|
|
@@ -1955,9 +1955,13 @@ class AnthropicGen {
|
|
|
1955
1955
|
completionTokens,
|
|
1956
1956
|
totalTokens: promptTokens + completionTokens,
|
|
1957
1957
|
};
|
|
1958
|
+
const messages = anthropicToChatMessages(response, genseq, forceJsonResponse ? ANTHROPIC_JSON_RESPONSE_TOOL_NAME : undefined);
|
|
1959
|
+
const orderedOutputs = outputs.length > 0
|
|
1960
|
+
? [...outputs, ...messages.map((message) => ({ kind: 'message', message }))]
|
|
1961
|
+
: [];
|
|
1958
1962
|
return {
|
|
1959
|
-
messages
|
|
1960
|
-
...(
|
|
1963
|
+
messages,
|
|
1964
|
+
...(orderedOutputs.length > 0 ? { outputs: orderedOutputs } : {}),
|
|
1961
1965
|
usage,
|
|
1962
1966
|
llmGenModel: returnedModel,
|
|
1963
1967
|
};
|