dominds 1.17.7 → 1.18.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-fork.js +11 -5
- package/dist/dialog-instance-registry.js +1 -18
- package/dist/dialog.d.ts +21 -31
- package/dist/dialog.js +207 -56
- package/dist/docs/dialog-system.md +3 -2
- package/dist/docs/dialog-system.zh.md +3 -2
- package/dist/docs/tellask-collab.md +2 -1
- package/dist/docs/tellask-collab.zh.md +2 -1
- package/dist/llm/defaults.yaml +43 -0
- package/dist/llm/gen/anthropic.js +153 -12
- package/dist/llm/gen/codex.js +160 -10
- package/dist/llm/gen/openai-compatible.js +141 -81
- package/dist/llm/gen/openai.js +178 -12
- package/dist/llm/gen/tool-result-image-ingest.d.ts +17 -8
- package/dist/llm/gen/tool-result-image-ingest.js +127 -27
- package/dist/llm/gen.d.ts +13 -0
- package/dist/llm/kernel-driver/drive.js +79 -15
- package/dist/llm/kernel-driver/flow.js +158 -41
- package/dist/llm/kernel-driver/reply-guidance.d.ts +6 -6
- package/dist/llm/kernel-driver/reply-guidance.js +169 -2
- package/dist/llm/kernel-driver/runtime.d.ts +2 -2
- package/dist/llm/kernel-driver/subdialog.js +4 -0
- package/dist/llm/kernel-driver/tellask-special.d.ts +2 -0
- package/dist/llm/kernel-driver/tellask-special.js +11 -6
- package/dist/llm/kernel-driver/types.d.ts +14 -24
- package/dist/minds/system-prompt.js +8 -8
- package/dist/persistence.d.ts +6 -5
- package/dist/persistence.js +198 -39
- package/dist/priming.js +98 -3
- package/dist/runtime/driver-messages.d.ts +1 -0
- package/dist/runtime/driver-messages.js +32 -10
- package/dist/runtime/reply-prompt-copy.js +4 -4
- package/dist/server/api-routes.js +11 -43
- package/dist/server/websocket-handler.js +155 -10
- package/dist/tools/builtins.js +10 -4
- package/dist/tools/cmd-runner.js +110 -49
- package/dist/tools/picture.d.ts +3 -0
- package/dist/tools/picture.js +344 -0
- package/dist/tools/prompts/control/en/principles.md +4 -2
- package/dist/tools/prompts/control/en/scenarios.md +2 -1
- package/dist/tools/prompts/control/en/tools.md +6 -6
- package/dist/tools/prompts/control/zh/principles.md +4 -2
- package/dist/tools/prompts/control/zh/scenarios.md +2 -1
- package/dist/tools/prompts/control/zh/tools.md +1 -1
- package/dist/tools/prompts/ws_mod.en.md +1 -0
- package/dist/tools/prompts/ws_mod.zh.md +1 -0
- package/dist/tools/prompts/ws_read/en/tools.md +25 -5
- package/dist/tools/prompts/ws_read/zh/tools.md +25 -5
- package/package.json +4 -4
- package/webapp/dist/assets/{_basePickBy-u7tNFRWr.js → _basePickBy-BPJaiZdW.js} +3 -3
- package/webapp/dist/assets/{_basePickBy-u7tNFRWr.js.map → _basePickBy-BPJaiZdW.js.map} +1 -1
- package/webapp/dist/assets/{_baseUniq-CH9LRkiH.js → _baseUniq-BEetT15i.js} +2 -2
- package/webapp/dist/assets/{_baseUniq-CH9LRkiH.js.map → _baseUniq-BEetT15i.js.map} +1 -1
- package/webapp/dist/assets/{arc-Bo0Lw3ZP.js → arc-Dm7Zf36f.js} +2 -2
- package/webapp/dist/assets/{arc-Bo0Lw3ZP.js.map → arc-Dm7Zf36f.js.map} +1 -1
- package/webapp/dist/assets/{architectureDiagram-VXUJARFQ-Ckyr89Iw.js → architectureDiagram-VXUJARFQ-BpTPtkuo.js} +7 -7
- package/webapp/dist/assets/{architectureDiagram-VXUJARFQ-Ckyr89Iw.js.map → architectureDiagram-VXUJARFQ-BpTPtkuo.js.map} +1 -1
- package/webapp/dist/assets/{blockDiagram-VD42YOAC-BSXoLLq_.js → blockDiagram-VD42YOAC-C8fLN0iu.js} +7 -7
- package/webapp/dist/assets/{blockDiagram-VD42YOAC-BSXoLLq_.js.map → blockDiagram-VD42YOAC-C8fLN0iu.js.map} +1 -1
- package/webapp/dist/assets/{c4Diagram-YG6GDRKO-CgCG1cP0.js → c4Diagram-YG6GDRKO-BpPr62CH.js} +3 -3
- package/webapp/dist/assets/{c4Diagram-YG6GDRKO-CgCG1cP0.js.map → c4Diagram-YG6GDRKO-BpPr62CH.js.map} +1 -1
- package/webapp/dist/assets/{channel-Crbz0zgt.js → channel-EMYoPjW3.js} +2 -2
- package/webapp/dist/assets/{channel-Crbz0zgt.js.map → channel-EMYoPjW3.js.map} +1 -1
- package/webapp/dist/assets/{chunk-4BX2VUAB-BIIEb_5S.js → chunk-4BX2VUAB-CefNtjWG.js} +2 -2
- package/webapp/dist/assets/{chunk-4BX2VUAB-BIIEb_5S.js.map → chunk-4BX2VUAB-CefNtjWG.js.map} +1 -1
- package/webapp/dist/assets/{chunk-55IACEB6-CaJzGgc9.js → chunk-55IACEB6-C_X7T43V.js} +2 -2
- package/webapp/dist/assets/{chunk-55IACEB6-CaJzGgc9.js.map → chunk-55IACEB6-C_X7T43V.js.map} +1 -1
- package/webapp/dist/assets/{chunk-B4BG7PRW-DHQwhO9F.js → chunk-B4BG7PRW-BRe3_2oA.js} +5 -5
- package/webapp/dist/assets/{chunk-B4BG7PRW-DHQwhO9F.js.map → chunk-B4BG7PRW-BRe3_2oA.js.map} +1 -1
- package/webapp/dist/assets/{chunk-DI55MBZ5-CG1lO0R8.js → chunk-DI55MBZ5-CbvrsI_w.js} +4 -4
- package/webapp/dist/assets/{chunk-DI55MBZ5-CG1lO0R8.js.map → chunk-DI55MBZ5-CbvrsI_w.js.map} +1 -1
- package/webapp/dist/assets/{chunk-FMBD7UC4-DAUsTLPS.js → chunk-FMBD7UC4-ORmtkrtS.js} +2 -2
- package/webapp/dist/assets/{chunk-FMBD7UC4-DAUsTLPS.js.map → chunk-FMBD7UC4-ORmtkrtS.js.map} +1 -1
- package/webapp/dist/assets/{chunk-QN33PNHL-BfQs-QHE.js → chunk-QN33PNHL-LTAOVhWu.js} +2 -2
- package/webapp/dist/assets/{chunk-QN33PNHL-BfQs-QHE.js.map → chunk-QN33PNHL-LTAOVhWu.js.map} +1 -1
- package/webapp/dist/assets/{chunk-QZHKN3VN-C5iKQ6mQ.js → chunk-QZHKN3VN-ZoUM_4u5.js} +2 -2
- package/webapp/dist/assets/{chunk-QZHKN3VN-C5iKQ6mQ.js.map → chunk-QZHKN3VN-ZoUM_4u5.js.map} +1 -1
- package/webapp/dist/assets/{chunk-TZMSLE5B-CBShDwy2.js → chunk-TZMSLE5B-Gao4qrq7.js} +2 -2
- package/webapp/dist/assets/{chunk-TZMSLE5B-CBShDwy2.js.map → chunk-TZMSLE5B-Gao4qrq7.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-2ON5EDUG-DrfJDzYO.js → classDiagram-2ON5EDUG-uha1vIGN.js} +6 -6
- package/webapp/dist/assets/{classDiagram-2ON5EDUG-DrfJDzYO.js.map → classDiagram-2ON5EDUG-uha1vIGN.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-v2-WZHVMYZB-DrfJDzYO.js → classDiagram-v2-WZHVMYZB-uha1vIGN.js} +6 -6
- package/webapp/dist/assets/{classDiagram-v2-WZHVMYZB-DrfJDzYO.js.map → classDiagram-v2-WZHVMYZB-uha1vIGN.js.map} +1 -1
- package/webapp/dist/assets/{clone-Cd-48URG.js → clone-_9Ayb1Gp.js} +2 -2
- package/webapp/dist/assets/{clone-Cd-48URG.js.map → clone-_9Ayb1Gp.js.map} +1 -1
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-CCji0YN3.js → cose-bilkent-S5V4N54A-C8wDw3NY.js} +2 -2
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-CCji0YN3.js.map → cose-bilkent-S5V4N54A-C8wDw3NY.js.map} +1 -1
- package/webapp/dist/assets/{dagre-6UL2VRFP-B94p-Dpl.js → dagre-6UL2VRFP-BUSeNot0.js} +7 -7
- package/webapp/dist/assets/{dagre-6UL2VRFP-B94p-Dpl.js.map → dagre-6UL2VRFP-BUSeNot0.js.map} +1 -1
- package/webapp/dist/assets/{diagram-PSM6KHXK-DP-zGmAS.js → diagram-PSM6KHXK-CMZAksVC.js} +8 -8
- package/webapp/dist/assets/{diagram-PSM6KHXK-DP-zGmAS.js.map → diagram-PSM6KHXK-CMZAksVC.js.map} +1 -1
- package/webapp/dist/assets/{diagram-QEK2KX5R-DquJirs4.js → diagram-QEK2KX5R-BQKoRtwy.js} +7 -7
- package/webapp/dist/assets/{diagram-QEK2KX5R-DquJirs4.js.map → diagram-QEK2KX5R-BQKoRtwy.js.map} +1 -1
- package/webapp/dist/assets/{diagram-S2PKOQOG-Dt5W2t6V.js → diagram-S2PKOQOG-DjMG97kd.js} +7 -7
- package/webapp/dist/assets/{diagram-S2PKOQOG-Dt5W2t6V.js.map → diagram-S2PKOQOG-DjMG97kd.js.map} +1 -1
- package/webapp/dist/assets/{erDiagram-Q2GNP2WA-Bs0-2Rfj.js → erDiagram-Q2GNP2WA-BujwA137.js} +5 -5
- package/webapp/dist/assets/{erDiagram-Q2GNP2WA-Bs0-2Rfj.js.map → erDiagram-Q2GNP2WA-BujwA137.js.map} +1 -1
- package/webapp/dist/assets/{flowDiagram-NV44I4VS-cJjXWAlK.js → flowDiagram-NV44I4VS-DgwPjg4y.js} +6 -6
- package/webapp/dist/assets/{flowDiagram-NV44I4VS-cJjXWAlK.js.map → flowDiagram-NV44I4VS-DgwPjg4y.js.map} +1 -1
- package/webapp/dist/assets/{ganttDiagram-JELNMOA3-Du1AUaKm.js → ganttDiagram-JELNMOA3-Db2ykf3E.js} +3 -3
- package/webapp/dist/assets/{ganttDiagram-JELNMOA3-Du1AUaKm.js.map → ganttDiagram-JELNMOA3-Db2ykf3E.js.map} +1 -1
- package/webapp/dist/assets/{gitGraphDiagram-V2S2FVAM-D_jVOYOK.js → gitGraphDiagram-V2S2FVAM-D_gSifkv.js} +8 -8
- package/webapp/dist/assets/{gitGraphDiagram-V2S2FVAM-D_jVOYOK.js.map → gitGraphDiagram-V2S2FVAM-D_gSifkv.js.map} +1 -1
- package/webapp/dist/assets/{graph-CuF_sq4r.js → graph-BHjCU5xP.js} +3 -3
- package/webapp/dist/assets/{graph-CuF_sq4r.js.map → graph-BHjCU5xP.js.map} +1 -1
- package/webapp/dist/assets/{index-DAShQcjb.js → index-DLajsIDJ.js} +1363 -248
- package/webapp/dist/assets/{index-DAShQcjb.js.map → index-DLajsIDJ.js.map} +1 -1
- package/webapp/dist/assets/{infoDiagram-HS3SLOUP-CEFlo_Hl.js → infoDiagram-HS3SLOUP-BDba5pKs.js} +6 -6
- package/webapp/dist/assets/{infoDiagram-HS3SLOUP-CEFlo_Hl.js.map → infoDiagram-HS3SLOUP-BDba5pKs.js.map} +1 -1
- package/webapp/dist/assets/{journeyDiagram-XKPGCS4Q-zc2Q4Se9.js → journeyDiagram-XKPGCS4Q-CmJAbmlm.js} +5 -5
- package/webapp/dist/assets/{journeyDiagram-XKPGCS4Q-zc2Q4Se9.js.map → journeyDiagram-XKPGCS4Q-CmJAbmlm.js.map} +1 -1
- package/webapp/dist/assets/{kanban-definition-3W4ZIXB7-oT42RM2a.js → kanban-definition-3W4ZIXB7-DxQeBTDk.js} +3 -3
- package/webapp/dist/assets/{kanban-definition-3W4ZIXB7-oT42RM2a.js.map → kanban-definition-3W4ZIXB7-DxQeBTDk.js.map} +1 -1
- package/webapp/dist/assets/{layout-BvaOu3k2.js → layout-DteV_yE8.js} +5 -5
- package/webapp/dist/assets/{layout-BvaOu3k2.js.map → layout-DteV_yE8.js.map} +1 -1
- package/webapp/dist/assets/{linear-Cg-CjocS.js → linear-zItbPrND.js} +2 -2
- package/webapp/dist/assets/{linear-Cg-CjocS.js.map → linear-zItbPrND.js.map} +1 -1
- package/webapp/dist/assets/{mindmap-definition-VGOIOE7T-CVFVrU22.js → mindmap-definition-VGOIOE7T-BJXI7UqO.js} +4 -4
- package/webapp/dist/assets/{mindmap-definition-VGOIOE7T-CVFVrU22.js.map → mindmap-definition-VGOIOE7T-BJXI7UqO.js.map} +1 -1
- package/webapp/dist/assets/{pieDiagram-ADFJNKIX-Bai5CMos.js → pieDiagram-ADFJNKIX-BpM-aH2p.js} +8 -8
- package/webapp/dist/assets/{pieDiagram-ADFJNKIX-Bai5CMos.js.map → pieDiagram-ADFJNKIX-BpM-aH2p.js.map} +1 -1
- package/webapp/dist/assets/{quadrantDiagram-AYHSOK5B-BPXDO_2E.js → quadrantDiagram-AYHSOK5B-NXdIpA15.js} +3 -3
- package/webapp/dist/assets/{quadrantDiagram-AYHSOK5B-BPXDO_2E.js.map → quadrantDiagram-AYHSOK5B-NXdIpA15.js.map} +1 -1
- package/webapp/dist/assets/{requirementDiagram-UZGBJVZJ-Dgj9X9cE.js → requirementDiagram-UZGBJVZJ-D1AICAA0.js} +4 -4
- package/webapp/dist/assets/{requirementDiagram-UZGBJVZJ-Dgj9X9cE.js.map → requirementDiagram-UZGBJVZJ-D1AICAA0.js.map} +1 -1
- package/webapp/dist/assets/{sankeyDiagram-TZEHDZUN-Dc0mO4OD.js → sankeyDiagram-TZEHDZUN-WiReDPfo.js} +2 -2
- package/webapp/dist/assets/{sankeyDiagram-TZEHDZUN-Dc0mO4OD.js.map → sankeyDiagram-TZEHDZUN-WiReDPfo.js.map} +1 -1
- package/webapp/dist/assets/{sequenceDiagram-WL72ISMW-DZJTga0d.js → sequenceDiagram-WL72ISMW-Cw76oP8t.js} +4 -4
- package/webapp/dist/assets/{sequenceDiagram-WL72ISMW-DZJTga0d.js.map → sequenceDiagram-WL72ISMW-Cw76oP8t.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-FKZM4ZOC-RNxYatKM.js → stateDiagram-FKZM4ZOC-QjCeRczs.js} +9 -9
- package/webapp/dist/assets/{stateDiagram-FKZM4ZOC-RNxYatKM.js.map → stateDiagram-FKZM4ZOC-QjCeRczs.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-v2-4FDKWEC3-ADxYqWzo.js → stateDiagram-v2-4FDKWEC3-IClqxQ4s.js} +5 -5
- package/webapp/dist/assets/{stateDiagram-v2-4FDKWEC3-ADxYqWzo.js.map → stateDiagram-v2-4FDKWEC3-IClqxQ4s.js.map} +1 -1
- package/webapp/dist/assets/{timeline-definition-IT6M3QCI-Qx_h1e-i.js → timeline-definition-IT6M3QCI-BfyfTY7m.js} +3 -3
- package/webapp/dist/assets/{timeline-definition-IT6M3QCI-Qx_h1e-i.js.map → timeline-definition-IT6M3QCI-BfyfTY7m.js.map} +1 -1
- package/webapp/dist/assets/{treemap-GDKQZRPO-BHzYvXGn.js → treemap-GDKQZRPO-C5MiL6--.js} +5 -5
- package/webapp/dist/assets/{treemap-GDKQZRPO-BHzYvXGn.js.map → treemap-GDKQZRPO-C5MiL6--.js.map} +1 -1
- package/webapp/dist/assets/{xychartDiagram-PRI3JC2R-DGdjkYQQ.js → xychartDiagram-PRI3JC2R-ybaJrSry.js} +3 -3
- package/webapp/dist/assets/{xychartDiagram-PRI3JC2R-DGdjkYQQ.js.map → xychartDiagram-PRI3JC2R-ybaJrSry.js.map} +1 -1
- package/webapp/dist/index.html +1 -1
package/dist/tools/cmd-runner.js
CHANGED
|
@@ -43,6 +43,20 @@ function sendIpc(msg) {
|
|
|
43
43
|
}
|
|
44
44
|
process.send(msg);
|
|
45
45
|
}
|
|
46
|
+
async function flushIpc(msg) {
|
|
47
|
+
if (typeof process.send !== 'function') {
|
|
48
|
+
throw new Error('cmd_runner must be launched with an IPC channel');
|
|
49
|
+
}
|
|
50
|
+
await new Promise((resolve, reject) => {
|
|
51
|
+
process.send?.(msg, (error) => {
|
|
52
|
+
if (error) {
|
|
53
|
+
reject(error);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
resolve();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
46
60
|
async function readProcessCommandLine(pid) {
|
|
47
61
|
try {
|
|
48
62
|
if (process.platform === 'win32') {
|
|
@@ -140,13 +154,90 @@ async function main() {
|
|
|
140
154
|
stdout: new ScrollingBuffer(init.scrollbackLines),
|
|
141
155
|
stderr: new ScrollingBuffer(init.scrollbackLines),
|
|
142
156
|
};
|
|
157
|
+
let server;
|
|
158
|
+
let closeRequested = false;
|
|
159
|
+
let timeoutHandle;
|
|
160
|
+
const closeServerAndExit = (code) => {
|
|
161
|
+
if (closeRequested) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
closeRequested = true;
|
|
165
|
+
const exit = () => {
|
|
166
|
+
setImmediate(() => {
|
|
167
|
+
process.exit(code);
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
const cleanupEndpoint = () => {
|
|
171
|
+
if (process.platform !== 'win32') {
|
|
172
|
+
void promises_1.default.unlink(endpoint).catch(() => {
|
|
173
|
+
// Best effort only.
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
if (!server) {
|
|
178
|
+
cleanupEndpoint();
|
|
179
|
+
exit();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
server.close(() => {
|
|
184
|
+
cleanupEndpoint();
|
|
185
|
+
exit();
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
const codeValue = typeof error === 'object' && error !== null
|
|
190
|
+
? error.code
|
|
191
|
+
: undefined;
|
|
192
|
+
if (codeValue !== 'ERR_SERVER_NOT_RUNNING') {
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
cleanupEndpoint();
|
|
196
|
+
exit();
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
childProcess.once('close', (code, signal) => {
|
|
200
|
+
if (timeoutHandle) {
|
|
201
|
+
clearTimeout(timeoutHandle);
|
|
202
|
+
}
|
|
203
|
+
state.isRunning = false;
|
|
204
|
+
state.exitCode = code;
|
|
205
|
+
state.exitSignal = signal;
|
|
206
|
+
void (async () => {
|
|
207
|
+
if (state.daemonCommandLine === null) {
|
|
208
|
+
await flushIpc({
|
|
209
|
+
type: 'completed',
|
|
210
|
+
exitCode: code,
|
|
211
|
+
exitSignal: signal,
|
|
212
|
+
stdout: state.stdout.snapshot(),
|
|
213
|
+
stderr: state.stderr.snapshot(),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
closeServerAndExit(0);
|
|
217
|
+
})().catch(() => {
|
|
218
|
+
closeServerAndExit(0);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
childProcess.once('error', (error) => {
|
|
222
|
+
if (timeoutHandle) {
|
|
223
|
+
clearTimeout(timeoutHandle);
|
|
224
|
+
}
|
|
225
|
+
void flushIpc({
|
|
226
|
+
type: 'failed',
|
|
227
|
+
errorText: error.message,
|
|
228
|
+
})
|
|
229
|
+
.catch(() => undefined)
|
|
230
|
+
.finally(() => {
|
|
231
|
+
closeServerAndExit(1);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
143
234
|
childProcess.stdout?.on('data', (data) => {
|
|
144
235
|
state.stdout.addText(data.toString());
|
|
145
236
|
});
|
|
146
237
|
childProcess.stderr?.on('data', (data) => {
|
|
147
238
|
state.stderr.addText(data.toString());
|
|
148
239
|
});
|
|
149
|
-
|
|
240
|
+
server = node_net_1.default.createServer((socket) => {
|
|
150
241
|
socket.setEncoding('utf8');
|
|
151
242
|
let buffer = '';
|
|
152
243
|
socket.on('data', (chunk) => {
|
|
@@ -211,9 +302,12 @@ async function main() {
|
|
|
211
302
|
resolve();
|
|
212
303
|
});
|
|
213
304
|
});
|
|
214
|
-
|
|
305
|
+
timeoutHandle = setTimeout(() => {
|
|
215
306
|
void (async () => {
|
|
216
307
|
const daemonCommandLine = await readProcessCommandLine(daemonPid);
|
|
308
|
+
if (!state.isRunning) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
217
311
|
if (daemonCommandLine === undefined || daemonCommandLine.trim() === '') {
|
|
218
312
|
try {
|
|
219
313
|
process.kill(daemonPid, 'SIGTERM');
|
|
@@ -221,12 +315,18 @@ async function main() {
|
|
|
221
315
|
catch {
|
|
222
316
|
// Best effort only.
|
|
223
317
|
}
|
|
318
|
+
if (!state.isRunning) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
224
321
|
sendIpc({
|
|
225
322
|
type: 'failed',
|
|
226
323
|
errorText: `failed to capture daemon command line from OS for pid ${String(daemonPid)}`,
|
|
227
324
|
});
|
|
228
325
|
return;
|
|
229
326
|
}
|
|
327
|
+
if (!state.isRunning) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
230
330
|
state.daemonCommandLine = daemonCommandLine;
|
|
231
331
|
sendIpc({
|
|
232
332
|
type: 'daemonized',
|
|
@@ -245,43 +345,6 @@ async function main() {
|
|
|
245
345
|
});
|
|
246
346
|
});
|
|
247
347
|
}, init.timeoutSeconds * 1000);
|
|
248
|
-
childProcess.once('close', (code, signal) => {
|
|
249
|
-
clearTimeout(timeoutHandle);
|
|
250
|
-
state.isRunning = false;
|
|
251
|
-
state.exitCode = code;
|
|
252
|
-
state.exitSignal = signal;
|
|
253
|
-
if (state.daemonCommandLine === null) {
|
|
254
|
-
sendIpc({
|
|
255
|
-
type: 'completed',
|
|
256
|
-
exitCode: code,
|
|
257
|
-
exitSignal: signal,
|
|
258
|
-
stdout: state.stdout.snapshot(),
|
|
259
|
-
stderr: state.stderr.snapshot(),
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
server.close(() => {
|
|
263
|
-
if (process.platform !== 'win32') {
|
|
264
|
-
void promises_1.default.unlink(endpoint).catch(() => {
|
|
265
|
-
// Best effort only.
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
setImmediate(() => {
|
|
269
|
-
process.exit(0);
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
childProcess.once('error', (error) => {
|
|
274
|
-
clearTimeout(timeoutHandle);
|
|
275
|
-
sendIpc({
|
|
276
|
-
type: 'failed',
|
|
277
|
-
errorText: error.message,
|
|
278
|
-
});
|
|
279
|
-
server.close(() => {
|
|
280
|
-
setImmediate(() => {
|
|
281
|
-
process.exit(1);
|
|
282
|
-
});
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
348
|
}
|
|
286
349
|
async function handleStopRequest(request, state, childProcess) {
|
|
287
350
|
if (!state.isRunning) {
|
|
@@ -307,14 +370,12 @@ async function handleStopRequest(request, state, childProcess) {
|
|
|
307
370
|
}
|
|
308
371
|
}
|
|
309
372
|
void main().catch((error) => {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
process.exit(1);
|
|
373
|
+
void flushIpc({
|
|
374
|
+
type: 'failed',
|
|
375
|
+
errorText: error instanceof Error ? error.message : String(error),
|
|
376
|
+
})
|
|
377
|
+
.catch(() => undefined)
|
|
378
|
+
.finally(() => {
|
|
379
|
+
process.exit(1);
|
|
380
|
+
});
|
|
320
381
|
});
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.writePictureTool = exports.readPictureTool = void 0;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const access_control_1 = require("../access-control");
|
|
11
|
+
const persistence_1 = require("../persistence");
|
|
12
|
+
const work_language_1 = require("../runtime/work-language");
|
|
13
|
+
const tool_1 = require("../tool");
|
|
14
|
+
const PICTURE_MAX_BYTES = 50 * 1024 * 1024;
|
|
15
|
+
function ok(content, contentItems) {
|
|
16
|
+
return (0, tool_1.toolSuccess)(content, contentItems);
|
|
17
|
+
}
|
|
18
|
+
function fail(content) {
|
|
19
|
+
return (0, tool_1.toolFailure)(content);
|
|
20
|
+
}
|
|
21
|
+
function formatYamlCodeBlock(yaml) {
|
|
22
|
+
return `\`\`\`yaml\n${yaml}\n\`\`\``;
|
|
23
|
+
}
|
|
24
|
+
function yamlQuote(value) {
|
|
25
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
26
|
+
}
|
|
27
|
+
function ensureInsideWorkspace(rel) {
|
|
28
|
+
const absPath = path_1.default.resolve(process.cwd(), rel);
|
|
29
|
+
const cwd = path_1.default.resolve(process.cwd());
|
|
30
|
+
const relative = path_1.default.relative(cwd, absPath);
|
|
31
|
+
if (relative === '' || (!relative.startsWith('..') && !path_1.default.isAbsolute(relative))) {
|
|
32
|
+
return absPath;
|
|
33
|
+
}
|
|
34
|
+
throw new Error('Path must be within rtws (runtime workspace)');
|
|
35
|
+
}
|
|
36
|
+
function requirePathArg(args) {
|
|
37
|
+
const value = args['path'];
|
|
38
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
39
|
+
throw new Error('Invalid arguments: `path` must be a non-empty string');
|
|
40
|
+
}
|
|
41
|
+
return value.trim();
|
|
42
|
+
}
|
|
43
|
+
function optionalBooleanArg(args, key) {
|
|
44
|
+
const value = args[key];
|
|
45
|
+
if (value === undefined)
|
|
46
|
+
return undefined;
|
|
47
|
+
if (typeof value !== 'boolean') {
|
|
48
|
+
throw new Error(`Invalid arguments: \`${key}\` must be a boolean`);
|
|
49
|
+
}
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
function extToMimeType(relPath) {
|
|
53
|
+
switch (path_1.default.extname(relPath).toLowerCase()) {
|
|
54
|
+
case '.png':
|
|
55
|
+
return 'image/png';
|
|
56
|
+
case '.jpg':
|
|
57
|
+
case '.jpeg':
|
|
58
|
+
return 'image/jpeg';
|
|
59
|
+
case '.webp':
|
|
60
|
+
return 'image/webp';
|
|
61
|
+
case '.gif':
|
|
62
|
+
return 'image/gif';
|
|
63
|
+
default:
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function mimeTypeToExt(mimeType) {
|
|
68
|
+
switch (mimeType) {
|
|
69
|
+
case 'image/png':
|
|
70
|
+
return 'png';
|
|
71
|
+
case 'image/jpeg':
|
|
72
|
+
return 'jpg';
|
|
73
|
+
case 'image/webp':
|
|
74
|
+
return 'webp';
|
|
75
|
+
case 'image/gif':
|
|
76
|
+
return 'gif';
|
|
77
|
+
default: {
|
|
78
|
+
const _exhaustive = mimeType;
|
|
79
|
+
return _exhaustive;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function parseSupportedMimeType(value) {
|
|
84
|
+
switch (value) {
|
|
85
|
+
case 'image/png':
|
|
86
|
+
case 'image/jpeg':
|
|
87
|
+
case 'image/webp':
|
|
88
|
+
case 'image/gif':
|
|
89
|
+
return value;
|
|
90
|
+
default:
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function detectImageMimeType(bytes) {
|
|
95
|
+
if (bytes.length >= 8 &&
|
|
96
|
+
bytes[0] === 0x89 &&
|
|
97
|
+
bytes[1] === 0x50 &&
|
|
98
|
+
bytes[2] === 0x4e &&
|
|
99
|
+
bytes[3] === 0x47 &&
|
|
100
|
+
bytes[4] === 0x0d &&
|
|
101
|
+
bytes[5] === 0x0a &&
|
|
102
|
+
bytes[6] === 0x1a &&
|
|
103
|
+
bytes[7] === 0x0a) {
|
|
104
|
+
return 'image/png';
|
|
105
|
+
}
|
|
106
|
+
if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
|
|
107
|
+
return 'image/jpeg';
|
|
108
|
+
}
|
|
109
|
+
if (bytes.length >= 12 &&
|
|
110
|
+
bytes.subarray(0, 4).toString('ascii') === 'RIFF' &&
|
|
111
|
+
bytes.subarray(8, 12).toString('ascii') === 'WEBP') {
|
|
112
|
+
return 'image/webp';
|
|
113
|
+
}
|
|
114
|
+
if (bytes.length >= 6 &&
|
|
115
|
+
(bytes.subarray(0, 6).toString('ascii') === 'GIF87a' ||
|
|
116
|
+
bytes.subarray(0, 6).toString('ascii') === 'GIF89a')) {
|
|
117
|
+
return 'image/gif';
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
function validateImageBytesMatchMimeType(bytes, mimeType) {
|
|
122
|
+
const detected = detectImageMimeType(bytes);
|
|
123
|
+
if (detected === null) {
|
|
124
|
+
throw new Error('Image bytes do not match a supported PNG/JPEG/WebP/GIF signature');
|
|
125
|
+
}
|
|
126
|
+
if (detected !== mimeType) {
|
|
127
|
+
throw new Error(`Image bytes are ${detected}, but path/mime_type declares ${mimeType}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function stripDataUrlPrefix(value) {
|
|
131
|
+
const trimmed = value.trim();
|
|
132
|
+
if (!trimmed.startsWith('data:'))
|
|
133
|
+
return { base64: trimmed };
|
|
134
|
+
const match = /^data:([^;,]+);base64,(.*)$/s.exec(trimmed);
|
|
135
|
+
if (!match)
|
|
136
|
+
return { base64: trimmed };
|
|
137
|
+
const mimeType = parseSupportedMimeType(match[1]);
|
|
138
|
+
return {
|
|
139
|
+
base64: match[2] ?? '',
|
|
140
|
+
...(mimeType === null ? {} : { mimeType }),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function isStrictBase64Payload(value) {
|
|
144
|
+
if (value.length === 0 || value.length % 4 !== 0)
|
|
145
|
+
return false;
|
|
146
|
+
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
|
|
147
|
+
}
|
|
148
|
+
function decodeStrictBase64(value) {
|
|
149
|
+
const normalized = value.replace(/\s+/g, '');
|
|
150
|
+
if (!isStrictBase64Payload(normalized)) {
|
|
151
|
+
throw new Error('Image data must be strict base64 or a base64 data URL');
|
|
152
|
+
}
|
|
153
|
+
return Buffer.from(normalized, 'base64');
|
|
154
|
+
}
|
|
155
|
+
function sanitizePathSegment(value) {
|
|
156
|
+
const cleaned = value.replace(/[^0-9A-Za-z._-]/g, '_').replace(/_+/g, '_');
|
|
157
|
+
const trimmed = cleaned.replace(/^_+|_+$/g, '');
|
|
158
|
+
return trimmed.length > 0 ? trimmed.slice(0, 96) : 'picture';
|
|
159
|
+
}
|
|
160
|
+
async function persistPictureArtifact(args) {
|
|
161
|
+
const eventsBase = persistence_1.DialogPersistence.getDialogEventsPath(args.dlg.id, args.dlg.status);
|
|
162
|
+
const relPath = path_1.default.posix.join('artifacts', 'workspace', sanitizePathSegment(args.toolName), `${Date.now().toString(36)}-${(0, crypto_1.randomUUID)()}.${mimeTypeToExt(args.mimeType)}`);
|
|
163
|
+
const absPath = path_1.default.join(eventsBase, ...relPath.split('/'));
|
|
164
|
+
await promises_1.default.mkdir(path_1.default.dirname(absPath), { recursive: true });
|
|
165
|
+
await promises_1.default.writeFile(absPath, args.bytes);
|
|
166
|
+
return {
|
|
167
|
+
type: 'input_image',
|
|
168
|
+
mimeType: args.mimeType,
|
|
169
|
+
byteLength: args.bytes.length,
|
|
170
|
+
artifact: {
|
|
171
|
+
rootId: args.dlg.id.rootId,
|
|
172
|
+
selfId: args.dlg.id.selfId,
|
|
173
|
+
status: args.dlg.status,
|
|
174
|
+
relPath,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function formatPictureResultYaml(args) {
|
|
179
|
+
return formatYamlCodeBlock([
|
|
180
|
+
`status: ${args.status}`,
|
|
181
|
+
`action: ${args.action}`,
|
|
182
|
+
`path: ${yamlQuote(args.path)}`,
|
|
183
|
+
`mime_type: ${yamlQuote(args.mimeType)}`,
|
|
184
|
+
`byte_length: ${String(args.byteLength)}`,
|
|
185
|
+
`artifact_rel_path: ${yamlQuote(args.artifactRelPath)}`,
|
|
186
|
+
'llm_context: image_attached',
|
|
187
|
+
].join('\n'));
|
|
188
|
+
}
|
|
189
|
+
exports.readPictureTool = {
|
|
190
|
+
type: 'func',
|
|
191
|
+
name: 'read_picture',
|
|
192
|
+
description: 'Read a PNG/JPEG/WebP/GIF image from rtws and attach it as an image content item for the next LLM context.',
|
|
193
|
+
descriptionI18n: {
|
|
194
|
+
en: 'Read a PNG/JPEG/WebP/GIF image from rtws and attach it as an image content item for the next LLM context.',
|
|
195
|
+
zh: '读取 rtws 中的 PNG/JPEG/WebP/GIF 图片,并作为图片 content item 放入后续 LLM 上下文。',
|
|
196
|
+
},
|
|
197
|
+
parameters: {
|
|
198
|
+
type: 'object',
|
|
199
|
+
additionalProperties: false,
|
|
200
|
+
properties: {
|
|
201
|
+
path: {
|
|
202
|
+
type: 'string',
|
|
203
|
+
description: 'rtws-relative image path to read. Supported extensions: .png, .jpg, .jpeg, .webp, .gif.',
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
required: ['path'],
|
|
207
|
+
},
|
|
208
|
+
argsValidation: 'dominds',
|
|
209
|
+
call: async (dlg, caller, args) => {
|
|
210
|
+
const language = (0, work_language_1.getWorkLanguage)();
|
|
211
|
+
try {
|
|
212
|
+
const relPath = requirePathArg(args);
|
|
213
|
+
if (!(0, access_control_1.hasReadAccess)(caller, relPath)) {
|
|
214
|
+
return fail((0, access_control_1.getAccessDeniedMessage)('read', relPath, language));
|
|
215
|
+
}
|
|
216
|
+
const mimeType = extToMimeType(relPath);
|
|
217
|
+
if (mimeType === null) {
|
|
218
|
+
return fail('Unsupported image extension. Supported extensions: .png, .jpg, .jpeg, .webp, .gif');
|
|
219
|
+
}
|
|
220
|
+
const absPath = ensureInsideWorkspace(relPath);
|
|
221
|
+
const stat = await promises_1.default.stat(absPath);
|
|
222
|
+
if (!stat.isFile())
|
|
223
|
+
return fail(`Path is not a file: ${relPath}`);
|
|
224
|
+
if (stat.size <= 0 || stat.size > PICTURE_MAX_BYTES) {
|
|
225
|
+
return fail(`Image must be between 1 byte and ${String(PICTURE_MAX_BYTES)} bytes`);
|
|
226
|
+
}
|
|
227
|
+
const bytes = await promises_1.default.readFile(absPath);
|
|
228
|
+
validateImageBytesMatchMimeType(bytes, mimeType);
|
|
229
|
+
const item = await persistPictureArtifact({
|
|
230
|
+
dlg,
|
|
231
|
+
toolName: 'read_picture',
|
|
232
|
+
mimeType,
|
|
233
|
+
bytes,
|
|
234
|
+
});
|
|
235
|
+
return ok(formatPictureResultYaml({
|
|
236
|
+
status: 'ok',
|
|
237
|
+
action: 'read_picture',
|
|
238
|
+
path: relPath,
|
|
239
|
+
mimeType,
|
|
240
|
+
byteLength: bytes.length,
|
|
241
|
+
artifactRelPath: item.artifact.relPath,
|
|
242
|
+
}), [item]);
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
return fail(error instanceof Error ? error.message : String(error));
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
exports.writePictureTool = {
|
|
250
|
+
type: 'func',
|
|
251
|
+
name: 'write_picture',
|
|
252
|
+
description: 'Write a PNG/JPEG/WebP/GIF image to rtws from strict base64 or a base64 data URL, then attach the written image as a content item.',
|
|
253
|
+
descriptionI18n: {
|
|
254
|
+
en: 'Write a PNG/JPEG/WebP/GIF image to rtws from strict base64 or a base64 data URL, then attach the written image as a content item.',
|
|
255
|
+
zh: '把 strict base64 或 base64 data URL 写成 rtws 中的 PNG/JPEG/WebP/GIF 图片,并把写出的图片作为 content item 返回。',
|
|
256
|
+
},
|
|
257
|
+
parameters: {
|
|
258
|
+
type: 'object',
|
|
259
|
+
additionalProperties: false,
|
|
260
|
+
properties: {
|
|
261
|
+
path: {
|
|
262
|
+
type: 'string',
|
|
263
|
+
description: 'rtws-relative destination image path. Supported extensions: .png, .jpg, .jpeg, .webp, .gif.',
|
|
264
|
+
},
|
|
265
|
+
data_base64: {
|
|
266
|
+
type: 'string',
|
|
267
|
+
description: 'Strict base64 image payload, or a base64 data URL.',
|
|
268
|
+
},
|
|
269
|
+
mime_type: {
|
|
270
|
+
type: 'string',
|
|
271
|
+
description: 'Optional MIME type. Supported values: image/png, image/jpeg, image/webp, image/gif.',
|
|
272
|
+
},
|
|
273
|
+
overwrite: {
|
|
274
|
+
type: 'boolean',
|
|
275
|
+
description: 'Whether to overwrite an existing file. Defaults to false.',
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
required: ['path', 'data_base64'],
|
|
279
|
+
},
|
|
280
|
+
argsValidation: 'dominds',
|
|
281
|
+
call: async (dlg, caller, args) => {
|
|
282
|
+
const language = (0, work_language_1.getWorkLanguage)();
|
|
283
|
+
try {
|
|
284
|
+
const relPath = requirePathArg(args);
|
|
285
|
+
if (!(0, access_control_1.hasWriteAccess)(caller, relPath)) {
|
|
286
|
+
return fail((0, access_control_1.getAccessDeniedMessage)('write', relPath, language));
|
|
287
|
+
}
|
|
288
|
+
const rawData = args['data_base64'];
|
|
289
|
+
if (typeof rawData !== 'string' || rawData.trim() === '') {
|
|
290
|
+
return fail('Invalid arguments: `data_base64` must be a non-empty string');
|
|
291
|
+
}
|
|
292
|
+
const parsedData = stripDataUrlPrefix(rawData);
|
|
293
|
+
const explicitMimeType = parseSupportedMimeType(args['mime_type']);
|
|
294
|
+
if (args['mime_type'] !== undefined && explicitMimeType === null) {
|
|
295
|
+
return fail('Unsupported mime_type. Supported values: image/png, image/jpeg, image/webp, image/gif');
|
|
296
|
+
}
|
|
297
|
+
const pathMimeType = extToMimeType(relPath);
|
|
298
|
+
if (pathMimeType === null) {
|
|
299
|
+
return fail('Unsupported image extension. Supported extensions: .png, .jpg, .jpeg, .webp, .gif');
|
|
300
|
+
}
|
|
301
|
+
const mimeType = explicitMimeType ?? parsedData.mimeType ?? pathMimeType;
|
|
302
|
+
if (mimeType !== pathMimeType) {
|
|
303
|
+
return fail(`mime_type ${mimeType} does not match destination extension for ${relPath}`);
|
|
304
|
+
}
|
|
305
|
+
const bytes = decodeStrictBase64(parsedData.base64);
|
|
306
|
+
if (bytes.length <= 0 || bytes.length > PICTURE_MAX_BYTES) {
|
|
307
|
+
return fail(`Image must be between 1 byte and ${String(PICTURE_MAX_BYTES)} bytes`);
|
|
308
|
+
}
|
|
309
|
+
validateImageBytesMatchMimeType(bytes, mimeType);
|
|
310
|
+
const overwrite = optionalBooleanArg(args, 'overwrite') ?? false;
|
|
311
|
+
const absPath = ensureInsideWorkspace(relPath);
|
|
312
|
+
if (!overwrite) {
|
|
313
|
+
try {
|
|
314
|
+
await promises_1.default.stat(absPath);
|
|
315
|
+
return fail(`File already exists: ${relPath}. Pass overwrite=true to replace it.`);
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
if (!(error instanceof Error) || !('code' in error) || error.code !== 'ENOENT') {
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
await promises_1.default.mkdir(path_1.default.dirname(absPath), { recursive: true });
|
|
324
|
+
await promises_1.default.writeFile(absPath, bytes);
|
|
325
|
+
const item = await persistPictureArtifact({
|
|
326
|
+
dlg,
|
|
327
|
+
toolName: 'write_picture',
|
|
328
|
+
mimeType,
|
|
329
|
+
bytes,
|
|
330
|
+
});
|
|
331
|
+
return ok(formatPictureResultYaml({
|
|
332
|
+
status: 'ok',
|
|
333
|
+
action: 'write_picture',
|
|
334
|
+
path: relPath,
|
|
335
|
+
mimeType,
|
|
336
|
+
byteLength: bytes.length,
|
|
337
|
+
artifactRelPath: item.artifact.relPath,
|
|
338
|
+
}), [item]);
|
|
339
|
+
}
|
|
340
|
+
catch (error) {
|
|
341
|
+
return fail(error instanceof Error ? error.message : String(error));
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
};
|
|
@@ -92,7 +92,9 @@ Taskdoc is a **task contract** and the task's **team-shared source of current tr
|
|
|
92
92
|
|
|
93
93
|
### Decision Rules
|
|
94
94
|
|
|
95
|
-
- If the current sideline is unfinished,
|
|
95
|
+
- If the current sideline is unfinished, first judge whether team SOP / role ownership already identifies the responsible owner; if yes and the issue is execution work, directly use `tellask` / `tellaskSessionless` for that owner
|
|
96
|
+
- Call `tellaskBack({ tellaskContent })` only when upstream must clarify the request, decide a tradeoff, confirm acceptance criteria, provide missing input, or current SOP cannot determine ownership
|
|
97
|
+
- If a human must personally perform login / GUI / captcha / high-risk authorization: call `askHuman({ tellaskContent })`
|
|
96
98
|
- If the current sideline is complete and the assignment header says `replyTellask`: call `replyTellask({ replyContent })`
|
|
97
99
|
- If the current sideline is complete and the assignment header says `replyTellaskSessionless`: call `replyTellaskSessionless({ replyContent })`
|
|
98
100
|
- If you are answering an upstream `tellaskBack` follow-up and runtime exposes `replyTellaskBack`: call `replyTellaskBack({ replyContent })`
|
|
@@ -104,7 +106,7 @@ Taskdoc is a **task contract** and the task's **team-shared source of current tr
|
|
|
104
106
|
- Do not memorize reply variants by yourself; follow the current assignment header and the function currently exposed by runtime
|
|
105
107
|
- `reply*` tool descriptions are intentionally minimal and spec-like; use this manual's principles / scenarios for situational guidance
|
|
106
108
|
- If runtime exposes only one `reply*`, that is the only correct completion path for the current state
|
|
107
|
-
- `tellaskBack` is
|
|
109
|
+
- `tellaskBack` is the fallback when ownership cannot be determined from existing SOP, or when upstream must answer; it is not the default first move for every blocked state
|
|
108
110
|
|
|
109
111
|
## Best Practices
|
|
110
112
|
|
|
@@ -89,7 +89,8 @@ tellaskBack({
|
|
|
89
89
|
|
|
90
90
|
### Key Points
|
|
91
91
|
|
|
92
|
-
-
|
|
92
|
+
- This example uses `tellaskBack` because upstream input is specifically required
|
|
93
|
+
- If team SOP / role ownership already identifies the responsible executor, directly use `tellask` / `tellaskSessionless` for that owner instead of mapping every unfinished state to `tellaskBack`
|
|
93
94
|
- Do not use `replyTellask*` for intermediate clarifications
|
|
94
95
|
|
|
95
96
|
## Scenario 4: Upstream answered the ask-back, so use replyTellaskBack to close
|
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
|
|
24
24
|
The **tool descriptions themselves** for these functions intentionally stay minimal and spec-like. This section carries the smallest practical lookup for when they appear and how to choose among them.
|
|
25
25
|
|
|
26
|
-
| Function | Minimal parameter contract | When runtime exposes it
|
|
27
|
-
| ------------------------- | ---------------------------- |
|
|
28
|
-
| `replyTellask` | `{ replyContent: string }` | Current sideline comes from a sessioned `tellask` and is ready for final delivery
|
|
29
|
-
| `replyTellaskSessionless` | `{ replyContent: string }` | Current sideline comes from a one-shot `tellaskSessionless` and is ready for final delivery
|
|
30
|
-
| `replyTellaskBack` | `{ replyContent: string }` | Current dialog holds an unresolved `tellaskBack` reply directive
|
|
31
|
-
| `tellaskBack` | `{ tellaskContent: string }` | Current sideline
|
|
26
|
+
| Function | Minimal parameter contract | When runtime exposes it | Effect |
|
|
27
|
+
| ------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
28
|
+
| `replyTellask` | `{ replyContent: string }` | Current sideline comes from a sessioned `tellask` and is ready for final delivery | Delivers the final result for the current tellask session |
|
|
29
|
+
| `replyTellaskSessionless` | `{ replyContent: string }` | Current sideline comes from a one-shot `tellaskSessionless` and is ready for final delivery | Delivers the final result for the current one-shot tellask |
|
|
30
|
+
| `replyTellaskBack` | `{ replyContent: string }` | Current dialog holds an unresolved `tellaskBack` reply directive | Delivers the final answer to the upstream ask-back |
|
|
31
|
+
| `tellaskBack` | `{ tellaskContent: string }` | Current sideline must ask upstream back, and existing team SOP cannot directly assign another owner | Sends a follow-up request upstream; not final delivery |
|
|
32
32
|
|
|
33
33
|
### Minimal Usage Rules
|
|
34
34
|
|
|
@@ -92,7 +92,9 @@
|
|
|
92
92
|
|
|
93
93
|
### 决策规则
|
|
94
94
|
|
|
95
|
-
-
|
|
95
|
+
- 当前支线未完成时,先判断团队规程 / SOP / 职责卡能否明确负责人;若能明确且属于执行性处理,直接 `tellask` / `tellaskSessionless` 对应负责人
|
|
96
|
+
- 只有当必须向上游补需求、澄清目标、裁决取舍、确认验收口径、提供缺失输入,或现有规程无法明确判责时:调用 `tellaskBack({ tellaskContent })`
|
|
97
|
+
- 需要人类亲自登录 / GUI / 验证码 / 高风险授权时:调用 `askHuman({ tellaskContent })`
|
|
96
98
|
- 当前支线已经完成,且当前 assignment 明确要求 `replyTellask`:调用 `replyTellask({ replyContent })`
|
|
97
99
|
- 当前支线已经完成,且当前 assignment 明确要求 `replyTellaskSessionless`:调用 `replyTellaskSessionless({ replyContent })`
|
|
98
100
|
- 当前是在回复一条上游发来的 `tellaskBack` 续诉请,且 runtime 暴露了 `replyTellaskBack`:调用 `replyTellaskBack({ replyContent })`
|
|
@@ -104,7 +106,7 @@
|
|
|
104
106
|
- 不要靠记忆硬选 reply 变体;以当前 assignment 头部和 runtime 当前暴露的函数名为准
|
|
105
107
|
- `reply*` 函数自身说明文案故意保持极简,只承载最小规格;情景判断看本手册的 principles / scenarios
|
|
106
108
|
- 若 runtime 只暴露一个 `reply*`,那就是当前应调用的唯一完成路径
|
|
107
|
-
- `tellaskBack`
|
|
109
|
+
- `tellaskBack` 是“无法按现有规程明确判责,或必须回问上游”的兜底动作,不是所有阻塞的默认第一动作
|
|
108
110
|
|
|
109
111
|
## 最佳实践
|
|
110
112
|
|
|
@@ -89,7 +89,8 @@ tellaskBack({
|
|
|
89
89
|
|
|
90
90
|
### 关键点
|
|
91
91
|
|
|
92
|
-
-
|
|
92
|
+
- 这里只是“必须向上游补输入”的例子,所以用 `tellaskBack`
|
|
93
|
+
- 若团队规程 / SOP / 职责卡已经能明确执行负责人,应直接 `tellask` / `tellaskSessionless` 对应负责人,而不是机械因为“未完成态”就用 `tellaskBack`
|
|
93
94
|
- `tellaskBack` 只负责把问题问回去,不负责最终交付
|
|
94
95
|
|
|
95
96
|
## 场景 4:收到 ask-back 续诉请后,用 replyTellaskBack 收口
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
| `replyTellask` | `{ replyContent: string }` | 当前支线承接的是 sessioned `tellask`,且已进入可交付完成态 | 把最终结果回复给当前 `tellask` 会话 |
|
|
29
29
|
| `replyTellaskSessionless` | `{ replyContent: string }` | 当前支线承接的是 one-shot `tellaskSessionless`,且已进入可交付完成态 | 把最终结果回复给当前一次性诉请 |
|
|
30
30
|
| `replyTellaskBack` | `{ replyContent: string }` | 当前对话持有一条未完成的 `tellaskBack` 回复指令 | 把对上一条回问的最终答复送回上游 |
|
|
31
|
-
| `tellaskBack` | `{ tellaskContent: string }` |
|
|
31
|
+
| `tellaskBack` | `{ tellaskContent: string }` | 当前支线必须回问上游,且现有团队规程无法直接判责到其他负责人 | 向上游发起续诉请,不算最终交付 |
|
|
32
32
|
|
|
33
33
|
### 最小使用规则
|
|
34
34
|
|
|
@@ -13,6 +13,7 @@ You have read/write access to the rtws (runtime workspace), but **all incrementa
|
|
|
13
13
|
- Normalization: all writes follow “each line ends with `\n` (including the last line)”; missing EOF newline will be added and shown in `normalized.*`.
|
|
14
14
|
- Exception: `overwrite_entire_file` overwrites an existing file (writes immediately; does not use prepare/apply). It requires `known_old_total_lines/known_old_total_bytes` guardrails (read `total_lines/size_bytes` from the YAML header of `read_file`). `content_format` accepts any non-empty text label (for example `yaml`), but diff/patch-like content is still rejected by default unless `content_format=diff|patch`. Use it only for “small content (<100 lines)” or “intentional reset/generated output”; otherwise prefer prepare/apply.
|
|
15
15
|
- Exception: `create_new_file` only creates a new file (empty content allowed). It does not do incremental edits and does not use prepare/apply; it refuses to overwrite existing files.
|
|
16
|
+
- Binary image tools: use `read_picture({ path })` to inspect PNG/JPEG/WebP/GIF images as real image context; use `write_picture({ path, data_base64, mime_type, overwrite })` to write a base64 image. These are binary image operations and do not use prepare/apply.
|
|
16
17
|
|
|
17
18
|
## Which `prepare_*` to use
|
|
18
19
|
|