@tea-agent/loop-agent 0.43.0-next.4 → 0.43.0-next.6
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 +82 -9
- package/dist/application/task-lifecycle/advance.js +17 -4
- package/dist/application/task-lifecycle/observe.js +43 -29
- package/dist/application/task-lifecycle/plan-transitions.js +5 -4
- package/dist/build-stamp.json +3 -3
- package/dist/executors/dag-pi-executor.js +233 -202
- package/dist/executors/pi-executor.js +2 -0
- package/dist/executors/pi-sdk-executor.js +77 -39
- package/dist/task/source-prepare/source-fidelity-pi.js +2 -2
- package/dist/task/source-references.js +48 -23
- package/dist/worker/console/chat/pi-runtime.js +113 -95
- package/dist/worker/console/chat/routes.js +164 -54
- package/dist/worker/console/chat/scm-routes.js +193 -0
- package/dist/worker/console/chat/scm-service.js +253 -0
- package/dist/worker/console/chat/scm-tools.js +111 -0
- package/dist/worker/console/chat/session-catalog.js +1 -0
- package/dist/worker/console/chat/session-mode-view.js +48 -0
- package/dist/worker/console/chat/session-mode.js +218 -0
- package/dist/worker/console/chat/session-store.js +22 -6
- package/dist/worker/console/chat/shortcuts.js +6 -0
- package/dist/worker/console/chat/tools.js +1 -0
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CCj36aaC.js → abnfDiagram-N423BO3Z-BuyrlONK.js} +1 -1
- package/dist/worker/console/static/assets/{arc-Cl3MIVFh.js → arc-BvCl_wpi.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-C_n4kMJS.js → architectureDiagram-T3A2C74G-BkBpBaRq.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-DlWYJ7cK.js → blockDiagram-VBNYF7ZC-yve4Mcb_.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-Ud5pS7vS.js → c4Diagram-5PPSVZJV-9yLGboBx.js} +1 -1
- package/dist/worker/console/static/assets/channel-BRahIhjw.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-CQPwOv_j.js → chunk-2GRJ4B5K-BKP69b8r.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CMzjxrWI.js → chunk-2Q5K7J3B-NWFRnXju.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-pcnXnD6t.js → chunk-5RXB4S5H-BiweqLEc.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CEB3AvU2.js → chunk-5VM5RSS4-CP9GHmRY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DSKnbXbp.js → chunk-6Q2QTUOP-BiGDkBtj.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CS6-PjCZ.js → chunk-GF5L2VYU-DkJ4ZjQS.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-f6q8Tnzz.js → chunk-JWPE2WC7-B5jjn7zq.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DkB0QX3q.js → chunk-KBJHAD2P-C6KoK9O0.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-BdB4jAv6.js → chunk-RYQCIY6F-BvNIfyn-.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-BVm1bnX6.js → chunk-XXDRQBXY-BZ33iX4W.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-GOC80mhq.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-GOC80mhq.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-FV_P-IEp.js → cose-bilkent-JH36ORCC-CP8eIuZd.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BM7RtkA2.js → cynefin-VYW2F7L2-DZECjpOe.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-C1BZwTG5.js → cynefinDiagram-MW4NZA55-CvVJoFqf.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-C6McNKmY.js → dagre-VZM6K2ZE-D_JTqdAn.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-C0aWRUaE.js → diagram-7IWD3JNH-Db7AQ0z0.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Bfk_SKE8.js → diagram-B4RE2ZJO-AZPVo5CZ.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-prx1T4qf.js → diagram-LBJQPF4R-BgXqI3E6.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DBvty0eU.js → diagram-Q27KOJAE-BYjFn3Ba.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-CF0em8e9.js → diagram-UB23O5K3-B4rJgGGO.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CF90b4Ws.js → ebnfDiagram-BXEA7PRR-C6XWZhpw.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-hfunxzof.js → erDiagram-JOGREHBK-1YdQRIQW.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-D-QSy4Nl.js → flowDiagram-UKHOOZJN-l3a0AwN0.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DaBGNcvT.js → ganttDiagram-PKOTCBZU-CQL96F2Z.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-BChcubGL.js → gitGraphDiagram-DS77QQ5N-BxCvafRb.js} +1 -1
- package/dist/worker/console/static/assets/index-4wCGsXuU.js +465 -0
- package/dist/worker/console/static/assets/index-CiF9WBoR.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BkC67fIa.js → infoDiagram-6WML65LV-BUipIeDO.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-ibhLczCD.js → ishikawaDiagram-WSZJBQD7-CRfomVMX.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DCRMitay.js → journeyDiagram-NVQOT4AX-_UFvyviX.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DJ_hKaYI.js → kanban-definition-27J2QSJJ-CKIRoqKv.js} +1 -1
- package/dist/worker/console/static/assets/{linear-CIlLsYsA.js → linear-CjttJDCM.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-C-5IQMP_.js → mermaid.core-DPvHX155.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-TCzV5TQT.js → mindmap-definition-FAOFIHXS-Qmj-qwBe.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-bfhd2BQH.js → pegDiagram-VL7TDLO6-Auw6DRgq.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BxFRAm5N.js → pieDiagram-7S7Q4E2Y-CqMrfD4c.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-C-m12lxv.js → quadrantDiagram-CIZ2JOQS-BAddeggH.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-CwmLiGgx.js → railroadDiagram-AXF67PYL-DG1JuOu2.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-oc0Q1jiD.js → requirementDiagram-LRYGKXZP-DLYGMKlC.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-9Ght6Yur.js → sankeyDiagram-W5VNT64P-g68SbLM9.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-ndm3lyz9.js → sequenceDiagram-SI44F4Z6-CmszLKv8.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-7sPlKVcw.js → sizeCapture-X5ZJPWSS-D2tEKUCj.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Izl21-oS.js → stateDiagram-OKZ733FA-Syc5E_Jf.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CwWwuPI-.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CtO3D65o.js → swimlanes-SLNWSIFB-Ibn0IRCa.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-A7fqemr6.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Cyg5cY7z.js → timeline-definition-Z64GVDOM-2ZW9W3iS.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-CwtE_TFK.js → vennDiagram-T6HMQDX7-v50HsKUh.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-Dtt9v8OO.js → wardleyDiagram-T6FBY63Y-DqCXEoDH.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-B2Y3ryb6.js → xychartDiagram-ELKLHX3M-vIP8Vo9d.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +20 -4
- package/dist/worker/console/static-src/operator-chat/useComposer.js +13 -7
- package/dist/worker/console/workspace-context.js +6 -0
- package/dist/workflows/dag/frontend-capacity.js +9 -0
- package/dist/workflows/dag/frontend-design-policy.js +2 -1
- package/dist/workflows/dag/frontend-plan-completeness.js +186 -0
- package/dist/workflows/dag/frontend-plan-recovery-policy.js +18 -0
- package/dist/workflows/dag/frontend-shape-facts.js +12 -2
- package/package.json +1 -1
- package/skills/frontend-plan/SKILL.md +7 -0
- package/dist/worker/console/static/assets/channel-CEMRpNm-.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C9lhaZkR.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C9lhaZkR.js +0 -1
- package/dist/worker/console/static/assets/index-CJkCY1XR.js +0 -464
- package/dist/worker/console/static/assets/index-DUBCbiqv.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CmElLFpP.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DKRbGG8V.js +0 -8
|
@@ -32,7 +32,8 @@ import { extractAssistantContentBlocks, extractAssistantText, isAssistantSdkMess
|
|
|
32
32
|
import { parseProviderError, } from "./provider-error.js";
|
|
33
33
|
import { projectCompactSnapshot, } from "./chat-event-store.js";
|
|
34
34
|
import { extractUsageSample } from "./usage.js";
|
|
35
|
-
import { OPERATOR_CHAT_ALLOWED_TOOLS,
|
|
35
|
+
import { OPERATOR_CHAT_ALLOWED_TOOLS, authorizeOperatorChatTool, assertNoWriteToolInList, } from "./tools.js";
|
|
36
|
+
import { authorizeChatSessionTool, DEFAULT_CONSOLE_CHAT_SESSION_MODE, PI_TODO_WRITE_DESCRIPTION, chatActiveToolBaseline, composeChatSystemPrompt, composeChatSystemPromptParts, computeChatActiveToolNames, shouldInjectGoalContinuation, shouldLoadWorkflowBusinessTools, } from "./session-mode.js";
|
|
36
37
|
import { buildAgentCustomTool, ExploreOrchestrator, } from "./subagents/index.js";
|
|
37
38
|
import { createOperatorChatResourceLoader, } from "./resource-loader.js";
|
|
38
39
|
import { applySkillAutoInvocationPreferences, isAutoInvocationEnabled, loadResourcePreferences, skillResourceId, } from "./resource-preferences-store.js";
|
|
@@ -44,6 +45,7 @@ import { filterActiveInterviewTools } from "../interview/tools.js";
|
|
|
44
45
|
import { RUNTIME_CONTEXT_TEXT_MAX, redactRuntimeText, } from "./runtime-context.js";
|
|
45
46
|
import { buildTodoContinuationContext, } from "./todos.js";
|
|
46
47
|
import { buildPersistentTerminalTools } from "./terminal-tools.js";
|
|
48
|
+
import { buildScmTools } from "./scm-tools.js";
|
|
47
49
|
import { buildGoalContinuationContext, } from "./goals.js";
|
|
48
50
|
import { injectWizardLocalHeaders, } from "./sdd-data-alignment.js";
|
|
49
51
|
/**
|
|
@@ -76,15 +78,6 @@ export const OPERATOR_CHAT_SYSTEM_PROMPT_BASE = [
|
|
|
76
78
|
"Continue until success, user stop, or no safe recovery remains; then stop and report failure/evidence. Never create a new task for a transient failure or replace repair-pi with direct edits.",
|
|
77
79
|
"Narrate long-DAG progress briefly at start, meaningful phase changes/findings, verification failure/recovery, prolonged quiet and terminal state: say what finished and what is next. Never narrate unchanged operationWait polls or heartbeats, or claim beyond structured facts.",
|
|
78
80
|
].join("\n");
|
|
79
|
-
/** Compose the inspectable system prompt actually injected into Operator Chat. */
|
|
80
|
-
export function composeOperatorChatSystemPrompt(input) {
|
|
81
|
-
return [
|
|
82
|
-
OPERATOR_CHAT_SYSTEM_PROMPT_BASE,
|
|
83
|
-
...(input.systemPromptSuffix?.trim()
|
|
84
|
-
? [input.systemPromptSuffix.trim()]
|
|
85
|
-
: []),
|
|
86
|
-
].join("\n\n");
|
|
87
|
-
}
|
|
88
81
|
/**
|
|
89
82
|
* Built-in SDK tool names registered for every Chat session (ADR 0011).
|
|
90
83
|
* Full Pi builtins: read/write/edit/bash/grep/find/ls. safe-* custom tools
|
|
@@ -113,27 +106,8 @@ export const OPERATOR_CHAT_SAFE_EXPLORE_TOOL_IDS = Object.freeze([
|
|
|
113
106
|
"git-diff",
|
|
114
107
|
]);
|
|
115
108
|
export function OPERATOR_CHAT_ACTIVE_TOOL_NAMES() {
|
|
116
|
-
return
|
|
117
|
-
...OPERATOR_CHAT_ALLOWED_TOOLS,
|
|
118
|
-
...OPERATOR_CHAT_BUILTIN_EXPLORE_TOOLS,
|
|
119
|
-
...OPERATOR_CHAT_SAFE_EXPLORE_TOOL_IDS,
|
|
120
|
-
...OPERATOR_CHAT_BUILTIN_CUSTOM_TOOLS,
|
|
121
|
-
];
|
|
109
|
+
return chatActiveToolBaseline("workflow");
|
|
122
110
|
}
|
|
123
|
-
/**
|
|
124
|
-
* Non-Pi write / coding channels that must never be activated in Operator
|
|
125
|
-
* Chat even when a user/project extension registers them (ADR 0011 / 0012).
|
|
126
|
-
* Mirrors the NON_PI_WRITE_CHANNELS guard in tools.ts for the Gate 2 pin.
|
|
127
|
-
*/
|
|
128
|
-
const OPERATOR_CHAT_EXTENSION_DENIED_TOOL_IDS = new Set([
|
|
129
|
-
"apply_patch",
|
|
130
|
-
"apply-patch",
|
|
131
|
-
"full-tools",
|
|
132
|
-
"full_tools",
|
|
133
|
-
"coding-chat",
|
|
134
|
-
"coding_chat",
|
|
135
|
-
"shell",
|
|
136
|
-
].map((t) => t.toLowerCase()));
|
|
137
111
|
/**
|
|
138
112
|
* Gate 2 active-tool set for a live session (ADR 0012): the operator-chat
|
|
139
113
|
* baseline (operator actions + Pi builtins + safe explore) PLUS extension
|
|
@@ -144,24 +118,8 @@ const OPERATOR_CHAT_EXTENSION_DENIED_TOOL_IDS = new Set([
|
|
|
144
118
|
* coding-chat). Unknown/denied names are never activated; Gate 3 still
|
|
145
119
|
* re-authorizes every tool call per invocation.
|
|
146
120
|
*/
|
|
147
|
-
export function computeOperatorChatActiveToolNames(session) {
|
|
148
|
-
|
|
149
|
-
if (!session?.getAllTools)
|
|
150
|
-
return baseline;
|
|
151
|
-
const baselineLower = new Set(baseline.map((t) => t.toLowerCase()));
|
|
152
|
-
const extras = [];
|
|
153
|
-
for (const tool of session.getAllTools()) {
|
|
154
|
-
const name = tool?.name;
|
|
155
|
-
if (!name || typeof name !== "string")
|
|
156
|
-
continue;
|
|
157
|
-
const lower = name.toLowerCase();
|
|
158
|
-
if (baselineLower.has(lower))
|
|
159
|
-
continue;
|
|
160
|
-
if (OPERATOR_CHAT_EXTENSION_DENIED_TOOL_IDS.has(lower))
|
|
161
|
-
continue;
|
|
162
|
-
extras.push(name);
|
|
163
|
-
}
|
|
164
|
-
return extras.length > 0 ? [...baseline, ...extras] : baseline;
|
|
121
|
+
export function computeOperatorChatActiveToolNames(session, sessionMode = DEFAULT_CONSOLE_CHAT_SESSION_MODE) {
|
|
122
|
+
return computeChatActiveToolNames(session, sessionMode);
|
|
165
123
|
}
|
|
166
124
|
const OPERATOR_CHAT_SESSION_EXCLUDE_TOOLS = Object.freeze([
|
|
167
125
|
"apply_patch",
|
|
@@ -217,8 +175,8 @@ async function bindSessionExtensions(session) {
|
|
|
217
175
|
return;
|
|
218
176
|
await session.bindExtensions(createConsoleExtensionBindings());
|
|
219
177
|
}
|
|
220
|
-
function pinOperatorChatTools(session) {
|
|
221
|
-
session.setActiveToolsByName(
|
|
178
|
+
function pinOperatorChatTools(session, sessionMode = DEFAULT_CONSOLE_CHAT_SESSION_MODE) {
|
|
179
|
+
session.setActiveToolsByName(computeChatActiveToolNames(session, sessionMode));
|
|
222
180
|
}
|
|
223
181
|
/**
|
|
224
182
|
* Pi has no hook result that merely appends instructions to its built-in
|
|
@@ -370,7 +328,7 @@ async function buildCustomOperatorTools(options) {
|
|
|
370
328
|
promptSnippet: schema.description,
|
|
371
329
|
parameters: parameters,
|
|
372
330
|
async execute(toolCallId, params) {
|
|
373
|
-
const decision =
|
|
331
|
+
const decision = authorizeChatSessionTool(schema.toolId, options.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE);
|
|
374
332
|
if (!decision.ok) {
|
|
375
333
|
return {
|
|
376
334
|
content: [
|
|
@@ -387,7 +345,7 @@ async function buildCustomOperatorTools(options) {
|
|
|
387
345
|
}
|
|
388
346
|
// Defer require to avoid circular import at module load.
|
|
389
347
|
const { dispatchChatToolCall } = await import("./session-store.js");
|
|
390
|
-
const result = await dispatchChatToolCall(ctx, decision.toolId, params, toolCallId);
|
|
348
|
+
const result = await dispatchChatToolCall(ctx, decision.toolId, params, toolCallId, options.sessionMode);
|
|
391
349
|
const payload = result.ok
|
|
392
350
|
? result.result
|
|
393
351
|
: { error: result.message, code: result.errorCode };
|
|
@@ -445,11 +403,14 @@ async function buildTodoWriteTool(options) {
|
|
|
445
403
|
import("typebox"),
|
|
446
404
|
import("@earendil-works/pi-coding-agent"),
|
|
447
405
|
]);
|
|
406
|
+
const description = options.sessionMode === "pi"
|
|
407
|
+
? PI_TODO_WRITE_DESCRIPTION
|
|
408
|
+
: TODO_WRITE_DESCRIPTION;
|
|
448
409
|
return defineTool({
|
|
449
410
|
name: "todo_write",
|
|
450
411
|
label: "Update todo list",
|
|
451
|
-
description
|
|
452
|
-
promptSnippet:
|
|
412
|
+
description,
|
|
413
|
+
promptSnippet: description,
|
|
453
414
|
parameters: Type.Object({
|
|
454
415
|
todos: Type.Array(Type.Object({
|
|
455
416
|
content: Type.String({ description: "Short imperative task description." }),
|
|
@@ -1022,12 +983,14 @@ export class ConsolePiRuntime {
|
|
|
1022
983
|
sessionInit = new Map();
|
|
1023
984
|
/** Resolved model binding after materialization (create may return before this is known). */
|
|
1024
985
|
sessionModels = new Map();
|
|
986
|
+
/** Durable session mode; record is the source of truth, this is the live handle cache. */
|
|
987
|
+
sessionModes = new Map();
|
|
1025
988
|
/** SessionIds disposed while materialization was still in flight. */
|
|
1026
989
|
disposedSessions = new Set();
|
|
1027
990
|
compactionControllers = new Map();
|
|
1028
991
|
siftStates = new Map();
|
|
1029
992
|
/** Session-less tool definition caches (no AgentSession state). */
|
|
1030
|
-
|
|
993
|
+
operatorCustomToolsByMode = new Map();
|
|
1031
994
|
exploreCustomToolsPromise;
|
|
1032
995
|
exploreOrchestrator;
|
|
1033
996
|
bindings;
|
|
@@ -1086,10 +1049,20 @@ export class ConsolePiRuntime {
|
|
|
1086
1049
|
* after a PATCH sees the latest resource-preferences.json (not create-time
|
|
1087
1050
|
* closure state).
|
|
1088
1051
|
*/
|
|
1052
|
+
sessionModeOf(sessionId) {
|
|
1053
|
+
if (!sessionId)
|
|
1054
|
+
return DEFAULT_CONSOLE_CHAT_SESSION_MODE;
|
|
1055
|
+
return this.sessionModes.get(sessionId) ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE;
|
|
1056
|
+
}
|
|
1057
|
+
rememberSessionMode(sessionId, sessionMode = DEFAULT_CONSOLE_CHAT_SESSION_MODE) {
|
|
1058
|
+
this.sessionModes.set(sessionId, sessionMode);
|
|
1059
|
+
return sessionMode;
|
|
1060
|
+
}
|
|
1089
1061
|
async buildResourceLoaderOptions(base = {}, sessionId) {
|
|
1090
1062
|
const inheritedFactories = Array.isArray(base.extensionFactories)
|
|
1091
1063
|
? base.extensionFactories
|
|
1092
1064
|
: [];
|
|
1065
|
+
const sessionMode = this.sessionModeOf(sessionId);
|
|
1093
1066
|
const todoContextExtension = sessionId && this.options.todoRegistry
|
|
1094
1067
|
? createTodoCompactionContextExtension({
|
|
1095
1068
|
sessionId,
|
|
@@ -1099,7 +1072,9 @@ export class ConsolePiRuntime {
|
|
|
1099
1072
|
const pressureExtension = sessionId
|
|
1100
1073
|
? this.createContextPressureInlineExtension(sessionId)
|
|
1101
1074
|
: undefined;
|
|
1102
|
-
const goalContextExtension = sessionId &&
|
|
1075
|
+
const goalContextExtension = sessionId &&
|
|
1076
|
+
this.options.goalRegistry &&
|
|
1077
|
+
shouldInjectGoalContinuation(sessionMode)
|
|
1103
1078
|
? createGoalCompactionContextExtension({
|
|
1104
1079
|
sessionId,
|
|
1105
1080
|
registry: this.options.goalRegistry,
|
|
@@ -1348,6 +1323,7 @@ export class ConsolePiRuntime {
|
|
|
1348
1323
|
await this.syncAimaxAuthToken();
|
|
1349
1324
|
const sessionId = `operator-chat-${randomBytes(12).toString("hex")}`;
|
|
1350
1325
|
this.disposedSessions.delete(sessionId);
|
|
1326
|
+
const sessionMode = this.rememberSessionMode(sessionId, init?.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE);
|
|
1351
1327
|
const sessionManager = await this.bindings.createSessionManager({
|
|
1352
1328
|
cwd: this.options.cwd,
|
|
1353
1329
|
sessionDir: this.options.sessionDir,
|
|
@@ -1373,6 +1349,7 @@ export class ConsolePiRuntime {
|
|
|
1373
1349
|
sessionManager,
|
|
1374
1350
|
model: init?.model,
|
|
1375
1351
|
systemPromptSuffix: init?.systemPromptSuffix,
|
|
1352
|
+
sessionMode,
|
|
1376
1353
|
// Create path must resolve default model from the SAME services object
|
|
1377
1354
|
// used for formal materialization (no throwaway createServices).
|
|
1378
1355
|
resolveDefaultModel: !init?.model,
|
|
@@ -1382,7 +1359,8 @@ export class ConsolePiRuntime {
|
|
|
1382
1359
|
sessionFile,
|
|
1383
1360
|
createdAt: new Date().toISOString(),
|
|
1384
1361
|
model: init?.model,
|
|
1385
|
-
activeTools:
|
|
1362
|
+
activeTools: chatActiveToolBaseline(sessionMode),
|
|
1363
|
+
sessionMode,
|
|
1386
1364
|
initializing: true,
|
|
1387
1365
|
};
|
|
1388
1366
|
}
|
|
@@ -1444,14 +1422,16 @@ export class ConsolePiRuntime {
|
|
|
1444
1422
|
if (this.disposedSessions.has(sessionId))
|
|
1445
1423
|
return;
|
|
1446
1424
|
await this.syncAimaxAuthToken();
|
|
1425
|
+
const sessionMode = this.rememberSessionMode(sessionId, init.sessionMode ?? this.sessionModeOf(sessionId));
|
|
1447
1426
|
const agentDir = await safeGetAgentDir(this.bindings);
|
|
1448
1427
|
// Capture before services parse models.json. A concurrent edit can therefore
|
|
1449
1428
|
// cause at most one harmless extra refresh, never a missed next-turn refresh.
|
|
1450
1429
|
const modelConfigFile = await captureModelConfigFile(agentDir);
|
|
1451
|
-
const appendSystemPrompt =
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1430
|
+
const appendSystemPrompt = composeChatSystemPromptParts({
|
|
1431
|
+
sessionMode,
|
|
1432
|
+
workflowPrompt: OPERATOR_CHAT_SYSTEM_PROMPT_BASE,
|
|
1433
|
+
systemPromptSuffix: init.systemPromptSuffix,
|
|
1434
|
+
});
|
|
1455
1435
|
// Single services construction for formal materialization (+ optional
|
|
1456
1436
|
// default-model resolve from the same modelRuntime). Repo-scoped skill
|
|
1457
1437
|
// auto-invocation prefs inject skillsOverride without touching SKILL.md.
|
|
@@ -1502,7 +1482,7 @@ export class ConsolePiRuntime {
|
|
|
1502
1482
|
return;
|
|
1503
1483
|
}
|
|
1504
1484
|
await bindSessionExtensions(session);
|
|
1505
|
-
pinOperatorChatTools(session);
|
|
1485
|
+
pinOperatorChatTools(session, sessionMode);
|
|
1506
1486
|
// Register then re-check dispose race: a concurrent dispose must win.
|
|
1507
1487
|
this.sessions.set(sessionId, session);
|
|
1508
1488
|
this.sessionManagers.set(sessionId, init.sessionManager);
|
|
@@ -1530,6 +1510,7 @@ export class ConsolePiRuntime {
|
|
|
1530
1510
|
this.modelRuntimes.delete(sessionId);
|
|
1531
1511
|
this.modelConfigFiles.delete(sessionId);
|
|
1532
1512
|
this.sessionModels.delete(sessionId);
|
|
1513
|
+
this.sessionModes.delete(sessionId);
|
|
1533
1514
|
this.serviceScopes.delete(sessionId);
|
|
1534
1515
|
this.revisions.delete(sessionId);
|
|
1535
1516
|
this.thinkingSelections.delete(sessionId);
|
|
@@ -1537,8 +1518,12 @@ export class ConsolePiRuntime {
|
|
|
1537
1518
|
}
|
|
1538
1519
|
/** Cached session-less custom tool definitions (operator + explore). */
|
|
1539
1520
|
async loadCustomTools(sessionId) {
|
|
1521
|
+
const sessionMode = this.sessionModeOf(sessionId);
|
|
1522
|
+
const loadWorkflowTools = shouldLoadWorkflowBusinessTools(sessionMode);
|
|
1540
1523
|
const [operatorCustomTools, exploreCustomTools] = await Promise.all([
|
|
1541
|
-
|
|
1524
|
+
loadWorkflowTools
|
|
1525
|
+
? this.loadOperatorCustomTools(sessionMode)
|
|
1526
|
+
: Promise.resolve([]),
|
|
1542
1527
|
this.loadExploreCustomTools(),
|
|
1543
1528
|
]);
|
|
1544
1529
|
const questionTool = this.options.questionRegistry
|
|
@@ -1548,9 +1533,13 @@ export class ConsolePiRuntime {
|
|
|
1548
1533
|
})
|
|
1549
1534
|
: undefined;
|
|
1550
1535
|
const todoTool = this.options.todoRegistry
|
|
1551
|
-
? await buildTodoWriteTool({
|
|
1536
|
+
? await buildTodoWriteTool({
|
|
1537
|
+
sessionId,
|
|
1538
|
+
registry: this.options.todoRegistry,
|
|
1539
|
+
sessionMode,
|
|
1540
|
+
})
|
|
1552
1541
|
: undefined;
|
|
1553
|
-
const goalTools = this.options.goalRegistry
|
|
1542
|
+
const goalTools = loadWorkflowTools && this.options.goalRegistry
|
|
1554
1543
|
? await buildGoalTools({ sessionId, registry: this.options.goalRegistry })
|
|
1555
1544
|
: [];
|
|
1556
1545
|
const terminalTools = this.options.terminalRegistry
|
|
@@ -1563,6 +1552,12 @@ export class ConsolePiRuntime {
|
|
|
1563
1552
|
return [];
|
|
1564
1553
|
})
|
|
1565
1554
|
: [];
|
|
1555
|
+
const scmTools = this.options.scmService
|
|
1556
|
+
? await buildScmTools({ scm: this.options.scmService }).catch((error) => {
|
|
1557
|
+
process.stderr.write(`[console] chat scm-tools build failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
1558
|
+
return [];
|
|
1559
|
+
})
|
|
1560
|
+
: [];
|
|
1566
1561
|
const agentTool = await buildAgentCustomTool({
|
|
1567
1562
|
parentSessionId: sessionId,
|
|
1568
1563
|
orchestrator: this.exploreOrchestrator,
|
|
@@ -1588,23 +1583,27 @@ export class ConsolePiRuntime {
|
|
|
1588
1583
|
...(todoTool ? [todoTool] : []),
|
|
1589
1584
|
...goalTools,
|
|
1590
1585
|
...terminalTools,
|
|
1586
|
+
...scmTools,
|
|
1591
1587
|
...(agentTool ? [agentTool] : []),
|
|
1592
1588
|
];
|
|
1593
1589
|
}
|
|
1594
|
-
loadOperatorCustomTools() {
|
|
1590
|
+
loadOperatorCustomTools(sessionMode) {
|
|
1595
1591
|
if (!this.options.actionContext)
|
|
1596
1592
|
return Promise.resolve([]);
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1593
|
+
const cached = this.operatorCustomToolsByMode.get(sessionMode);
|
|
1594
|
+
if (cached)
|
|
1595
|
+
return cached;
|
|
1596
|
+
const promise = buildCustomOperatorTools({
|
|
1597
|
+
actionContext: this.options.actionContext,
|
|
1598
|
+
sessionMode,
|
|
1599
|
+
}).catch((error) => {
|
|
1600
|
+
process.stderr.write(`[console] chat custom-tools build failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
1601
|
+
// Allow a later create/reopen to retry after a transient failure.
|
|
1602
|
+
this.operatorCustomToolsByMode.delete(sessionMode);
|
|
1603
|
+
return [];
|
|
1604
|
+
});
|
|
1605
|
+
this.operatorCustomToolsByMode.set(sessionMode, promise);
|
|
1606
|
+
return promise;
|
|
1608
1607
|
}
|
|
1609
1608
|
loadExploreCustomTools() {
|
|
1610
1609
|
if (!this.exploreCustomToolsPromise) {
|
|
@@ -1622,6 +1621,7 @@ export class ConsolePiRuntime {
|
|
|
1622
1621
|
if (!this.bindings.forkSessionManager)
|
|
1623
1622
|
throw new Error("SESSION_FORK_UNSUPPORTED");
|
|
1624
1623
|
const sessionId = `operator-chat-${randomBytes(12).toString("hex")}`;
|
|
1624
|
+
const sessionMode = this.rememberSessionMode(sessionId, init.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE);
|
|
1625
1625
|
const sessionManager = await this.bindings.forkSessionManager({
|
|
1626
1626
|
sourcePath: init.sourceSessionFile,
|
|
1627
1627
|
targetCwd: this.options.cwd,
|
|
@@ -1632,8 +1632,8 @@ export class ConsolePiRuntime {
|
|
|
1632
1632
|
sessionId,
|
|
1633
1633
|
sessionManager,
|
|
1634
1634
|
model: init.model,
|
|
1635
|
+
sessionMode,
|
|
1635
1636
|
});
|
|
1636
|
-
built.session.setActiveToolsByName(computeOperatorChatActiveToolNames(built.session));
|
|
1637
1637
|
this.sessions.set(sessionId, built.session);
|
|
1638
1638
|
this.sessionManagers.set(sessionId, sessionManager);
|
|
1639
1639
|
this.modelRuntimes.set(sessionId, built.modelRuntime);
|
|
@@ -1649,6 +1649,7 @@ export class ConsolePiRuntime {
|
|
|
1649
1649
|
createdAt: new Date().toISOString(),
|
|
1650
1650
|
model: init.model,
|
|
1651
1651
|
activeTools: built.session.getActiveToolNames(),
|
|
1652
|
+
sessionMode,
|
|
1652
1653
|
};
|
|
1653
1654
|
}
|
|
1654
1655
|
async branchSession(input) {
|
|
@@ -1827,15 +1828,22 @@ export class ConsolePiRuntime {
|
|
|
1827
1828
|
async getRuntimeSystemPrompt(sessionId) {
|
|
1828
1829
|
await this.ensureSessionReady(sessionId).catch(() => undefined);
|
|
1829
1830
|
const session = this.sessions.get(sessionId);
|
|
1830
|
-
if (!session)
|
|
1831
|
-
return
|
|
1831
|
+
if (!session) {
|
|
1832
|
+
return composeChatSystemPrompt({
|
|
1833
|
+
sessionMode: this.sessionModeOf(sessionId),
|
|
1834
|
+
workflowPrompt: OPERATOR_CHAT_SYSTEM_PROMPT_BASE,
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1832
1837
|
const fromState = session.state?.systemPrompt;
|
|
1833
1838
|
const fromGetter = session.systemPrompt;
|
|
1834
1839
|
const loader = this.serviceScopes.get(sessionId)?.resourceLoader;
|
|
1835
1840
|
return (fromState ||
|
|
1836
1841
|
fromGetter ||
|
|
1837
1842
|
loader?.getSystemPrompt?.() ||
|
|
1838
|
-
|
|
1843
|
+
composeChatSystemPrompt({
|
|
1844
|
+
sessionMode: this.sessionModeOf(sessionId),
|
|
1845
|
+
workflowPrompt: OPERATOR_CHAT_SYSTEM_PROMPT_BASE,
|
|
1846
|
+
}));
|
|
1839
1847
|
}
|
|
1840
1848
|
/**
|
|
1841
1849
|
* Read the RAW system prompt for the snapshot, converting any projection
|
|
@@ -1928,6 +1936,7 @@ export class ConsolePiRuntime {
|
|
|
1928
1936
|
if (services)
|
|
1929
1937
|
this.applySessionCompactionOverride(sessionId, services, session);
|
|
1930
1938
|
await this.refreshModelConfiguration(sessionId, "force");
|
|
1939
|
+
pinOperatorChatTools(session, this.sessionModeOf(sessionId));
|
|
1931
1940
|
}
|
|
1932
1941
|
catch (error) {
|
|
1933
1942
|
return {
|
|
@@ -2366,6 +2375,7 @@ export class ConsolePiRuntime {
|
|
|
2366
2375
|
async reopenSession(init) {
|
|
2367
2376
|
await this.syncAimaxAuthToken();
|
|
2368
2377
|
const sessionId = init.sessionId;
|
|
2378
|
+
const sessionMode = this.rememberSessionMode(sessionId, init.sessionMode ?? this.sessionModeOf(sessionId));
|
|
2369
2379
|
// Wait for in-flight create materialization rather than racing reopen.
|
|
2370
2380
|
const initState = this.sessionInit.get(sessionId);
|
|
2371
2381
|
if (initState?.status === "initializing") {
|
|
@@ -2442,6 +2452,7 @@ export class ConsolePiRuntime {
|
|
|
2442
2452
|
sessionManager,
|
|
2443
2453
|
model: init.model,
|
|
2444
2454
|
systemPromptSuffix: init.systemPromptSuffix,
|
|
2455
|
+
sessionMode,
|
|
2445
2456
|
});
|
|
2446
2457
|
const session = built.session;
|
|
2447
2458
|
// Prefer the SessionManager id (from the JSONL header). Some SDK
|
|
@@ -2464,7 +2475,6 @@ export class ConsolePiRuntime {
|
|
|
2464
2475
|
message: `reopened Pi sessionId mismatch: expected ${sessionId}, got ${reportedId}`,
|
|
2465
2476
|
};
|
|
2466
2477
|
}
|
|
2467
|
-
session.setActiveToolsByName(computeOperatorChatActiveToolNames(session));
|
|
2468
2478
|
this.sessions.set(sessionId, session);
|
|
2469
2479
|
this.sessionManagers.set(sessionId, sessionManager);
|
|
2470
2480
|
this.modelRuntimes.set(sessionId, built.modelRuntime);
|
|
@@ -2482,6 +2492,7 @@ export class ConsolePiRuntime {
|
|
|
2482
2492
|
createdAt: new Date().toISOString(),
|
|
2483
2493
|
model: init.model,
|
|
2484
2494
|
activeTools: session.getActiveToolNames(),
|
|
2495
|
+
sessionMode,
|
|
2485
2496
|
},
|
|
2486
2497
|
};
|
|
2487
2498
|
}
|
|
@@ -2513,6 +2524,7 @@ export class ConsolePiRuntime {
|
|
|
2513
2524
|
createdAt: new Date().toISOString(),
|
|
2514
2525
|
model,
|
|
2515
2526
|
activeTools: session.getActiveToolNames(),
|
|
2527
|
+
sessionMode: this.sessionModeOf(sessionId),
|
|
2516
2528
|
};
|
|
2517
2529
|
}
|
|
2518
2530
|
/**
|
|
@@ -2521,12 +2533,14 @@ export class ConsolePiRuntime {
|
|
|
2521
2533
|
* before AgentSession is ready. Tool definitions reuse runtime-level caches.
|
|
2522
2534
|
*/
|
|
2523
2535
|
async buildSessionWithServices(init) {
|
|
2536
|
+
const sessionMode = this.rememberSessionMode(init.sessionId, init.sessionMode ?? this.sessionModeOf(init.sessionId));
|
|
2524
2537
|
const agentDir = await safeGetAgentDir(this.bindings);
|
|
2525
2538
|
const modelConfigFile = await captureModelConfigFile(agentDir);
|
|
2526
|
-
const appendSystemPrompt =
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2539
|
+
const appendSystemPrompt = composeChatSystemPromptParts({
|
|
2540
|
+
sessionMode,
|
|
2541
|
+
workflowPrompt: OPERATOR_CHAT_SYSTEM_PROMPT_BASE,
|
|
2542
|
+
systemPromptSuffix: init.systemPromptSuffix,
|
|
2543
|
+
});
|
|
2530
2544
|
await this.refreshSkillPrefsCache().catch(() => undefined);
|
|
2531
2545
|
const { services } = await this.bindings.createServices({
|
|
2532
2546
|
cwd: this.options.cwd,
|
|
@@ -2551,7 +2565,7 @@ export class ConsolePiRuntime {
|
|
|
2551
2565
|
...(resolvedModel ? { model: resolvedModel } : {}),
|
|
2552
2566
|
});
|
|
2553
2567
|
await bindSessionExtensions(session);
|
|
2554
|
-
pinOperatorChatTools(session);
|
|
2568
|
+
pinOperatorChatTools(session, sessionMode);
|
|
2555
2569
|
this.applySessionCompactionOverride(init.sessionId, services, session);
|
|
2556
2570
|
return {
|
|
2557
2571
|
session,
|
|
@@ -2620,7 +2634,7 @@ export class ConsolePiRuntime {
|
|
|
2620
2634
|
}
|
|
2621
2635
|
/**
|
|
2622
2636
|
* Send a prompt and stream events. Gate 3: each tool invocation is
|
|
2623
|
-
* re-authorized by
|
|
2637
|
+
* re-authorized by authorizeChatSessionTool(mode) before the dispatcher runs it
|
|
2624
2638
|
* (the dispatcher is wired by the HTTP layer, see chat-session.ts).
|
|
2625
2639
|
*
|
|
2626
2640
|
* Prompt ownership is acquired synchronously before the first await so two
|
|
@@ -2662,7 +2676,8 @@ export class ConsolePiRuntime {
|
|
|
2662
2676
|
if (options?.turnId && this.options.todoRegistry) {
|
|
2663
2677
|
this.options.todoRegistry.startTurn(sessionId, options.turnId);
|
|
2664
2678
|
}
|
|
2665
|
-
if (this.options.goalRegistry
|
|
2679
|
+
if (this.options.goalRegistry &&
|
|
2680
|
+
shouldInjectGoalContinuation(this.sessionModeOf(sessionId))) {
|
|
2666
2681
|
this.options.goalRegistry.startTurn(sessionId, text);
|
|
2667
2682
|
}
|
|
2668
2683
|
// AC-FIX-002: if Stop already fired before readiness, never start model work.
|
|
@@ -2683,10 +2698,11 @@ export class ConsolePiRuntime {
|
|
|
2683
2698
|
// existing closed interview allow/deny registry. The next ordinary turn
|
|
2684
2699
|
// explicitly restores the normal Operator Chat set (baseline + extension
|
|
2685
2700
|
// tools, ADR 0012).
|
|
2686
|
-
const
|
|
2687
|
-
const
|
|
2701
|
+
const sessionMode = this.sessionModeOf(sessionId);
|
|
2702
|
+
const requestedTools = chatActiveToolBaseline(sessionMode);
|
|
2703
|
+
const activeTools = options?.mode === "requirement-interview" && sessionMode === "workflow"
|
|
2688
2704
|
? filterActiveInterviewTools(requestedTools).allowed
|
|
2689
|
-
:
|
|
2705
|
+
: computeChatActiveToolNames(session, sessionMode);
|
|
2690
2706
|
session.setActiveToolsByName(activeTools);
|
|
2691
2707
|
// Final pre-prompt fence: abort after tool pin must still skip session.prompt.
|
|
2692
2708
|
if (options?.signal?.aborted) {
|
|
@@ -3024,6 +3040,7 @@ export class ConsolePiRuntime {
|
|
|
3024
3040
|
this.modelRuntimes.delete(sessionId);
|
|
3025
3041
|
this.modelConfigFiles.delete(sessionId);
|
|
3026
3042
|
this.sessionModels.delete(sessionId);
|
|
3043
|
+
this.sessionModes.delete(sessionId);
|
|
3027
3044
|
this.serviceScopes.delete(sessionId);
|
|
3028
3045
|
this.revisions.delete(sessionId);
|
|
3029
3046
|
this.thinkingSelections.delete(sessionId);
|
|
@@ -3339,7 +3356,8 @@ export function createDefaultPiSdkBindings() {
|
|
|
3339
3356
|
};
|
|
3340
3357
|
}
|
|
3341
3358
|
/**
|
|
3342
|
-
* Re-export the tool
|
|
3343
|
-
* (Gate 3) lives in exactly one place.
|
|
3359
|
+
* Re-export the tool gates for the dispatcher layer so the per-tool-call gate
|
|
3360
|
+
* (Gate 3) lives in exactly one place. authorizeChatSessionTool is the
|
|
3361
|
+
* mode-aware gate; the legacy name stays for workflow-only callers.
|
|
3344
3362
|
*/
|
|
3345
|
-
export { authorizeOperatorChatTool, assertNoWriteToolInList, OPERATOR_CHAT_ALLOWED_TOOLS, };
|
|
3363
|
+
export { authorizeChatSessionTool, authorizeOperatorChatTool, assertNoWriteToolInList, OPERATOR_CHAT_ALLOWED_TOOLS, };
|