@tea-agent/loop-agent 0.42.0-next.8 → 0.42.0
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/CHANGELOG.md +56 -50
- package/dist/application/dag/run-dag.js +41 -0
- package/dist/application/task-lifecycle/advance.js +9 -4
- package/dist/build-stamp.json +3 -3
- package/dist/cli/program.js +1 -1
- package/dist/commands/dag-rerun-task.js +2 -0
- package/dist/commands/task-source-prepare.js +3 -1
- package/dist/executors/dag-pi-executor.js +1809 -213
- package/dist/executors/pi-extension-resolver.js +14 -2
- package/dist/executors/shell-executor.js +178 -73
- package/dist/shared/dag-failure-category.js +6 -0
- package/dist/task/contract/apply.js +36 -2
- package/dist/task/source-prepare/parse-intent.js +7 -0
- package/dist/worker/console/chat/chat-event-store.js +4 -2
- package/dist/worker/console/chat/pi-runtime.js +45 -2
- package/dist/worker/console/chat/resource-loader.js +4 -1
- package/dist/worker/console/chat/routes.js +28 -12
- package/dist/worker/console/chat/sdd-data-alignment.js +13 -2
- package/dist/worker/console/chat/session-store.js +5 -1
- package/dist/worker/console/chat/subagents/agent-tool.js +62 -0
- package/dist/worker/console/chat/subagents/explore-agent.js +169 -0
- package/dist/worker/console/chat/subagents/index.js +5 -0
- package/dist/worker/console/chat/subagents/orchestrator.js +273 -0
- package/dist/worker/console/chat/subagents/tool-policy.js +53 -0
- package/dist/worker/console/chat/subagents/types.js +13 -0
- package/dist/worker/console/chat/tool-preview.js +10 -0
- package/dist/worker/console/chat/tools.js +11 -1
- package/dist/worker/console/chat/turn-process.js +1 -0
- package/dist/worker/console/interview/tools.js +1 -0
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C6n9_m0P.js → abnfDiagram-N423BO3Z-B0Q0nClf.js} +1 -1
- package/dist/worker/console/static/assets/{arc-DQh-IfZ1.js → arc-DCPjC19G.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-54NnrwUC.js → architectureDiagram-T3A2C74G-CP5n9jmG.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-pivRALGK.js → blockDiagram-VBNYF7ZC-CmaWi_Wg.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BR7OV2NJ.js → c4Diagram-5PPSVZJV-Ct5tcMfZ.js} +1 -1
- package/dist/worker/console/static/assets/channel-DAS07MdS.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-B1Aq6BcK.js → chunk-2GRJ4B5K-C0osm1Zf.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CbdU0rjo.js → chunk-2Q5K7J3B-CDWviED7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-Dqi2GJeD.js → chunk-5RXB4S5H-mtSk1-j7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BYn1Hu4R.js → chunk-5VM5RSS4-D5J9PHC7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DRLjDL0k.js → chunk-6Q2QTUOP-Begg4WAa.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CY9Xx2jV.js → chunk-GF5L2VYU-sF1AEy7T.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BNCZs7_z.js → chunk-JWPE2WC7-BqbsWXZb.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DZ8AStLL.js → chunk-KBJHAD2P-BKJrPcJ6.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DsxjYrzz.js → chunk-RYQCIY6F-CcwNMRho.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-Ddx1KC1l.js → chunk-XXDRQBXY-BEJi3iIs.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-Cwk-5jiW.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-Cwk-5jiW.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-W9TveCnK.js → cose-bilkent-JH36ORCC-DRLgTvVu.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-l9j_ztZH.js → cynefin-VYW2F7L2-BoAVG3cs.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BMJMKi4G.js → cynefinDiagram-MW4NZA55-Bzol06hR.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-Bb4mG9pH.js → dagre-VZM6K2ZE-UmliJM77.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-BMgL_Qv0.js → diagram-7IWD3JNH-BWLcJkFo.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Bvo2T4OQ.js → diagram-B4RE2ZJO-CgApOm-O.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-_5kWRN9c.js → diagram-LBJQPF4R-Bh3RgTLs.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DqdMrltM.js → diagram-Q27KOJAE-Dsh-D5nE.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-CDDYsNkp.js → diagram-UB23O5K3-Dkbbpcpb.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-c4nfnZUV.js → ebnfDiagram-BXEA7PRR-3EBaA3t3.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DnkUcNMs.js → erDiagram-JOGREHBK-Bq2Dc5ok.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-Dz0KGLZE.js → flowDiagram-UKHOOZJN-De7y55ha.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Cj1t1uka.js → ganttDiagram-PKOTCBZU-fLiDbQRh.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-tp2FrBHd.js → gitGraphDiagram-DS77QQ5N-Du617mp1.js} +1 -1
- package/dist/worker/console/static/assets/index-C0O48S_P.js +449 -0
- package/dist/worker/console/static/assets/index-CzKf4U8P.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DQwJS8DH.js → infoDiagram-6WML65LV-BwmlF-XP.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-eimCQWD4.js → ishikawaDiagram-WSZJBQD7-zsGtS59u.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-Dd9Gbwgv.js → journeyDiagram-NVQOT4AX-DTTPTe3f.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Qve3cyft.js → kanban-definition-27J2QSJJ-BkXg9aP-.js} +1 -1
- package/dist/worker/console/static/assets/{linear-UXKSe36Z.js → linear-7U2ue5IE.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-CWhj4JXN.js → mermaid.core-BUuGHmWO.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-yTcwf4SJ.js → mindmap-definition-FAOFIHXS-7q6fX0Sv.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-_7qToaZP.js → pegDiagram-VL7TDLO6-CkQPJN55.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CXmrKmDm.js → pieDiagram-7S7Q4E2Y-CCal_tfX.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-hMmrJyaS.js → quadrantDiagram-CIZ2JOQS-B7bpxyAZ.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BXw8tCBe.js → railroadDiagram-AXF67PYL-CJmww7D-.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BmjgnLZl.js → requirementDiagram-LRYGKXZP-D6ldWJEv.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Bj77SPpN.js → sankeyDiagram-W5VNT64P-VGh33I9e.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-B2FDVysL.js → sequenceDiagram-SI44F4Z6-CCkDrIjU.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-UChNY9ZZ.js → sizeCapture-X5ZJPWSS-NC8f5Otb.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-wbAEkbd7.js → stateDiagram-OKZ733FA-_92ezZdF.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DyJg5gzW.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DCEkU8HR.js → swimlanes-SLNWSIFB-BdUCGtbP.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-B1cw_0Uy.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-BGp7H06U.js → timeline-definition-Z64GVDOM-CdD1H8ia.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DsCIQuWR.js → vennDiagram-T6HMQDX7-Dkdk3oFo.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-cRZLP4Xe.js → wardleyDiagram-T6FBY63Y-CKu2uPPY.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CP0xLR9Y.js → xychartDiagram-ELKLHX3M-ClqAnuG8.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/chat-view-types.js +1 -1
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +23 -0
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +32 -0
- package/dist/worker/console/static-src/operator-chat/tools-catalog.js +21 -2
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +2 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -0
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +30 -14
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +133 -5
- package/dist/worker/console/static-src/shell/workspace-route.js +4 -0
- package/dist/worker/observe/routes.js +4 -0
- package/dist/worker/observe/static/constants.js +22 -22
- package/dist/worker/observe/static/dag-context-reason-labels.js +19 -0
- package/dist/worker/observe/static/dag-history-labels.js +1 -0
- package/dist/worker/observe/static/dag-inspector-humanize.d.ts +16 -0
- package/dist/worker/observe/static/dag-inspector-humanize.js +339 -0
- package/dist/worker/observe/static/dag-node-purpose.js +10 -10
- package/dist/worker/observe/static/index.html +4 -4
- package/dist/worker/observe/static/prompt-restart-candidates.js +4 -2
- package/dist/worker/observe/static/relations.js +5 -5
- package/dist/worker/observe/static/styles.css +171 -0
- package/dist/worker/observe/static/views/dag-graph.js +1 -1
- package/dist/worker/observe/static/views/dag-inspector.js +329 -174
- package/dist/worker/observe/static/views/dag.js +16 -12
- package/dist/worker/observe/static/views/session-timeline.js +5 -3
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +18 -0
- package/dist/workflows/dag/backend-test-plan-protocol.js +104 -0
- package/dist/workflows/dag/backend-test-scenario-param.js +30 -1
- package/dist/workflows/dag/dag-retry-schema.js +3 -0
- package/dist/workflows/dag/frontend-contract-facts.js +130 -0
- package/dist/workflows/dag/frontend-design-policy.js +101 -16
- package/dist/workflows/dag/frontend-implementation-contract.js +410 -41
- package/dist/workflows/dag/frontend-plan-render.js +13 -2
- package/dist/workflows/dag/frontend-prewrite-gate.js +1 -1
- package/dist/workflows/dag/frontend-recovery-controller.js +25 -1
- package/dist/workflows/dag/frontend-recovery-plan.js +6 -2
- package/dist/workflows/dag/frontend-recovery-run.js +169 -15
- package/dist/workflows/dag/frontend-risk.js +2 -0
- package/dist/workflows/dag/frontend-shadow-dual-write.js +17 -1
- package/dist/workflows/dag/frontend-shape.js +16 -6
- package/dist/workflows/dag/frontend-test-execution-evidence.js +48 -0
- package/dist/workflows/dag/frontend-typed-event-store.js +3 -0
- package/dist/workflows/dag/frontend-verification-trace.js +38 -4
- package/dist/workflows/dag/frontend-writer-admission.js +46 -12
- package/dist/workflows/dag/init-hybrid.js +59 -29
- package/dist/workflows/dag/node-execution.js +277 -85
- package/dist/workflows/dag/recovery-lease.js +106 -16
- package/dist/workflows/dag/rerun-feedback.js +60 -0
- package/dist/workflows/dag/rerun-plan.js +90 -4
- package/dist/workflows/dag/rerun-run.js +28 -6
- package/dist/workflows/dag/rerun-task.js +224 -15
- package/dist/workflows/dag/retry-policy.js +27 -10
- package/dist/workflows/dag/runner-exit-diagnostics.js +125 -0
- package/dist/workflows/dag/runner.js +238 -29
- package/dist/workflows/dag/scheduler.js +21 -6
- package/dist/workflows/dag/structured-output-repair.js +4 -1
- package/dist/workflows/dag/types.js +4 -3
- package/dist/workflows/dag/validate.js +10 -8
- package/dist/workflows/dag/workspace-checkpoint.js +66 -0
- package/docs/operations/README.md +1 -0
- package/docs/templates/agent-dag.schema.json +2 -2
- package/docs/templates/backend-test-dag.json +6 -4
- package/docs/templates/frontend-implementation-contract.schema.json +34 -2
- package/harness.json +1 -1
- package/package.json +4 -5
- package/skills/frontend-plan/SKILL.md +14 -1
- package/skills/frontend-plan/references/decision-contract.md +101 -5
- package/skills/frontend-plan/references/design-decisions.md +32 -0
- package/dist/worker/console/static/assets/channel-DsZxrgqe.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-CuToPeGV.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-CuToPeGV.js +0 -1
- package/dist/worker/console/static/assets/index-D9Sc0f0y.js +0 -449
- package/dist/worker/console/static/assets/index-DDQc5a50.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-yPoT19ft.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-VWdarchG.js +0 -8
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* The three-gate authorization (authorizeOperatorChatTool) is the actual
|
|
16
16
|
* enforcement; this adapter describes what that gate admits.
|
|
17
17
|
*/
|
|
18
|
-
import { OPERATOR_CHAT_ALLOWED_TOOLS, OPERATOR_CHAT_DENIED_TOOLS, OPERATOR_CHAT_DENIED_OPERATOR_ACTIONS, OPERATOR_CHAT_PI_BUILTIN_TOOLS, authorizeOperatorChatTool, filterOperatorChatTools, assertNoWriteToolInList, } from "./tools.js";
|
|
18
|
+
import { OPERATOR_CHAT_ALLOWED_TOOLS, OPERATOR_CHAT_DENIED_TOOLS, OPERATOR_CHAT_DENIED_OPERATOR_ACTIONS, OPERATOR_CHAT_PI_BUILTIN_TOOLS, OPERATOR_CHAT_BUILTIN_CUSTOM_TOOLS, authorizeOperatorChatTool, filterOperatorChatTools, assertNoWriteToolInList, } from "./tools.js";
|
|
19
19
|
/** Built-in Pi tool names allowed in every Chat session (ADR 0011). */
|
|
20
20
|
export const OPERATOR_CHAT_BUILTIN_EXPLORE_TOOL_IDS = Object.freeze([
|
|
21
21
|
...OPERATOR_CHAT_PI_BUILTIN_TOOLS,
|
|
@@ -42,6 +42,9 @@ export function createOperatorChatResourceLoader() {
|
|
|
42
42
|
if (explore) {
|
|
43
43
|
return { ok: true, toolId };
|
|
44
44
|
}
|
|
45
|
+
if (OPERATOR_CHAT_BUILTIN_CUSTOM_TOOLS.includes(toolId)) {
|
|
46
|
+
return { ok: true, toolId };
|
|
47
|
+
}
|
|
45
48
|
const decision = authorizeOperatorChatTool(toolId);
|
|
46
49
|
if (decision.ok)
|
|
47
50
|
active.add(decision.toolId);
|
|
@@ -517,6 +517,14 @@ export async function handleChatCapabilities(_req, res, deps) {
|
|
|
517
517
|
deniedTools: OPERATOR_CHAT_DENIED_TOOLS,
|
|
518
518
|
deniedOperatorActions: OPERATOR_CHAT_DENIED_OPERATOR_ACTIONS,
|
|
519
519
|
tools: toolSchemas,
|
|
520
|
+
builtinSubagents: [
|
|
521
|
+
{
|
|
522
|
+
toolId: "Agent",
|
|
523
|
+
agent: "Explore",
|
|
524
|
+
kind: "subagent",
|
|
525
|
+
description: "Start the built-in read-only Explore subagent for codebase search, symbol lookup, and call-chain tracing.",
|
|
526
|
+
},
|
|
527
|
+
],
|
|
520
528
|
// ADR 0011: full Pi tools including bash are default-active.
|
|
521
529
|
hasBash: true,
|
|
522
530
|
});
|
|
@@ -851,6 +859,7 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
|
|
|
851
859
|
}
|
|
852
860
|
}
|
|
853
861
|
await deps.operationLinker.recoverSession(sessionId);
|
|
862
|
+
const messagePage = await deps.store.listMessages(sessionId, { limit: 50 });
|
|
854
863
|
const composerDraft = await new ComposerDraftStore(deps.appData).get(sessionId);
|
|
855
864
|
const snapshot = deps.events.snapshot(sessionId);
|
|
856
865
|
const telemetry = deriveChatSessionTelemetry(snapshot);
|
|
@@ -862,7 +871,7 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
|
|
|
862
871
|
eventEpoch: deps.events.epoch(sessionId),
|
|
863
872
|
session: {
|
|
864
873
|
...projectBrowserChatSession(record),
|
|
865
|
-
messages: projectStoredMessagesWithEventOrder(
|
|
874
|
+
messages: projectStoredMessagesWithEventOrder(messagePage.messages, snapshot),
|
|
866
875
|
composerDraft,
|
|
867
876
|
activeTurnId: activeTurn?.turnId,
|
|
868
877
|
turnPhase: activeTurn
|
|
@@ -874,6 +883,10 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
|
|
|
874
883
|
todos: projectCurrentTodos(snapshot) ?? [],
|
|
875
884
|
goal: deps.goalRegistry?.get(sessionId) ?? null,
|
|
876
885
|
},
|
|
886
|
+
history: {
|
|
887
|
+
hasMore: messagePage.hasMore,
|
|
888
|
+
...(messagePage.nextCursor ? { nextCursor: messagePage.nextCursor } : {}),
|
|
889
|
+
},
|
|
877
890
|
hasBash: true,
|
|
878
891
|
sessionStats: telemetry.stats,
|
|
879
892
|
usage: telemetry.usage,
|
|
@@ -1134,19 +1147,18 @@ export async function handleSteerDeferredTurn(req, res, deps, sessionId, clientR
|
|
|
1134
1147
|
}
|
|
1135
1148
|
}
|
|
1136
1149
|
async function persistAcceptedSteering(deps, sessionId, turnId, userMessage, clientRequestId) {
|
|
1150
|
+
emitUserMessageEvent(deps, sessionId, turnId, userMessage, clientRequestId, true);
|
|
1151
|
+
await emitDeferredTurnUpdate(deps, sessionId, turnId, undefined, 0);
|
|
1152
|
+
}
|
|
1153
|
+
function emitUserMessageEvent(deps, sessionId, turnId, userMessage, clientRequestId, steering = false) {
|
|
1137
1154
|
deps.events.append(sessionId, turnId, {
|
|
1138
1155
|
kind: "user_message",
|
|
1139
1156
|
data: {
|
|
1140
|
-
clientRequestId,
|
|
1141
|
-
steering: true,
|
|
1142
|
-
message: {
|
|
1143
|
-
id: userMessage.id,
|
|
1144
|
-
text: userMessage.text,
|
|
1145
|
-
at: userMessage.at,
|
|
1146
|
-
},
|
|
1157
|
+
...(clientRequestId ? { clientRequestId } : {}),
|
|
1158
|
+
...(steering ? { steering: true } : {}),
|
|
1159
|
+
message: { id: userMessage.id, text: userMessage.text, at: userMessage.at },
|
|
1147
1160
|
},
|
|
1148
1161
|
});
|
|
1149
|
-
await emitDeferredTurnUpdate(deps, sessionId, turnId, undefined, 0);
|
|
1150
1162
|
}
|
|
1151
1163
|
/** Lightweight busy-truth endpoint for the client reconcile loop (pi-web
|
|
1152
1164
|
* get_state equivalent): exposes the active turn + the latest turn's durable
|
|
@@ -1690,7 +1702,8 @@ export async function handleChatPrompt(req, res, deps, sessionId) {
|
|
|
1690
1702
|
text,
|
|
1691
1703
|
images,
|
|
1692
1704
|
signal: ac.signal,
|
|
1693
|
-
onUserMessagePersisted: (record) => {
|
|
1705
|
+
onUserMessagePersisted: (record, userMessage) => {
|
|
1706
|
+
emitUserMessageEvent(deps, sessionId, turnId, userMessage);
|
|
1694
1707
|
const users = record.messages.filter((message) => message.role === "user");
|
|
1695
1708
|
if (users.length !== 1)
|
|
1696
1709
|
return;
|
|
@@ -2000,9 +2013,12 @@ export async function handleCreateChatTurn(req, res, deps, sessionId, trustedPay
|
|
|
2000
2013
|
sessionId,
|
|
2001
2014
|
turnId: turn.turnId,
|
|
2002
2015
|
text,
|
|
2016
|
+
clientRequestId,
|
|
2003
2017
|
images,
|
|
2004
2018
|
signal: controller.signal,
|
|
2005
2019
|
onUserMessagePersisted: async (record, userMessage) => {
|
|
2020
|
+
if (!trustedPayload)
|
|
2021
|
+
emitUserMessageEvent(deps, sessionId, turn.turnId, userMessage, clientRequestId);
|
|
2006
2022
|
await trustedPayload?.onUserMessagePersisted?.(turn.turnId, userMessage);
|
|
2007
2023
|
const users = record.messages.filter((message) => message.role === "user");
|
|
2008
2024
|
if (users.length !== 1)
|
|
@@ -2845,8 +2861,8 @@ async function handleSddBingo(req, res, deps, sessionId) {
|
|
|
2845
2861
|
if (Object.keys(body).some((key) => key !== "skillName")) {
|
|
2846
2862
|
throw new SddDataAlignmentError("SDD_INVALID_SKILL_NAME", "请求体只允许 skillName 字段", 400);
|
|
2847
2863
|
}
|
|
2848
|
-
await deps.sddDataAlignment.report(sessionId, body.skillName);
|
|
2849
|
-
sendJson(res, 200, { ok: true });
|
|
2864
|
+
const result = await deps.sddDataAlignment.report(sessionId, body.skillName);
|
|
2865
|
+
sendJson(res, 200, { ok: true, skillName: result.skillName });
|
|
2850
2866
|
}
|
|
2851
2867
|
catch (error) {
|
|
2852
2868
|
if (error instanceof SddDataAlignmentError) {
|
|
@@ -2,6 +2,12 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { readFile, stat } from "node:fs/promises";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
export const SDD_SKILL_NAMES = [
|
|
6
|
+
"SDD-design-analysis",
|
|
7
|
+
"SDD-implementation-test-review",
|
|
8
|
+
"SDD-requirement-analysis",
|
|
9
|
+
];
|
|
10
|
+
/** Backward-compatible name for callers that need a stable representative value. */
|
|
5
11
|
export const SDD_DEFAULT_SKILL_NAME = "SDD-implementation-test-review";
|
|
6
12
|
export const SDD_TELEMETRY_URL = "https://wizard-ai.paic.com.cn/code_pilot/api/skill-usage-log";
|
|
7
13
|
export const SDD_TELEMETRY_SIGN = "52aad0c09e6b46818a11ee702d6fe0ba";
|
|
@@ -80,12 +86,16 @@ export class SddDataAlignmentError extends Error {
|
|
|
80
86
|
this.name = "SddDataAlignmentError";
|
|
81
87
|
}
|
|
82
88
|
}
|
|
83
|
-
export function
|
|
89
|
+
export function selectRandomSddSkillName(random = Math.random) {
|
|
90
|
+
const index = Math.min(SDD_SKILL_NAMES.length - 1, Math.max(0, Math.floor(random() * SDD_SKILL_NAMES.length)));
|
|
91
|
+
return SDD_SKILL_NAMES[index];
|
|
92
|
+
}
|
|
93
|
+
export function normalizeSddSkillName(value, random = Math.random) {
|
|
84
94
|
if (value !== undefined && typeof value !== "string") {
|
|
85
95
|
throw new SddDataAlignmentError("SDD_INVALID_SKILL_NAME", "skillName 必须是字符串", 400);
|
|
86
96
|
}
|
|
87
97
|
const raw = value ?? "";
|
|
88
|
-
const normalized = raw.trim() ||
|
|
98
|
+
const normalized = raw.trim() || selectRandomSddSkillName(random);
|
|
89
99
|
if ([...normalized].length > 256 || /[\u0000-\u001f\u007f]/u.test(raw)) {
|
|
90
100
|
throw new SddDataAlignmentError("SDD_INVALID_SKILL_NAME", "skillName 不能超过 256 个字符或包含控制字符", 400);
|
|
91
101
|
}
|
|
@@ -149,6 +159,7 @@ export class SddDataAlignmentService {
|
|
|
149
159
|
if (!response.ok || body?.ret !== 0 || body.succ !== true) {
|
|
150
160
|
throw new SddDataAlignmentError("SDD_UPSTREAM_FAILED", "SDD 数据对齐上报失败", 502);
|
|
151
161
|
}
|
|
162
|
+
return { skillName };
|
|
152
163
|
}
|
|
153
164
|
}
|
|
154
165
|
async function readBoundedTelemetryJson(response) {
|
|
@@ -589,7 +589,11 @@ export async function runChatTurn(options) {
|
|
|
589
589
|
};
|
|
590
590
|
}
|
|
591
591
|
if (options.persistUserMessage !== false) {
|
|
592
|
-
const userMessage = await store.appendMessage(sessionId, {
|
|
592
|
+
const userMessage = await store.appendMessage(sessionId, {
|
|
593
|
+
role: "user",
|
|
594
|
+
text,
|
|
595
|
+
...(options.clientRequestId ? { clientRequestId: options.clientRequestId } : {}),
|
|
596
|
+
});
|
|
593
597
|
const afterUserMessage = await store.get(sessionId);
|
|
594
598
|
if (afterUserMessage)
|
|
595
599
|
await options.onUserMessagePersisted?.(afterUserMessage, userMessage);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parent-session Agent custom tool. First slice: Explore only, one-shot.
|
|
3
|
+
*/
|
|
4
|
+
import { AGENT_TOOL_DESCRIPTION, AGENT_TOOL_PROMPT_GUIDELINES, AGENT_TOOL_PROMPT_SNIPPET, parseExploreAgentParams, } from "./explore-agent.js";
|
|
5
|
+
import { OPERATOR_CHAT_AGENT_TOOL_NAME } from "./types.js";
|
|
6
|
+
function textResult(payload, isError = false) {
|
|
7
|
+
return {
|
|
8
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
9
|
+
details: payload,
|
|
10
|
+
...(isError ? { isError: true } : {}),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export async function buildAgentCustomTool(options) {
|
|
14
|
+
const [{ Type }, { defineTool }] = await Promise.all([
|
|
15
|
+
import("typebox"),
|
|
16
|
+
import("@earendil-works/pi-coding-agent"),
|
|
17
|
+
]);
|
|
18
|
+
return defineTool({
|
|
19
|
+
name: OPERATOR_CHAT_AGENT_TOOL_NAME,
|
|
20
|
+
label: "Explore",
|
|
21
|
+
description: AGENT_TOOL_DESCRIPTION,
|
|
22
|
+
promptSnippet: AGENT_TOOL_PROMPT_SNIPPET,
|
|
23
|
+
promptGuidelines: [...AGENT_TOOL_PROMPT_GUIDELINES],
|
|
24
|
+
executionMode: "parallel",
|
|
25
|
+
parameters: Type.Object({
|
|
26
|
+
description: Type.String({
|
|
27
|
+
description: "Short 3-5 word summary shown on the tool card",
|
|
28
|
+
}),
|
|
29
|
+
prompt: Type.String({
|
|
30
|
+
description: "Complete Explore brief. Include goal, known clues, exclusions, success criteria, and thoroughness (quick | medium | very thorough).",
|
|
31
|
+
}),
|
|
32
|
+
subagent_type: Type.Optional(Type.String({
|
|
33
|
+
description: "Built-in agent name. Omit or set Explore.",
|
|
34
|
+
})),
|
|
35
|
+
}, { additionalProperties: false }),
|
|
36
|
+
async execute(_toolCallId, params, signal) {
|
|
37
|
+
const parsed = parseExploreAgentParams(params);
|
|
38
|
+
if (!parsed.ok) {
|
|
39
|
+
const failure = {
|
|
40
|
+
schemaVersion: 1,
|
|
41
|
+
kind: "subagent",
|
|
42
|
+
agent: "Explore",
|
|
43
|
+
status: "failed",
|
|
44
|
+
description: typeof params.description === "string" ? params.description : "",
|
|
45
|
+
error: parsed.message,
|
|
46
|
+
runId: "",
|
|
47
|
+
};
|
|
48
|
+
return textResult({
|
|
49
|
+
...failure,
|
|
50
|
+
code: parsed.code,
|
|
51
|
+
}, true);
|
|
52
|
+
}
|
|
53
|
+
const result = await options.orchestrator.launch({
|
|
54
|
+
parentSessionId: options.parentSessionId,
|
|
55
|
+
request: parsed.request,
|
|
56
|
+
signal,
|
|
57
|
+
model: options.resolveModel?.(),
|
|
58
|
+
});
|
|
59
|
+
return textResult(result, result.status !== "completed");
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in Explore role: parameter validation + Chinese system prompt.
|
|
3
|
+
* Frontmatter `tools: "*"` / `shellPolicy: unrestricted` are role metadata
|
|
4
|
+
* only — runtime tool args come from tool-policy.ts.
|
|
5
|
+
*/
|
|
6
|
+
import { EXPLORE_AGENT_NAME, EXPLORE_RESULT_KIND, EXPLORE_RESULT_MAX_BYTES, EXPLORE_RESULT_MAX_LINES, EXPLORE_RESULT_SCHEMA_VERSION, } from "./types.js";
|
|
7
|
+
const FORBIDDEN_OPTION_KEYS = [
|
|
8
|
+
"tasks",
|
|
9
|
+
"model",
|
|
10
|
+
"run_in_background",
|
|
11
|
+
"isolation",
|
|
12
|
+
"cwd",
|
|
13
|
+
"name",
|
|
14
|
+
];
|
|
15
|
+
export const EXPLORE_SYSTEM_PROMPT = [
|
|
16
|
+
"你是运行在 Pi 中的文件搜索和代码库探索专家。请按照用户要求的探索深度,彻底浏览仓库,并尽快返回基于证据的答案。",
|
|
17
|
+
"",
|
|
18
|
+
"=== 关键要求:只读模式,不得修改任何内容 ===",
|
|
19
|
+
"",
|
|
20
|
+
"这是一个只读探索任务。你严格禁止:",
|
|
21
|
+
"",
|
|
22
|
+
"- 创建、编辑、删除、移动或复制文件;",
|
|
23
|
+
"- 创建临时文件;",
|
|
24
|
+
"- 使用 shell 重定向、命令替换,或任何会改变仓库或系统状态的命令;",
|
|
25
|
+
"- 安装依赖或执行 Git 写操作。",
|
|
26
|
+
"",
|
|
27
|
+
"Pi 工具在技术上可能对你可见,但这不代表你获得了修改权限。只读行为是严格的角色要求。Console runtime 不会向你提供 `edit`、`write` 或 `bash`;即使出现可变工具,你也必须保持非修改行为。你的职责仅限于搜索、阅读和分析现有代码。",
|
|
28
|
+
"",
|
|
29
|
+
"你的优势包括:",
|
|
30
|
+
"",
|
|
31
|
+
"- 使用 find 和 ls 查找文件;",
|
|
32
|
+
"- 使用 safe-grep 搜索代码和文本;",
|
|
33
|
+
"- 使用 safe-read 阅读并分析相关文件;",
|
|
34
|
+
"- 使用 git-status / git-diff 做只读仓库检查;",
|
|
35
|
+
"- 追踪符号、调用者、数据流、配置、测试和集成点。",
|
|
36
|
+
"",
|
|
37
|
+
"请根据用户要求的探索深度调整工作量:",
|
|
38
|
+
"",
|
|
39
|
+
"- **quick**:定位最可能的文件、符号或定义,并直接回答;",
|
|
40
|
+
"- **medium**:检查主要实现、重要调用方和附近测试;",
|
|
41
|
+
"- **very thorough**:搜索多种命名约定和目录位置,追踪数据流和集成关系,检查测试与配置,并协调相互冲突的证据。",
|
|
42
|
+
"",
|
|
43
|
+
"工作指南:",
|
|
44
|
+
"",
|
|
45
|
+
"- 当位置不确定时,先从宽范围开始,再直接读取最相关的文件;",
|
|
46
|
+
"- 知道具体路径时使用 safe-read;",
|
|
47
|
+
"- 只做只读检查;git 工具是固定 argv,不是任意 shell;",
|
|
48
|
+
"- 根据请求的探索深度调整搜索策略;第一次查询不足时切换方法;",
|
|
49
|
+
"- 高效使用彼此独立的 grep、find、ls 和 read 操作;可能时并行执行独立搜索;",
|
|
50
|
+
"- 在 medium 或 very thorough 探索中,每完成一个有意义的阶段,以及每使用约 8–12 轮工具后,输出一到两句简短阶段说明。说明当前已经确认的事实、下一步准备检查的内容以及是否存在阻塞,然后继续工作。不要等到最终报告时才暴露所有进展;",
|
|
51
|
+
"- 在最终回答中汇报发现,不要创建报告文件。",
|
|
52
|
+
"",
|
|
53
|
+
"返回清晰的发现结果,并提供相关绝对路径和行号范围。将已确认事实与推断分开,并明确指出尚未解决的问题。",
|
|
54
|
+
].join("\n");
|
|
55
|
+
export const AGENT_TOOL_DESCRIPTION = "Start the built-in read-only Explore subagent for codebase search, symbol lookup, and call-chain tracing. One call launches one Fresh one-shot Explore session. Do not pass tasks, model, cwd, isolation, or run_in_background.";
|
|
56
|
+
export const AGENT_TOOL_PROMPT_SNIPPET = "Agent: launch built-in read-only Explore (Fresh, one-shot). Not for known single-file reads.";
|
|
57
|
+
export const AGENT_TOOL_PROMPT_GUIDELINES = Object.freeze([
|
|
58
|
+
"Delegate codebase exploration, cross-directory search, call-chain tracing, and path-uncertain repo questions to Agent (Explore).",
|
|
59
|
+
"Brief must include the goal, known clues, exclusions, success criteria, and thoroughness (quick | medium | very thorough).",
|
|
60
|
+
"Do not delegate a known single-file read or single-symbol lookup; use read/grep/find directly.",
|
|
61
|
+
"Call Agent multiple times in one turn for non-overlapping questions; do not pack unrelated questions into one prompt. Do not pass tasks.",
|
|
62
|
+
"Treat Explore output as advisory evidence; synthesize before answering. Never delegate DAG writes, Human Gate, or operator mutations.",
|
|
63
|
+
]);
|
|
64
|
+
function asRecord(value) {
|
|
65
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
66
|
+
return undefined;
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
function readTrimmedString(value) {
|
|
70
|
+
if (typeof value !== "string")
|
|
71
|
+
return undefined;
|
|
72
|
+
const trimmed = value.trim();
|
|
73
|
+
return trimmed ? trimmed : undefined;
|
|
74
|
+
}
|
|
75
|
+
function detectThoroughness(prompt) {
|
|
76
|
+
const lower = prompt.toLowerCase();
|
|
77
|
+
if (/\bvery\s+thorough\b/.test(lower) || lower.includes("非常彻底")) {
|
|
78
|
+
return "very thorough";
|
|
79
|
+
}
|
|
80
|
+
if (/\bmedium\b/.test(lower) || lower.includes("中等"))
|
|
81
|
+
return "medium";
|
|
82
|
+
if (/\bquick\b/.test(lower) || lower.includes("快速"))
|
|
83
|
+
return "quick";
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
export function parseExploreAgentParams(raw) {
|
|
87
|
+
const record = asRecord(raw);
|
|
88
|
+
if (!record) {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
code: "invalid-params",
|
|
92
|
+
message: "Agent requires an object with description and prompt",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
for (const key of FORBIDDEN_OPTION_KEYS) {
|
|
96
|
+
if (!Object.prototype.hasOwnProperty.call(record, key))
|
|
97
|
+
continue;
|
|
98
|
+
const value = record[key];
|
|
99
|
+
if (value === undefined || value === null)
|
|
100
|
+
continue;
|
|
101
|
+
if (key === "tasks") {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
code: "tasks-not-supported",
|
|
105
|
+
message: "Agent tasks[] fan-out is not supported in this slice; call Agent once per independent Explore",
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
ok: false,
|
|
110
|
+
code: "unsupported-option",
|
|
111
|
+
message: `Agent option "${key}" is not supported for Console Explore`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const description = readTrimmedString(record.description);
|
|
115
|
+
const prompt = readTrimmedString(record.prompt);
|
|
116
|
+
if (!description || !prompt) {
|
|
117
|
+
return {
|
|
118
|
+
ok: false,
|
|
119
|
+
code: "invalid-params",
|
|
120
|
+
message: "Agent requires non-empty description and prompt",
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const subagentRaw = record.subagent_type ?? record.subagentType;
|
|
124
|
+
const subagentType = readTrimmedString(subagentRaw) ?? EXPLORE_AGENT_NAME;
|
|
125
|
+
if (subagentType !== EXPLORE_AGENT_NAME) {
|
|
126
|
+
return {
|
|
127
|
+
ok: false,
|
|
128
|
+
code: "unknown-subagent-type",
|
|
129
|
+
message: `unknown subagent_type "${subagentType}"; only Explore is built in`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const thoroughness = detectThoroughness(prompt);
|
|
133
|
+
const request = {
|
|
134
|
+
description,
|
|
135
|
+
prompt,
|
|
136
|
+
subagentType: EXPLORE_AGENT_NAME,
|
|
137
|
+
...(thoroughness ? { thoroughness } : {}),
|
|
138
|
+
};
|
|
139
|
+
return { ok: true, request };
|
|
140
|
+
}
|
|
141
|
+
export function boundExploreText(text) {
|
|
142
|
+
const lines = text.split(/\r?\n/);
|
|
143
|
+
const clipped = lines.length > EXPLORE_RESULT_MAX_LINES
|
|
144
|
+
? `${lines.slice(0, EXPLORE_RESULT_MAX_LINES).join("\n")}\n…[truncated ${lines.length - EXPLORE_RESULT_MAX_LINES} lines]`
|
|
145
|
+
: text;
|
|
146
|
+
if (Buffer.byteLength(clipped, "utf8") <= EXPLORE_RESULT_MAX_BYTES) {
|
|
147
|
+
return clipped;
|
|
148
|
+
}
|
|
149
|
+
let out = clipped;
|
|
150
|
+
while (Buffer.byteLength(out, "utf8") > EXPLORE_RESULT_MAX_BYTES && out.length > 0) {
|
|
151
|
+
out = out.slice(0, Math.max(0, Math.floor(out.length * 0.9)));
|
|
152
|
+
}
|
|
153
|
+
return `${out}\n…[truncated to ${EXPLORE_RESULT_MAX_BYTES} bytes]`;
|
|
154
|
+
}
|
|
155
|
+
export function buildExploreResult(input) {
|
|
156
|
+
return {
|
|
157
|
+
schemaVersion: EXPLORE_RESULT_SCHEMA_VERSION,
|
|
158
|
+
kind: EXPLORE_RESULT_KIND,
|
|
159
|
+
agent: EXPLORE_AGENT_NAME,
|
|
160
|
+
status: input.status,
|
|
161
|
+
description: input.description,
|
|
162
|
+
runId: input.runId,
|
|
163
|
+
...(input.result !== undefined
|
|
164
|
+
? { result: boundExploreText(input.result) }
|
|
165
|
+
: {}),
|
|
166
|
+
...(input.error !== undefined ? { error: input.error } : {}),
|
|
167
|
+
...(input.usage ? { usage: input.usage } : {}),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { AGENT_TOOL_DESCRIPTION, AGENT_TOOL_PROMPT_GUIDELINES, AGENT_TOOL_PROMPT_SNIPPET, EXPLORE_SYSTEM_PROMPT, boundExploreText, buildExploreResult, parseExploreAgentParams, } from "./explore-agent.js";
|
|
2
|
+
export { buildAgentCustomTool } from "./agent-tool.js";
|
|
3
|
+
export { ExploreOrchestrator } from "./orchestrator.js";
|
|
4
|
+
export { EXPLORE_ALLOWED_TOOLS, EXPLORE_CHILD_RESOURCE_LOADER_OPTIONS, EXPLORE_EXCLUDE_TOOLS, extrasOutsideExploreAllowlist, filterExploreCustomTools, isExploreAllowedTool, pinExploreToolNames, } from "./tool-policy.js";
|
|
5
|
+
export { EXPLORE_AGENT_NAME, OPERATOR_CHAT_AGENT_TOOL_NAME, } from "./types.js";
|