wave-agent-sdk 1.0.4 → 1.0.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/dist/agent.d.ts +23 -1
- package/dist/agent.js +34 -4
- package/dist/managers/aiManager.d.ts +36 -0
- package/dist/managers/aiManager.js +240 -8
- package/dist/managers/messageManager.d.ts +1 -3
- package/dist/managers/messageManager.js +19 -9
- package/dist/managers/slashCommandManager.js +28 -0
- package/dist/managers/subagentManager.d.ts +0 -2
- package/dist/services/session.js +2 -9
- package/dist/telemetry/instrumentation.d.ts +1 -1
- package/dist/telemetry/instrumentation.js +57 -28
- package/dist/tools/bashTool.js +16 -6
- package/dist/tools/grepTool.js +11 -3
- package/dist/types/index.d.ts +3 -0
- package/dist/types/messaging.d.ts +2 -0
- package/dist/utils/containerSetup.js +0 -3
- package/dist/utils/messageOperations.d.ts +10 -1
- package/dist/utils/messageOperations.js +19 -1
- package/dist/utils/notificationXml.js +5 -0
- package/dist/utils/ripgrep.d.ts +4 -4
- package/dist/utils/ripgrep.js +4 -27
- package/package.json +20 -8
- package/bin/rg +0 -79
- package/dist/managers/forkedAgentManager.d.ts +0 -50
- package/dist/managers/forkedAgentManager.js +0 -130
- package/scripts/install_ripgrep.js +0 -111
- package/scripts/postinstall.js +0 -38
- package/src/agent.ts +0 -1271
- package/src/constants/subagents.ts +0 -4
- package/src/constants/toolLimits.ts +0 -15
- package/src/constants/tools.ts +0 -24
- package/src/core/plugin.ts +0 -237
- package/src/core/session.ts +0 -9
- package/src/index.ts +0 -38
- package/src/managers/MemoryRuleManager.ts +0 -198
- package/src/managers/aiManager.ts +0 -2429
- package/src/managers/backgroundTaskManager.ts +0 -480
- package/src/managers/bangManager.ts +0 -119
- package/src/managers/cronManager.ts +0 -401
- package/src/managers/foregroundTaskManager.ts +0 -30
- package/src/managers/forkedAgentManager.ts +0 -216
- package/src/managers/hookManager.ts +0 -1089
- package/src/managers/liveConfigManager.ts +0 -445
- package/src/managers/lspManager.ts +0 -470
- package/src/managers/mcpManager.ts +0 -1010
- package/src/managers/messageManager.ts +0 -1180
- package/src/managers/messageQueue.ts +0 -157
- package/src/managers/permissionManager.ts +0 -1140
- package/src/managers/planManager.ts +0 -112
- package/src/managers/pluginManager.ts +0 -330
- package/src/managers/pluginScopeManager.ts +0 -124
- package/src/managers/reversionManager.ts +0 -178
- package/src/managers/skillManager.ts +0 -578
- package/src/managers/slashCommandManager.ts +0 -564
- package/src/managers/subagentManager.ts +0 -915
- package/src/managers/toolManager.ts +0 -489
- package/src/managers/workflowManager.ts +0 -493
- package/src/prompts/autoMemory.ts +0 -33
- package/src/prompts/autoMemoryExtraction.ts +0 -146
- package/src/prompts/index.ts +0 -506
- package/src/prompts/planModeReminders.ts +0 -126
- package/src/services/GitService.ts +0 -131
- package/src/services/MarketplaceService.ts +0 -1052
- package/src/services/MemoryRuleService.ts +0 -71
- package/src/services/aiService.ts +0 -919
- package/src/services/authService.ts +0 -565
- package/src/services/autoMemoryService.ts +0 -280
- package/src/services/configurationService.ts +0 -1520
- package/src/services/fileWatcher.ts +0 -319
- package/src/services/hook.ts +0 -348
- package/src/services/initializationService.ts +0 -357
- package/src/services/interactionService.ts +0 -229
- package/src/services/jsonlHandler.ts +0 -295
- package/src/services/memory.ts +0 -234
- package/src/services/pluginLoader.ts +0 -252
- package/src/services/remoteSettingsService.ts +0 -366
- package/src/services/reversionService.ts +0 -122
- package/src/services/session.ts +0 -922
- package/src/services/taskManager.ts +0 -321
- package/src/telemetry/events.ts +0 -65
- package/src/telemetry/instrumentation.ts +0 -499
- package/src/telemetry/sessionTracing.ts +0 -348
- package/src/tools/agentTool.ts +0 -322
- package/src/tools/askUserQuestion.ts +0 -160
- package/src/tools/bashTool.ts +0 -621
- package/src/tools/buildTool.ts +0 -61
- package/src/tools/cronCreateTool.ts +0 -161
- package/src/tools/cronDeleteTool.ts +0 -51
- package/src/tools/cronListTool.ts +0 -47
- package/src/tools/editTool.ts +0 -313
- package/src/tools/enterPlanMode.ts +0 -124
- package/src/tools/enterWorktreeTool.ts +0 -190
- package/src/tools/exitPlanMode.ts +0 -139
- package/src/tools/exitWorktreeTool.ts +0 -236
- package/src/tools/globTool.ts +0 -167
- package/src/tools/grepTool.ts +0 -399
- package/src/tools/lspTool.ts +0 -883
- package/src/tools/readTool.ts +0 -426
- package/src/tools/skillTool.ts +0 -248
- package/src/tools/taskManagementTools.ts +0 -574
- package/src/tools/taskStopTool.ts +0 -78
- package/src/tools/types.ts +0 -137
- package/src/tools/webFetchTool.ts +0 -373
- package/src/tools/workflowTool.ts +0 -205
- package/src/tools/writeTool.ts +0 -267
- package/src/types/agent.ts +0 -128
- package/src/types/auth.ts +0 -19
- package/src/types/commands.ts +0 -30
- package/src/types/config.ts +0 -43
- package/src/types/configuration.ts +0 -168
- package/src/types/core.ts +0 -105
- package/src/types/cron.ts +0 -13
- package/src/types/environment.ts +0 -106
- package/src/types/fileSearch.ts +0 -4
- package/src/types/history.ts +0 -7
- package/src/types/hooks.ts +0 -256
- package/src/types/index.ts +0 -41
- package/src/types/lsp.ts +0 -98
- package/src/types/marketplace.ts +0 -71
- package/src/types/mcp.ts +0 -43
- package/src/types/memoryRule.ts +0 -31
- package/src/types/messaging.ts +0 -114
- package/src/types/permissions.ts +0 -80
- package/src/types/plugins.ts +0 -39
- package/src/types/processes.ts +0 -99
- package/src/types/reversion.ts +0 -29
- package/src/types/session.ts +0 -12
- package/src/types/skills.ts +0 -108
- package/src/types/tasks.ts +0 -13
- package/src/types/telemetry.ts +0 -98
- package/src/types/tools.ts +0 -44
- package/src/types/workflow.ts +0 -6
- package/src/utils/abortUtils.ts +0 -118
- package/src/utils/atomicWrite.ts +0 -61
- package/src/utils/bashParser.ts +0 -899
- package/src/utils/cacheControlUtils.ts +0 -426
- package/src/utils/commandArgumentParser.ts +0 -161
- package/src/utils/commandPathResolver.ts +0 -88
- package/src/utils/configPaths.ts +0 -220
- package/src/utils/configValidator.ts +0 -100
- package/src/utils/constants.ts +0 -39
- package/src/utils/container.ts +0 -92
- package/src/utils/containerSetup.ts +0 -371
- package/src/utils/convertMessagesForAPI.ts +0 -326
- package/src/utils/cronTasks.ts +0 -128
- package/src/utils/cronTasksLock.ts +0 -182
- package/src/utils/cronToHuman.ts +0 -99
- package/src/utils/customCommands.ts +0 -95
- package/src/utils/editUtils.ts +0 -20
- package/src/utils/fileFormat.ts +0 -40
- package/src/utils/fileSearch.ts +0 -151
- package/src/utils/fileUtils.ts +0 -223
- package/src/utils/gitUtils.ts +0 -315
- package/src/utils/globalLogger.ts +0 -128
- package/src/utils/groupMessagesByApiRound.ts +0 -121
- package/src/utils/hookMatcher.ts +0 -176
- package/src/utils/markdownParser.ts +0 -317
- package/src/utils/mcpUtils.ts +0 -138
- package/src/utils/messageOperations.ts +0 -641
- package/src/utils/modelCapabilities.ts +0 -30
- package/src/utils/nameGenerator.ts +0 -99
- package/src/utils/notificationXml.ts +0 -57
- package/src/utils/openaiClient.ts +0 -251
- package/src/utils/parseCronExpression.ts +0 -78
- package/src/utils/path.ts +0 -72
- package/src/utils/pathEncoder.ts +0 -400
- package/src/utils/pathSafety.ts +0 -40
- package/src/utils/promptHistory.ts +0 -168
- package/src/utils/ripgrep.ts +0 -35
- package/src/utils/shellResolver.ts +0 -190
- package/src/utils/skillParser.ts +0 -246
- package/src/utils/stringUtils.ts +0 -156
- package/src/utils/subagentParser.ts +0 -279
- package/src/utils/taskReminder.ts +0 -96
- package/src/utils/tokenCalculation.ts +0 -43
- package/src/utils/tokenEstimate.ts +0 -34
- package/src/utils/toolResultStorage.ts +0 -117
- package/src/utils/worktreeSession.ts +0 -26
- package/src/utils/worktreeUtils.ts +0 -786
- package/src/workflow/budgetTracker.ts +0 -34
- package/src/workflow/concurrencyLimiter.ts +0 -47
- package/src/workflow/journal.ts +0 -95
- package/src/workflow/progressReporter.ts +0 -141
- package/src/workflow/runState.ts +0 -65
- package/src/workflow/scriptRuntime.ts +0 -274
- package/src/workflow/structuredOutput.ts +0 -123
- package/src/workflow/types.ts +0 -101
- package/src/workflow/workflowApis.ts +0 -410
- package/vendor/ripgrep/linux-aarch64/rg +0 -0
- package/vendor/ripgrep/linux-x86_64/rg +0 -0
- package/vendor/ripgrep/macos-aarch64/rg +0 -0
- package/vendor/ripgrep/macos-x86_64/rg +0 -0
- package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
- package/vendor/ripgrep/windows-x86_64/rg.exe +0 -0
|
@@ -1,371 +0,0 @@
|
|
|
1
|
-
import { Container } from "./container.js";
|
|
2
|
-
import { ForegroundTaskManager } from "../managers/foregroundTaskManager.js";
|
|
3
|
-
import { BackgroundTaskManager } from "../managers/backgroundTaskManager.js";
|
|
4
|
-
import { MessageQueue } from "../managers/messageQueue.js";
|
|
5
|
-
import { TaskManager } from "../services/taskManager.js";
|
|
6
|
-
import { MessageManager } from "../managers/messageManager.js";
|
|
7
|
-
import { AIManager } from "../managers/aiManager.js";
|
|
8
|
-
import { ToolManager } from "../managers/toolManager.js";
|
|
9
|
-
import { McpManager } from "../managers/mcpManager.js";
|
|
10
|
-
import { LspManager } from "../managers/lspManager.js";
|
|
11
|
-
import { PermissionManager } from "../managers/permissionManager.js";
|
|
12
|
-
import { PlanManager } from "../managers/planManager.js";
|
|
13
|
-
import { HookManager } from "../managers/hookManager.js";
|
|
14
|
-
import { SkillManager } from "../managers/skillManager.js";
|
|
15
|
-
import { SlashCommandManager } from "../managers/slashCommandManager.js";
|
|
16
|
-
import { PluginManager } from "../managers/pluginManager.js";
|
|
17
|
-
import { BangManager } from "../managers/bangManager.js";
|
|
18
|
-
import { CronManager } from "../managers/cronManager.js";
|
|
19
|
-
import { WorkflowManager } from "../managers/workflowManager.js";
|
|
20
|
-
import { MemoryRuleManager } from "../managers/MemoryRuleManager.js";
|
|
21
|
-
import { ReversionManager } from "../managers/reversionManager.js";
|
|
22
|
-
import { SubagentManager } from "../managers/subagentManager.js";
|
|
23
|
-
import { ForkedAgentManager } from "../managers/forkedAgentManager.js";
|
|
24
|
-
import { LiveConfigManager } from "../managers/liveConfigManager.js";
|
|
25
|
-
import { ConfigurationService } from "../services/configurationService.js";
|
|
26
|
-
import { ReversionService } from "../services/reversionService.js";
|
|
27
|
-
import { cleanupMetaOnlySessions } from "../services/session.js";
|
|
28
|
-
import { MemoryService } from "../services/memory.js";
|
|
29
|
-
import { AutoMemoryService } from "../services/autoMemoryService.js";
|
|
30
|
-
import { USER_MEMORY_FILE } from "./constants.js";
|
|
31
|
-
import { getGitMainRepoRoot } from "./gitUtils.js";
|
|
32
|
-
import type { AgentOptions, McpServerConfig } from "../types/index.js";
|
|
33
|
-
import type {
|
|
34
|
-
PermissionMode,
|
|
35
|
-
Usage,
|
|
36
|
-
Task,
|
|
37
|
-
BackgroundTask,
|
|
38
|
-
ToolPermissionContext,
|
|
39
|
-
} from "../types/index.js";
|
|
40
|
-
|
|
41
|
-
import { logger } from "./globalLogger.js";
|
|
42
|
-
import { authService } from "../services/authService.js";
|
|
43
|
-
import { remoteSettingsService } from "../services/remoteSettingsService.js";
|
|
44
|
-
|
|
45
|
-
export interface AgentContainerSetupOptions {
|
|
46
|
-
options: AgentOptions;
|
|
47
|
-
workdir: string;
|
|
48
|
-
configurationService: ConfigurationService;
|
|
49
|
-
systemPrompt?: string;
|
|
50
|
-
stream: boolean;
|
|
51
|
-
|
|
52
|
-
// Callbacks to Agent methods
|
|
53
|
-
onBackgroundTasksChange: (tasks: BackgroundTask[]) => void;
|
|
54
|
-
onTasksChange: (tasks: Task[]) => void;
|
|
55
|
-
onPermissionModeChange: (mode: PermissionMode) => void;
|
|
56
|
-
handlePlanModeTransition: (mode: PermissionMode) => void;
|
|
57
|
-
setPermissionMode: (mode: PermissionMode) => void;
|
|
58
|
-
addPermissionRule: (rule: string) => Promise<void>;
|
|
59
|
-
addUsage: (usage: Usage) => void;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function setupAgentContainer(
|
|
63
|
-
setupOptions: AgentContainerSetupOptions,
|
|
64
|
-
): Container {
|
|
65
|
-
const {
|
|
66
|
-
options,
|
|
67
|
-
workdir,
|
|
68
|
-
configurationService,
|
|
69
|
-
systemPrompt,
|
|
70
|
-
stream,
|
|
71
|
-
onBackgroundTasksChange,
|
|
72
|
-
onTasksChange,
|
|
73
|
-
onPermissionModeChange,
|
|
74
|
-
handlePlanModeTransition,
|
|
75
|
-
setPermissionMode,
|
|
76
|
-
addPermissionRule,
|
|
77
|
-
addUsage,
|
|
78
|
-
} = setupOptions;
|
|
79
|
-
|
|
80
|
-
const callbacks = options.callbacks || {};
|
|
81
|
-
const container = new Container();
|
|
82
|
-
container.register("AgentOptions", options);
|
|
83
|
-
container.register("Workdir", workdir);
|
|
84
|
-
|
|
85
|
-
if (options.worktreeName) {
|
|
86
|
-
container.register("WorktreeName", options.worktreeName);
|
|
87
|
-
container.register("MainRepoRoot", getGitMainRepoRoot(workdir));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Per-agent worktree session state (EnterWorktree/ExitWorktree). Stored in the
|
|
91
|
-
// container so it is isolated per session, not shared process-wide.
|
|
92
|
-
container.register("WorktreeSession", null);
|
|
93
|
-
|
|
94
|
-
const messageQueue = new MessageQueue();
|
|
95
|
-
container.register("MessageQueue", messageQueue);
|
|
96
|
-
|
|
97
|
-
const foregroundTaskManager = new ForegroundTaskManager(container);
|
|
98
|
-
container.register("ForegroundTaskManager", foregroundTaskManager);
|
|
99
|
-
container.register("ConfigurationService", configurationService);
|
|
100
|
-
|
|
101
|
-
const memoryService = new MemoryService(container);
|
|
102
|
-
container.register("MemoryService", memoryService);
|
|
103
|
-
|
|
104
|
-
const autoMemoryService = new AutoMemoryService(container);
|
|
105
|
-
container.register("AutoMemoryService", autoMemoryService);
|
|
106
|
-
|
|
107
|
-
const memoryRuleManager = new MemoryRuleManager(container, { workdir });
|
|
108
|
-
container.register("MemoryRuleManager", memoryRuleManager);
|
|
109
|
-
|
|
110
|
-
const messageManager = new MessageManager(container, {
|
|
111
|
-
callbacks: {
|
|
112
|
-
...callbacks,
|
|
113
|
-
onSessionIdChange: (sessionId) => {
|
|
114
|
-
const taskManager = container.get<TaskManager>("TaskManager");
|
|
115
|
-
if (taskManager) {
|
|
116
|
-
taskManager.syncWithSession().catch((error) => {
|
|
117
|
-
logger.error("Failed to sync task list with session:", error);
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
memoryService.clearCache();
|
|
121
|
-
callbacks.onSessionIdChange?.(sessionId);
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
workdir,
|
|
125
|
-
});
|
|
126
|
-
container.register("MessageManager", messageManager);
|
|
127
|
-
|
|
128
|
-
const resolvedTaskListId =
|
|
129
|
-
process.env.WAVE_TASK_LIST_ID || messageManager.getRootSessionId();
|
|
130
|
-
|
|
131
|
-
const taskManager = new TaskManager(container, resolvedTaskListId);
|
|
132
|
-
container.register("TaskManager", taskManager);
|
|
133
|
-
taskManager.on("tasksChange", async () => {
|
|
134
|
-
const tasks = await taskManager.listTasks();
|
|
135
|
-
onTasksChange(tasks);
|
|
136
|
-
});
|
|
137
|
-
taskManager.cleanupOldTaskLists(30).catch((error) => {
|
|
138
|
-
logger.error("Failed to cleanup old task lists:", error);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
const backgroundTaskManager = new BackgroundTaskManager(container, {
|
|
142
|
-
callbacks: {
|
|
143
|
-
...callbacks,
|
|
144
|
-
onBackgroundTasksChange: (tasks) => {
|
|
145
|
-
onBackgroundTasksChange(tasks);
|
|
146
|
-
callbacks.onBackgroundTasksChange?.(tasks);
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
workdir,
|
|
150
|
-
});
|
|
151
|
-
container.register("BackgroundTaskManager", backgroundTaskManager);
|
|
152
|
-
|
|
153
|
-
if (options.serverUrl) {
|
|
154
|
-
authService.setServerUrl(options.serverUrl);
|
|
155
|
-
}
|
|
156
|
-
const mcpManager = new McpManager(container, {
|
|
157
|
-
callbacks,
|
|
158
|
-
mcpServers: options.mcpServers as
|
|
159
|
-
| Record<string, McpServerConfig>
|
|
160
|
-
| undefined,
|
|
161
|
-
});
|
|
162
|
-
container.register("McpManager", mcpManager);
|
|
163
|
-
|
|
164
|
-
// Wire up auth change callback to refresh/clear remote settings
|
|
165
|
-
authService.onAuthChange(async (event) => {
|
|
166
|
-
if (event === "login") {
|
|
167
|
-
await remoteSettingsService.refresh();
|
|
168
|
-
} else if (event === "logout") {
|
|
169
|
-
remoteSettingsService.clear();
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const lspManager = options.lspManager || new LspManager(container);
|
|
174
|
-
container.register("LspManager", lspManager);
|
|
175
|
-
|
|
176
|
-
const permissionManager = new PermissionManager(container, {
|
|
177
|
-
instanceAllowedRules: options.allowedTools,
|
|
178
|
-
instanceDeniedRules: options.disallowedTools,
|
|
179
|
-
instanceAdditionalDirectories: options.additionalDirectories,
|
|
180
|
-
});
|
|
181
|
-
if (configurationService.resolveAutoMemoryEnabled()) {
|
|
182
|
-
const autoMemoryDir = memoryService.getAutoMemoryDirectory(workdir);
|
|
183
|
-
permissionManager.addSystemAdditionalDirectory(autoMemoryDir);
|
|
184
|
-
permissionManager.addSystemAdditionalDirectory(USER_MEMORY_FILE);
|
|
185
|
-
}
|
|
186
|
-
container.register("PermissionManager", permissionManager);
|
|
187
|
-
permissionManager.setOnConfiguredPermissionModeChange((mode) => {
|
|
188
|
-
handlePlanModeTransition(mode);
|
|
189
|
-
onPermissionModeChange(mode);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
const planManager = new PlanManager(container);
|
|
193
|
-
container.register("PlanManager", planManager);
|
|
194
|
-
|
|
195
|
-
const hookManager = new HookManager(container, workdir);
|
|
196
|
-
if (options.hooks) {
|
|
197
|
-
hookManager.loadConfiguration(options.hooks);
|
|
198
|
-
}
|
|
199
|
-
container.register("HookManager", hookManager);
|
|
200
|
-
|
|
201
|
-
const skillManager = new SkillManager(container, {
|
|
202
|
-
workdir,
|
|
203
|
-
watch: options.watchSkills ?? true,
|
|
204
|
-
});
|
|
205
|
-
container.register("SkillManager", skillManager);
|
|
206
|
-
|
|
207
|
-
const rootSessionId = messageManager.getRootSessionId();
|
|
208
|
-
|
|
209
|
-
const reversionService = new ReversionService(rootSessionId);
|
|
210
|
-
container.register("ReversionService", reversionService);
|
|
211
|
-
reversionService.cleanupOldSessions(30).catch((error) => {
|
|
212
|
-
logger.error("Failed to cleanup old file history:", error);
|
|
213
|
-
});
|
|
214
|
-
// Remove pre-existing meta-only session files (SessionStart hook context
|
|
215
|
-
// with no real messages) that were persisted before lazy materialization.
|
|
216
|
-
cleanupMetaOnlySessions()
|
|
217
|
-
.then((count) => {
|
|
218
|
-
if (count > 0) {
|
|
219
|
-
logger.debug(`Removed ${count} meta-only session file(s)`);
|
|
220
|
-
}
|
|
221
|
-
})
|
|
222
|
-
.catch((error) => {
|
|
223
|
-
logger.error("Failed to cleanup meta-only session files:", error);
|
|
224
|
-
});
|
|
225
|
-
const reversionManager = new ReversionManager(container);
|
|
226
|
-
container.register("ReversionManager", reversionManager);
|
|
227
|
-
|
|
228
|
-
const canUseToolWithPermissionRequest = options.canUseTool
|
|
229
|
-
? async (context: ToolPermissionContext) => {
|
|
230
|
-
try {
|
|
231
|
-
const results = await hookManager.executeHooks("PermissionRequest", {
|
|
232
|
-
event: "PermissionRequest",
|
|
233
|
-
projectDir: workdir,
|
|
234
|
-
timestamp: new Date(),
|
|
235
|
-
sessionId: messageManager.getSessionId(),
|
|
236
|
-
transcriptPath: messageManager.getTranscriptPath(),
|
|
237
|
-
cwd: workdir,
|
|
238
|
-
toolName: context.toolName,
|
|
239
|
-
toolInput: context.toolInput,
|
|
240
|
-
planFilePath: permissionManager.getPlanFilePath(),
|
|
241
|
-
env: Object.fromEntries(
|
|
242
|
-
Object.entries(configurationService.getMergedEnv()).filter(
|
|
243
|
-
(e) => e[1] !== undefined,
|
|
244
|
-
),
|
|
245
|
-
) as Record<string, string>,
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
if (results.length > 0) {
|
|
249
|
-
const processResult = hookManager.processHookResults(
|
|
250
|
-
"PermissionRequest",
|
|
251
|
-
results,
|
|
252
|
-
messageManager,
|
|
253
|
-
);
|
|
254
|
-
|
|
255
|
-
if (processResult.shouldBlock) {
|
|
256
|
-
return {
|
|
257
|
-
behavior: "deny",
|
|
258
|
-
message:
|
|
259
|
-
processResult.errorMessage ||
|
|
260
|
-
"Permission denied by hook execution",
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
} catch (error) {
|
|
265
|
-
logger.warn("Failed to execute permission request hooks", {
|
|
266
|
-
toolName: context.toolName,
|
|
267
|
-
error: error instanceof Error ? error.message : String(error),
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const decision = await options.canUseTool!(context);
|
|
272
|
-
|
|
273
|
-
if (decision.newPermissionMode) {
|
|
274
|
-
setPermissionMode(decision.newPermissionMode);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (decision.newPermissionRule) {
|
|
278
|
-
await addPermissionRule(decision.newPermissionRule);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return decision;
|
|
282
|
-
}
|
|
283
|
-
: undefined;
|
|
284
|
-
|
|
285
|
-
const toolManager = new ToolManager({
|
|
286
|
-
container,
|
|
287
|
-
tools: options.tools,
|
|
288
|
-
customTools: options.customTools,
|
|
289
|
-
});
|
|
290
|
-
container.register("ToolManager", toolManager);
|
|
291
|
-
|
|
292
|
-
container.register("PermissionMode", options.permissionMode);
|
|
293
|
-
// Register the full permission mode transition (Agent.setPermissionMode) so
|
|
294
|
-
// tools like EnterPlanMode can trigger planManager.handlePlanModeTransition
|
|
295
|
-
// and onPermissionModeChange even in bypass mode (where canUseTool is skipped).
|
|
296
|
-
container.register("PermissionModeTransition", setPermissionMode);
|
|
297
|
-
logger.info("Registering CanUseToolCallback", {
|
|
298
|
-
hasCallback: !!canUseToolWithPermissionRequest,
|
|
299
|
-
});
|
|
300
|
-
container.register("CanUseToolCallback", canUseToolWithPermissionRequest);
|
|
301
|
-
|
|
302
|
-
const liveConfigManager = new LiveConfigManager(container, {
|
|
303
|
-
workdir,
|
|
304
|
-
onReload: () => {
|
|
305
|
-
const models = configurationService.getConfiguredModels();
|
|
306
|
-
callbacks.onConfiguredModelsChange?.(models);
|
|
307
|
-
},
|
|
308
|
-
});
|
|
309
|
-
container.register("LiveConfigManager", liveConfigManager);
|
|
310
|
-
|
|
311
|
-
// Wire up remote settings hot-update: when polling detects changed settings,
|
|
312
|
-
// reload configuration so admin changes propagate to the running agent.
|
|
313
|
-
remoteSettingsService.onSettingsUpdate(async () => {
|
|
314
|
-
await liveConfigManager.reload();
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
const subagentManager = new SubagentManager(container, {
|
|
318
|
-
workdir,
|
|
319
|
-
callbacks: {
|
|
320
|
-
onSubagentUserMessageAdded: callbacks.onSubagentUserMessageAdded,
|
|
321
|
-
onSubagentAssistantMessageAdded:
|
|
322
|
-
callbacks.onSubagentAssistantMessageAdded,
|
|
323
|
-
onSubagentAssistantContentUpdated:
|
|
324
|
-
callbacks.onSubagentAssistantContentUpdated,
|
|
325
|
-
onSubagentAssistantReasoningUpdated:
|
|
326
|
-
callbacks.onSubagentAssistantReasoningUpdated,
|
|
327
|
-
onSubagentToolBlockUpdated: callbacks.onSubagentToolBlockUpdated,
|
|
328
|
-
onSubagentMessagesChange: (subagentId, messages) => {
|
|
329
|
-
callbacks.onSubagentMessagesChange?.(subagentId, messages);
|
|
330
|
-
},
|
|
331
|
-
onSubagentLatestTotalTokensChange:
|
|
332
|
-
callbacks.onSubagentLatestTotalTokensChange,
|
|
333
|
-
},
|
|
334
|
-
onUsageAdded: (usage: Usage) => addUsage(usage),
|
|
335
|
-
stream,
|
|
336
|
-
});
|
|
337
|
-
container.register("SubagentManager", subagentManager);
|
|
338
|
-
|
|
339
|
-
const forkedAgentManager = new ForkedAgentManager(container);
|
|
340
|
-
container.register("ForkedAgentManager", forkedAgentManager);
|
|
341
|
-
|
|
342
|
-
const aiManager = new AIManager(container, {
|
|
343
|
-
callbacks: {
|
|
344
|
-
...callbacks,
|
|
345
|
-
onUsageAdded: (usage: Usage) => addUsage(usage),
|
|
346
|
-
},
|
|
347
|
-
workdir,
|
|
348
|
-
systemPrompt,
|
|
349
|
-
stream,
|
|
350
|
-
});
|
|
351
|
-
container.register("AIManager", aiManager);
|
|
352
|
-
|
|
353
|
-
const slashCommandManager = new SlashCommandManager(container, { workdir });
|
|
354
|
-
container.register("SlashCommandManager", slashCommandManager);
|
|
355
|
-
slashCommandManager.initialize();
|
|
356
|
-
|
|
357
|
-
const pluginManager = new PluginManager(container, { workdir });
|
|
358
|
-
container.register("PluginManager", pluginManager);
|
|
359
|
-
|
|
360
|
-
const bangManager = new BangManager(container, { workdir });
|
|
361
|
-
container.register("BangManager", bangManager);
|
|
362
|
-
|
|
363
|
-
const cronManager = new CronManager(container, messageManager.getSessionId());
|
|
364
|
-
container.register("CronManager", cronManager);
|
|
365
|
-
cronManager.start();
|
|
366
|
-
|
|
367
|
-
const workflowManager = new WorkflowManager(container);
|
|
368
|
-
container.register("WorkflowManager", workflowManager);
|
|
369
|
-
|
|
370
|
-
return container;
|
|
371
|
-
}
|
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
import type { Message } from "../types/index.js";
|
|
2
|
-
import { convertImageToBase64 } from "./messageOperations.js";
|
|
3
|
-
import { taskNotificationToXml } from "./notificationXml.js";
|
|
4
|
-
import { ChatCompletionMessageToolCall } from "openai/resources";
|
|
5
|
-
import { recoverTruncatedJson, stripAnsiColors } from "./stringUtils.js";
|
|
6
|
-
import {
|
|
7
|
-
ChatCompletionContentPart,
|
|
8
|
-
ChatCompletionMessageParam,
|
|
9
|
-
} from "openai/resources.js";
|
|
10
|
-
import { logger } from "./globalLogger.js";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Safely handle tool call parameters, ensuring a legal JSON string is returned.
|
|
14
|
-
* Attempts to recover truncated JSON (e.g., missing closing braces).
|
|
15
|
-
* @param args Tool call parameters
|
|
16
|
-
* @returns Legal JSON string
|
|
17
|
-
*/
|
|
18
|
-
function safeToolArguments(args: string): string {
|
|
19
|
-
if (!args) {
|
|
20
|
-
return "{}";
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
// Try to parse as JSON to validate format
|
|
25
|
-
JSON.parse(args);
|
|
26
|
-
return args;
|
|
27
|
-
} catch {
|
|
28
|
-
// Attempt to recover truncated JSON
|
|
29
|
-
const recovered = recoverTruncatedJson(args);
|
|
30
|
-
try {
|
|
31
|
-
JSON.parse(recovered);
|
|
32
|
-
return recovered;
|
|
33
|
-
} catch {
|
|
34
|
-
// Truly malformed JSON — return sanitized fallback
|
|
35
|
-
return JSON.stringify({
|
|
36
|
-
invalid_arguments: args,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Options for converting messages to API format.
|
|
44
|
-
*/
|
|
45
|
-
export interface ConvertMessagesOptions {
|
|
46
|
-
/** When false, images are stripped and replaced with text placeholders. */
|
|
47
|
-
supportsVision?: boolean;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Convert message format to API call format, stopping when a compacted message is encountered.
|
|
52
|
-
* Messages with no meaningful content or tool calls are filtered out.
|
|
53
|
-
* @param messages Message list
|
|
54
|
-
* @param options Optional conversion options (e.g. supportsVision)
|
|
55
|
-
* @returns Converted API message format list
|
|
56
|
-
*/
|
|
57
|
-
export function convertMessagesForAPI(
|
|
58
|
-
messages: Message[],
|
|
59
|
-
options?: ConvertMessagesOptions,
|
|
60
|
-
): ChatCompletionMessageParam[] {
|
|
61
|
-
const supportsVision = options?.supportsVision !== false;
|
|
62
|
-
const recentMessages: ChatCompletionMessageParam[] = [];
|
|
63
|
-
|
|
64
|
-
const startIndex = messages.length - 1;
|
|
65
|
-
for (let i = startIndex; i >= 0; i--) {
|
|
66
|
-
const message = messages[i];
|
|
67
|
-
|
|
68
|
-
// Check if a compaction block is encountered, if so, stop iteration
|
|
69
|
-
if (
|
|
70
|
-
message.role === "assistant" &&
|
|
71
|
-
message.blocks.some((block) => block.type === "compact")
|
|
72
|
-
) {
|
|
73
|
-
// Add the content of the compaction block as an assistant message to the history
|
|
74
|
-
const compactBlock = message.blocks.find(
|
|
75
|
-
(block) => block.type === "compact",
|
|
76
|
-
);
|
|
77
|
-
if (compactBlock && compactBlock.type === "compact") {
|
|
78
|
-
recentMessages.unshift({
|
|
79
|
-
role: "user",
|
|
80
|
-
content: compactBlock.content,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Skip empty assistant messages (no blocks or all blocks are empty)
|
|
87
|
-
if (message.role === "assistant" && message.blocks.length === 0) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (message.role === "assistant") {
|
|
92
|
-
// First check if there is a tool block, if so, add the tool message first
|
|
93
|
-
// Filter out incomplete tool blocks (no result or still running)
|
|
94
|
-
const toolBlocks = message.blocks.filter(
|
|
95
|
-
(block) => block.type === "tool",
|
|
96
|
-
);
|
|
97
|
-
const completedToolIds = new Set<string>(); // Record completed tool IDs
|
|
98
|
-
|
|
99
|
-
if (toolBlocks.length > 0) {
|
|
100
|
-
// Collect image user messages to place after all tool messages
|
|
101
|
-
const imageUserMessages: ChatCompletionMessageParam[] = [];
|
|
102
|
-
|
|
103
|
-
toolBlocks.forEach((toolBlock) => {
|
|
104
|
-
// Only add completed tool blocks (i.e., stage is 'end')
|
|
105
|
-
if (toolBlock.id && toolBlock.stage === "end") {
|
|
106
|
-
completedToolIds.add(toolBlock.id);
|
|
107
|
-
|
|
108
|
-
// Always add a proper tool message to satisfy tool_call_id pairing
|
|
109
|
-
recentMessages.unshift({
|
|
110
|
-
tool_call_id: toolBlock.id,
|
|
111
|
-
role: "tool",
|
|
112
|
-
content: stripAnsiColors(toolBlock.result || ""),
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// If there are images, also prepare a user message with image content
|
|
116
|
-
if (toolBlock.images && toolBlock.images.length > 0) {
|
|
117
|
-
if (supportsVision) {
|
|
118
|
-
const contentParts: ChatCompletionContentPart[] = [];
|
|
119
|
-
|
|
120
|
-
toolBlock.images.forEach((image) => {
|
|
121
|
-
const imageUrl = image.data.startsWith("data:")
|
|
122
|
-
? image.data
|
|
123
|
-
: `data:${image.mediaType || "image/png"};base64,${image.data}`;
|
|
124
|
-
|
|
125
|
-
contentParts.push({
|
|
126
|
-
type: "image_url",
|
|
127
|
-
image_url: {
|
|
128
|
-
url: imageUrl,
|
|
129
|
-
detail: "auto",
|
|
130
|
-
},
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
imageUserMessages.push({
|
|
135
|
-
role: "user",
|
|
136
|
-
content: contentParts,
|
|
137
|
-
});
|
|
138
|
-
} else {
|
|
139
|
-
// Non-vision model: replace images with a text placeholder
|
|
140
|
-
imageUserMessages.push({
|
|
141
|
-
role: "user",
|
|
142
|
-
content:
|
|
143
|
-
"[Tool returned an image, but the current model does not support image recognition]",
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
// Insert image user messages after all tool messages but before the
|
|
151
|
-
// assistant message (which will be unshifted next). Since tool messages
|
|
152
|
-
// were unshifted to the front, we splice images right after them.
|
|
153
|
-
if (imageUserMessages.length > 0) {
|
|
154
|
-
// Tool messages are at indices 0..N-1, existing messages start at N
|
|
155
|
-
const toolMsgCount = completedToolIds.size;
|
|
156
|
-
recentMessages.splice(toolMsgCount, 0, ...imageUserMessages);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Construct the content of the assistant message
|
|
161
|
-
let content = "";
|
|
162
|
-
let tool_calls: ChatCompletionMessageToolCall[] | undefined = undefined;
|
|
163
|
-
|
|
164
|
-
// Construct content from text blocks - filter out empty content
|
|
165
|
-
const textBlocks = message.blocks.filter(
|
|
166
|
-
(block) =>
|
|
167
|
-
block.type === "text" &&
|
|
168
|
-
block.content &&
|
|
169
|
-
block.content.trim().length > 0,
|
|
170
|
-
);
|
|
171
|
-
if (textBlocks.length > 0) {
|
|
172
|
-
content = textBlocks
|
|
173
|
-
.map((block) => (block.type === "text" ? block.content : ""))
|
|
174
|
-
.join("\n");
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Extract reasoning content from reasoning blocks
|
|
178
|
-
const reasoningBlocks = message.blocks.filter(
|
|
179
|
-
(block) =>
|
|
180
|
-
block.type === "reasoning" &&
|
|
181
|
-
block.content &&
|
|
182
|
-
block.content.trim().length > 0,
|
|
183
|
-
);
|
|
184
|
-
let reasoning_content: string | undefined;
|
|
185
|
-
if (reasoningBlocks.length > 0) {
|
|
186
|
-
reasoning_content = reasoningBlocks
|
|
187
|
-
.map((block) => (block.type === "reasoning" ? block.content : ""))
|
|
188
|
-
.join("\n");
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Construct tool calls from tool blocks
|
|
192
|
-
if (toolBlocks.length > 0) {
|
|
193
|
-
tool_calls = toolBlocks
|
|
194
|
-
.filter(
|
|
195
|
-
(toolBlock) => toolBlock.id && completedToolIds.has(toolBlock.id),
|
|
196
|
-
)
|
|
197
|
-
.map((toolBlock) => ({
|
|
198
|
-
id: toolBlock.id!,
|
|
199
|
-
type: "function",
|
|
200
|
-
function: {
|
|
201
|
-
name: toolBlock.name || "",
|
|
202
|
-
arguments: safeToolArguments(
|
|
203
|
-
String(toolBlock.parameters || "{}"),
|
|
204
|
-
),
|
|
205
|
-
},
|
|
206
|
-
}));
|
|
207
|
-
|
|
208
|
-
if (tool_calls.length === 0) {
|
|
209
|
-
tool_calls = undefined;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Construct assistant message - only add if there is meaningful content or tool calls
|
|
214
|
-
const hasContent = content && content.trim().length > 0;
|
|
215
|
-
const hasToolCalls = tool_calls && tool_calls.length > 0;
|
|
216
|
-
|
|
217
|
-
if (hasContent || hasToolCalls) {
|
|
218
|
-
const assistantMessage: ChatCompletionMessageParam = {
|
|
219
|
-
role: "assistant",
|
|
220
|
-
content: hasContent ? content : undefined,
|
|
221
|
-
tool_calls,
|
|
222
|
-
...(reasoning_content ? { reasoning_content } : {}),
|
|
223
|
-
...(message.additionalFields ? { ...message.additionalFields } : {}),
|
|
224
|
-
} as ChatCompletionMessageParam;
|
|
225
|
-
|
|
226
|
-
recentMessages.unshift(assistantMessage);
|
|
227
|
-
}
|
|
228
|
-
} else if (message.role === "user") {
|
|
229
|
-
// User messages converted to standard format
|
|
230
|
-
const contentParts: ChatCompletionContentPart[] = [];
|
|
231
|
-
|
|
232
|
-
message.blocks.forEach((block) => {
|
|
233
|
-
// Add text content - only if it has meaningful content
|
|
234
|
-
if (
|
|
235
|
-
block.type === "text" &&
|
|
236
|
-
block.content &&
|
|
237
|
-
block.content.trim().length > 0
|
|
238
|
-
) {
|
|
239
|
-
const textForApi = block.customCommandContent ?? block.content;
|
|
240
|
-
contentParts.push({
|
|
241
|
-
type: "text",
|
|
242
|
-
text: textForApi,
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// If there is an image, add image content
|
|
247
|
-
if (
|
|
248
|
-
block.type === "image" &&
|
|
249
|
-
block.imageUrls &&
|
|
250
|
-
block.imageUrls.length > 0
|
|
251
|
-
) {
|
|
252
|
-
if (!supportsVision) {
|
|
253
|
-
// Non-vision model: replace images with a text placeholder
|
|
254
|
-
contentParts.push({
|
|
255
|
-
type: "text",
|
|
256
|
-
text: "[User shared an image, but the current model does not support image recognition]",
|
|
257
|
-
});
|
|
258
|
-
} else {
|
|
259
|
-
block.imageUrls.forEach((imageUrl: string) => {
|
|
260
|
-
// Check if it's already base64, convert if not
|
|
261
|
-
let finalImageUrl = imageUrl;
|
|
262
|
-
if (!imageUrl.startsWith("data:image/")) {
|
|
263
|
-
// If it's a file path, it needs to be converted to base64
|
|
264
|
-
try {
|
|
265
|
-
finalImageUrl = convertImageToBase64(imageUrl);
|
|
266
|
-
} catch (error) {
|
|
267
|
-
logger.error(
|
|
268
|
-
"Failed to convert image path to base64:",
|
|
269
|
-
imageUrl,
|
|
270
|
-
error,
|
|
271
|
-
);
|
|
272
|
-
// Skip this image, do not add to content
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
contentParts.push({
|
|
278
|
-
type: "image_url",
|
|
279
|
-
image_url: {
|
|
280
|
-
url: finalImageUrl,
|
|
281
|
-
detail: "auto",
|
|
282
|
-
},
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// If there is a tool block in user message, add its result
|
|
289
|
-
if (block.type === "tool" && block.stage === "end" && block.result) {
|
|
290
|
-
contentParts.push({
|
|
291
|
-
type: "text",
|
|
292
|
-
text: `<local-command-stdout>\n${stripAnsiColors(block.result)}\n</local-command-stdout>`,
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// If there is a task notification block, convert it back to XML
|
|
297
|
-
if (block.type === "task_notification") {
|
|
298
|
-
contentParts.push({
|
|
299
|
-
type: "text",
|
|
300
|
-
text: taskNotificationToXml(block),
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
// Only add user message if there is meaningful content
|
|
306
|
-
if (contentParts.length > 0) {
|
|
307
|
-
// Filter out empty text parts
|
|
308
|
-
const meaningfulParts = contentParts.filter((part) => {
|
|
309
|
-
if (part.type === "text") {
|
|
310
|
-
return part.text && part.text.trim().length > 0;
|
|
311
|
-
}
|
|
312
|
-
return true; // Keep image parts
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
if (meaningfulParts.length > 0) {
|
|
316
|
-
recentMessages.unshift({
|
|
317
|
-
role: "user",
|
|
318
|
-
content: meaningfulParts,
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return recentMessages;
|
|
326
|
-
}
|