pulseed 0.4.20 → 0.5.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/dist/adapters/types/mcp.d.ts +6 -6
- package/dist/base/config/global-config.d.ts +4 -4
- package/dist/base/llm/codex-llm-client.d.ts +8 -2
- package/dist/base/llm/codex-llm-client.d.ts.map +1 -1
- package/dist/base/llm/codex-llm-client.js +75 -30
- package/dist/base/llm/codex-llm-client.js.map +1 -1
- package/dist/base/llm/provider-config.d.ts +14 -0
- package/dist/base/llm/provider-config.d.ts.map +1 -1
- package/dist/base/llm/provider-config.js +56 -2
- package/dist/base/llm/provider-config.js.map +1 -1
- package/dist/base/llm/provider-factory.d.ts.map +1 -1
- package/dist/base/llm/provider-factory.js +3 -0
- package/dist/base/llm/provider-factory.js.map +1 -1
- package/dist/grounding/contracts.d.ts +160 -0
- package/dist/grounding/contracts.d.ts.map +1 -0
- package/dist/grounding/contracts.js +2 -0
- package/dist/grounding/contracts.js.map +1 -0
- package/dist/grounding/gateway.d.ts +12 -0
- package/dist/grounding/gateway.d.ts.map +1 -0
- package/dist/grounding/gateway.js +116 -0
- package/dist/grounding/gateway.js.map +1 -0
- package/dist/grounding/profiles.d.ts +4 -0
- package/dist/grounding/profiles.d.ts.map +1 -0
- package/dist/grounding/profiles.js +159 -0
- package/dist/grounding/profiles.js.map +1 -0
- package/dist/grounding/providers/agents-provider.d.ts +14 -0
- package/dist/grounding/providers/agents-provider.d.ts.map +1 -0
- package/dist/grounding/providers/agents-provider.js +129 -0
- package/dist/grounding/providers/agents-provider.js.map +1 -0
- package/dist/grounding/providers/goal-state-provider.d.ts +3 -0
- package/dist/grounding/providers/goal-state-provider.d.ts.map +1 -0
- package/dist/grounding/providers/goal-state-provider.js +34 -0
- package/dist/grounding/providers/goal-state-provider.js.map +1 -0
- package/dist/grounding/providers/helpers.d.ts +13 -0
- package/dist/grounding/providers/helpers.d.ts.map +1 -0
- package/dist/grounding/providers/helpers.js +93 -0
- package/dist/grounding/providers/helpers.js.map +1 -0
- package/dist/grounding/providers/knowledge-provider.d.ts +3 -0
- package/dist/grounding/providers/knowledge-provider.d.ts.map +1 -0
- package/dist/grounding/providers/knowledge-provider.js +49 -0
- package/dist/grounding/providers/knowledge-provider.js.map +1 -0
- package/dist/grounding/providers/lessons-provider.d.ts +3 -0
- package/dist/grounding/providers/lessons-provider.d.ts.map +1 -0
- package/dist/grounding/providers/lessons-provider.js +36 -0
- package/dist/grounding/providers/lessons-provider.js.map +1 -0
- package/dist/grounding/providers/plugins-provider.d.ts +3 -0
- package/dist/grounding/providers/plugins-provider.d.ts.map +1 -0
- package/dist/grounding/providers/plugins-provider.js +35 -0
- package/dist/grounding/providers/plugins-provider.js.map +1 -0
- package/dist/grounding/providers/progress-history-provider.d.ts +3 -0
- package/dist/grounding/providers/progress-history-provider.d.ts.map +1 -0
- package/dist/grounding/providers/progress-history-provider.js +30 -0
- package/dist/grounding/providers/progress-history-provider.js.map +1 -0
- package/dist/grounding/providers/provider-state-provider.d.ts +3 -0
- package/dist/grounding/providers/provider-state-provider.d.ts.map +1 -0
- package/dist/grounding/providers/provider-state-provider.js +32 -0
- package/dist/grounding/providers/provider-state-provider.js.map +1 -0
- package/dist/grounding/providers/session-history-provider.d.ts +3 -0
- package/dist/grounding/providers/session-history-provider.d.ts.map +1 -0
- package/dist/grounding/providers/session-history-provider.js +72 -0
- package/dist/grounding/providers/session-history-provider.js.map +1 -0
- package/dist/grounding/providers/soil-provider.d.ts +3 -0
- package/dist/grounding/providers/soil-provider.d.ts.map +1 -0
- package/dist/grounding/providers/soil-provider.js +70 -0
- package/dist/grounding/providers/soil-provider.js.map +1 -0
- package/dist/grounding/providers/static-policy-provider.d.ts +8 -0
- package/dist/grounding/providers/static-policy-provider.d.ts.map +1 -0
- package/dist/grounding/providers/static-policy-provider.js +81 -0
- package/dist/grounding/providers/static-policy-provider.js.map +1 -0
- package/dist/grounding/providers/task-state-provider.d.ts +3 -0
- package/dist/grounding/providers/task-state-provider.d.ts.map +1 -0
- package/dist/grounding/providers/task-state-provider.js +55 -0
- package/dist/grounding/providers/task-state-provider.js.map +1 -0
- package/dist/grounding/providers/trust-state-provider.d.ts +3 -0
- package/dist/grounding/providers/trust-state-provider.d.ts.map +1 -0
- package/dist/grounding/providers/trust-state-provider.js +25 -0
- package/dist/grounding/providers/trust-state-provider.js.map +1 -0
- package/dist/grounding/providers/workspace-facts-provider.d.ts +3 -0
- package/dist/grounding/providers/workspace-facts-provider.d.ts.map +1 -0
- package/dist/grounding/providers/workspace-facts-provider.js +22 -0
- package/dist/grounding/providers/workspace-facts-provider.js.map +1 -0
- package/dist/grounding/renderers/debug-renderer.d.ts +3 -0
- package/dist/grounding/renderers/debug-renderer.d.ts.map +1 -0
- package/dist/grounding/renderers/debug-renderer.js +11 -0
- package/dist/grounding/renderers/debug-renderer.js.map +1 -0
- package/dist/grounding/renderers/prompt-renderer.d.ts +10 -0
- package/dist/grounding/renderers/prompt-renderer.d.ts.map +1 -0
- package/dist/grounding/renderers/prompt-renderer.js +23 -0
- package/dist/grounding/renderers/prompt-renderer.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/interface/chat/chat-event-state.d.ts +1 -0
- package/dist/interface/chat/chat-event-state.d.ts.map +1 -1
- package/dist/interface/chat/chat-event-state.js +12 -2
- package/dist/interface/chat/chat-event-state.js.map +1 -1
- package/dist/interface/chat/chat-runner.d.ts +18 -6
- package/dist/interface/chat/chat-runner.d.ts.map +1 -1
- package/dist/interface/chat/chat-runner.js +331 -148
- package/dist/interface/chat/chat-runner.js.map +1 -1
- package/dist/interface/chat/cross-platform-session-global.d.ts +5 -0
- package/dist/interface/chat/cross-platform-session-global.d.ts.map +1 -0
- package/dist/interface/chat/cross-platform-session-global.js +17 -0
- package/dist/interface/chat/cross-platform-session-global.js.map +1 -0
- package/dist/interface/chat/cross-platform-session.d.ts +22 -0
- package/dist/interface/chat/cross-platform-session.d.ts.map +1 -1
- package/dist/interface/chat/cross-platform-session.js +192 -61
- package/dist/interface/chat/cross-platform-session.js.map +1 -1
- package/dist/interface/chat/event-subscriber.d.ts +14 -0
- package/dist/interface/chat/event-subscriber.d.ts.map +1 -1
- package/dist/interface/chat/event-subscriber.js +138 -28
- package/dist/interface/chat/event-subscriber.js.map +1 -1
- package/dist/interface/chat/grounding.d.ts +22 -1
- package/dist/interface/chat/grounding.d.ts.map +1 -1
- package/dist/interface/chat/grounding.js +82 -127
- package/dist/interface/chat/grounding.js.map +1 -1
- package/dist/interface/chat/ingress-router.d.ts +110 -0
- package/dist/interface/chat/ingress-router.d.ts.map +1 -0
- package/dist/interface/chat/ingress-router.js +183 -0
- package/dist/interface/chat/ingress-router.js.map +1 -0
- package/dist/interface/cli/setup.d.ts.map +1 -1
- package/dist/interface/cli/setup.js +1 -0
- package/dist/interface/cli/setup.js.map +1 -1
- package/dist/interface/tui/app.d.ts +2 -2
- package/dist/interface/tui/app.d.ts.map +1 -1
- package/dist/interface/tui/chat/scroll.d.ts +1 -1
- package/dist/interface/tui/chat/scroll.d.ts.map +1 -1
- package/dist/interface/tui/chat/scroll.js +19 -4
- package/dist/interface/tui/chat/scroll.js.map +1 -1
- package/dist/interface/tui/chat/types.d.ts +2 -0
- package/dist/interface/tui/chat/types.d.ts.map +1 -1
- package/dist/interface/tui/chat/viewport.d.ts.map +1 -1
- package/dist/interface/tui/chat/viewport.js +1 -0
- package/dist/interface/tui/chat/viewport.js.map +1 -1
- package/dist/interface/tui/chat-surface.d.ts +20 -0
- package/dist/interface/tui/chat-surface.d.ts.map +1 -0
- package/dist/interface/tui/chat-surface.js +59 -0
- package/dist/interface/tui/chat-surface.js.map +1 -0
- package/dist/interface/tui/chat.d.ts +1 -1
- package/dist/interface/tui/chat.d.ts.map +1 -1
- package/dist/interface/tui/chat.js +9 -6
- package/dist/interface/tui/chat.js.map +1 -1
- package/dist/interface/tui/entry.d.ts.map +1 -1
- package/dist/interface/tui/entry.js +64 -8
- package/dist/interface/tui/entry.js.map +1 -1
- package/dist/interface/tui/flicker/MouseTracking.d.ts +1 -0
- package/dist/interface/tui/flicker/MouseTracking.d.ts.map +1 -1
- package/dist/interface/tui/flicker/MouseTracking.js +7 -0
- package/dist/interface/tui/flicker/MouseTracking.js.map +1 -1
- package/dist/interface/tui/flicker/index.d.ts +1 -1
- package/dist/interface/tui/flicker/index.d.ts.map +1 -1
- package/dist/interface/tui/flicker/index.js +1 -1
- package/dist/interface/tui/flicker/index.js.map +1 -1
- package/dist/interface/tui/fullscreen-chat.d.ts +28 -3
- package/dist/interface/tui/fullscreen-chat.d.ts.map +1 -1
- package/dist/interface/tui/fullscreen-chat.js +61 -45
- package/dist/interface/tui/fullscreen-chat.js.map +1 -1
- package/dist/interface/tui/markdown-renderer.d.ts +1 -1
- package/dist/interface/tui/markdown-renderer.d.ts.map +1 -1
- package/dist/interface/tui/markdown-renderer.js +137 -11
- package/dist/interface/tui/markdown-renderer.js.map +1 -1
- package/dist/interface/tui/test-entry.d.ts.map +1 -1
- package/dist/interface/tui/test-entry.js +3 -2
- package/dist/interface/tui/test-entry.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-context-assembler.d.ts +3 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-context-assembler.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-context-assembler.js +76 -112
- package/dist/orchestrator/execution/agent-loop/agent-loop-context-assembler.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-default-profile.d.ts +11 -0
- package/dist/orchestrator/execution/agent-loop/agent-loop-default-profile.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-default-profile.js +13 -0
- package/dist/orchestrator/execution/agent-loop/agent-loop-default-profile.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-events.d.ts +1 -0
- package/dist/orchestrator/execution/agent-loop/agent-loop-events.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-events.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-prompts.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-prompts.js +8 -0
- package/dist/orchestrator/execution/agent-loop/agent-loop-prompts.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-session-state.d.ts +1 -0
- package/dist/orchestrator/execution/agent-loop/agent-loop-session-state.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-session-state.js +1 -0
- package/dist/orchestrator/execution/agent-loop/agent-loop-session-state.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-turn-context.d.ts +3 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-turn-context.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/agent-loop-turn-context.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/bounded-agent-loop-runner.d.ts +1 -1
- package/dist/orchestrator/execution/agent-loop/bounded-agent-loop-runner.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/bounded-agent-loop-runner.js +60 -50
- package/dist/orchestrator/execution/agent-loop/bounded-agent-loop-runner.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/chat-agent-loop-runner.d.ts +239 -10
- package/dist/orchestrator/execution/agent-loop/chat-agent-loop-runner.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/chat-agent-loop-runner.js +298 -96
- package/dist/orchestrator/execution/agent-loop/chat-agent-loop-runner.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/prompted-tool-protocol.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/prompted-tool-protocol.js +1 -0
- package/dist/orchestrator/execution/agent-loop/prompted-tool-protocol.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-context.d.ts +2 -5
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-context.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-context.js +10 -12
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-context.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-factory.d.ts +2 -0
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-factory.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-factory.js +16 -9
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-factory.js.map +1 -1
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-result.d.ts +6 -6
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-runner.d.ts.map +1 -1
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-runner.js +53 -36
- package/dist/orchestrator/execution/agent-loop/task-agent-loop-runner.js.map +1 -1
- package/dist/orchestrator/loop/core-loop/phase-policy.d.ts.map +1 -1
- package/dist/orchestrator/loop/core-loop/phase-policy.js +87 -34
- package/dist/orchestrator/loop/core-loop/phase-policy.js.map +1 -1
- package/dist/orchestrator/loop/core-loop.d.ts +1 -0
- package/dist/orchestrator/loop/core-loop.d.ts.map +1 -1
- package/dist/orchestrator/loop/core-loop.js +191 -176
- package/dist/orchestrator/loop/core-loop.js.map +1 -1
- package/dist/platform/dream/dream-types.d.ts +14 -14
- package/dist/platform/knowledge/index.d.ts +3 -0
- package/dist/platform/knowledge/index.d.ts.map +1 -0
- package/dist/platform/knowledge/index.js +3 -0
- package/dist/platform/knowledge/index.js.map +1 -0
- package/dist/platform/knowledge/knowledge-manager.d.ts +1 -4
- package/dist/platform/knowledge/knowledge-manager.d.ts.map +1 -1
- package/dist/platform/knowledge/knowledge-manager.js +1 -4
- package/dist/platform/knowledge/knowledge-manager.js.map +1 -1
- package/dist/platform/knowledge/public-api.d.ts +4 -0
- package/dist/platform/knowledge/public-api.d.ts.map +1 -0
- package/dist/platform/knowledge/public-api.js +4 -0
- package/dist/platform/knowledge/public-api.js.map +1 -0
- package/dist/platform/soil/contracts.d.ts +66 -66
- package/dist/runtime/daemon/runner-goal-cycle.d.ts.map +1 -1
- package/dist/runtime/daemon/runner-goal-cycle.js +36 -1
- package/dist/runtime/daemon/runner-goal-cycle.js.map +1 -1
- package/dist/runtime/plugin-loader.d.ts.map +1 -1
- package/dist/runtime/plugin-loader.js +3 -6
- package/dist/runtime/plugin-loader.js.map +1 -1
- package/dist/runtime/schedule/history.d.ts +3 -3
- package/dist/runtime/schedule/presets.d.ts +20 -20
- package/dist/runtime/schedule/source.d.ts +4 -4
- package/dist/runtime/store/runtime-operation-schemas.d.ts +2 -2
- package/dist/runtime/store/runtime-schemas.d.ts +2 -2
- package/dist/runtime/types/cron.d.ts +4 -4
- package/dist/runtime/types/schedule.d.ts +51 -51
- package/dist/runtime/types/trigger.d.ts +6 -6
- package/dist/tools/builtin/exports.d.ts +79 -0
- package/dist/tools/builtin/exports.d.ts.map +1 -0
- package/dist/tools/builtin/exports.js +78 -0
- package/dist/tools/builtin/exports.js.map +1 -0
- package/dist/tools/builtin/factory.d.ts +33 -0
- package/dist/tools/builtin/factory.d.ts.map +1 -0
- package/dist/tools/builtin/factory.js +182 -0
- package/dist/tools/builtin/factory.js.map +1 -0
- package/dist/tools/builtin/index.d.ts +3 -110
- package/dist/tools/builtin/index.d.ts.map +1 -1
- package/dist/tools/builtin/index.js +2 -262
- package/dist/tools/builtin/index.js.map +1 -1
- package/dist/tools/execution/SoilOpenTool/SoilOpenTool.d.ts +4 -4
- package/dist/tools/execution/SoilPublishTool/SoilPublishTool.d.ts +2 -2
- package/dist/tools/index.d.ts +5 -3
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/mutation/TaskCreateTool/TaskCreateTool.d.ts +4 -4
- package/dist/tools/network/GitHubCliTool/GitHubCliTool.d.ts +4 -4
- package/dist/tools/network/McpStdioTool/McpStdioTool.d.ts +8 -8
- package/dist/tools/schedule/CreateScheduleTool/CreateScheduleTool.d.ts +44 -44
- package/dist/tools/schedule/ListSchedulesTool/ListSchedulesTool.d.ts +4 -4
- package/dist/tools/schedule/UpdateScheduleTool/UpdateScheduleTool.d.ts +58 -58
- package/dist/tools/system/ProcessSessionTool/ProcessSessionTool.d.ts +6 -6
- package/dist/tools/types.d.ts +2 -2
- package/package.json +1 -1
|
@@ -5,25 +5,25 @@
|
|
|
5
5
|
import { execFile } from "node:child_process";
|
|
6
6
|
import * as fsp from "node:fs/promises";
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
+
import { getPulseedDirPath } from "../../base/utils/paths.js";
|
|
8
9
|
import { loadProviderConfig } from "../../base/llm/provider-config.js";
|
|
10
|
+
import { TaskSchema } from "../../base/types/task.js";
|
|
9
11
|
import { ChatHistory } from "./chat-history.js";
|
|
10
12
|
import { ChatSessionCatalog, ChatSessionSelectorError, } from "./chat-session-store.js";
|
|
11
13
|
import { buildChatContext, resolveGitRoot } from "../../platform/observation/context-provider.js";
|
|
12
|
-
import {
|
|
14
|
+
import { buildChatAgentLoopSystemPrompt, buildStaticSystemPrompt, createChatGroundingGateway } from "./grounding.js";
|
|
13
15
|
import { verifyChatAction } from "./chat-verifier.js";
|
|
14
16
|
import { toToolDefinitionsFiltered } from "../../tools/tool-definition-adapter.js";
|
|
15
17
|
import { TendCommand } from "./tend-command.js";
|
|
16
18
|
import { EventSubscriber } from "./event-subscriber.js";
|
|
17
19
|
import { buildPromptedToolProtocolSystemPrompt, extractPromptedToolCalls, } from "../../orchestrator/execution/agent-loop/prompted-tool-protocol.js";
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { summarizeExecutionPolicy, withExecutionPolicyOverrides, } from "../../orchestrator/execution/agent-loop/execution-policy.js";
|
|
21
|
-
import { ChatStateService } from "./chat-state-service.js";
|
|
20
|
+
import { resolveExecutionPolicy, summarizeExecutionPolicy, withExecutionPolicyOverrides, } from "../../orchestrator/execution/agent-loop/execution-policy.js";
|
|
21
|
+
import { buildStandaloneIngressMessage, createIngressRouter, } from "./ingress-router.js";
|
|
22
22
|
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
23
23
|
const MAX_VERIFY_RETRIES = 2;
|
|
24
24
|
const MAX_TOOL_LOOPS = 5;
|
|
25
25
|
const ACTIVITY_PREVIEW_CHARS = 40;
|
|
26
|
-
const
|
|
26
|
+
const standaloneIngressRouter = createIngressRouter();
|
|
27
27
|
// ─── Command help text ───
|
|
28
28
|
const COMMAND_HELP = `Available commands:
|
|
29
29
|
Session
|
|
@@ -76,32 +76,10 @@ function formatToolActivity(action, toolName, detail) {
|
|
|
76
76
|
const preview = detail ? previewActivityText(detail) : "";
|
|
77
77
|
return preview ? `${action} tool: ${toolName} - ${preview}` : `${action} tool: ${toolName}`;
|
|
78
78
|
}
|
|
79
|
-
function shouldUseDirectAnswerRoute(input) {
|
|
80
|
-
const normalized = input.trim();
|
|
81
|
-
if (!normalized)
|
|
82
|
-
return false;
|
|
83
|
-
const lowered = normalized.toLowerCase();
|
|
84
|
-
const questionSignals = [
|
|
85
|
-
/[??]/,
|
|
86
|
-
/\b(what|why|how|when|where|who|which|is|are|can|could|would|should|tell me|explain|describe|help me understand)\b/,
|
|
87
|
-
/(教えて|説明して|教えてください|説明してください|どう思う|なんで|なぜ|どうして|いつ|どこ|だれ|誰|何|どれ|どっち)/,
|
|
88
|
-
];
|
|
89
|
-
if (!questionSignals.some((pattern) => pattern.test(lowered))) {
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
const workSignals = [
|
|
93
|
-
/\b(fix|implement|change|changed|add|remove|delete|update|refactor|patch|debug|diagnose|investigate|review|write|create|build|run|execute|test|verify|confirm|check|inspect|search|open|read|edit|modify|commit|push|merge|release|deploy|start|stop|restart|resume|compare|convert|migrate|optimize|improve|configure|setup|set up)\b/,
|
|
94
|
-
/(修正|実装|変更|追加|削除|更新|リファクタ|デバッグ|調査|確認|レビュー|書いて|作って|作成|実行|走らせ|テスト|検証|調べて|開いて|読んで|編集|コミット|プッシュ|マージ|デプロイ|再起動|再開|設定)/,
|
|
95
|
-
/\b(git|repo|repository|branch|commit|diff|pull request|pr|issue|ticket|adapter|agentloop|tool|tools|code)\b|コード|src\//,
|
|
96
|
-
/\b(latest|most recent|current|today|now|recent|news|web|internet|api|docs|github|release|version)\b|最新|最新版|今日|現在|最近|今|外部|ネット/,
|
|
97
|
-
/\bwhat\s+(files?\s+)?changed\b|\bwhich\s+files?\s+(changed|were\s+(modified|edited))\b/,
|
|
98
|
-
/(\.(ts|tsx|js|jsx|json|md|yml|yaml|toml|py|go|rs|sh|sql)\b|\/[^/\s]+\.[A-Za-z0-9]+$)/,
|
|
99
|
-
];
|
|
100
|
-
return !workSignals.some((pattern) => pattern.test(lowered));
|
|
101
|
-
}
|
|
102
79
|
// ─── ChatRunner ───
|
|
103
80
|
export class ChatRunner {
|
|
104
81
|
deps;
|
|
82
|
+
groundingGateway;
|
|
105
83
|
history = null;
|
|
106
84
|
sessionCwd = null;
|
|
107
85
|
/** True when startSession() has been called — enables session persistence across execute() calls. */
|
|
@@ -123,10 +101,12 @@ export class ChatRunner {
|
|
|
123
101
|
nativeAgentLoopStatePath = null;
|
|
124
102
|
runtimeControlContext = null;
|
|
125
103
|
sessionExecutionPolicy = null;
|
|
126
|
-
stateView;
|
|
127
104
|
constructor(deps) {
|
|
128
105
|
this.deps = deps;
|
|
129
|
-
this.
|
|
106
|
+
this.groundingGateway = createChatGroundingGateway({
|
|
107
|
+
stateManager: deps.stateManager,
|
|
108
|
+
pluginLoader: deps.pluginLoader,
|
|
109
|
+
});
|
|
130
110
|
}
|
|
131
111
|
/**
|
|
132
112
|
* Initialize a persistent session for interactive (multi-turn) mode.
|
|
@@ -161,6 +141,69 @@ export class ChatRunner {
|
|
|
161
141
|
setRuntimeControlContext(context) {
|
|
162
142
|
this.runtimeControlContext = context;
|
|
163
143
|
}
|
|
144
|
+
async executeIngressMessage(ingress, cwd, timeoutMs = DEFAULT_TIMEOUT_MS, selectedRoute) {
|
|
145
|
+
if (!selectedRoute) {
|
|
146
|
+
throw new Error("executeIngressMessage requires selectedRoute; use CrossPlatformChatSessionManager for ingress route selection.");
|
|
147
|
+
}
|
|
148
|
+
const runtimeControlContext = this.buildRuntimeControlContextFromIngress(ingress);
|
|
149
|
+
return this.execute(ingress.text, cwd, timeoutMs, { selectedRoute, runtimeControlContext });
|
|
150
|
+
}
|
|
151
|
+
resolveRouteFromIngress(ingress) {
|
|
152
|
+
return standaloneIngressRouter.selectRoute(ingress, this.getRouteCapabilities());
|
|
153
|
+
}
|
|
154
|
+
resolveRouteFromInput(input, runtimeControlContext) {
|
|
155
|
+
return this.resolveRouteFromIngress(this.buildStandaloneIngressMessage(input, runtimeControlContext));
|
|
156
|
+
}
|
|
157
|
+
getRouteCapabilities() {
|
|
158
|
+
return {
|
|
159
|
+
hasLightweightLlm: this.deps.llmClient !== undefined,
|
|
160
|
+
hasAgentLoop: this.deps.chatAgentLoopRunner !== undefined,
|
|
161
|
+
hasToolLoop: this.deps.llmClient !== undefined,
|
|
162
|
+
hasRuntimeControlService: this.deps.runtimeControlService !== undefined,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
buildStandaloneIngressMessage(input, runtimeControlContext) {
|
|
166
|
+
const channel = runtimeControlContext?.replyTarget?.surface === "tui"
|
|
167
|
+
? "tui"
|
|
168
|
+
: runtimeControlContext?.replyTarget?.surface === "cli"
|
|
169
|
+
? "cli"
|
|
170
|
+
: runtimeControlContext?.replyTarget?.surface === "gateway"
|
|
171
|
+
? "plugin_gateway"
|
|
172
|
+
: "cli";
|
|
173
|
+
const runtimeApprovalFn = runtimeControlContext?.approvalFn
|
|
174
|
+
?? this.deps.runtimeControlApprovalFn
|
|
175
|
+
?? this.deps.approvalFn;
|
|
176
|
+
return buildStandaloneIngressMessage({
|
|
177
|
+
text: input,
|
|
178
|
+
channel,
|
|
179
|
+
platform: runtimeControlContext?.replyTarget?.platform ?? this.deps.runtimeReplyTarget?.platform,
|
|
180
|
+
identity_key: runtimeControlContext?.replyTarget?.identity_key ?? this.deps.runtimeReplyTarget?.identity_key,
|
|
181
|
+
conversation_id: runtimeControlContext?.replyTarget?.conversation_id ?? this.deps.runtimeReplyTarget?.conversation_id,
|
|
182
|
+
user_id: runtimeControlContext?.replyTarget?.user_id ?? this.deps.runtimeReplyTarget?.user_id,
|
|
183
|
+
actor: runtimeControlContext?.actor ?? this.deps.runtimeControlActor,
|
|
184
|
+
replyTarget: runtimeControlContext?.replyTarget ?? this.deps.runtimeReplyTarget,
|
|
185
|
+
runtimeControl: {
|
|
186
|
+
allowed: true,
|
|
187
|
+
approvalMode: "interactive",
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
buildRuntimeControlContextFromIngress(ingress) {
|
|
192
|
+
if (!ingress.actor && !ingress.replyTarget)
|
|
193
|
+
return null;
|
|
194
|
+
const interactiveApproval = this.runtimeControlContext?.approvalFn
|
|
195
|
+
?? this.deps.runtimeControlApprovalFn
|
|
196
|
+
?? this.deps.approvalFn;
|
|
197
|
+
return {
|
|
198
|
+
actor: ingress.actor,
|
|
199
|
+
replyTarget: ingress.replyTarget,
|
|
200
|
+
approvalFn: ingress.runtimeControl.approvalMode === "preapproved"
|
|
201
|
+
? async () => true
|
|
202
|
+
: ingress.runtimeControl.approvalMode === "interactive"
|
|
203
|
+
? interactiveApproval
|
|
204
|
+
: undefined,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
164
207
|
loadedSessionToChatSession(session) {
|
|
165
208
|
return {
|
|
166
209
|
id: session.id,
|
|
@@ -177,7 +220,6 @@ export class ChatRunner {
|
|
|
177
220
|
...(session.agentLoopResumable ? { agentLoopResumable: true } : {}),
|
|
178
221
|
...(session.agentLoopUpdatedAt ? { agentLoopUpdatedAt: session.agentLoopUpdatedAt } : {}),
|
|
179
222
|
...(session.agentLoop ? { agentLoop: session.agentLoop } : {}),
|
|
180
|
-
...(session.usage ? { usage: session.usage } : {}),
|
|
181
223
|
};
|
|
182
224
|
}
|
|
183
225
|
formatSessionsList(entries) {
|
|
@@ -202,13 +244,53 @@ export class ChatRunner {
|
|
|
202
244
|
return `Session ${session.id}${title} (${session.cwd})\n${lines.join("\n")}`;
|
|
203
245
|
}
|
|
204
246
|
async loadGoals() {
|
|
205
|
-
|
|
247
|
+
const goalIds = await this.deps.stateManager.listGoalIds();
|
|
248
|
+
const goals = await Promise.all(goalIds.map((id) => this.deps.stateManager.loadGoal(id)));
|
|
249
|
+
return goals.filter((goal) => goal !== null);
|
|
206
250
|
}
|
|
207
251
|
async listAllGoalIds() {
|
|
208
|
-
|
|
252
|
+
const activeIds = await this.deps.stateManager.listGoalIds();
|
|
253
|
+
const archivedIds = await this.deps.stateManager.listArchivedGoals();
|
|
254
|
+
const recoverableArchivedIds = await this.listRecoverableArchivedGoalIds();
|
|
255
|
+
return [...new Set([...activeIds, ...archivedIds, ...recoverableArchivedIds])];
|
|
256
|
+
}
|
|
257
|
+
resolveStatePath(baseDir, ...segments) {
|
|
258
|
+
const base = path.resolve(baseDir);
|
|
259
|
+
const resolved = path.resolve(base, ...segments);
|
|
260
|
+
if (!resolved.startsWith(base + path.sep))
|
|
261
|
+
return null;
|
|
262
|
+
return resolved;
|
|
263
|
+
}
|
|
264
|
+
async listRecoverableArchivedGoalIds() {
|
|
265
|
+
const stateManager = this.deps.stateManager;
|
|
266
|
+
if (typeof stateManager.getBaseDir !== "function")
|
|
267
|
+
return [];
|
|
268
|
+
const archiveDir = this.resolveStatePath(stateManager.getBaseDir(), "archive");
|
|
269
|
+
if (archiveDir === null)
|
|
270
|
+
return [];
|
|
271
|
+
let entries = [];
|
|
272
|
+
try {
|
|
273
|
+
entries = await fsp.readdir(archiveDir, { withFileTypes: true });
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
return [];
|
|
277
|
+
}
|
|
278
|
+
const goalIds = [];
|
|
279
|
+
for (const entry of entries) {
|
|
280
|
+
if (!entry.isDirectory() || entry.name === ".staging")
|
|
281
|
+
continue;
|
|
282
|
+
try {
|
|
283
|
+
await fsp.access(path.join(archiveDir, entry.name, "goal", "goal.json"));
|
|
284
|
+
goalIds.push(entry.name);
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return goalIds;
|
|
209
291
|
}
|
|
210
292
|
activeGoals(goals) {
|
|
211
|
-
return
|
|
293
|
+
return goals.filter((goal) => goal.status === "active" || goal.status === "waiting" || goal.loop_status === "running");
|
|
212
294
|
}
|
|
213
295
|
formatGoalLine(goal) {
|
|
214
296
|
const dimensions = goal.dimensions.length === 0
|
|
@@ -259,8 +341,44 @@ export class ChatRunner {
|
|
|
259
341
|
elapsed_ms: Date.now() - start,
|
|
260
342
|
};
|
|
261
343
|
}
|
|
344
|
+
async readTasksFromDir(tasksDir) {
|
|
345
|
+
let entries = [];
|
|
346
|
+
try {
|
|
347
|
+
entries = await fsp.readdir(tasksDir);
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return [];
|
|
351
|
+
}
|
|
352
|
+
const tasks = [];
|
|
353
|
+
for (const entry of entries) {
|
|
354
|
+
if (!entry.endsWith(".json") || entry === "task-history.json" || entry === "last-failure-context.json")
|
|
355
|
+
continue;
|
|
356
|
+
let raw;
|
|
357
|
+
try {
|
|
358
|
+
raw = JSON.parse(await fsp.readFile(path.join(tasksDir, entry), "utf-8"));
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
const parsed = TaskSchema.safeParse(raw);
|
|
364
|
+
if (parsed.success)
|
|
365
|
+
tasks.push(parsed.data);
|
|
366
|
+
}
|
|
367
|
+
return tasks.sort((a, b) => (a.created_at < b.created_at ? 1 : -1));
|
|
368
|
+
}
|
|
262
369
|
async readTasksForGoal(goalId) {
|
|
263
|
-
|
|
370
|
+
const stateManager = this.deps.stateManager;
|
|
371
|
+
if (typeof stateManager.getBaseDir !== "function")
|
|
372
|
+
return [];
|
|
373
|
+
const baseDir = stateManager.getBaseDir();
|
|
374
|
+
const activeTasksDir = this.resolveStatePath(baseDir, "tasks", goalId);
|
|
375
|
+
const archiveTasksDir = this.resolveStatePath(baseDir, "archive", goalId, "tasks");
|
|
376
|
+
if (activeTasksDir === null || archiveTasksDir === null)
|
|
377
|
+
return [];
|
|
378
|
+
const activeTasks = await this.readTasksFromDir(activeTasksDir);
|
|
379
|
+
if (activeTasks.length > 0)
|
|
380
|
+
return activeTasks;
|
|
381
|
+
return this.readTasksFromDir(archiveTasksDir);
|
|
264
382
|
}
|
|
265
383
|
async resolveGoalForTasks(selector) {
|
|
266
384
|
if (selector)
|
|
@@ -302,7 +420,28 @@ export class ChatRunner {
|
|
|
302
420
|
return { taskId: parts[0], goalId: parts[1] };
|
|
303
421
|
}
|
|
304
422
|
async findTask(taskId, goalId) {
|
|
305
|
-
|
|
423
|
+
const goalIds = goalId ? [goalId] : await this.listAllGoalIds();
|
|
424
|
+
const matches = [];
|
|
425
|
+
for (const candidateGoalId of goalIds) {
|
|
426
|
+
let raw = null;
|
|
427
|
+
try {
|
|
428
|
+
raw = await this.deps.stateManager.readRaw(`tasks/${candidateGoalId}/${taskId}.json`);
|
|
429
|
+
}
|
|
430
|
+
catch {
|
|
431
|
+
raw = null;
|
|
432
|
+
}
|
|
433
|
+
if (!raw) {
|
|
434
|
+
const tasks = await this.readTasksForGoal(candidateGoalId);
|
|
435
|
+
const matched = tasks.find((task) => task.id === taskId || task.id.startsWith(taskId));
|
|
436
|
+
if (matched)
|
|
437
|
+
matches.push({ goalId: candidateGoalId, task: matched });
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
const parsed = TaskSchema.safeParse(raw);
|
|
441
|
+
if (parsed.success)
|
|
442
|
+
matches.push({ goalId: candidateGoalId, task: parsed.data });
|
|
443
|
+
}
|
|
444
|
+
return { task: matches.length === 1 ? matches[0].task : undefined, matches };
|
|
306
445
|
}
|
|
307
446
|
formatTask(task) {
|
|
308
447
|
const lines = [
|
|
@@ -347,11 +486,30 @@ export class ChatRunner {
|
|
|
347
486
|
}
|
|
348
487
|
return { success: true, output: this.formatTask(found.task), elapsed_ms: Date.now() - start };
|
|
349
488
|
}
|
|
489
|
+
providerConfigBaseDir() {
|
|
490
|
+
const stateManager = this.deps.stateManager;
|
|
491
|
+
return typeof stateManager.getBaseDir === "function" ? stateManager.getBaseDir() : getPulseedDirPath();
|
|
492
|
+
}
|
|
350
493
|
async readProviderConfigSummary() {
|
|
351
|
-
|
|
494
|
+
const config = await loadProviderConfig({
|
|
495
|
+
baseDir: this.providerConfigBaseDir(),
|
|
496
|
+
saveMigration: false,
|
|
497
|
+
});
|
|
498
|
+
return {
|
|
499
|
+
provider: config.provider,
|
|
500
|
+
model: config.model,
|
|
501
|
+
adapter: config.adapter,
|
|
502
|
+
light_model: config.light_model,
|
|
503
|
+
base_url: config.base_url,
|
|
504
|
+
codex_cli_path: config.codex_cli_path,
|
|
505
|
+
has_api_key: Boolean(config.api_key),
|
|
506
|
+
};
|
|
352
507
|
}
|
|
353
508
|
formatConfig(config) {
|
|
354
|
-
return
|
|
509
|
+
return Object.entries(config)
|
|
510
|
+
.filter(([, value]) => value !== undefined)
|
|
511
|
+
.map(([key, value]) => `${key}: ${typeof value === "string" && /key|token|secret/i.test(key) ? "[masked]" : String(value)}`)
|
|
512
|
+
.join("\n");
|
|
355
513
|
}
|
|
356
514
|
async handleConfig(start) {
|
|
357
515
|
const config = await this.readProviderConfigSummary();
|
|
@@ -394,11 +552,7 @@ export class ChatRunner {
|
|
|
394
552
|
const totalTokens = Number.isFinite(usage.totalTokens)
|
|
395
553
|
? Math.max(0, Math.floor(usage.totalTokens))
|
|
396
554
|
: inputTokens + outputTokens;
|
|
397
|
-
return {
|
|
398
|
-
inputTokens,
|
|
399
|
-
outputTokens,
|
|
400
|
-
totalTokens,
|
|
401
|
-
};
|
|
555
|
+
return { inputTokens, outputTokens, totalTokens };
|
|
402
556
|
}
|
|
403
557
|
usageFromLLMResponse(response) {
|
|
404
558
|
const inputTokens = response.usage?.input_tokens ?? 0;
|
|
@@ -776,7 +930,7 @@ export class ChatRunner {
|
|
|
776
930
|
if (!args) {
|
|
777
931
|
return {
|
|
778
932
|
success: true,
|
|
779
|
-
output:
|
|
933
|
+
output: summarizeExecutionPolicy(policy),
|
|
780
934
|
elapsed_ms: Date.now() - start,
|
|
781
935
|
};
|
|
782
936
|
}
|
|
@@ -818,15 +972,17 @@ export class ChatRunner {
|
|
|
818
972
|
this.sessionExecutionPolicy = nextPolicy;
|
|
819
973
|
return {
|
|
820
974
|
success: true,
|
|
821
|
-
output:
|
|
975
|
+
output: summarizeExecutionPolicy(nextPolicy),
|
|
822
976
|
elapsed_ms: Date.now() - start,
|
|
823
977
|
};
|
|
824
978
|
}
|
|
825
979
|
async handleReview(start) {
|
|
826
980
|
const cwd = this.sessionCwd ?? process.cwd();
|
|
827
981
|
const diffStat = await checkGitChanges(cwd);
|
|
828
|
-
const
|
|
829
|
-
|
|
982
|
+
const reviewPolicy = withExecutionPolicyOverrides(await this.getSessionExecutionPolicy(), {
|
|
983
|
+
sandboxMode: "read_only",
|
|
984
|
+
approvalPolicy: "never",
|
|
985
|
+
});
|
|
830
986
|
if (this.deps.reviewAgentLoopRunner) {
|
|
831
987
|
const review = await this.deps.reviewAgentLoopRunner.execute({
|
|
832
988
|
cwd,
|
|
@@ -841,9 +997,6 @@ export class ChatRunner {
|
|
|
841
997
|
"",
|
|
842
998
|
"Execution policy",
|
|
843
999
|
summarizeExecutionPolicy(reviewPolicy),
|
|
844
|
-
"",
|
|
845
|
-
"Review profile",
|
|
846
|
-
formatAgentLoopResolvedProfileSummary(summarizeAgentLoopResolvedProfile(reviewProfile, reviewPolicy)),
|
|
847
1000
|
].join("\n");
|
|
848
1001
|
return { success: true, output, elapsed_ms: Date.now() - start };
|
|
849
1002
|
}
|
|
@@ -957,32 +1110,47 @@ export class ChatRunner {
|
|
|
957
1110
|
elapsed_ms: Date.now() - start,
|
|
958
1111
|
};
|
|
959
1112
|
}
|
|
960
|
-
try {
|
|
961
|
-
await this.deps.daemonClient.startGoal(pending.goalId);
|
|
962
|
-
}
|
|
963
|
-
catch (err) {
|
|
964
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
965
|
-
return {
|
|
966
|
-
success: false,
|
|
967
|
-
output: `Daemon unavailable: ${msg}. Start the daemon with 'pulseed daemon start' first.`,
|
|
968
|
-
elapsed_ms: Date.now() - start,
|
|
969
|
-
};
|
|
970
|
-
}
|
|
971
|
-
// Subscribe to EventServer progress notifications (non-blocking)
|
|
972
1113
|
const { goalId, maxIterations } = pending;
|
|
1114
|
+
let subscriber = null;
|
|
973
1115
|
if (this.deps.daemonBaseUrl && !this.activeSubscribers.has(goalId)) {
|
|
974
|
-
|
|
1116
|
+
subscriber = new EventSubscriber(this.deps.daemonBaseUrl, goalId, "normal");
|
|
975
1117
|
this.activeSubscribers.set(goalId, subscriber);
|
|
976
1118
|
subscriber.on("notification", (notification) => {
|
|
977
1119
|
const n = notification;
|
|
978
|
-
// Invoke both the deps callback (wired at construction) and the public
|
|
979
|
-
// onNotification property (wired post-construction, e.g. from React useEffect)
|
|
980
1120
|
this.deps.onNotification?.(n.message);
|
|
981
1121
|
this.onNotification?.(n.message);
|
|
982
1122
|
});
|
|
983
|
-
subscriber.
|
|
984
|
-
|
|
1123
|
+
subscriber.on("chat_event", (event) => {
|
|
1124
|
+
this.emitEvent(event);
|
|
985
1125
|
});
|
|
1126
|
+
try {
|
|
1127
|
+
await subscriber.subscribeReady();
|
|
1128
|
+
}
|
|
1129
|
+
catch (err) {
|
|
1130
|
+
subscriber.unsubscribe();
|
|
1131
|
+
this.activeSubscribers.delete(goalId);
|
|
1132
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1133
|
+
return {
|
|
1134
|
+
success: false,
|
|
1135
|
+
output: `Daemon event stream unavailable: ${msg}. Goal was not started.`,
|
|
1136
|
+
elapsed_ms: Date.now() - start,
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
try {
|
|
1141
|
+
await this.deps.daemonClient.startGoal(goalId);
|
|
1142
|
+
}
|
|
1143
|
+
catch (err) {
|
|
1144
|
+
if (subscriber) {
|
|
1145
|
+
subscriber.unsubscribe();
|
|
1146
|
+
this.activeSubscribers.delete(goalId);
|
|
1147
|
+
}
|
|
1148
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1149
|
+
return {
|
|
1150
|
+
success: false,
|
|
1151
|
+
output: `Daemon unavailable: ${msg}. Start the daemon with 'pulseed daemon start' first.`,
|
|
1152
|
+
elapsed_ms: Date.now() - start,
|
|
1153
|
+
};
|
|
986
1154
|
}
|
|
987
1155
|
const iterNote = maxIterations !== undefined ? ` (max ${maxIterations} iterations)` : "";
|
|
988
1156
|
const shortId = goalId.length > 12 ? goalId.slice(0, 12) : goalId;
|
|
@@ -1004,10 +1172,11 @@ export class ChatRunner {
|
|
|
1004
1172
|
* 6. Verify changes (git diff + tests); retry up to MAX_VERIFY_RETRIES if tests fail
|
|
1005
1173
|
* 7. Persist assistant response only after the final assistant text is complete
|
|
1006
1174
|
*/
|
|
1007
|
-
async execute(input, cwd, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
1175
|
+
async execute(input, cwd, timeoutMs = DEFAULT_TIMEOUT_MS, options = {}) {
|
|
1008
1176
|
const eventContext = this.createEventContext();
|
|
1009
1177
|
const resumeCommand = this.parseResumeCommand(input);
|
|
1010
1178
|
const resumeOnly = resumeCommand !== null;
|
|
1179
|
+
const runtimeControlContext = options.runtimeControlContext ?? this.runtimeControlContext;
|
|
1011
1180
|
// Intercept commands before any adapter call
|
|
1012
1181
|
const commandResult = resumeOnly ? null : await this.handleCommand(input);
|
|
1013
1182
|
if (commandResult !== null) {
|
|
@@ -1036,21 +1205,6 @@ export class ChatRunner {
|
|
|
1036
1205
|
this.emitLifecycleEndEvent(confirmationResult.success ? "completed" : "error", confirmationResult.elapsed_ms, eventContext, false);
|
|
1037
1206
|
return confirmationResult;
|
|
1038
1207
|
}
|
|
1039
|
-
const runtimeControlResult = resumeOnly
|
|
1040
|
-
? null
|
|
1041
|
-
: await this.handleRuntimeControlIntent(input, cwd, Date.now());
|
|
1042
|
-
if (runtimeControlResult !== null) {
|
|
1043
|
-
if (runtimeControlResult.output) {
|
|
1044
|
-
this.emitEvent({
|
|
1045
|
-
type: "assistant_final",
|
|
1046
|
-
text: runtimeControlResult.output,
|
|
1047
|
-
persisted: false,
|
|
1048
|
-
...this.eventBase(eventContext),
|
|
1049
|
-
});
|
|
1050
|
-
}
|
|
1051
|
-
this.emitLifecycleEndEvent(runtimeControlResult.success ? "completed" : "error", runtimeControlResult.elapsed_ms, eventContext, false);
|
|
1052
|
-
return runtimeControlResult;
|
|
1053
|
-
}
|
|
1054
1208
|
if (resumeOnly && resumeCommand.selector) {
|
|
1055
1209
|
try {
|
|
1056
1210
|
const catalog = new ChatSessionCatalog(this.deps.stateManager);
|
|
@@ -1127,18 +1281,39 @@ export class ChatRunner {
|
|
|
1127
1281
|
if (historySections.length > 0) {
|
|
1128
1282
|
historyBlock = `${historySections.join("\n\n")}\n\nCurrent message:\n`;
|
|
1129
1283
|
}
|
|
1130
|
-
const
|
|
1284
|
+
const selectedRoute = resumeOnly
|
|
1285
|
+
? null
|
|
1286
|
+
: (options.selectedRoute ?? this.resolveRouteFromInput(input, runtimeControlContext));
|
|
1131
1287
|
const directPrompt = historyBlock ? `${historyBlock}${input}` : input;
|
|
1132
1288
|
const start = Date.now();
|
|
1133
1289
|
const assistantBuffer = { text: "" };
|
|
1134
1290
|
const turnUsage = this.zeroUsageCounter();
|
|
1135
|
-
if (
|
|
1291
|
+
if (selectedRoute?.kind === "runtime_control") {
|
|
1292
|
+
const runtimeControlResult = await this.executeRuntimeControlRoute(selectedRoute, runtimeControlContext, cwd, start);
|
|
1293
|
+
if (runtimeControlResult.success) {
|
|
1294
|
+
await history.appendAssistantMessage(runtimeControlResult.output);
|
|
1295
|
+
this.emitActivity("lifecycle", "Finalizing response...", eventContext, "lifecycle:finalizing");
|
|
1296
|
+
this.emitEvent({
|
|
1297
|
+
type: "assistant_final",
|
|
1298
|
+
text: runtimeControlResult.output,
|
|
1299
|
+
persisted: true,
|
|
1300
|
+
...this.eventBase(eventContext),
|
|
1301
|
+
});
|
|
1302
|
+
this.emitLifecycleEndEvent("completed", runtimeControlResult.elapsed_ms, eventContext, true);
|
|
1303
|
+
}
|
|
1304
|
+
else {
|
|
1305
|
+
this.emitLifecycleErrorEvent(runtimeControlResult.output, assistantBuffer.text, eventContext);
|
|
1306
|
+
this.emitLifecycleEndEvent("error", runtimeControlResult.elapsed_ms, eventContext, false);
|
|
1307
|
+
}
|
|
1308
|
+
return runtimeControlResult;
|
|
1309
|
+
}
|
|
1310
|
+
if (selectedRoute?.kind === "direct_answer") {
|
|
1136
1311
|
try {
|
|
1137
1312
|
this.emitActivity("lifecycle", "Calling model...", eventContext, "lifecycle:model");
|
|
1138
1313
|
const directResponse = await this.sendLLMMessage(this.deps.llmClient, [{ role: "user", content: directPrompt }], {
|
|
1139
1314
|
...(this.cachedStaticSystemPrompt ? { system: this.cachedStaticSystemPrompt } : {}),
|
|
1140
|
-
model_tier:
|
|
1141
|
-
max_tokens:
|
|
1315
|
+
model_tier: selectedRoute.modelTier,
|
|
1316
|
+
max_tokens: selectedRoute.maxTokens,
|
|
1142
1317
|
}, assistantBuffer, eventContext);
|
|
1143
1318
|
this.addUsageCounter(turnUsage, this.usageFromLLMResponse(directResponse));
|
|
1144
1319
|
const elapsed_ms = Date.now() - start;
|
|
@@ -1161,9 +1336,9 @@ export class ChatRunner {
|
|
|
1161
1336
|
elapsed_ms,
|
|
1162
1337
|
diagnostics: {
|
|
1163
1338
|
route: "direct",
|
|
1164
|
-
reason:
|
|
1165
|
-
modelTier:
|
|
1166
|
-
maxTokens:
|
|
1339
|
+
reason: selectedRoute.reason,
|
|
1340
|
+
modelTier: selectedRoute.modelTier,
|
|
1341
|
+
maxTokens: selectedRoute.maxTokens,
|
|
1167
1342
|
},
|
|
1168
1343
|
};
|
|
1169
1344
|
}
|
|
@@ -1179,25 +1354,49 @@ export class ChatRunner {
|
|
|
1179
1354
|
elapsed_ms: Date.now() - start,
|
|
1180
1355
|
diagnostics: {
|
|
1181
1356
|
route: "direct",
|
|
1182
|
-
reason:
|
|
1183
|
-
modelTier:
|
|
1184
|
-
maxTokens:
|
|
1357
|
+
reason: selectedRoute.reason,
|
|
1358
|
+
modelTier: selectedRoute.modelTier,
|
|
1359
|
+
maxTokens: selectedRoute.maxTokens,
|
|
1185
1360
|
},
|
|
1186
1361
|
};
|
|
1187
1362
|
}
|
|
1188
1363
|
}
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1364
|
+
const usesNativeAgentLoop = resumeOnly || selectedRoute?.kind === "agent_loop";
|
|
1365
|
+
const groundingWorkspaceContext = !resumeOnly && usesNativeAgentLoop
|
|
1366
|
+
? await buildChatContext(input, cwd)
|
|
1367
|
+
: undefined;
|
|
1368
|
+
let systemPrompt = this.cachedStaticSystemPrompt ?? "";
|
|
1369
|
+
if (!resumeOnly) {
|
|
1370
|
+
try {
|
|
1371
|
+
this.emitActivity("lifecycle", "Preparing context...", eventContext, "lifecycle:context");
|
|
1372
|
+
if (usesNativeAgentLoop) {
|
|
1373
|
+
systemPrompt = await buildChatAgentLoopSystemPrompt({
|
|
1374
|
+
stateManager: this.deps.stateManager,
|
|
1375
|
+
pluginLoader: this.deps.pluginLoader,
|
|
1376
|
+
workspaceRoot: cwd,
|
|
1377
|
+
goalId: this.deps.goalId,
|
|
1378
|
+
userMessage: input,
|
|
1379
|
+
trustProjectInstructions: this.sessionExecutionPolicy?.trustProjectInstructions ?? true,
|
|
1380
|
+
workspaceContext: groundingWorkspaceContext,
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
else {
|
|
1384
|
+
const groundingBundle = await this.groundingGateway.build({
|
|
1385
|
+
surface: "chat",
|
|
1386
|
+
purpose: "general_turn",
|
|
1387
|
+
workspaceRoot: cwd,
|
|
1388
|
+
goalId: this.deps.goalId,
|
|
1389
|
+
userMessage: input,
|
|
1390
|
+
query: input,
|
|
1391
|
+
trustProjectInstructions: this.sessionExecutionPolicy?.trustProjectInstructions ?? true,
|
|
1392
|
+
});
|
|
1393
|
+
systemPrompt = String(groundingBundle.render("prompt"));
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
catch {
|
|
1397
|
+
systemPrompt = this.cachedStaticSystemPrompt ?? "";
|
|
1398
|
+
}
|
|
1196
1399
|
}
|
|
1197
|
-
const systemPrompt = [this.cachedStaticSystemPrompt, dynamicSystemPrompt]
|
|
1198
|
-
.filter((section) => section && section.trim().length > 0)
|
|
1199
|
-
.join("\n\n")
|
|
1200
|
-
.trim();
|
|
1201
1400
|
const agentLoopSystemPrompt = [
|
|
1202
1401
|
systemPrompt,
|
|
1203
1402
|
compactionSummary ? `## Compacted Chat Summary\n${compactionSummary}` : "",
|
|
@@ -1205,7 +1404,7 @@ export class ChatRunner {
|
|
|
1205
1404
|
.filter((section) => section && section.trim().length > 0)
|
|
1206
1405
|
.join("\n\n")
|
|
1207
1406
|
.trim();
|
|
1208
|
-
const context = resumeOnly ? "" : await buildChatContext(input, gitRoot);
|
|
1407
|
+
const context = resumeOnly || usesNativeAgentLoop ? "" : await buildChatContext(input, gitRoot);
|
|
1209
1408
|
const basePrompt = resumeOnly ? "" : (context ? `${context}\n\n${input}` : input);
|
|
1210
1409
|
const prompt = historyBlock ? `${historyBlock}${basePrompt}` : basePrompt;
|
|
1211
1410
|
if (resumeOnly && !this.deps.chatAgentLoopRunner) {
|
|
@@ -1224,7 +1423,8 @@ export class ChatRunner {
|
|
|
1224
1423
|
elapsed_ms,
|
|
1225
1424
|
};
|
|
1226
1425
|
}
|
|
1227
|
-
|
|
1426
|
+
const chatAgentLoopRunner = this.deps.chatAgentLoopRunner;
|
|
1427
|
+
if (resumeOnly || selectedRoute?.kind === "agent_loop") {
|
|
1228
1428
|
try {
|
|
1229
1429
|
const resumeState = resumeOnly ? await this.loadResumableAgentLoopState() : null;
|
|
1230
1430
|
if (resumeOnly && !resumeState) {
|
|
@@ -1244,7 +1444,7 @@ export class ChatRunner {
|
|
|
1244
1444
|
};
|
|
1245
1445
|
}
|
|
1246
1446
|
this.emitActivity("lifecycle", "Calling model...", eventContext, "lifecycle:model");
|
|
1247
|
-
const result = await
|
|
1447
|
+
const result = await chatAgentLoopRunner.execute({
|
|
1248
1448
|
message: basePrompt,
|
|
1249
1449
|
cwd,
|
|
1250
1450
|
goalId: this.deps.goalId,
|
|
@@ -1268,7 +1468,9 @@ export class ChatRunner {
|
|
|
1268
1468
|
...(agentLoopSystemPrompt ? { systemPrompt: agentLoopSystemPrompt } : {}),
|
|
1269
1469
|
});
|
|
1270
1470
|
const elapsed_ms = Date.now() - start;
|
|
1271
|
-
const agentLoopUsage =
|
|
1471
|
+
const agentLoopUsage = result.agentLoop?.usage
|
|
1472
|
+
? this.normalizeUsageCounter(result.agentLoop.usage)
|
|
1473
|
+
: this.zeroUsageCounter();
|
|
1272
1474
|
if (this.hasUsage(agentLoopUsage)) {
|
|
1273
1475
|
history.recordUsage("agentloop", agentLoopUsage);
|
|
1274
1476
|
}
|
|
@@ -1287,9 +1489,6 @@ export class ChatRunner {
|
|
|
1287
1489
|
this.emitLifecycleEndEvent("completed", elapsed_ms, eventContext, true);
|
|
1288
1490
|
}
|
|
1289
1491
|
else {
|
|
1290
|
-
if (this.hasUsage(agentLoopUsage)) {
|
|
1291
|
-
await history.persist();
|
|
1292
|
-
}
|
|
1293
1492
|
this.emitLifecycleErrorEvent(result.output || result.error || "Unknown error", assistantBuffer.text, eventContext);
|
|
1294
1493
|
this.emitLifecycleEndEvent("error", elapsed_ms, eventContext, false);
|
|
1295
1494
|
}
|
|
@@ -1313,7 +1512,7 @@ export class ChatRunner {
|
|
|
1313
1512
|
}
|
|
1314
1513
|
}
|
|
1315
1514
|
// Prefer the local LLM/tool loop over the external adapter fallback whenever a client is available.
|
|
1316
|
-
if (
|
|
1515
|
+
if (selectedRoute?.kind === "tool_loop") {
|
|
1317
1516
|
try {
|
|
1318
1517
|
const toolResult = await this.executeWithTools(prompt, eventContext, assistantBuffer, systemPrompt || undefined);
|
|
1319
1518
|
const elapsed_ms = Date.now() - start;
|
|
@@ -1344,6 +1543,17 @@ export class ChatRunner {
|
|
|
1344
1543
|
};
|
|
1345
1544
|
}
|
|
1346
1545
|
}
|
|
1546
|
+
if (!resumeOnly && selectedRoute && selectedRoute.kind !== "adapter") {
|
|
1547
|
+
const elapsed_ms = Date.now() - start;
|
|
1548
|
+
const output = `Unsupported chat route: ${selectedRoute.kind}`;
|
|
1549
|
+
this.emitLifecycleErrorEvent(output, assistantBuffer.text, eventContext);
|
|
1550
|
+
this.emitLifecycleEndEvent("error", elapsed_ms, eventContext, false);
|
|
1551
|
+
return {
|
|
1552
|
+
success: false,
|
|
1553
|
+
output,
|
|
1554
|
+
elapsed_ms,
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1347
1557
|
const task = {
|
|
1348
1558
|
prompt,
|
|
1349
1559
|
timeout_ms: timeoutMs,
|
|
@@ -1413,10 +1623,7 @@ export class ChatRunner {
|
|
|
1413
1623
|
elapsed_ms,
|
|
1414
1624
|
};
|
|
1415
1625
|
}
|
|
1416
|
-
async
|
|
1417
|
-
const intent = recognizeRuntimeControlIntent(input);
|
|
1418
|
-
if (intent === null)
|
|
1419
|
-
return null;
|
|
1626
|
+
async executeRuntimeControlRoute(route, runtimeControlContext, cwd, start) {
|
|
1420
1627
|
if (!this.deps.runtimeControlService) {
|
|
1421
1628
|
return {
|
|
1422
1629
|
success: false,
|
|
@@ -1424,10 +1631,10 @@ export class ChatRunner {
|
|
|
1424
1631
|
elapsed_ms: Date.now() - start,
|
|
1425
1632
|
};
|
|
1426
1633
|
}
|
|
1427
|
-
const replyTarget =
|
|
1428
|
-
const actor =
|
|
1634
|
+
const replyTarget = runtimeControlContext?.replyTarget ?? this.deps.runtimeReplyTarget;
|
|
1635
|
+
const actor = runtimeControlContext?.actor ?? this.deps.runtimeControlActor;
|
|
1429
1636
|
const result = await this.deps.runtimeControlService.request({
|
|
1430
|
-
intent,
|
|
1637
|
+
intent: route.intent,
|
|
1431
1638
|
cwd,
|
|
1432
1639
|
requestedBy: actor ?? {
|
|
1433
1640
|
surface: replyTarget?.surface ?? "chat",
|
|
@@ -1437,7 +1644,7 @@ export class ChatRunner {
|
|
|
1437
1644
|
user_id: replyTarget?.user_id,
|
|
1438
1645
|
},
|
|
1439
1646
|
replyTarget: replyTarget ?? { surface: "chat" },
|
|
1440
|
-
approvalFn:
|
|
1647
|
+
approvalFn: runtimeControlContext?.approvalFn
|
|
1441
1648
|
?? this.deps.runtimeControlApprovalFn
|
|
1442
1649
|
?? this.deps.approvalFn,
|
|
1443
1650
|
});
|
|
@@ -1470,13 +1677,13 @@ export class ChatRunner {
|
|
|
1470
1677
|
? { tools, ...(systemPrompt ? { system: systemPrompt } : {}) }
|
|
1471
1678
|
: { system: buildPromptedToolProtocolSystemPrompt({ systemPrompt, tools }) }),
|
|
1472
1679
|
}, assistantBuffer, eventContext);
|
|
1473
|
-
this.addUsageCounter(usage, this.usageFromLLMResponse(response));
|
|
1474
1680
|
}
|
|
1475
1681
|
catch (err) {
|
|
1476
1682
|
console.error("[chat-runner] executeWithTools error:", err);
|
|
1477
1683
|
const hint = err instanceof Error ? `: ${err.message}` : "";
|
|
1478
1684
|
throw new Error(`Sorry, I encountered an error processing your request${hint}.`);
|
|
1479
1685
|
}
|
|
1686
|
+
this.addUsageCounter(usage, this.usageFromLLMResponse(response));
|
|
1480
1687
|
const toolCalls = response.tool_calls?.length
|
|
1481
1688
|
? response.tool_calls
|
|
1482
1689
|
: supportsNativeToolCalling
|
|
@@ -1676,19 +1883,10 @@ export class ChatRunner {
|
|
|
1676
1883
|
return null;
|
|
1677
1884
|
if (raw.status === "completed")
|
|
1678
1885
|
return null;
|
|
1679
|
-
const usageCandidate = raw.usage;
|
|
1680
|
-
const usage = usageCandidate
|
|
1681
|
-
? this.normalizeUsageCounter({
|
|
1682
|
-
inputTokens: typeof usageCandidate.inputTokens === "number" ? usageCandidate.inputTokens : 0,
|
|
1683
|
-
outputTokens: typeof usageCandidate.outputTokens === "number" ? usageCandidate.outputTokens : 0,
|
|
1684
|
-
totalTokens: typeof usageCandidate.totalTokens === "number" ? usageCandidate.totalTokens : 0,
|
|
1685
|
-
})
|
|
1686
|
-
: this.zeroUsageCounter();
|
|
1687
1886
|
return {
|
|
1688
1887
|
...raw,
|
|
1689
1888
|
messages: [...raw.messages],
|
|
1690
1889
|
calledTools: [...raw.calledTools],
|
|
1691
|
-
usage,
|
|
1692
1890
|
};
|
|
1693
1891
|
}
|
|
1694
1892
|
isAgentLoopSessionState(value) {
|
|
@@ -1928,27 +2126,12 @@ export class ChatRunner {
|
|
|
1928
2126
|
async getSessionExecutionPolicy() {
|
|
1929
2127
|
if (this.sessionExecutionPolicy)
|
|
1930
2128
|
return this.sessionExecutionPolicy;
|
|
1931
|
-
const profile = await this.getAgentLoopDefaultProfile("chat");
|
|
1932
|
-
if (!profile.executionPolicy) {
|
|
1933
|
-
throw new Error("Chat profile did not resolve an execution policy.");
|
|
1934
|
-
}
|
|
1935
|
-
this.sessionExecutionPolicy = profile.executionPolicy;
|
|
1936
|
-
return this.sessionExecutionPolicy;
|
|
1937
|
-
}
|
|
1938
|
-
async getAgentLoopDefaultProfile(surface) {
|
|
1939
2129
|
const config = await loadProviderConfig({ saveMigration: false });
|
|
1940
|
-
|
|
1941
|
-
surface,
|
|
2130
|
+
this.sessionExecutionPolicy = resolveExecutionPolicy({
|
|
1942
2131
|
workspaceRoot: this.sessionCwd ?? process.cwd(),
|
|
1943
2132
|
security: config.agent_loop?.security,
|
|
1944
2133
|
});
|
|
1945
|
-
|
|
1946
|
-
async getAgentLoopProfileSummary(surface, executionPolicy) {
|
|
1947
|
-
const profile = await this.getAgentLoopDefaultProfile(surface);
|
|
1948
|
-
return formatAgentLoopResolvedProfileSummary(summarizeAgentLoopResolvedProfile(profile, executionPolicy));
|
|
1949
|
-
}
|
|
1950
|
-
formatExecutionPolicyOutput(policySummary, profileHeading, profileSummary) {
|
|
1951
|
-
return [policySummary, "", profileHeading, profileSummary].join("\n");
|
|
2134
|
+
return this.sessionExecutionPolicy;
|
|
1952
2135
|
}
|
|
1953
2136
|
async buildToolCallContext() {
|
|
1954
2137
|
const executionPolicy = await this.getSessionExecutionPolicy();
|