dominds 1.16.1 → 1.16.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/dialog-display-state.d.ts +4 -0
- package/dist/dialog-display-state.js +138 -19
- package/dist/dialog-fork.js +13 -5
- package/dist/dialog-interruption.d.ts +18 -0
- package/dist/dialog-interruption.js +34 -0
- package/dist/docs/dominds-agent-collaboration.zh.md +401 -0
- package/dist/llm/api-quirks.d.ts +11 -0
- package/dist/llm/api-quirks.js +322 -24
- package/dist/llm/defaults.yaml +2 -1
- package/dist/llm/gen/mock.d.ts +1 -1
- package/dist/llm/gen/mock.js +12 -0
- package/dist/llm/gen/openai-compatible.d.ts +1 -1
- package/dist/llm/gen/openai-compatible.js +9 -1
- package/dist/llm/gen/openai.d.ts +1 -1
- package/dist/llm/gen/openai.js +16 -2
- package/dist/llm/gen.d.ts +10 -0
- package/dist/llm/gen.js +10 -0
- package/dist/llm/kernel-driver/drive.js +994 -866
- package/dist/llm/kernel-driver/runtime.d.ts +16 -2
- package/dist/llm/kernel-driver/runtime.js +75 -10
- package/dist/llm/stop-reason-i18n.d.ts +9 -0
- package/dist/llm/stop-reason-i18n.js +114 -0
- package/dist/persistence-errors.d.ts +26 -0
- package/dist/persistence-errors.js +68 -0
- package/dist/persistence.d.ts +119 -82
- package/dist/persistence.js +1055 -426
- package/dist/server/api-routes.js +174 -58
- package/dist/server/websocket-handler.js +125 -21
- package/dist/tools/team_mgmt.js +2 -2
- package/package.json +3 -3
- package/webapp/dist/assets/{_basePickBy-C0MXVhMo.js → _basePickBy-BJWCmtUm.js} +3 -3
- package/webapp/dist/assets/_basePickBy-BJWCmtUm.js.map +1 -0
- package/webapp/dist/assets/{_baseUniq-CRygl41M.js → _baseUniq-D6k_lGfs.js} +2 -2
- package/webapp/dist/assets/_baseUniq-D6k_lGfs.js.map +1 -0
- package/webapp/dist/assets/{arc-BeHJtnt2.js → arc-DYDaESgj.js} +2 -2
- package/webapp/dist/assets/arc-DYDaESgj.js.map +1 -0
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-CGdo5TVi.js → architectureDiagram-VXUJARFQ-DZMT7dqc.js} +8 -26
- package/webapp/dist/assets/architectureDiagram-VXUJARFQ-DZMT7dqc.js.map +1 -0
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-C59VaSGw.js → blockDiagram-VD42YOAC-CABpgVAa.js} +170 -187
- package/webapp/dist/assets/blockDiagram-VD42YOAC-CABpgVAa.js.map +1 -0
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-B3YCBmTx.js → c4Diagram-YG6GDRKO-COLZS8Ul.js} +4 -4
- package/webapp/dist/assets/c4Diagram-YG6GDRKO-COLZS8Ul.js.map +1 -0
- package/webapp/dist/assets/{channel-Dn4i8EAY.js → channel-CYFm9Cri.js} +2 -2
- package/webapp/dist/assets/channel-CYFm9Cri.js.map +1 -0
- package/webapp/dist/assets/{chunk-4BX2VUAB-CQbB3HlW.js → chunk-4BX2VUAB-CX_-XbaN.js} +2 -2
- package/webapp/dist/assets/chunk-4BX2VUAB-CX_-XbaN.js.map +1 -0
- package/webapp/dist/assets/{chunk-55IACEB6-CkQR_Qu9.js → chunk-55IACEB6-ByD-NdBC.js} +2 -2
- package/webapp/dist/assets/chunk-55IACEB6-ByD-NdBC.js.map +1 -0
- package/webapp/dist/assets/{chunk-WL4C6EOR-Bjl-j3bf.js → chunk-B4BG7PRW-BANemsDD.js} +121 -171
- package/webapp/dist/assets/chunk-B4BG7PRW-BANemsDD.js.map +1 -0
- package/webapp/dist/assets/{chunk-NQ4KR5QH-DBxY8LL2.js → chunk-DI55MBZ5-DV7sdJmQ.js} +7 -9
- package/webapp/dist/assets/chunk-DI55MBZ5-DV7sdJmQ.js.map +1 -0
- package/webapp/dist/assets/{chunk-FMBD7UC4-YSIOuaST.js → chunk-FMBD7UC4-DYGviJnf.js} +2 -2
- package/webapp/dist/assets/chunk-FMBD7UC4-DYGviJnf.js.map +1 -0
- package/webapp/dist/assets/{chunk-KX2RTZJC-DFiwgnFf.js → chunk-QN33PNHL-B8DWRL9f.js} +2 -2
- package/webapp/dist/assets/chunk-QN33PNHL-B8DWRL9f.js.map +1 -0
- package/webapp/dist/assets/{chunk-QZHKN3VN-BAdR6lLc.js → chunk-QZHKN3VN-B1aYIzMR.js} +2 -2
- package/webapp/dist/assets/chunk-QZHKN3VN-B1aYIzMR.js.map +1 -0
- package/webapp/dist/assets/{chunk-JSJVCQXG-CWDLRawz.js → chunk-TZMSLE5B-_HISzxl3.js} +6 -14
- package/webapp/dist/assets/chunk-TZMSLE5B-_HISzxl3.js.map +1 -0
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-KBeS6WXD.js → classDiagram-2ON5EDUG-CpyYj1Rc.js} +6 -7
- package/webapp/dist/assets/classDiagram-2ON5EDUG-CpyYj1Rc.js.map +1 -0
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-KBeS6WXD.js → classDiagram-v2-WZHVMYZB-CpyYj1Rc.js} +6 -7
- package/webapp/dist/assets/classDiagram-v2-WZHVMYZB-CpyYj1Rc.js.map +1 -0
- package/webapp/dist/assets/{clone-C7-aS2vm.js → clone-B_9AxWIU.js} +2 -2
- package/webapp/dist/assets/clone-B_9AxWIU.js.map +1 -0
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-Bo5IsL-5.js → cose-bilkent-S5V4N54A-17ECLfPR.js} +2 -2
- package/webapp/dist/assets/cose-bilkent-S5V4N54A-17ECLfPR.js.map +1 -0
- package/webapp/dist/assets/cytoscape.esm-Bm8DJGmZ.js.map +1 -1
- package/webapp/dist/assets/{dagre-KLK3FWXG-C3FeHj7D.js → dagre-6UL2VRFP-DhRqcF1o.js} +7 -7
- package/webapp/dist/assets/dagre-6UL2VRFP-DhRqcF1o.js.map +1 -0
- package/webapp/dist/assets/defaultLocale-B2RvLBDe.js.map +1 -1
- package/webapp/dist/assets/{diagram-E7M64L7V-0HfiRW0u.js → diagram-PSM6KHXK-lpDT6Wwb.js} +10 -10
- package/webapp/dist/assets/diagram-PSM6KHXK-lpDT6Wwb.js.map +1 -0
- package/webapp/dist/assets/{diagram-IFDJBPK2-DJwh7SMO.js → diagram-QEK2KX5R-ohxbPpDH.js} +8 -9
- package/webapp/dist/assets/diagram-QEK2KX5R-ohxbPpDH.js.map +1 -0
- package/webapp/dist/assets/{diagram-P4PSJMXO-Y0RbvUZX.js → diagram-S2PKOQOG-DAFFGfch.js} +8 -8
- package/webapp/dist/assets/diagram-S2PKOQOG-DAFFGfch.js.map +1 -0
- package/webapp/dist/assets/{erDiagram-INFDFZHY-B183xyLa.js → erDiagram-Q2GNP2WA-BH-7rI43.js} +75 -96
- package/webapp/dist/assets/erDiagram-Q2GNP2WA-BH-7rI43.js.map +1 -0
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-C_BR3Y3J.js → flowDiagram-NV44I4VS-CdEjFbz4.js} +81 -98
- package/webapp/dist/assets/flowDiagram-NV44I4VS-CdEjFbz4.js.map +1 -0
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-CHLgkuJT.js → ganttDiagram-JELNMOA3-Cju2t-lK.js} +3 -28
- package/webapp/dist/assets/ganttDiagram-JELNMOA3-Cju2t-lK.js.map +1 -0
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-D6C_HU1q.js → gitGraphDiagram-V2S2FVAM-CUJ5oxCg.js} +46 -38
- package/webapp/dist/assets/gitGraphDiagram-V2S2FVAM-CUJ5oxCg.js.map +1 -0
- package/webapp/dist/assets/graph-mhcc7ldf.js +425 -0
- package/webapp/dist/assets/graph-mhcc7ldf.js.map +1 -0
- package/webapp/dist/assets/{index-CLoNHmSQ.js → index-BLnM-uON.js} +2098 -1841
- package/webapp/dist/assets/{index-CLoNHmSQ.js.map → index-BLnM-uON.js.map} +1 -1
- package/webapp/dist/assets/{index-YaxF76or.css → index-xvYYeHuy.css} +1 -1
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-mnMS61NO.js → infoDiagram-HS3SLOUP-Df8p0okQ.js} +7 -7
- package/webapp/dist/assets/infoDiagram-HS3SLOUP-Df8p0okQ.js.map +1 -0
- package/webapp/dist/assets/init-ZxktEp_H.js.map +1 -1
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-BdeERn0r.js → journeyDiagram-XKPGCS4Q-BXMl8H-d.js} +5 -5
- package/webapp/dist/assets/journeyDiagram-XKPGCS4Q-BXMl8H-d.js.map +1 -0
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-MLeCGcYg.js → kanban-definition-3W4ZIXB7-Cc5RwCEh.js} +3 -5
- package/webapp/dist/assets/kanban-definition-3W4ZIXB7-Cc5RwCEh.js.map +1 -0
- package/webapp/dist/assets/{layout-DY9VEQ9M.js → layout-BB2SvQcE.js} +5 -5
- package/webapp/dist/assets/layout-BB2SvQcE.js.map +1 -0
- package/webapp/dist/assets/{linear-D-T1xRsr.js → linear-Cj50lA0a.js} +2 -2
- package/webapp/dist/assets/linear-Cj50lA0a.js.map +1 -0
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-CrVm8vj2.js → mindmap-definition-VGOIOE7T-BLBklJVX.js} +5 -7
- package/webapp/dist/assets/mindmap-definition-VGOIOE7T-BLBklJVX.js.map +1 -0
- package/webapp/dist/assets/ordinal-CxptdPJm.js.map +1 -1
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-GtLLV0r1.js → pieDiagram-ADFJNKIX-BQrOgSc-.js} +8 -8
- package/webapp/dist/assets/pieDiagram-ADFJNKIX-BQrOgSc-.js.map +1 -0
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-BCgk_2LP.js → quadrantDiagram-AYHSOK5B-C62TxtsO.js} +3 -3
- package/webapp/dist/assets/quadrantDiagram-AYHSOK5B-C62TxtsO.js.map +1 -0
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-DYUKHWKR.js → requirementDiagram-UZGBJVZJ-Is6Q3osM.js} +6 -16
- package/webapp/dist/assets/requirementDiagram-UZGBJVZJ-Is6Q3osM.js.map +1 -0
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-CFAH8OaY.js → sankeyDiagram-TZEHDZUN-CCAW8Dr2.js} +2 -2
- package/webapp/dist/assets/sankeyDiagram-TZEHDZUN-CCAW8Dr2.js.map +1 -0
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-BTnhbv6w.js → sequenceDiagram-WL72ISMW-DpODpbl6.js} +201 -601
- package/webapp/dist/assets/sequenceDiagram-WL72ISMW-DpODpbl6.js.map +1 -0
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-DWUnJTwO.js → stateDiagram-FKZM4ZOC-B8LHaf5T.js} +9 -9
- package/webapp/dist/assets/stateDiagram-FKZM4ZOC-B8LHaf5T.js.map +1 -0
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-B-fc52bp.js → stateDiagram-v2-4FDKWEC3-4FzTkpgz.js} +5 -5
- package/webapp/dist/assets/stateDiagram-v2-4FDKWEC3-4FzTkpgz.js.map +1 -0
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-BMZ52QaG.js → timeline-definition-IT6M3QCI-Ckxc4qZe.js} +3 -3
- package/webapp/dist/assets/timeline-definition-IT6M3QCI-Ckxc4qZe.js.map +1 -0
- package/webapp/dist/assets/{treemap-KZPCXAKY-fgSrze0S.js → treemap-GDKQZRPO-QQa4vKMv.js} +24 -37
- package/webapp/dist/assets/treemap-GDKQZRPO-QQa4vKMv.js.map +1 -0
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-D6aviLtC.js → xychartDiagram-PRI3JC2R-Ba2uJcs6.js} +4 -4
- package/webapp/dist/assets/xychartDiagram-PRI3JC2R-Ba2uJcs6.js.map +1 -0
- package/webapp/dist/index.html +2 -2
- package/webapp/dist/assets/_basePickBy-C0MXVhMo.js.map +0 -1
- package/webapp/dist/assets/_baseUniq-CRygl41M.js.map +0 -1
- package/webapp/dist/assets/arc-BeHJtnt2.js.map +0 -1
- package/webapp/dist/assets/architectureDiagram-2XIMDMQ5-CGdo5TVi.js.map +0 -1
- package/webapp/dist/assets/blockDiagram-WCTKOSBZ-C59VaSGw.js.map +0 -1
- package/webapp/dist/assets/c4Diagram-IC4MRINW-B3YCBmTx.js.map +0 -1
- package/webapp/dist/assets/channel-Dn4i8EAY.js.map +0 -1
- package/webapp/dist/assets/chunk-4BX2VUAB-CQbB3HlW.js.map +0 -1
- package/webapp/dist/assets/chunk-55IACEB6-CkQR_Qu9.js.map +0 -1
- package/webapp/dist/assets/chunk-FMBD7UC4-YSIOuaST.js.map +0 -1
- package/webapp/dist/assets/chunk-JSJVCQXG-CWDLRawz.js.map +0 -1
- package/webapp/dist/assets/chunk-KX2RTZJC-DFiwgnFf.js.map +0 -1
- package/webapp/dist/assets/chunk-NQ4KR5QH-DBxY8LL2.js.map +0 -1
- package/webapp/dist/assets/chunk-QZHKN3VN-BAdR6lLc.js.map +0 -1
- package/webapp/dist/assets/chunk-WL4C6EOR-Bjl-j3bf.js.map +0 -1
- package/webapp/dist/assets/classDiagram-VBA2DB6C-KBeS6WXD.js.map +0 -1
- package/webapp/dist/assets/classDiagram-v2-RAHNMMFH-KBeS6WXD.js.map +0 -1
- package/webapp/dist/assets/clone-C7-aS2vm.js.map +0 -1
- package/webapp/dist/assets/cose-bilkent-S5V4N54A-Bo5IsL-5.js.map +0 -1
- package/webapp/dist/assets/dagre-KLK3FWXG-C3FeHj7D.js.map +0 -1
- package/webapp/dist/assets/diagram-E7M64L7V-0HfiRW0u.js.map +0 -1
- package/webapp/dist/assets/diagram-IFDJBPK2-DJwh7SMO.js.map +0 -1
- package/webapp/dist/assets/diagram-P4PSJMXO-Y0RbvUZX.js.map +0 -1
- package/webapp/dist/assets/erDiagram-INFDFZHY-B183xyLa.js.map +0 -1
- package/webapp/dist/assets/flowDiagram-PKNHOUZH-C_BR3Y3J.js.map +0 -1
- package/webapp/dist/assets/ganttDiagram-A5KZAMGK-CHLgkuJT.js.map +0 -1
- package/webapp/dist/assets/gitGraphDiagram-K3NZZRJ6-D6C_HU1q.js.map +0 -1
- package/webapp/dist/assets/graph-D0hgB-X8.js +0 -782
- package/webapp/dist/assets/graph-D0hgB-X8.js.map +0 -1
- package/webapp/dist/assets/infoDiagram-LFFYTUFH-mnMS61NO.js.map +0 -1
- package/webapp/dist/assets/ishikawaDiagram-PHBUUO56-XFIJsnJj.js +0 -966
- package/webapp/dist/assets/ishikawaDiagram-PHBUUO56-XFIJsnJj.js.map +0 -1
- package/webapp/dist/assets/journeyDiagram-4ABVD52K-BdeERn0r.js.map +0 -1
- package/webapp/dist/assets/kanban-definition-K7BYSVSG-MLeCGcYg.js.map +0 -1
- package/webapp/dist/assets/layout-DY9VEQ9M.js.map +0 -1
- package/webapp/dist/assets/linear-D-T1xRsr.js.map +0 -1
- package/webapp/dist/assets/mindmap-definition-YRQLILUH-CrVm8vj2.js.map +0 -1
- package/webapp/dist/assets/pieDiagram-SKSYHLDU-GtLLV0r1.js.map +0 -1
- package/webapp/dist/assets/quadrantDiagram-337W2JSQ-BCgk_2LP.js.map +0 -1
- package/webapp/dist/assets/requirementDiagram-Z7DCOOCP-DYUKHWKR.js.map +0 -1
- package/webapp/dist/assets/sankeyDiagram-WA2Y5GQK-CFAH8OaY.js.map +0 -1
- package/webapp/dist/assets/sequenceDiagram-2WXFIKYE-BTnhbv6w.js.map +0 -1
- package/webapp/dist/assets/stateDiagram-RAJIS63D-DWUnJTwO.js.map +0 -1
- package/webapp/dist/assets/stateDiagram-v2-FVOUBMTO-B-fc52bp.js.map +0 -1
- package/webapp/dist/assets/timeline-definition-YZTLITO2-BMZ52QaG.js.map +0 -1
- package/webapp/dist/assets/treemap-KZPCXAKY-fgSrze0S.js.map +0 -1
- package/webapp/dist/assets/vennDiagram-LZ73GAT5-D5DmDY9l.js +0 -2487
- package/webapp/dist/assets/vennDiagram-LZ73GAT5-D5DmDY9l.js.map +0 -1
- package/webapp/dist/assets/xychartDiagram-JWTSCODW-D6aviLtC.js.map +0 -1
|
@@ -55,6 +55,7 @@ const dialog_fork_1 = require("../dialog-fork");
|
|
|
55
55
|
const dialog_global_registry_1 = require("../dialog-global-registry");
|
|
56
56
|
const log_1 = require("../log");
|
|
57
57
|
const persistence_1 = require("../persistence");
|
|
58
|
+
const persistence_errors_1 = require("../persistence-errors");
|
|
58
59
|
const priming_1 = require("../priming");
|
|
59
60
|
const work_language_1 = require("../runtime/work-language");
|
|
60
61
|
const team_1 = require("../team");
|
|
@@ -90,24 +91,108 @@ function getErrorCode(error) {
|
|
|
90
91
|
function isRecord(value) {
|
|
91
92
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
92
93
|
}
|
|
93
|
-
function
|
|
94
|
-
const raw = urlObj.searchParams.get('status');
|
|
95
|
-
if (raw === null)
|
|
96
|
-
return 'running';
|
|
94
|
+
function parsePersistableDialogStatus(raw) {
|
|
97
95
|
if (raw === 'running' || raw === 'completed' || raw === 'archived') {
|
|
98
96
|
return raw;
|
|
99
97
|
}
|
|
100
98
|
return null;
|
|
101
99
|
}
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
function readOptionalPersistableDialogStatusQuery(urlObj) {
|
|
101
|
+
const raw = urlObj.searchParams.get('status');
|
|
102
|
+
if (raw === null) {
|
|
103
|
+
return { kind: 'missing' };
|
|
104
|
+
}
|
|
105
|
+
const status = parsePersistableDialogStatus(raw);
|
|
106
|
+
if (status === null) {
|
|
107
|
+
return { kind: 'invalid' };
|
|
108
|
+
}
|
|
109
|
+
return { kind: 'value', status };
|
|
110
|
+
}
|
|
111
|
+
function readOptionalPersistableDialogStatus(raw) {
|
|
112
|
+
if (raw === undefined) {
|
|
113
|
+
return { kind: 'missing' };
|
|
114
|
+
}
|
|
115
|
+
const status = parsePersistableDialogStatus(raw);
|
|
116
|
+
if (status === null) {
|
|
117
|
+
return { kind: 'invalid' };
|
|
118
|
+
}
|
|
119
|
+
return { kind: 'value', status };
|
|
120
|
+
}
|
|
121
|
+
async function loadDialogMetadataForLookup(dialogId, status, context) {
|
|
122
|
+
try {
|
|
123
|
+
return await persistence_1.DialogPersistence.loadDialogMetadata(dialogId, status);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (!(0, persistence_errors_1.findDomindsPersistenceFileError)(error)) {
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
log.warn(`${context}: dialog metadata quarantined during lazy lookup`, error, {
|
|
130
|
+
dialogId: dialogId.valueOf(),
|
|
131
|
+
status,
|
|
132
|
+
});
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function loadRootDialogMetadataForLookup(dialogId, status, context) {
|
|
137
|
+
try {
|
|
138
|
+
return await persistence_1.DialogPersistence.loadRootDialogMetadata(dialogId, status);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (!(0, persistence_errors_1.findDomindsPersistenceFileError)(error)) {
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
log.warn(`${context}: root dialog metadata quarantined during lazy lookup`, error, {
|
|
145
|
+
dialogId: dialogId.valueOf(),
|
|
146
|
+
status,
|
|
147
|
+
});
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async function loadDialogLatestForLookup(dialogId, status, context) {
|
|
152
|
+
try {
|
|
153
|
+
return await persistence_1.DialogPersistence.loadDialogLatest(dialogId, status);
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (!(0, persistence_errors_1.findDomindsPersistenceFileError)(error)) {
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
log.warn(`${context}: latest.yaml quarantined during lazy lookup`, error, {
|
|
160
|
+
dialogId: dialogId.valueOf(),
|
|
161
|
+
status,
|
|
162
|
+
});
|
|
163
|
+
return null;
|
|
105
164
|
}
|
|
106
|
-
return null;
|
|
107
165
|
}
|
|
108
166
|
async function detectWaitingForFreshBootsReasoning(dialogId, status) {
|
|
109
|
-
|
|
110
|
-
|
|
167
|
+
try {
|
|
168
|
+
// Pending-subdialogs is also lazy-loaded per dialog. A malformed queue should quarantine just
|
|
169
|
+
// that dialog and degrade this derived flag to "unknown/false" instead of taking down the
|
|
170
|
+
// surrounding list or hierarchy response.
|
|
171
|
+
const pending = await persistence_1.DialogPersistence.loadPendingSubdialogs(dialogId, status);
|
|
172
|
+
return pending.some((entry) => entry.callName === 'freshBootsReasoning');
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
if (!(0, persistence_errors_1.findDomindsPersistenceFileError)(error)) {
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
log.warn('detectWaitingForFreshBootsReasoning: pending-subdialogs quarantined during lookup', error, {
|
|
179
|
+
dialogId: dialogId.valueOf(),
|
|
180
|
+
status,
|
|
181
|
+
});
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async function pathStillExistsForLookup(targetPath) {
|
|
186
|
+
try {
|
|
187
|
+
await promises_1.default.access(targetPath);
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
if (getErrorCode(error) === 'ENOENT') {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
111
196
|
}
|
|
112
197
|
function buildPrimingWarningSummary(warnings) {
|
|
113
198
|
if (warnings.length === 0)
|
|
@@ -219,7 +304,17 @@ async function handleSaveCurrentCoursePriming(req, res) {
|
|
|
219
304
|
}
|
|
220
305
|
const rootId = typeof dialogRaw['rootId'] === 'string' ? dialogRaw['rootId'].trim() : '';
|
|
221
306
|
const selfId = typeof dialogRaw['selfId'] === 'string' ? dialogRaw['selfId'].trim() : '';
|
|
222
|
-
const
|
|
307
|
+
const parsedStatus = readOptionalPersistableDialogStatus(dialogRaw['status']);
|
|
308
|
+
if (parsedStatus.kind === 'invalid') {
|
|
309
|
+
const payload = {
|
|
310
|
+
success: false,
|
|
311
|
+
error: 'dialog.status must be running, completed, or archived',
|
|
312
|
+
errorCode: 'INVALID_REQUEST',
|
|
313
|
+
};
|
|
314
|
+
respondJson(res, 400, payload);
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
const status = parsedStatus.kind === 'missing' ? 'running' : parsedStatus.status;
|
|
223
318
|
const course = typeof courseRaw === 'number' && Number.isFinite(courseRaw) ? Math.floor(courseRaw) : 0;
|
|
224
319
|
const slug = typeof slugRaw === 'string' ? slugRaw.trim() : '';
|
|
225
320
|
const overwrite = overwriteRaw === true;
|
|
@@ -1073,11 +1168,12 @@ async function handleApiRoute(req, res, pathname, context) {
|
|
|
1073
1168
|
// Dialog list endpoint
|
|
1074
1169
|
if (pathname === '/api/dialogs' && req.method === 'GET') {
|
|
1075
1170
|
const urlObj = new URL(req.url ?? '', 'http://127.0.0.1');
|
|
1076
|
-
const
|
|
1077
|
-
if (
|
|
1171
|
+
const parsedStatus = readOptionalPersistableDialogStatusQuery(urlObj);
|
|
1172
|
+
if (parsedStatus.kind === 'invalid') {
|
|
1078
1173
|
respondJson(res, 400, { success: false, error: 'Invalid status' });
|
|
1079
1174
|
return true;
|
|
1080
1175
|
}
|
|
1176
|
+
const status = parsedStatus.kind === 'missing' ? 'running' : parsedStatus.status;
|
|
1081
1177
|
return await handleGetDialogs(res, status);
|
|
1082
1178
|
}
|
|
1083
1179
|
if (pathname === '/api/dialogs/run-control-counts' && req.method === 'GET') {
|
|
@@ -1137,11 +1233,12 @@ async function handleApiRoute(req, res, pathname, context) {
|
|
|
1137
1233
|
const parts = pathname.split('/');
|
|
1138
1234
|
const rootId = parts[3].replace(/%2F/g, '/');
|
|
1139
1235
|
const urlObj = new URL(req.url ?? '', 'http://127.0.0.1');
|
|
1140
|
-
const
|
|
1141
|
-
if (
|
|
1236
|
+
const parsedStatus = readOptionalPersistableDialogStatusQuery(urlObj);
|
|
1237
|
+
if (parsedStatus.kind === 'invalid') {
|
|
1142
1238
|
respondJson(res, 400, { success: false, error: 'Invalid status' });
|
|
1143
1239
|
return true;
|
|
1144
1240
|
}
|
|
1241
|
+
const status = parsedStatus.kind === 'missing' ? 'running' : parsedStatus.status;
|
|
1145
1242
|
return await handleGetDialogHierarchy(res, rootId, status);
|
|
1146
1243
|
}
|
|
1147
1244
|
// Serve persisted dialog artifacts (binary)
|
|
@@ -1164,11 +1261,12 @@ async function handleApiRoute(req, res, pathname, context) {
|
|
|
1164
1261
|
return true;
|
|
1165
1262
|
}
|
|
1166
1263
|
const urlObj = new URL(req.url ?? '', 'http://127.0.0.1');
|
|
1167
|
-
const
|
|
1168
|
-
if (
|
|
1264
|
+
const parsedStatus = readOptionalPersistableDialogStatusQuery(urlObj);
|
|
1265
|
+
if (parsedStatus.kind === 'invalid') {
|
|
1169
1266
|
respondJson(res, 400, { success: false, error: 'Invalid status' });
|
|
1170
1267
|
return true;
|
|
1171
1268
|
}
|
|
1269
|
+
const status = parsedStatus.kind === 'missing' ? 'running' : parsedStatus.status;
|
|
1172
1270
|
return await handleGetDialogArtifact(req, res, { rootId, selfId }, status);
|
|
1173
1271
|
}
|
|
1174
1272
|
// Get specific dialog
|
|
@@ -1177,11 +1275,12 @@ async function handleApiRoute(req, res, pathname, context) {
|
|
|
1177
1275
|
const selfId = (parts[4] || parts[3]).replace(/%2F/g, '/');
|
|
1178
1276
|
const rootId = parts[3].replace(/%2F/g, '/');
|
|
1179
1277
|
const urlObj = new URL(req.url ?? '', 'http://127.0.0.1');
|
|
1180
|
-
const
|
|
1181
|
-
if (
|
|
1278
|
+
const parsedStatus = readOptionalPersistableDialogStatusQuery(urlObj);
|
|
1279
|
+
if (parsedStatus.kind === 'invalid') {
|
|
1182
1280
|
respondJson(res, 400, { success: false, error: 'Invalid status' });
|
|
1183
1281
|
return true;
|
|
1184
1282
|
}
|
|
1283
|
+
const status = parsedStatus.kind === 'missing' ? 'running' : parsedStatus.status;
|
|
1185
1284
|
const dialog = { selfId, rootId, status };
|
|
1186
1285
|
return await handleGetDialog(res, dialog, status);
|
|
1187
1286
|
}
|
|
@@ -1850,25 +1949,29 @@ async function handleGetToolsRegistry(req, res) {
|
|
|
1850
1949
|
const selfId = typeof selfIdRaw === 'string' ? selfIdRaw.trim() : '';
|
|
1851
1950
|
const requestedAgentId = typeof agentIdRaw === 'string' ? agentIdRaw.trim() : '';
|
|
1852
1951
|
const requestedTaskDocPath = typeof taskDocPathRaw === 'string' ? taskDocPathRaw.trim() : '';
|
|
1952
|
+
const requestedStatusParam = readOptionalPersistableDialogStatusQuery(urlObj);
|
|
1953
|
+
if (requestedStatusParam.kind === 'invalid') {
|
|
1954
|
+
respondJson(res, 400, { success: false, error: 'Invalid status' });
|
|
1955
|
+
return true;
|
|
1956
|
+
}
|
|
1853
1957
|
const resolveDialogMetadata = async () => {
|
|
1854
1958
|
if (rootId === '' || selfId === '') {
|
|
1855
1959
|
return null;
|
|
1856
1960
|
}
|
|
1857
|
-
const requestedStatus = parseDialogStatusFromUrl(urlObj);
|
|
1858
1961
|
const statusOrder = [
|
|
1859
1962
|
'running',
|
|
1860
1963
|
'completed',
|
|
1861
1964
|
'archived',
|
|
1862
1965
|
];
|
|
1863
|
-
const candidateStatuses =
|
|
1966
|
+
const candidateStatuses = requestedStatusParam.kind === 'missing'
|
|
1864
1967
|
? statusOrder
|
|
1865
1968
|
: [
|
|
1866
|
-
|
|
1867
|
-
...statusOrder.filter((status) => status !==
|
|
1969
|
+
requestedStatusParam.status,
|
|
1970
|
+
...statusOrder.filter((status) => status !== requestedStatusParam.status),
|
|
1868
1971
|
];
|
|
1869
1972
|
for (const status of candidateStatuses) {
|
|
1870
1973
|
const dialogId = new dialog_1.DialogID(selfId, rootId);
|
|
1871
|
-
const metadata = await
|
|
1974
|
+
const metadata = await loadDialogMetadataForLookup(dialogId, status, 'resolveDialogMetadata');
|
|
1872
1975
|
if (metadata) {
|
|
1873
1976
|
return metadata;
|
|
1874
1977
|
}
|
|
@@ -1992,21 +2095,14 @@ async function handleGetDialogs(res, status) {
|
|
|
1992
2095
|
const ids = await persistence_1.DialogPersistence.listDialogs(status);
|
|
1993
2096
|
for (const id of ids) {
|
|
1994
2097
|
const dialogId = new dialog_1.DialogID(id);
|
|
1995
|
-
const meta = await
|
|
2098
|
+
const meta = await loadRootDialogMetadataForLookup(dialogId, status, 'handleListDialogs');
|
|
1996
2099
|
if (!meta)
|
|
1997
2100
|
continue;
|
|
1998
|
-
//
|
|
1999
|
-
|
|
2101
|
+
// listDialogs() only yields candidate IDs. Metadata/latest stay lazy so one malformed dialog
|
|
2102
|
+
// can quarantine itself here without taking down the whole list response.
|
|
2103
|
+
const latest = await loadDialogLatestForLookup(dialogId, status, 'handleListDialogs');
|
|
2000
2104
|
const rootPath = persistence_1.DialogPersistence.getRootDialogPath(dialogId, status);
|
|
2001
|
-
const rootStillExists = await
|
|
2002
|
-
.access(rootPath)
|
|
2003
|
-
.then(() => true)
|
|
2004
|
-
.catch((error) => {
|
|
2005
|
-
if (getErrorCode(error) === 'ENOENT') {
|
|
2006
|
-
return false;
|
|
2007
|
-
}
|
|
2008
|
-
throw error;
|
|
2009
|
-
});
|
|
2105
|
+
const rootStillExists = await pathStillExistsForLookup(rootPath);
|
|
2010
2106
|
if (!rootStillExists) {
|
|
2011
2107
|
continue;
|
|
2012
2108
|
}
|
|
@@ -2014,6 +2110,9 @@ async function handleGetDialogs(res, status) {
|
|
|
2014
2110
|
// Count subdialogs for this root dialog
|
|
2015
2111
|
const subPath = path.join(rootPath, 'subdialogs');
|
|
2016
2112
|
const subdialogCount = await countSubdialogs(subPath);
|
|
2113
|
+
if (!(await pathStillExistsForLookup(rootPath))) {
|
|
2114
|
+
continue;
|
|
2115
|
+
}
|
|
2017
2116
|
rootDialogs.push({
|
|
2018
2117
|
rootId: meta.id,
|
|
2019
2118
|
agentId: meta.agentId,
|
|
@@ -2067,12 +2166,17 @@ async function countSubdialogs(dirPath) {
|
|
|
2067
2166
|
const dialogYamlPath = path.join(fullPath, 'dialog.yaml');
|
|
2068
2167
|
try {
|
|
2069
2168
|
await promises_1.default.access(dialogYamlPath);
|
|
2070
|
-
// This directory contains dialog.yaml - it's a subdialog
|
|
2169
|
+
// This directory contains dialog.yaml - it's a subdialog.
|
|
2071
2170
|
count++;
|
|
2072
2171
|
}
|
|
2073
|
-
catch {
|
|
2074
|
-
|
|
2075
|
-
|
|
2172
|
+
catch (error) {
|
|
2173
|
+
if (getErrorCode(error) === 'ENOENT') {
|
|
2174
|
+
// Only a missing dialog.yaml means "keep recursing". Permission/I/O failures must stay
|
|
2175
|
+
// loud so operators can distinguish inaccessible paths from ordinary non-dialog dirs.
|
|
2176
|
+
count += await countSubdialogs(fullPath);
|
|
2177
|
+
continue;
|
|
2178
|
+
}
|
|
2179
|
+
throw error;
|
|
2076
2180
|
}
|
|
2077
2181
|
}
|
|
2078
2182
|
}
|
|
@@ -2093,7 +2197,7 @@ async function countSubdialogs(dirPath) {
|
|
|
2093
2197
|
*/
|
|
2094
2198
|
async function handleGetDialogHierarchy(res, rootId, status) {
|
|
2095
2199
|
try {
|
|
2096
|
-
const rootMeta = await
|
|
2200
|
+
const rootMeta = await loadRootDialogMetadataForLookup(new dialog_1.DialogID(rootId), status, 'handleGetDialogHierarchy:root');
|
|
2097
2201
|
if (!rootMeta) {
|
|
2098
2202
|
respondJson(res, 404, {
|
|
2099
2203
|
success: false,
|
|
@@ -2102,17 +2206,9 @@ async function handleGetDialogHierarchy(res, rootId, status) {
|
|
|
2102
2206
|
return true;
|
|
2103
2207
|
}
|
|
2104
2208
|
// Load latest.yaml for root dialog currentCourse and lastModified timestamp
|
|
2105
|
-
const rootLatest = await
|
|
2209
|
+
const rootLatest = await loadDialogLatestForLookup(new dialog_1.DialogID(rootId), status, 'handleGetDialogHierarchy:root');
|
|
2106
2210
|
const rootPath = persistence_1.DialogPersistence.getRootDialogPath(new dialog_1.DialogID(rootId), status);
|
|
2107
|
-
const rootStillExists = await
|
|
2108
|
-
.access(rootPath)
|
|
2109
|
-
.then(() => true)
|
|
2110
|
-
.catch((error) => {
|
|
2111
|
-
if (getErrorCode(error) === 'ENOENT') {
|
|
2112
|
-
return false;
|
|
2113
|
-
}
|
|
2114
|
-
throw error;
|
|
2115
|
-
});
|
|
2211
|
+
const rootStillExists = await pathStillExistsForLookup(rootPath);
|
|
2116
2212
|
if (!rootStillExists) {
|
|
2117
2213
|
respondJson(res, 404, {
|
|
2118
2214
|
success: false,
|
|
@@ -2131,18 +2227,29 @@ async function handleGetDialogHierarchy(res, rootId, status) {
|
|
|
2131
2227
|
displayState: rootLatest?.displayState,
|
|
2132
2228
|
waitingForFreshBootsReasoning: await detectWaitingForFreshBootsReasoning(new dialog_1.DialogID(rootId), status),
|
|
2133
2229
|
};
|
|
2230
|
+
if (!(await pathStillExistsForLookup(rootPath))) {
|
|
2231
|
+
respondJson(res, 404, {
|
|
2232
|
+
success: false,
|
|
2233
|
+
error: `Root dialog ${rootId} was quarantined as malformed`,
|
|
2234
|
+
});
|
|
2235
|
+
return true;
|
|
2236
|
+
}
|
|
2134
2237
|
let subdialogs = [];
|
|
2135
2238
|
const dialogIds = await persistence_1.DialogPersistence.listAllDialogIds(status);
|
|
2136
2239
|
for (const dialogId of dialogIds) {
|
|
2137
2240
|
if (dialogId.rootId !== rootId || dialogId.selfId === rootId) {
|
|
2138
2241
|
continue;
|
|
2139
2242
|
}
|
|
2140
|
-
const meta = await
|
|
2243
|
+
const meta = await loadDialogMetadataForLookup(dialogId, status, 'handleGetDialogHierarchy:subdialog');
|
|
2141
2244
|
if (!meta) {
|
|
2142
2245
|
continue;
|
|
2143
2246
|
}
|
|
2144
|
-
const subLatest = await
|
|
2247
|
+
const subLatest = await loadDialogLatestForLookup(dialogId, status, 'handleGetDialogHierarchy:subdialog');
|
|
2145
2248
|
const waitingForFreshBootsReasoning = await detectWaitingForFreshBootsReasoning(dialogId, status);
|
|
2249
|
+
const subdialogPath = persistence_1.DialogPersistence.getSubdialogPath(dialogId, status);
|
|
2250
|
+
if (!(await pathStillExistsForLookup(subdialogPath))) {
|
|
2251
|
+
continue;
|
|
2252
|
+
}
|
|
2146
2253
|
const derivedSupdialogId = meta.assignmentFromSup?.callerDialogId &&
|
|
2147
2254
|
meta.assignmentFromSup.callerDialogId.trim() !== ''
|
|
2148
2255
|
? meta.assignmentFromSup.callerDialogId
|
|
@@ -2292,7 +2399,16 @@ async function handleForkDialog(req, res, context, rootIdRaw) {
|
|
|
2292
2399
|
const rootId = rootIdRaw.trim();
|
|
2293
2400
|
const course = typeof courseRaw === 'number' && Number.isFinite(courseRaw) ? Math.floor(courseRaw) : 0;
|
|
2294
2401
|
const genseq = typeof genseqRaw === 'number' && Number.isFinite(genseqRaw) ? Math.floor(genseqRaw) : 0;
|
|
2295
|
-
const
|
|
2402
|
+
const parsedStatus = readOptionalPersistableDialogStatus(statusRaw);
|
|
2403
|
+
if (parsedStatus.kind === 'invalid') {
|
|
2404
|
+
const payload = {
|
|
2405
|
+
success: false,
|
|
2406
|
+
error: 'status must be running, completed, or archived',
|
|
2407
|
+
};
|
|
2408
|
+
respondJson(res, 400, payload);
|
|
2409
|
+
return true;
|
|
2410
|
+
}
|
|
2411
|
+
const status = parsedStatus.kind === 'missing' ? 'running' : parsedStatus.status;
|
|
2296
2412
|
if (rootId === '') {
|
|
2297
2413
|
const payload = { success: false, error: 'rootId is required' };
|
|
2298
2414
|
respondJson(res, 400, payload);
|
|
@@ -2380,7 +2496,7 @@ async function handleMoveDialogs(req, res, context) {
|
|
|
2380
2496
|
respondJson(res, 400, { success: false, error: 'rootId must be a non-empty string' });
|
|
2381
2497
|
return true;
|
|
2382
2498
|
}
|
|
2383
|
-
const meta = await
|
|
2499
|
+
const meta = await loadRootDialogMetadataForLookup(new dialog_1.DialogID(rootId), fromStatus, 'handleMoveDialogs:root');
|
|
2384
2500
|
if (!meta) {
|
|
2385
2501
|
respondJson(res, 404, {
|
|
2386
2502
|
success: false,
|
|
@@ -2417,7 +2533,7 @@ async function handleMoveDialogs(req, res, context) {
|
|
|
2417
2533
|
for (const id of ids) {
|
|
2418
2534
|
if (typeof id !== 'string' || id.trim() === '')
|
|
2419
2535
|
continue;
|
|
2420
|
-
const meta = await
|
|
2536
|
+
const meta = await loadRootDialogMetadataForLookup(new dialog_1.DialogID(id), fromStatus, 'handleMoveDialogs:task-scan');
|
|
2421
2537
|
if (!meta)
|
|
2422
2538
|
continue;
|
|
2423
2539
|
if (meta.taskDocPath !== taskDocPath)
|
|
@@ -2551,7 +2667,7 @@ async function handleDeleteDialog(res, dialog, context) {
|
|
|
2551
2667
|
*/
|
|
2552
2668
|
async function handleGetDialog(res, dialog, status) {
|
|
2553
2669
|
try {
|
|
2554
|
-
const metadata = await
|
|
2670
|
+
const metadata = await loadDialogMetadataForLookup(new dialog_1.DialogID(dialog.selfId, dialog.rootId), status, 'handleGetDialog');
|
|
2555
2671
|
if (!metadata) {
|
|
2556
2672
|
respondJson(res, 404, { success: false, error: `Dialog not found in ${status}` });
|
|
2557
2673
|
return true;
|
|
@@ -2598,7 +2714,7 @@ async function handleResolveDialogStatus(req, res) {
|
|
|
2598
2714
|
const dialogId = new dialog_1.DialogID(selfId, rootId);
|
|
2599
2715
|
const candidates = ['running', 'completed', 'archived'];
|
|
2600
2716
|
for (const status of candidates) {
|
|
2601
|
-
const metadata = await
|
|
2717
|
+
const metadata = await loadDialogMetadataForLookup(dialogId, status, 'handleResolveDialogStatus');
|
|
2602
2718
|
if (!metadata)
|
|
2603
2719
|
continue;
|
|
2604
2720
|
respondJson(res, 200, {
|
|
@@ -25,6 +25,7 @@ const kernel_driver_1 = require("../llm/kernel-driver");
|
|
|
25
25
|
const runtime_2 = require("../llm/kernel-driver/runtime");
|
|
26
26
|
const log_1 = require("../log");
|
|
27
27
|
const persistence_1 = require("../persistence");
|
|
28
|
+
const persistence_errors_1 = require("../persistence-errors");
|
|
28
29
|
const priming_1 = require("../priming");
|
|
29
30
|
const problems_1 = require("../problems");
|
|
30
31
|
const reply_special_1 = require("../recovery/reply-special");
|
|
@@ -51,12 +52,22 @@ function normalizeDiligencePushMax(value) {
|
|
|
51
52
|
return 0;
|
|
52
53
|
return Math.floor(value);
|
|
53
54
|
}
|
|
54
|
-
function
|
|
55
|
+
function parsePersistableDialogStatus(raw) {
|
|
55
56
|
if (raw !== 'running' && raw !== 'completed' && raw !== 'archived') {
|
|
56
57
|
return null;
|
|
57
58
|
}
|
|
58
59
|
return raw;
|
|
59
60
|
}
|
|
61
|
+
function readOptionalPersistableDialogStatus(raw) {
|
|
62
|
+
if (raw === undefined) {
|
|
63
|
+
return { kind: 'missing' };
|
|
64
|
+
}
|
|
65
|
+
const status = parsePersistableDialogStatus(raw);
|
|
66
|
+
if (status === null) {
|
|
67
|
+
return { kind: 'invalid' };
|
|
68
|
+
}
|
|
69
|
+
return { kind: 'value', status };
|
|
70
|
+
}
|
|
60
71
|
function formatDeclaredDeadSubdialogNotice(language, dialogId, callName) {
|
|
61
72
|
if (language === 'zh') {
|
|
62
73
|
switch (callName) {
|
|
@@ -318,7 +329,15 @@ async function handleDeclareSubdialogDead(ws, packet) {
|
|
|
318
329
|
return;
|
|
319
330
|
}
|
|
320
331
|
const dialogIdObj = new dialog_1.DialogID(dialog.selfId, dialog.rootId);
|
|
321
|
-
const
|
|
332
|
+
const requestedStatusInput = readOptionalPersistableDialogStatus(dialog.status);
|
|
333
|
+
if (requestedStatusInput.kind === 'invalid') {
|
|
334
|
+
ws.send(JSON.stringify({
|
|
335
|
+
type: 'error',
|
|
336
|
+
message: 'declare_subdialog_dead requires status running, completed, or archived',
|
|
337
|
+
}));
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const requestedStatus = requestedStatusInput.kind === 'missing' ? 'running' : requestedStatusInput.status;
|
|
322
341
|
if (requestedStatus !== 'running') {
|
|
323
342
|
ws.send(JSON.stringify({
|
|
324
343
|
type: 'error',
|
|
@@ -405,7 +424,15 @@ async function handleSetDiligencePush(ws, packet) {
|
|
|
405
424
|
}
|
|
406
425
|
// Diligence Push is root-dialog state. Even if a subdialog is displayed, always mutate the root.
|
|
407
426
|
const dialogIdObj = new dialog_1.DialogID(rootId);
|
|
408
|
-
const
|
|
427
|
+
const requestedStatusInput = readOptionalPersistableDialogStatus(dialog.status);
|
|
428
|
+
if (requestedStatusInput.kind === 'invalid') {
|
|
429
|
+
ws.send(JSON.stringify({
|
|
430
|
+
type: 'error',
|
|
431
|
+
message: 'set_diligence_push requires status running, completed, or archived',
|
|
432
|
+
}));
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
const requestedStatus = requestedStatusInput.kind === 'missing' ? 'running' : requestedStatusInput.status;
|
|
409
436
|
const rootMeta = await persistence_1.DialogPersistence.loadDialogMetadata(dialogIdObj, requestedStatus);
|
|
410
437
|
if (!rootMeta) {
|
|
411
438
|
ws.send(JSON.stringify({
|
|
@@ -523,7 +550,15 @@ async function handleRefillDiligencePushBudget(ws, packet) {
|
|
|
523
550
|
return;
|
|
524
551
|
}
|
|
525
552
|
const rootDialogId = new dialog_1.DialogID(rootId);
|
|
526
|
-
const
|
|
553
|
+
const requestedStatusInput = readOptionalPersistableDialogStatus(dialog.status);
|
|
554
|
+
if (requestedStatusInput.kind === 'invalid') {
|
|
555
|
+
ws.send(JSON.stringify({
|
|
556
|
+
type: 'error',
|
|
557
|
+
message: 'refill_diligence_push_budget requires status running, completed, or archived',
|
|
558
|
+
}));
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const requestedStatus = requestedStatusInput.kind === 'missing' ? 'running' : requestedStatusInput.status;
|
|
527
562
|
const rootMeta = await persistence_1.DialogPersistence.loadDialogMetadata(rootDialogId, requestedStatus);
|
|
528
563
|
if (!rootMeta) {
|
|
529
564
|
ws.send(JSON.stringify({
|
|
@@ -742,7 +777,15 @@ async function handleDisplayDialog(ws, packet) {
|
|
|
742
777
|
cleanupWsClient(ws);
|
|
743
778
|
}
|
|
744
779
|
const dialogIdObj = new dialog_1.DialogID(dialogId, rootDialogId);
|
|
745
|
-
const
|
|
780
|
+
const requestedStatusInput = readOptionalPersistableDialogStatus(dialogIdent.status);
|
|
781
|
+
if (requestedStatusInput.kind === 'invalid') {
|
|
782
|
+
ws.send(JSON.stringify({
|
|
783
|
+
type: 'error',
|
|
784
|
+
message: 'display_dialog requires status running, completed, or archived',
|
|
785
|
+
}));
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
const requestedStatus = requestedStatusInput.kind === 'missing' ? 'running' : requestedStatusInput.status;
|
|
746
789
|
const dialogState = await persistence_1.DialogPersistence.restoreDialog(dialogIdObj, requestedStatus);
|
|
747
790
|
const metadata = await persistence_1.DialogPersistence.loadDialogMetadata(dialogIdObj, requestedStatus);
|
|
748
791
|
if (!dialogState || !metadata) {
|
|
@@ -957,7 +1000,15 @@ async function handleDisplayCourse(ws, packet) {
|
|
|
957
1000
|
}
|
|
958
1001
|
const dialogId = new dialog_1.DialogID(dialogIdStr, rootDialogIdStr);
|
|
959
1002
|
try {
|
|
960
|
-
const
|
|
1003
|
+
const requestedStatusInput = readOptionalPersistableDialogStatus(dialog.status);
|
|
1004
|
+
if (requestedStatusInput.kind === 'invalid') {
|
|
1005
|
+
ws.send(JSON.stringify({
|
|
1006
|
+
type: 'error',
|
|
1007
|
+
message: 'display_course requires status running, completed, or archived',
|
|
1008
|
+
}));
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
const requestedStatus = requestedStatusInput.kind === 'missing' ? 'running' : requestedStatusInput.status;
|
|
961
1012
|
const metadata = await persistence_1.DialogPersistence.loadDialogMetadata(dialogId, requestedStatus);
|
|
962
1013
|
if (!metadata) {
|
|
963
1014
|
log.warn('Metadata not found for display_course', undefined, {
|
|
@@ -1190,22 +1241,34 @@ async function handleResumeAll(ws, packet) {
|
|
|
1190
1241
|
}
|
|
1191
1242
|
const dialogIds = await persistence_1.DialogPersistence.listAllDialogIds('running');
|
|
1192
1243
|
for (const id of dialogIds) {
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1244
|
+
try {
|
|
1245
|
+
// listAllDialogIds() only gives candidate IDs. A malformed dialog can still quarantine itself
|
|
1246
|
+
// during lazy latest lookup here without preventing resume-all for the rest.
|
|
1247
|
+
const latest = await persistence_1.DialogPersistence.loadDialogLatest(id, 'running');
|
|
1248
|
+
if (!(0, dialog_display_state_1.isDialogLatestResumable)(latest))
|
|
1249
|
+
continue;
|
|
1250
|
+
void (async () => {
|
|
1251
|
+
try {
|
|
1252
|
+
const dlg = await restoreDialogForDrive(id, 'running');
|
|
1253
|
+
await (0, kernel_driver_1.driveDialogStream)(dlg, undefined, true, {
|
|
1254
|
+
allowResumeFromInterrupted: true,
|
|
1255
|
+
source: 'ws_resume_all',
|
|
1256
|
+
reason: 'resume_all',
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
catch (err) {
|
|
1260
|
+
log.warn('resume_all: failed to resume dialog', err, { dialogId: id.valueOf() });
|
|
1261
|
+
}
|
|
1262
|
+
})();
|
|
1263
|
+
}
|
|
1264
|
+
catch (error) {
|
|
1265
|
+
if (!(0, persistence_errors_1.findDomindsPersistenceFileError)(error)) {
|
|
1266
|
+
throw error;
|
|
1207
1267
|
}
|
|
1208
|
-
|
|
1268
|
+
log.warn('resume_all: skipping malformed dialog during latest lookup', error, {
|
|
1269
|
+
dialogId: id.valueOf(),
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1209
1272
|
}
|
|
1210
1273
|
emitRunControlRefresh('resume_all');
|
|
1211
1274
|
}
|
|
@@ -1390,6 +1453,44 @@ function setupWebSocketServer(httpServer, clients, auth, serverWorkLanguage, mod
|
|
|
1390
1453
|
broadcastDialogsIndexMessage = (msg) => {
|
|
1391
1454
|
broadcastToClients(msg);
|
|
1392
1455
|
};
|
|
1456
|
+
(0, persistence_1.setPrepareDialogQuarantineHook)(async ({ rootDialogId, status }) => {
|
|
1457
|
+
if (status !== 'running') {
|
|
1458
|
+
return;
|
|
1459
|
+
}
|
|
1460
|
+
(0, dialog_display_state_1.markRootDialogQuarantining)(rootDialogId);
|
|
1461
|
+
await (0, dialog_display_state_1.forceStopActiveRunsForRootDialog)(rootDialogId);
|
|
1462
|
+
});
|
|
1463
|
+
(0, persistence_1.setFinalizeDialogQuarantineHook)(({ rootDialogId, status, quarantined }) => {
|
|
1464
|
+
if (status !== 'running') {
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
if (quarantined) {
|
|
1468
|
+
(0, dialog_display_state_1.clearRootDialogQuarantiningIfIdle)(rootDialogId);
|
|
1469
|
+
return;
|
|
1470
|
+
}
|
|
1471
|
+
(0, dialog_display_state_1.clearRootDialogQuarantining)(rootDialogId);
|
|
1472
|
+
});
|
|
1473
|
+
(0, persistence_1.setDialogsQuarantinedBroadcaster)((msg) => {
|
|
1474
|
+
broadcastToClients(msg);
|
|
1475
|
+
if (msg.fromStatus !== 'running') {
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
void (0, dialog_display_state_1.getRunControlCountsSnapshot)()
|
|
1479
|
+
.then((counts) => {
|
|
1480
|
+
broadcastToClients({
|
|
1481
|
+
type: 'run_control_counts_evt',
|
|
1482
|
+
proceeding: counts.proceeding,
|
|
1483
|
+
resumable: counts.resumable,
|
|
1484
|
+
timestamp: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
1485
|
+
});
|
|
1486
|
+
})
|
|
1487
|
+
.catch((error) => {
|
|
1488
|
+
log.warn('Failed to broadcast run-control counts after dialog quarantine', error, {
|
|
1489
|
+
rootId: msg.rootId,
|
|
1490
|
+
dialogId: msg.dialogId,
|
|
1491
|
+
});
|
|
1492
|
+
});
|
|
1493
|
+
});
|
|
1393
1494
|
// Broadcast global run-control refresh hints so all clients converge from persisted dialog index.
|
|
1394
1495
|
broadcastRunControlRefreshMessage = (msg) => {
|
|
1395
1496
|
broadcastToClients(msg);
|
|
@@ -1418,6 +1519,9 @@ function setupWebSocketServer(httpServer, clients, auth, serverWorkLanguage, mod
|
|
|
1418
1519
|
(0, team_config_updates_1.stopTeamConfigWatcher)();
|
|
1419
1520
|
(0, team_config_updates_1.clearTeamConfigBroadcaster)();
|
|
1420
1521
|
(0, dominds_self_update_1.setDomindsSelfUpdateBroadcaster)(null);
|
|
1522
|
+
(0, persistence_1.setFinalizeDialogQuarantineHook)(null);
|
|
1523
|
+
(0, persistence_1.setPrepareDialogQuarantineHook)(null);
|
|
1524
|
+
(0, persistence_1.setDialogsQuarantinedBroadcaster)(null);
|
|
1421
1525
|
void wss.close();
|
|
1422
1526
|
});
|
|
1423
1527
|
wss.on('connection', (ws, req) => {
|
package/dist/tools/team_mgmt.js
CHANGED
|
@@ -5333,7 +5333,7 @@ async function renderTeamMgmtGuideContent(language, topicsRaw = []) {
|
|
|
5333
5333
|
'`model_param_options` 可选:用于记录该 provider 支持的 `.minds/team.yaml model_params` 选项(文档用途)。',
|
|
5334
5334
|
'`apiQuirks` 可选:写在 `providers.<providerKey>.apiQuirks`,类型是 `string|string[]`。它是 provider 级 transport / 网关兼容开关,用来描述“这个供应商/网关的 API 有非标准行为”,不是 `.minds/team.yaml` 的成员参数,也不是 `model_params`。',
|
|
5335
5335
|
'使用原则:只有在你确认某个上游网关确实偏离了标准协议,而且 Dominds 已为这个偏差实现了命名 quirk 时才配置;不要把它当作随意调参入口。当前实现里,未知 quirk 值通常不会报错,但也不会带来任何效果。',
|
|
5336
|
-
'当前已知示例:OpenAI Responses 包装层支持 `apiQuirks: xcode.best`(或数组里包含它)。它一方面会把供应商额外发出的 `keepalive` 流事件识别为 heartbeat
|
|
5336
|
+
'当前已知示例:OpenAI Responses 包装层支持 `apiQuirks: xcode.best`(或数组里包含它)。它一方面会把供应商额外发出的 `keepalive` 流事件识别为 heartbeat,而不是当作异常事件处理;另一方面也会对该网关特有的失败模式做 provider-specific failure handling,包括“同一对话上下文连续返回 empty response”时先做少量临时重试、连续达到阈值后停止自动重试,并明确提示直接继续大概率仍无真实进展,更建议结合真实情况灵活尝试多种新的指令;这类 provider/API retry 状态在同一次 driver 自动续跑链里会继续沿用,不因中途换 course 而自动清零;若当前对话启用了鞭策,driver 也会优先判断是否能按鞭策逻辑直接续跑一次,而不是先落入 stopped,并且一旦 driver 接受这次自动恢复资格,就会立刻记作已消费;以及把网关返回的 HTML 版 502 Bad Gateway 错误页归类为 conservative 策略重试。最小示例:\n```yaml\nproviders:\n my_gateway:\n apiType: openai\n baseUrl: https://example.invalid/v1\n apiKeyEnvVar: MY_GATEWAY_API_KEY\n apiQuirks: xcode.best\n models:\n my_model: { name: \"upstream-model-id\" }\n```',
|
|
5337
5337
|
'边界提醒:`apiQuirks` 只影响实现里显式消费它的 provider/generator。就当前实现看,至少 OpenAI Responses 路径会读取它;不要假设所有 `apiType` 都支持或需要它。若配置后行为仍异常,应继续检查上游网关文档、抓流事件类型,并结合 `team_mgmt_check_provider(...)` / 运行日志排查。',
|
|
5338
5338
|
])
|
|
5339
5339
|
: fmtHeader('.minds/llm.yaml') +
|
|
@@ -5347,7 +5347,7 @@ async function renderTeamMgmtGuideContent(language, topicsRaw = []) {
|
|
|
5347
5347
|
'Optional: `model_param_options` documents `.minds/team.yaml model_params` knobs (documentation only).',
|
|
5348
5348
|
'`apiQuirks` is optional under `providers.<providerKey>.apiQuirks`, with type `string|string[]`. It is a provider-level transport / gateway compatibility switch for non-standard upstream API behavior. It is not a `.minds/team.yaml` member field and not part of `model_params`.',
|
|
5349
5349
|
'Use it only when you have confirmed that an upstream gateway deviates from the expected protocol and Dominds has an explicitly named quirk for that deviation. Do not treat it as a generic tuning field. In the current implementation, unknown quirk values are usually ignored rather than rejected, so a typo may silently do nothing.',
|
|
5350
|
-
'Known current example: the OpenAI Responses wrapper supports `apiQuirks: xcode.best` (or an array containing it). It not only treats vendor-emitted `keepalive` stream events as heartbeat events instead of unexpected protocol noise, but also applies provider-specific failure handling for repeated empty responses in the same dialog context
|
|
5350
|
+
'Known current example: the OpenAI Responses wrapper supports `apiQuirks: xcode.best` (or an array containing it). It not only treats vendor-emitted `keepalive` stream events as heartbeat events instead of unexpected protocol noise, but also applies provider-specific failure handling for gateway-specific failures, including repeated empty responses in the same dialog context (a few temporary retries first, then an explicit stop of automatic retries with a warning that simply continuing is still unlikely to make real progress and that the better next step is to try different fresh instructions based on the real situation; this provider/API retry state intentionally continues across course changes within the same driver auto-continue chain; if Diligence Push is enabled for the dialog, the driver will first see whether it can continue once through that path before falling into stopped, and that recovery budget is considered consumed as soon as the driver accepts that path) and gateway-returned HTML 502 Bad Gateway pages classified into conservative retry. Minimal example:\n```yaml\nproviders:\n my_gateway:\n apiType: openai\n baseUrl: https://example.invalid/v1\n apiKeyEnvVar: MY_GATEWAY_API_KEY\n apiQuirks: xcode.best\n models:\n my_model: { name: \"upstream-model-id\" }\n```',
|
|
5351
5351
|
'Boundary reminder: `apiQuirks` only affects providers/generators that explicitly read it in code. In the current implementation, at least the OpenAI Responses path consumes it; do not assume every `apiType` supports or needs it. If behavior is still wrong after setting it, continue with upstream gateway docs, raw stream event inspection, and `team_mgmt_check_provider(...)` / runtime logs.',
|
|
5352
5352
|
]);
|
|
5353
5353
|
}
|