@tea-agent/loop-agent 0.37.0 → 0.37.1-beta.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/AGENTS.md +2 -6
- package/CHANGELOG.md +71 -144
- package/README.md +1 -1
- package/bin/loop-agent.js +1 -37
- package/dist/application/task-lifecycle/advance.js +0 -1
- package/dist/application/task-lifecycle/observe.js +0 -15
- package/dist/application/task-lifecycle/plan-transitions.js +0 -15
- package/dist/cli/command-definitions.js +0 -7
- package/dist/cli/program.js +3 -8
- package/dist/commands/init-upgrade.js +19 -351
- package/dist/commands/init.js +67 -14
- package/dist/commands/run-dag-progress.js +0 -14
- package/dist/commands/task-advance.js +3 -33
- package/dist/executors/dag-pi-executor.js +30 -47
- package/dist/executors/pi-sdk-executor.js +0 -34
- package/dist/executors/shell-executor.js +95 -6
- package/dist/shared/operator/capabilities.js +13 -200
- package/dist/shared/package-metadata.js +0 -42
- package/dist/task/contract/project.js +0 -4
- package/dist/task/source-prepare/completeness.js +0 -53
- package/dist/task/source-prepare/parse-intent.js +12 -82
- package/dist/task/source-prepare/prepare.js +5 -102
- package/dist/task/source-prepare/semantic-intake.js +23 -144
- package/dist/worker/console/chat/artifact-card.js +1 -8
- package/dist/worker/console/chat/chat-event-store.js +0 -152
- package/dist/worker/console/chat/human-gate-card.js +1 -9
- package/dist/worker/console/chat/operation-card.js +2 -71
- package/dist/worker/console/chat/pi-runtime.js +62 -111
- package/dist/worker/console/chat/routes.js +10 -43
- package/dist/worker/console/chat/session-store.js +1 -9
- package/dist/worker/console/chat/shortcuts.js +7 -9
- package/dist/worker/console/chat/turn-process.js +23 -204
- package/dist/worker/console/chat/workspace-landing.js +1 -2
- package/dist/worker/console/operation-runner.js +6 -155
- package/dist/worker/console/operator-actions.js +14 -391
- package/dist/worker/console/operator-user-error.js +0 -4
- package/dist/worker/console/recovery-cta.js +3 -50
- package/dist/worker/console/static/assets/index-HX1pbOyl.css +1 -0
- package/dist/worker/console/static/assets/index-M0BLEBfh.js +56 -0
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +9 -13
- package/dist/worker/console/static-src/app/useOperatorActions.js +2 -4
- package/dist/worker/console/static-src/app/useRecoveryActions.js +56 -65
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +1 -73
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +30 -114
- package/dist/worker/console/static-src/operator-chat/refs.js +0 -3
- package/dist/worker/console/static-src/operator-chat/spatial-overlay.js +1 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +13 -67
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -12
- package/dist/worker/console/static-src/operator-chat/useComposer.js +8 -45
- package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -7
- package/dist/worker/loop-agent/loop-agent-client.js +3 -17
- package/dist/worker/observability/read-model.js +0 -20
- package/dist/worker/observe/spec-evidence.js +8 -3
- package/dist/worker/observe/static/operator-chrome.d.ts +0 -1
- package/dist/worker/observe/static/operator-chrome.js +3 -10
- package/dist/worker/observe/static/views/dag-inspector.js +71 -6
- package/dist/worker/observe/static/views/dag.js +0 -12
- package/dist/worker/preflight.js +1 -2
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +707 -37
- package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +109 -7
- package/dist/workflows/dag/backend-test-module-stem.js +5 -0
- package/dist/workflows/dag/backend-test-pytest-collection.js +345 -24
- package/dist/workflows/dag/backend-test-scenario-param.js +890 -164
- package/dist/workflows/dag/backend-test-writer-completeness.js +47 -16
- package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
- package/dist/workflows/dag/dynamic-runtime/shared.js +1 -9
- package/dist/workflows/dag/frontend-implementation-contract.js +39 -233
- package/dist/workflows/dag/frontend-prewrite-gate.js +61 -364
- package/dist/workflows/dag/frontend-repair.js +18 -219
- package/dist/workflows/dag/frontend-verification-trace.js +32 -47
- package/dist/workflows/dag/init-hybrid.js +82 -165
- package/dist/workflows/dag/node-execution.js +0 -89
- package/dist/workflows/dag/recovery-recommendation.js +0 -58
- package/dist/workflows/dag/runner.js +15 -333
- package/dist/workflows/dag/scheduler.js +3 -257
- package/dist/workflows/dag/types.js +9 -130
- package/docs/README.md +3 -3
- package/docs/architecture/evolution.md +67 -102
- package/docs/templates/backend-test-dag.json +50 -32
- package/docs/templates/init-managed-agents.md +2 -5
- package/harness.json +2 -2
- package/package.json +3 -9
- package/skills/loop-agent/SKILL.md +0 -1
- package/skills/loop-agent/references/command-reference.md +0 -4
- package/dist/build-stamp.json +0 -6
- package/dist/commands/dag-request-interrupt.js +0 -20
- package/dist/worker/console/chat/assistant-content.js +0 -121
- package/dist/worker/console/chat/semantic-activity.js +0 -477
- package/dist/worker/console/operation-run-facts.js +0 -190
- package/dist/worker/console/operation-wait.js +0 -355
- package/dist/worker/console/recovery-error-copy.js +0 -198
- package/dist/worker/console/static/assets/abnfDiagram-N423BO3Z-DSvF6RXQ.js +0 -1
- package/dist/worker/console/static/assets/arc-DuI4ogtJ.js +0 -1
- package/dist/worker/console/static/assets/architectureDiagram-T3A2C74G-DdBbgD4y.js +0 -36
- package/dist/worker/console/static/assets/blockDiagram-VBNYF7ZC-xQC2HELm.js +0 -132
- package/dist/worker/console/static/assets/c4Diagram-5PPSVZJV-DPMSgwIZ.js +0 -10
- package/dist/worker/console/static/assets/channel-DLVz9TYW.js +0 -1
- package/dist/worker/console/static/assets/chunk-2GRJ4B5K-WTEKTxin.js +0 -1
- package/dist/worker/console/static/assets/chunk-2Q5K7J3B-B6vZ0Pv_.js +0 -1
- package/dist/worker/console/static/assets/chunk-5RXB4S5H-BrerNAix.js +0 -231
- package/dist/worker/console/static/assets/chunk-5VM5RSS4-D_ch2aaI.js +0 -15
- package/dist/worker/console/static/assets/chunk-6Q2QTUOP-VvfacNrq.js +0 -88
- package/dist/worker/console/static/assets/chunk-GF5L2VYU-B-uGFIg2.js +0 -206
- package/dist/worker/console/static/assets/chunk-JWPE2WC7-BlysCtod.js +0 -1
- package/dist/worker/console/static/assets/chunk-KBJHAD2P-BjAUAfcT.js +0 -1
- package/dist/worker/console/static/assets/chunk-RYQCIY6F-BeZnBmb-.js +0 -1
- package/dist/worker/console/static/assets/chunk-XXDRQBXY-Bbfe3UJG.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BeAuGcO9.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BeAuGcO9.js +0 -1
- package/dist/worker/console/static/assets/cose-bilkent-JH36ORCC-BKJQnYVM.js +0 -1
- package/dist/worker/console/static/assets/cynefin-VYW2F7L2-B1wtI3hU.js +0 -166
- package/dist/worker/console/static/assets/cynefinDiagram-MW4NZA55-DCF6DBSu.js +0 -62
- package/dist/worker/console/static/assets/cytoscape.esm-yzknjiTM.js +0 -321
- package/dist/worker/console/static/assets/dagre-VZM6K2ZE-BJyNGRlP.js +0 -4
- package/dist/worker/console/static/assets/defaultLocale-DX6XiGOO.js +0 -1
- package/dist/worker/console/static/assets/diagram-7IWD3JNH-B7j1-VsZ.js +0 -30
- package/dist/worker/console/static/assets/diagram-B4RE2ZJO-BREJ140a.js +0 -3
- package/dist/worker/console/static/assets/diagram-LBJQPF4R-CDPHmHGH.js +0 -24
- package/dist/worker/console/static/assets/diagram-Q27KOJAE-BtZLrez1.js +0 -24
- package/dist/worker/console/static/assets/diagram-UB23O5K3-mzybu8oU.js +0 -41
- package/dist/worker/console/static/assets/ebnfDiagram-BXEA7PRR-Dk3I2uO6.js +0 -1
- package/dist/worker/console/static/assets/erDiagram-JOGREHBK-BT97u_tQ.js +0 -85
- package/dist/worker/console/static/assets/flowDiagram-UKHOOZJN-CMOtYzui.js +0 -156
- package/dist/worker/console/static/assets/ganttDiagram-PKOTCBZU-DiNydkuY.js +0 -292
- package/dist/worker/console/static/assets/gitGraphDiagram-DS77QQ5N-Cwt6fLkl.js +0 -106
- package/dist/worker/console/static/assets/graph-DOmOIIwC.js +0 -1
- package/dist/worker/console/static/assets/index-DQxiso1w.js +0 -325
- package/dist/worker/console/static/assets/index-_j0Hzo69.css +0 -1
- package/dist/worker/console/static/assets/infoDiagram-6WML65LV-AsGIGKKB.js +0 -2
- package/dist/worker/console/static/assets/init-Gi6I4Gst.js +0 -1
- package/dist/worker/console/static/assets/ishikawaDiagram-WSZJBQD7-BL8ITZh3.js +0 -70
- package/dist/worker/console/static/assets/journeyDiagram-NVQOT4AX-VPKAUX8M.js +0 -139
- package/dist/worker/console/static/assets/kanban-definition-27J2QSJJ-BL56hfGp.js +0 -89
- package/dist/worker/console/static/assets/layout-D-LzfAck.js +0 -1
- package/dist/worker/console/static/assets/linear-BmSG3nIZ.js +0 -1
- package/dist/worker/console/static/assets/map-DxJ2ADlA.js +0 -1
- package/dist/worker/console/static/assets/mermaid.core-DWGK9kwP.js +0 -308
- package/dist/worker/console/static/assets/mindmap-definition-FAOFIHXS--vvKLjo0.js +0 -96
- package/dist/worker/console/static/assets/ordinal-Cboi1Yqb.js +0 -1
- package/dist/worker/console/static/assets/pegDiagram-VL7TDLO6-B41mxb2-.js +0 -1
- package/dist/worker/console/static/assets/pieDiagram-7S7Q4E2Y-DTlu77sw.js +0 -39
- package/dist/worker/console/static/assets/quadrantDiagram-CIZ2JOQS-Bk5A7alv.js +0 -7
- package/dist/worker/console/static/assets/railroadDiagram-AXF67PYL-Csf9jzQy.js +0 -1
- package/dist/worker/console/static/assets/requirementDiagram-LRYGKXZP-CeptoSNx.js +0 -84
- package/dist/worker/console/static/assets/sankeyDiagram-W5VNT64P-A-DLCLer.js +0 -40
- package/dist/worker/console/static/assets/sequenceDiagram-SI44F4Z6-22VbPdOI.js +0 -162
- package/dist/worker/console/static/assets/sizeCapture-X5ZJPWSS-DWvAyBC9.js +0 -1
- package/dist/worker/console/static/assets/stateDiagram-OKZ733FA-qICZ75yT.js +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DzKvfHTX.js +0 -1
- package/dist/worker/console/static/assets/swimlanes-SLNWSIFB-xi7lcMyp.js +0 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Cxqr_qM1.js +0 -8
- package/dist/worker/console/static/assets/timeline-definition-Z64GVDOM-Bu6Nl6O2.js +0 -120
- package/dist/worker/console/static/assets/vennDiagram-T6HMQDX7-BzMz4Bn9.js +0 -34
- package/dist/worker/console/static/assets/wardleyDiagram-T6FBY63Y-CxaJnzc5.js +0 -78
- package/dist/worker/console/static/assets/xychartDiagram-ELKLHX3M-5JK-omQK.js +0 -7
- package/dist/worker/console/static/fonts/katex/KaTeX_AMS-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-Italic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Math-Italic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Script-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size1-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size2-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size3-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size4-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/dist/worker/console/static-src/operator-chat/activity-journey.js +0 -125
- package/dist/worker/console/static-src/operator-chat/activity-rail-presentation.js +0 -73
- package/dist/worker/console/static-src/operator-chat/activity-references.js +0 -20
- package/dist/worker/console/static-src/operator-chat/slash-palette-layout.js +0 -24
- package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +0 -141
- package/dist/worker/console/static-src/operator-chat/useActivityRailTransition.js +0 -59
- package/dist/worker/observability/interrupt-eligibility.js +0 -264
- package/dist/workflows/dag/contract-output-registry.js +0 -14
- package/dist/workflows/dag/contract-validator-registrations.js +0 -8
- package/dist/workflows/dag/frontend-recovery-plan.js +0 -73
- package/dist/workflows/dag/frontend-recovery-root-manifest.js +0 -123
- package/dist/workflows/dag/frontend-recovery-run.js +0 -539
- package/dist/workflows/dag/frontend-writer-recovery.js +0 -106
- package/dist/workflows/dag/frontend-writer-rollback.js +0 -821
- package/dist/workflows/dag/interrupt-request.js +0 -559
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
import { createHash, randomBytes } from "node:crypto";
|
|
29
29
|
import { access } from "node:fs/promises";
|
|
30
30
|
import path from "node:path";
|
|
31
|
-
import { extractAssistantContentBlocks, extractAssistantText, isAssistantSdkMessage, } from "./assistant-content.js";
|
|
32
31
|
import { projectCompactSnapshot, } from "./chat-event-store.js";
|
|
33
32
|
import { extractUsageSample } from "./usage.js";
|
|
34
33
|
import { OPERATOR_CHAT_ALLOWED_TOOLS, authorizeOperatorChatTool, assertNoWriteToolInList, } from "./tools.js";
|
|
@@ -58,12 +57,12 @@ import { RUNTIME_CONTEXT_TEXT_MAX, redactRuntimeText, } from "./runtime-context.
|
|
|
58
57
|
* (AC-01: ≤ 1900 chars and ≤ 80% of the 2498-char baseline).
|
|
59
58
|
*/
|
|
60
59
|
export const OPERATOR_CHAT_SYSTEM_PROMPT_BASE = [
|
|
61
|
-
"You are General Operator Chat.",
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"On failure
|
|
66
|
-
"Continue until success, user stop, or no safe recovery remains
|
|
60
|
+
"You are the General Operator Chat for loop-agent / agent-worker.",
|
|
61
|
+
"Operate through operator_* tools first. Pi read/write/edit/bash/grep/find/ls are available, but obey the loaded repository AGENTS.md. apply_patch, full-tools, shell, and coding-chat are denied alternate runtimes. Prefer safe-read/safe-grep for sensitive probes.",
|
|
62
|
+
"If a repository has no loop-agent harness and the user requests initialization, run `loop-agent init instructions --repo-root .` then `loop-agent init --repo-root . --profile full --merge`; finish the generated setup, init doctor, inspect, docs audit, and quick verification. For updates use `loop-agent init upgrade --repo-root . --json` until stable; use init check-update only for an explicitly read-only request.",
|
|
63
|
+
"After a DAG is started or accepted, do not end on accepted/queued/running or an operationId. Supervise it to a terminal outcome. Poll operationGet, task status, dagReport, and dagDoctor after about 15 seconds on start/change, every 30 seconds during progress, and every 60 seconds after 3 minutes unchanged. Report only meaningful node/rank changes, review/verify/closeout, recovery, liveness concerns, and terminal outcomes.",
|
|
64
|
+
"On failure read primaryFailure, primaryRecovery, and doctor evidence. If meaningful progress exists, wait. Otherwise use a fresh eligible dagRerunPlan and rerun its safe node; when ineligible follow AGENTS.md/runtime recovery for same-task rerun/advance, resume, or Worker retry. Auto-approve only a bounded writeSet inside allowedPaths, outside forbiddenPaths, without broad/destructive risk, and with structured verification.",
|
|
65
|
+
"Continue until success, user stop, or no safe eligible recovery remains because limits, bindings, auth/quota recovery, or required external authorization are exhausted. Never create a new task for a transient failure or replace repair-pi with direct edits.",
|
|
67
66
|
].join("\n");
|
|
68
67
|
/** Compose the inspectable system prompt actually injected into Operator Chat. */
|
|
69
68
|
export function composeOperatorChatSystemPrompt(input) {
|
|
@@ -564,7 +563,28 @@ export function projectRuntimeSnapshot(input) {
|
|
|
564
563
|
hasBash: input.hasBash,
|
|
565
564
|
};
|
|
566
565
|
}
|
|
567
|
-
|
|
566
|
+
/**
|
|
567
|
+
* Extract the latest assistant text fragment from an SDK message object.
|
|
568
|
+
* Tolerant of multiple message shapes the SDK emits.
|
|
569
|
+
*/
|
|
570
|
+
export function extractAssistantText(message) {
|
|
571
|
+
if (!message || typeof message !== "object")
|
|
572
|
+
return "";
|
|
573
|
+
const m = message;
|
|
574
|
+
if (typeof m.text === "string")
|
|
575
|
+
return m.text;
|
|
576
|
+
const contents = Array.isArray(m.content) ? m.content : [];
|
|
577
|
+
const parts = Array.isArray(m.parts) ? m.parts : [];
|
|
578
|
+
const segments = [];
|
|
579
|
+
for (const c of [...contents, ...parts]) {
|
|
580
|
+
if (!c || typeof c !== "object")
|
|
581
|
+
continue;
|
|
582
|
+
const seg = c;
|
|
583
|
+
if (typeof seg.text === "string")
|
|
584
|
+
segments.push(seg.text);
|
|
585
|
+
}
|
|
586
|
+
return segments.join("");
|
|
587
|
+
}
|
|
568
588
|
function readSessionManagerId(manager) {
|
|
569
589
|
if (!manager || typeof manager !== "object")
|
|
570
590
|
return undefined;
|
|
@@ -678,12 +698,13 @@ export class ConsolePiRuntime {
|
|
|
678
698
|
* closure state).
|
|
679
699
|
*/
|
|
680
700
|
async buildResourceLoaderOptions(base = {}) {
|
|
701
|
+
const runtime = this;
|
|
681
702
|
return {
|
|
682
703
|
...base,
|
|
683
704
|
skillsOverride: (current) => {
|
|
684
705
|
// Synchronous override surface: use last-known prefs via a sync
|
|
685
706
|
// fail-closed path. Prefer async cache filled by ensurePrefs.
|
|
686
|
-
const prefs =
|
|
707
|
+
const prefs = runtime.cachedSkillPrefs ?? {
|
|
687
708
|
schemaVersion: 1,
|
|
688
709
|
skills: {},
|
|
689
710
|
};
|
|
@@ -903,27 +924,10 @@ export class ConsolePiRuntime {
|
|
|
903
924
|
const customTools = await this.loadCustomTools();
|
|
904
925
|
if (this.disposedSessions.has(sessionId))
|
|
905
926
|
return;
|
|
906
|
-
// The SDK filters BOTH built-in tools and customTools against
|
|
907
|
-
// `tools` (allowed-tool names) inside _refreshToolRegistry:
|
|
908
|
-
// isAllowedTool = (!allowedToolNames || allowedToolNames.has(name))
|
|
909
|
-
// && !excludedToolNames.has(name)
|
|
910
|
-
// Passing only OPERATOR_CHAT_BUILTIN_EXPLORE_TOOLS here silently dropped
|
|
911
|
-
// every custom operator tool (prepareDagExecution / runDag /
|
|
912
|
-
// operationWait / safe-read / git-status / ...) from the registry, so the
|
|
913
|
-
// model could only ever see bash/read/write/edit/grep/find/ls. The
|
|
914
|
-
// allowlist must cover the full tool surface that is later activated via
|
|
915
|
-
// setActiveToolsByName(computeOperatorChatActiveToolNames(session)) —
|
|
916
|
-
// operator actions + built-in explore tools + safe explore tools.
|
|
917
|
-
// Hard write/coding channels stay blocked via excludeTools below (they
|
|
918
|
-
// are removed even when present in the allowed list).
|
|
919
927
|
const { session } = await this.bindings.createSessionFromServices({
|
|
920
928
|
services,
|
|
921
929
|
sessionManager: init.sessionManager,
|
|
922
|
-
tools: [
|
|
923
|
-
...OPERATOR_CHAT_BUILTIN_EXPLORE_TOOLS,
|
|
924
|
-
...OPERATOR_CHAT_ALLOWED_TOOLS,
|
|
925
|
-
...OPERATOR_CHAT_SAFE_EXPLORE_TOOL_IDS,
|
|
926
|
-
],
|
|
930
|
+
tools: [...OPERATOR_CHAT_BUILTIN_EXPLORE_TOOLS],
|
|
927
931
|
excludeTools: [
|
|
928
932
|
"apply_patch",
|
|
929
933
|
"apply-patch",
|
|
@@ -1276,7 +1280,6 @@ export class ConsolePiRuntime {
|
|
|
1276
1280
|
* session is not active — callers fail closed instead of fabricating data.
|
|
1277
1281
|
*/
|
|
1278
1282
|
/**
|
|
1279
|
-
* ConsolePiRuntime.listSlashCommands
|
|
1280
1283
|
* Browser-safe slash command projection for UI-11.
|
|
1281
1284
|
* Sources: current Session extension commands, prompt templates, skills.
|
|
1282
1285
|
* Never returns prompt/skill file bodies.
|
|
@@ -1289,36 +1292,29 @@ export class ConsolePiRuntime {
|
|
|
1289
1292
|
.replace(/[A-Za-z]:\\Users\\[^\s]+/gi, "~")
|
|
1290
1293
|
.slice(0, 240);
|
|
1291
1294
|
};
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
+
try {
|
|
1296
|
+
await this.ensureSessionReady(sessionId);
|
|
1297
|
+
}
|
|
1298
|
+
catch {
|
|
1299
|
+
return [];
|
|
1300
|
+
}
|
|
1295
1301
|
const session = this.sessions.get(sessionId);
|
|
1296
1302
|
if (!session)
|
|
1297
|
-
return
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
const SOURCE_RANK = {
|
|
1301
|
-
extension: 0,
|
|
1302
|
-
skill: 1,
|
|
1303
|
-
prompt: 2,
|
|
1304
|
-
};
|
|
1305
|
-
const byKey = new Map();
|
|
1306
|
-
const sourceWarnings = [];
|
|
1303
|
+
return [];
|
|
1304
|
+
const out = [];
|
|
1305
|
+
const seen = new Set();
|
|
1307
1306
|
const push = (command, label, description, source) => {
|
|
1308
1307
|
const name = command.startsWith("/") ? command : `/${command}`;
|
|
1309
1308
|
const key = name.toLowerCase();
|
|
1310
|
-
if (!key || key === "/")
|
|
1309
|
+
if (!key || key === "/" || seen.has(key))
|
|
1311
1310
|
return;
|
|
1312
|
-
|
|
1311
|
+
seen.add(key);
|
|
1312
|
+
out.push({
|
|
1313
1313
|
command: name,
|
|
1314
1314
|
label: (label || name).slice(0, 80),
|
|
1315
1315
|
description: scrub(description),
|
|
1316
1316
|
source,
|
|
1317
|
-
};
|
|
1318
|
-
const existing = byKey.get(key);
|
|
1319
|
-
if (!existing || SOURCE_RANK[source] < SOURCE_RANK[existing.source]) {
|
|
1320
|
-
byKey.set(key, next);
|
|
1321
|
-
}
|
|
1317
|
+
});
|
|
1322
1318
|
};
|
|
1323
1319
|
try {
|
|
1324
1320
|
const cmds = session.extensionRunner?.getRegisteredCommands?.() ?? [];
|
|
@@ -1329,20 +1325,18 @@ export class ConsolePiRuntime {
|
|
|
1329
1325
|
push(String(name), String(cmd.name || name), String(cmd.description || ""), "extension");
|
|
1330
1326
|
}
|
|
1331
1327
|
}
|
|
1332
|
-
catch
|
|
1333
|
-
//
|
|
1334
|
-
sourceWarnings.push(`extension: ${scrub(error instanceof Error ? error.message : String(error))}`);
|
|
1328
|
+
catch {
|
|
1329
|
+
// non-blocking
|
|
1335
1330
|
}
|
|
1336
1331
|
try {
|
|
1337
|
-
// Enumerate prompts before skills on purpose: priority must still let skill win.
|
|
1338
1332
|
for (const tpl of session.promptTemplates ?? []) {
|
|
1339
1333
|
if (!tpl?.name)
|
|
1340
1334
|
continue;
|
|
1341
1335
|
push(String(tpl.name), String(tpl.name), String(tpl.description || ""), "prompt");
|
|
1342
1336
|
}
|
|
1343
1337
|
}
|
|
1344
|
-
catch
|
|
1345
|
-
|
|
1338
|
+
catch {
|
|
1339
|
+
// non-blocking
|
|
1346
1340
|
}
|
|
1347
1341
|
try {
|
|
1348
1342
|
const services = this.serviceScopes.get(sessionId);
|
|
@@ -1357,16 +1351,10 @@ export class ConsolePiRuntime {
|
|
|
1357
1351
|
push(command, skill.name, String(skill.description || ""), "skill");
|
|
1358
1352
|
}
|
|
1359
1353
|
}
|
|
1360
|
-
catch
|
|
1361
|
-
|
|
1354
|
+
catch {
|
|
1355
|
+
// non-blocking
|
|
1362
1356
|
}
|
|
1363
|
-
|
|
1364
|
-
? sourceWarnings.join("; ").slice(0, 160)
|
|
1365
|
-
: undefined;
|
|
1366
|
-
return {
|
|
1367
|
-
commands: [...byKey.values()],
|
|
1368
|
-
...(warning ? { warning } : {}),
|
|
1369
|
-
};
|
|
1357
|
+
return out;
|
|
1370
1358
|
}
|
|
1371
1359
|
async getRuntimeSnapshot(sessionId, options) {
|
|
1372
1360
|
try {
|
|
@@ -1833,17 +1821,10 @@ export class ConsolePiRuntime {
|
|
|
1833
1821
|
: undefined;
|
|
1834
1822
|
assertNoWriteToolInList(OPERATOR_CHAT_ALLOWED_TOOLS);
|
|
1835
1823
|
const customTools = await this.loadCustomTools();
|
|
1836
|
-
// Same allowlist rationale as materializeSession: the SDK filters
|
|
1837
|
-
// customTools against `tools`, so the allowed names must cover the full
|
|
1838
|
-
// operator + explore surface or every custom tool is silently dropped.
|
|
1839
1824
|
const { session } = await this.bindings.createSessionFromServices({
|
|
1840
1825
|
services,
|
|
1841
1826
|
sessionManager: init.sessionManager,
|
|
1842
|
-
tools: [
|
|
1843
|
-
...OPERATOR_CHAT_BUILTIN_EXPLORE_TOOLS,
|
|
1844
|
-
...OPERATOR_CHAT_ALLOWED_TOOLS,
|
|
1845
|
-
...OPERATOR_CHAT_SAFE_EXPLORE_TOOL_IDS,
|
|
1846
|
-
],
|
|
1827
|
+
tools: [...OPERATOR_CHAT_BUILTIN_EXPLORE_TOOLS],
|
|
1847
1828
|
excludeTools: [
|
|
1848
1829
|
"apply_patch",
|
|
1849
1830
|
"apply-patch",
|
|
@@ -1963,31 +1944,6 @@ export class ConsolePiRuntime {
|
|
|
1963
1944
|
if (usage)
|
|
1964
1945
|
onEvent({ type: "usage", sessionId, usage });
|
|
1965
1946
|
}
|
|
1966
|
-
// Context usage rides the usage event: refresh on agent_settled so the
|
|
1967
|
-
// bar reflects the post-turn context window fill (pi-web parity).
|
|
1968
|
-
if (event.type === "agent_settled") {
|
|
1969
|
-
try {
|
|
1970
|
-
const stats = session.getSessionStats?.();
|
|
1971
|
-
const contextUsage = stats?.contextUsage;
|
|
1972
|
-
if (contextUsage) {
|
|
1973
|
-
onEvent({
|
|
1974
|
-
type: "usage",
|
|
1975
|
-
sessionId,
|
|
1976
|
-
usage: {
|
|
1977
|
-
inputTokens: 0,
|
|
1978
|
-
outputTokens: 0,
|
|
1979
|
-
totalTokens: 0,
|
|
1980
|
-
...(contextUsage.tokens === null
|
|
1981
|
-
? {}
|
|
1982
|
-
: { contextUsage }),
|
|
1983
|
-
},
|
|
1984
|
-
});
|
|
1985
|
-
}
|
|
1986
|
-
}
|
|
1987
|
-
catch {
|
|
1988
|
-
// Stats getter is best-effort; never break the event stream.
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
1991
1947
|
});
|
|
1992
1948
|
options?.signal?.addEventListener("abort", onAbort);
|
|
1993
1949
|
if (options?.signal?.aborted) {
|
|
@@ -2160,15 +2116,6 @@ export class ConsolePiRuntime {
|
|
|
2160
2116
|
this.dispose(id);
|
|
2161
2117
|
}
|
|
2162
2118
|
}
|
|
2163
|
-
function mapAssistantMessageEvent(type, sessionId, message) {
|
|
2164
|
-
const content = extractAssistantContentBlocks(message);
|
|
2165
|
-
return {
|
|
2166
|
-
type,
|
|
2167
|
-
sessionId,
|
|
2168
|
-
text: extractAssistantText(message),
|
|
2169
|
-
...(content.length > 0 ? { content } : {}),
|
|
2170
|
-
};
|
|
2171
|
-
}
|
|
2172
2119
|
function mapSdkEvent(sessionId, event) {
|
|
2173
2120
|
switch (event.type) {
|
|
2174
2121
|
case "agent_start":
|
|
@@ -2180,13 +2127,17 @@ function mapSdkEvent(sessionId, event) {
|
|
|
2180
2127
|
willRetry: Boolean(event.willRetry),
|
|
2181
2128
|
};
|
|
2182
2129
|
case "message_update":
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2130
|
+
return {
|
|
2131
|
+
type: "message_update",
|
|
2132
|
+
sessionId,
|
|
2133
|
+
text: extractAssistantText(event.message),
|
|
2134
|
+
};
|
|
2186
2135
|
case "message_end":
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2136
|
+
return {
|
|
2137
|
+
type: "message_end",
|
|
2138
|
+
sessionId,
|
|
2139
|
+
text: extractAssistantText(event.message),
|
|
2140
|
+
};
|
|
2190
2141
|
case "turn_end":
|
|
2191
2142
|
// Usage is emitted from message_end (see prompt subscribe). turn_end
|
|
2192
2143
|
// carries the same final assistant message and would double-count.
|
|
@@ -12,10 +12,9 @@
|
|
|
12
12
|
* Mutation routes go through the Console mutation gate (boot token + Origin).
|
|
13
13
|
* Read routes (GET capabilities / sessions) are open to loopback.
|
|
14
14
|
*/
|
|
15
|
-
import { parseAssistantContent } from "./assistant-content.js";
|
|
16
15
|
import { OPERATOR_CHAT_ALLOWED_TOOLS, OPERATOR_CHAT_DENIED_TOOLS, OPERATOR_CHAT_DENIED_OPERATOR_ACTIONS, } from "./tools.js";
|
|
17
16
|
import { buildModelCallableToolSchemas } from "./tool-adapter.js";
|
|
18
|
-
import { cleanChatTitle
|
|
17
|
+
import { cleanChatTitle } from "./session-store.js";
|
|
19
18
|
import { hashChatTurnPayload, projectChatToolEventPayload, projectCompactSnapshot, } from "./chat-event-store.js";
|
|
20
19
|
import { THINKING_LEVELS, RuntimeSnapshotUnavailableError, } from "./pi-runtime.js";
|
|
21
20
|
import { ResourcePreferencesError, setSkillAutoInvocationPreference, } from "./resource-preferences-store.js";
|
|
@@ -84,16 +83,12 @@ function turnEventToStorePartial(event) {
|
|
|
84
83
|
case "agent_start":
|
|
85
84
|
return { kind: "agent_start", data: {} };
|
|
86
85
|
case "message_update":
|
|
87
|
-
case "message_end": {
|
|
88
|
-
const content = parseAssistantContent(event.content);
|
|
89
86
|
return {
|
|
90
|
-
kind:
|
|
91
|
-
data: {
|
|
92
|
-
text: String(event.text ?? ""),
|
|
93
|
-
...(content ? { content } : {}),
|
|
94
|
-
},
|
|
87
|
+
kind: "message_update",
|
|
88
|
+
data: { text: String(event.text ?? "") },
|
|
95
89
|
};
|
|
96
|
-
|
|
90
|
+
case "message_end":
|
|
91
|
+
return { kind: "message_end", data: { text: String(event.text ?? "") } };
|
|
97
92
|
case "usage":
|
|
98
93
|
return { kind: "usage", data: (event.usage ?? {}) };
|
|
99
94
|
case "tool_call":
|
|
@@ -106,10 +101,7 @@ function turnEventToStorePartial(event) {
|
|
|
106
101
|
value: event.args,
|
|
107
102
|
}),
|
|
108
103
|
};
|
|
109
|
-
case "tool_result":
|
|
110
|
-
// Plan A (2026-08-16): surface the accepted-operation link on the live
|
|
111
|
-
// SSE frame so the frontend semantic event can resolve operation:<id>.
|
|
112
|
-
const resultOperationId = acceptedOperationIdFromResult(String(event.toolName ?? ""), event.result);
|
|
104
|
+
case "tool_result":
|
|
113
105
|
return {
|
|
114
106
|
kind: "tool_result",
|
|
115
107
|
data: projectChatToolEventPayload({
|
|
@@ -118,10 +110,8 @@ function turnEventToStorePartial(event) {
|
|
|
118
110
|
toolName: String(event.toolName ?? ""),
|
|
119
111
|
value: event.result,
|
|
120
112
|
isError: Boolean(event.isError),
|
|
121
|
-
...(resultOperationId ? { operationId: resultOperationId } : {}),
|
|
122
113
|
}),
|
|
123
114
|
};
|
|
124
|
-
}
|
|
125
115
|
case "agent_end":
|
|
126
116
|
return {
|
|
127
117
|
kind: "agent_end",
|
|
@@ -1655,24 +1645,14 @@ async function handleChatFiles(res, deps, sessionId, query) {
|
|
|
1655
1645
|
}
|
|
1656
1646
|
export async function handleChatCommands(res, deps, sessionId) {
|
|
1657
1647
|
try {
|
|
1658
|
-
const
|
|
1648
|
+
const commands = typeof deps.runtime.listSlashCommands === "function"
|
|
1659
1649
|
? await deps.runtime.listSlashCommands(sessionId)
|
|
1660
|
-
:
|
|
1661
|
-
// Partial single-source failures keep successful commands + compact warning (AC-3).
|
|
1662
|
-
const commands = listed.commands ?? [];
|
|
1663
|
-
const warning = typeof listed.warning === "string" && listed.warning.trim()
|
|
1664
|
-
? listed.warning.trim().slice(0, 160)
|
|
1665
|
-
: undefined;
|
|
1650
|
+
: [];
|
|
1666
1651
|
res.statusCode = 200;
|
|
1667
1652
|
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
1668
|
-
res.end(JSON.stringify({
|
|
1669
|
-
ok: true,
|
|
1670
|
-
commands,
|
|
1671
|
-
...(warning ? { warning } : {}),
|
|
1672
|
-
}));
|
|
1653
|
+
res.end(JSON.stringify({ ok: true, commands }));
|
|
1673
1654
|
}
|
|
1674
1655
|
catch (error) {
|
|
1675
|
-
// Whole-list / readiness failures stay fail-soft with empty commands + warning.
|
|
1676
1656
|
res.statusCode = 200;
|
|
1677
1657
|
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
1678
1658
|
res.end(JSON.stringify({
|
|
@@ -2819,21 +2799,8 @@ export async function handleChatCompact(req, res, deps, sessionId) {
|
|
|
2819
2799
|
return;
|
|
2820
2800
|
}
|
|
2821
2801
|
}
|
|
2822
|
-
let body = {};
|
|
2823
|
-
try {
|
|
2824
|
-
body = await readJsonBody(req);
|
|
2825
|
-
}
|
|
2826
|
-
catch {
|
|
2827
|
-
sendJson(res, 400, {
|
|
2828
|
-
ok: false,
|
|
2829
|
-
error: { code: "INVALID_INPUT", message: "invalid json body" },
|
|
2830
|
-
});
|
|
2831
|
-
return;
|
|
2832
|
-
}
|
|
2833
|
-
const rawInstructions = typeof body.instructions === "string" ? body.instructions : undefined;
|
|
2834
|
-
const customInstructions = rawInstructions?.trim() || undefined;
|
|
2835
2802
|
try {
|
|
2836
|
-
const snapshot = await deps.runtime.compact(sessionId
|
|
2803
|
+
const snapshot = await deps.runtime.compact(sessionId);
|
|
2837
2804
|
const event = deps.events.append(sessionId, deps.events.latestTurnId(sessionId) ?? `${sessionId}:compact`, { kind: "compact", data: snapshot });
|
|
2838
2805
|
sendJson(res, 200, { ok: true, snapshot, eventId: event.eventId });
|
|
2839
2806
|
}
|
|
@@ -368,9 +368,6 @@ export async function runChatTurn(options) {
|
|
|
368
368
|
pending.push(store.appendMessage(sessionId, {
|
|
369
369
|
role: "assistant",
|
|
370
370
|
text: event.text,
|
|
371
|
-
...(event.content && event.content.length > 0
|
|
372
|
-
? { content: event.content }
|
|
373
|
-
: {}),
|
|
374
371
|
}));
|
|
375
372
|
}
|
|
376
373
|
break;
|
|
@@ -402,11 +399,6 @@ export async function runChatTurn(options) {
|
|
|
402
399
|
toolCallId: event.toolCallId,
|
|
403
400
|
toolName: event.toolName,
|
|
404
401
|
isError: event.isError,
|
|
405
|
-
// Durable tool→operation link (plan A): the restored timeline can
|
|
406
|
-
// resolve operation:<id> refs without the live operation-ref event.
|
|
407
|
-
...(acceptedOperationId
|
|
408
|
-
? { operationId: acceptedOperationId }
|
|
409
|
-
: {}),
|
|
410
402
|
}));
|
|
411
403
|
pending.push(store.recordToolInvocation(sessionId, {
|
|
412
404
|
toolCallId: event.toolCallId,
|
|
@@ -436,7 +428,7 @@ export async function runChatTurn(options) {
|
|
|
436
428
|
* huge operator-action payload (e.g. a full dagReport) cannot bloat the chat
|
|
437
429
|
* history record.
|
|
438
430
|
*/
|
|
439
|
-
|
|
431
|
+
function acceptedOperationIdFromResult(toolName, result) {
|
|
440
432
|
const candidates = [result];
|
|
441
433
|
if (result && typeof result === "object") {
|
|
442
434
|
const record = result;
|
|
@@ -41,6 +41,13 @@ export const SHORTCUTS = [
|
|
|
41
41
|
action: "reload",
|
|
42
42
|
source: "operator",
|
|
43
43
|
},
|
|
44
|
+
{
|
|
45
|
+
command: "/help",
|
|
46
|
+
label: "Shortcuts",
|
|
47
|
+
description: "显示可用 shortcut",
|
|
48
|
+
action: "show-help",
|
|
49
|
+
source: "operator",
|
|
50
|
+
},
|
|
44
51
|
];
|
|
45
52
|
/** Pi Web commands with real browser-equivalent behavior (UI-11). */
|
|
46
53
|
export const WEB_SLASH_COMMANDS = [
|
|
@@ -96,15 +103,6 @@ export function resolveShortcut(input) {
|
|
|
96
103
|
return { command: local.command, action: local.action };
|
|
97
104
|
return { command: token, action: "unknown" };
|
|
98
105
|
}
|
|
99
|
-
/** Map Operator panel shortcuts onto Console workspace routes. */
|
|
100
|
-
export function workspaceForShortcut(action) {
|
|
101
|
-
if (action === "focus-panel:task" || action === "focus-panel:contract") {
|
|
102
|
-
return "tasks";
|
|
103
|
-
}
|
|
104
|
-
if (action === "focus-panel:dag")
|
|
105
|
-
return "recovery";
|
|
106
|
-
return undefined;
|
|
107
|
-
}
|
|
108
106
|
/**
|
|
109
107
|
* Merge Operator, Web, and dynamic Session commands with conflict dedupe.
|
|
110
108
|
* Priority: operator/web > extension > skill > prompt. /reload is single-card.
|