wave-agent-sdk 0.0.1 → 0.0.3

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.
Files changed (82) hide show
  1. package/dist/agent.d.ts +37 -3
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +82 -5
  4. package/dist/index.d.ts +0 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +0 -1
  7. package/dist/managers/aiManager.d.ts +7 -1
  8. package/dist/managers/aiManager.d.ts.map +1 -1
  9. package/dist/managers/aiManager.js +11 -5
  10. package/dist/managers/messageManager.d.ts +8 -0
  11. package/dist/managers/messageManager.d.ts.map +1 -1
  12. package/dist/managers/messageManager.js +26 -2
  13. package/dist/managers/skillManager.d.ts +4 -5
  14. package/dist/managers/skillManager.d.ts.map +1 -1
  15. package/dist/managers/skillManager.js +6 -82
  16. package/dist/managers/subagentManager.d.ts +96 -0
  17. package/dist/managers/subagentManager.d.ts.map +1 -0
  18. package/dist/managers/subagentManager.js +261 -0
  19. package/dist/managers/toolManager.d.ts +33 -1
  20. package/dist/managers/toolManager.d.ts.map +1 -1
  21. package/dist/managers/toolManager.js +43 -5
  22. package/dist/services/aiService.d.ts +5 -0
  23. package/dist/services/aiService.d.ts.map +1 -1
  24. package/dist/services/aiService.js +58 -28
  25. package/dist/services/session.d.ts.map +1 -1
  26. package/dist/services/session.js +4 -0
  27. package/dist/tools/grepTool.d.ts.map +1 -1
  28. package/dist/tools/grepTool.js +8 -6
  29. package/dist/tools/readTool.d.ts.map +1 -1
  30. package/dist/tools/readTool.js +36 -6
  31. package/dist/tools/skillTool.d.ts +8 -0
  32. package/dist/tools/skillTool.d.ts.map +1 -0
  33. package/dist/tools/skillTool.js +72 -0
  34. package/dist/tools/taskTool.d.ts +8 -0
  35. package/dist/tools/taskTool.d.ts.map +1 -0
  36. package/dist/tools/taskTool.js +109 -0
  37. package/dist/tools/todoWriteTool.d.ts +6 -0
  38. package/dist/tools/todoWriteTool.d.ts.map +1 -0
  39. package/dist/tools/todoWriteTool.js +203 -0
  40. package/dist/types.d.ts +65 -1
  41. package/dist/types.d.ts.map +1 -1
  42. package/dist/types.js +16 -0
  43. package/dist/utils/configResolver.d.ts +38 -0
  44. package/dist/utils/configResolver.d.ts.map +1 -0
  45. package/dist/utils/configResolver.js +106 -0
  46. package/dist/utils/configValidator.d.ts +36 -0
  47. package/dist/utils/configValidator.d.ts.map +1 -0
  48. package/dist/utils/configValidator.js +78 -0
  49. package/dist/utils/constants.d.ts +10 -0
  50. package/dist/utils/constants.d.ts.map +1 -1
  51. package/dist/utils/constants.js +10 -0
  52. package/dist/utils/fileFormat.d.ts +17 -0
  53. package/dist/utils/fileFormat.d.ts.map +1 -0
  54. package/dist/utils/fileFormat.js +35 -0
  55. package/dist/utils/messageOperations.d.ts +18 -0
  56. package/dist/utils/messageOperations.d.ts.map +1 -1
  57. package/dist/utils/messageOperations.js +43 -0
  58. package/dist/utils/subagentParser.d.ts +19 -0
  59. package/dist/utils/subagentParser.d.ts.map +1 -0
  60. package/dist/utils/subagentParser.js +159 -0
  61. package/package.json +11 -15
  62. package/src/agent.ts +130 -9
  63. package/src/index.ts +0 -1
  64. package/src/managers/aiManager.ts +22 -10
  65. package/src/managers/messageManager.ts +55 -1
  66. package/src/managers/skillManager.ts +7 -96
  67. package/src/managers/subagentManager.ts +368 -0
  68. package/src/managers/toolManager.ts +50 -5
  69. package/src/services/aiService.ts +92 -36
  70. package/src/services/session.ts +5 -0
  71. package/src/tools/grepTool.ts +9 -6
  72. package/src/tools/readTool.ts +40 -6
  73. package/src/tools/skillTool.ts +82 -0
  74. package/src/tools/taskTool.ts +128 -0
  75. package/src/tools/todoWriteTool.ts +232 -0
  76. package/src/types.ts +85 -1
  77. package/src/utils/configResolver.ts +142 -0
  78. package/src/utils/configValidator.ts +133 -0
  79. package/src/utils/constants.ts +10 -0
  80. package/src/utils/fileFormat.ts +40 -0
  81. package/src/utils/messageOperations.ts +80 -0
  82. package/src/utils/subagentParser.ts +223 -0
@@ -0,0 +1,96 @@
1
+ import type { SubagentConfiguration } from "../utils/subagentParser.js";
2
+ import type { Message, Logger, GatewayConfig, ModelConfig } from "../types.js";
3
+ import { AIManager } from "./aiManager.js";
4
+ import { MessageManager } from "./messageManager.js";
5
+ import { ToolManager } from "./toolManager.js";
6
+ export interface SubagentInstance {
7
+ subagentId: string;
8
+ configuration: SubagentConfiguration;
9
+ aiManager: AIManager;
10
+ messageManager: MessageManager;
11
+ toolManager: ToolManager;
12
+ status: "initializing" | "active" | "completed" | "error" | "aborted";
13
+ taskDescription: string;
14
+ messages: Message[];
15
+ }
16
+ export interface SubagentManagerOptions {
17
+ workdir: string;
18
+ parentToolManager: ToolManager;
19
+ parentMessageManager: MessageManager;
20
+ logger?: Logger;
21
+ gatewayConfig: GatewayConfig;
22
+ modelConfig: ModelConfig;
23
+ tokenLimit: number;
24
+ }
25
+ export declare class SubagentManager {
26
+ private instances;
27
+ private cachedConfigurations;
28
+ private workdir;
29
+ private parentToolManager;
30
+ private parentMessageManager;
31
+ private logger?;
32
+ private gatewayConfig;
33
+ private modelConfig;
34
+ private tokenLimit;
35
+ constructor(options: SubagentManagerOptions);
36
+ /**
37
+ * Initialize the SubagentManager by loading and caching configurations
38
+ */
39
+ initialize(): Promise<void>;
40
+ /**
41
+ * Load all available subagent configurations and cache them
42
+ */
43
+ loadConfigurations(): Promise<SubagentConfiguration[]>;
44
+ /**
45
+ * Get cached configurations synchronously (must call loadConfigurations first)
46
+ */
47
+ getConfigurations(): SubagentConfiguration[];
48
+ /**
49
+ * Find subagent by exact name match
50
+ */
51
+ findSubagent(name: string): Promise<SubagentConfiguration | null>;
52
+ /**
53
+ * Create a new subagent instance with isolated managers
54
+ */
55
+ createInstance(configuration: SubagentConfiguration, taskDescription: string): Promise<SubagentInstance>;
56
+ /**
57
+ * Execute task using subagent instance
58
+ *
59
+ * IMPORTANT: This method automatically filters out the Task tool from allowedTools
60
+ * to prevent subagents from spawning other subagents (infinite recursion protection)
61
+ */
62
+ executeTask(instance: SubagentInstance, prompt: string): Promise<string>;
63
+ /**
64
+ * Get instance by subagent ID
65
+ */
66
+ getInstance(subagentId: string): SubagentInstance | null;
67
+ /**
68
+ * Update instance status
69
+ */
70
+ updateInstanceStatus(subagentId: string, status: SubagentInstance["status"]): void;
71
+ /**
72
+ * Add message to instance
73
+ */
74
+ addMessageToInstance(subagentId: string, message: Message): void;
75
+ /**
76
+ * Abort a running subagent instance
77
+ */
78
+ abortInstance(subagentId: string): boolean;
79
+ /**
80
+ * Abort all active subagent instances
81
+ */
82
+ abortAllInstances(): void;
83
+ /**
84
+ * Clean up completed, errored, or aborted instances
85
+ */
86
+ cleanupInstance(subagentId: string): void;
87
+ /**
88
+ * Get all active instances
89
+ */
90
+ getActiveInstances(): SubagentInstance[];
91
+ /**
92
+ * Clean up all instances (for session end)
93
+ */
94
+ cleanup(): void;
95
+ }
96
+ //# sourceMappingURL=subagentManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagentManager.d.ts","sourceRoot":"","sources":["../../src/managers/subagentManager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EACL,cAAc,EAEf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,qBAAqB,CAAC;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,cAAc,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,CAAC;IACtE,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,WAAW,CAAC;IAC/B,oBAAoB,EAAE,cAAc,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,oBAAoB,CAAwC;IAEpE,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,oBAAoB,CAAiB;IAC7C,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,EAAE,sBAAsB;IAU3C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAY5D;;OAEG;IACH,iBAAiB,IAAI,qBAAqB,EAAE;IAS5C;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM;IAK/B;;OAEG;IACG,cAAc,CAClB,aAAa,EAAE,qBAAqB,EACpC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,gBAAgB,CAAC;IAmF5B;;;;;OAKG;IACG,WAAW,CACf,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC;IAiElB;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAIxD;;OAEG;IACH,oBAAoB,CAClB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GACjC,IAAI;IAOP;;OAEG;IACH,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAOhE;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAiC1C;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAOzB;;OAEG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAYzC;;OAEG;IACH,kBAAkB,IAAI,gBAAgB,EAAE;IAOxC;;OAEG;IACH,OAAO,IAAI,IAAI;CAKhB"}
@@ -0,0 +1,261 @@
1
+ import { randomUUID } from "crypto";
2
+ import { AIManager } from "./aiManager.js";
3
+ import { MessageManager, } from "./messageManager.js";
4
+ export class SubagentManager {
5
+ constructor(options) {
6
+ this.instances = new Map();
7
+ this.cachedConfigurations = null;
8
+ this.workdir = options.workdir;
9
+ this.parentToolManager = options.parentToolManager;
10
+ this.parentMessageManager = options.parentMessageManager;
11
+ this.logger = options.logger;
12
+ this.gatewayConfig = options.gatewayConfig;
13
+ this.modelConfig = options.modelConfig;
14
+ this.tokenLimit = options.tokenLimit;
15
+ }
16
+ /**
17
+ * Initialize the SubagentManager by loading and caching configurations
18
+ */
19
+ async initialize() {
20
+ await this.loadConfigurations();
21
+ }
22
+ /**
23
+ * Load all available subagent configurations and cache them
24
+ */
25
+ async loadConfigurations() {
26
+ if (this.cachedConfigurations === null) {
27
+ const { loadSubagentConfigurations } = await import("../utils/subagentParser.js");
28
+ this.cachedConfigurations = await loadSubagentConfigurations(this.workdir);
29
+ }
30
+ return this.cachedConfigurations;
31
+ }
32
+ /**
33
+ * Get cached configurations synchronously (must call loadConfigurations first)
34
+ */
35
+ getConfigurations() {
36
+ if (this.cachedConfigurations === null) {
37
+ throw new Error("SubagentManager not initialized. Call loadConfigurations() first.");
38
+ }
39
+ return this.cachedConfigurations;
40
+ }
41
+ /**
42
+ * Find subagent by exact name match
43
+ */
44
+ async findSubagent(name) {
45
+ const { findSubagentByName } = await import("../utils/subagentParser.js");
46
+ return findSubagentByName(name, this.workdir);
47
+ }
48
+ /**
49
+ * Create a new subagent instance with isolated managers
50
+ */
51
+ async createInstance(configuration, taskDescription) {
52
+ if (!this.parentToolManager ||
53
+ !this.gatewayConfig ||
54
+ !this.modelConfig ||
55
+ !this.tokenLimit) {
56
+ throw new Error("SubagentManager not properly initialized - call initialize() first");
57
+ }
58
+ const subagentId = randomUUID();
59
+ // Create isolated MessageManager for the subagent
60
+ const subagentCallbacks = {
61
+ // These callbacks will be handled by the parent agent
62
+ onMessagesChange: (messages) => {
63
+ const instance = this.instances.get(subagentId);
64
+ if (instance) {
65
+ instance.messages = messages;
66
+ // Update parent's subagent block with latest messages
67
+ this.parentMessageManager.updateSubagentBlock(subagentId, {
68
+ messages: messages,
69
+ });
70
+ }
71
+ },
72
+ };
73
+ const messageManager = new MessageManager({
74
+ callbacks: subagentCallbacks,
75
+ workdir: this.workdir,
76
+ logger: this.logger,
77
+ });
78
+ // Use the parent tool manager directly - tool restrictions will be handled by allowedTools parameter
79
+ const toolManager = this.parentToolManager;
80
+ // Determine model to use
81
+ const modelToUse = configuration.model && configuration.model !== "inherit"
82
+ ? configuration.model
83
+ : this.modelConfig.agentModel;
84
+ // Create isolated AIManager for the subagent
85
+ const aiManager = new AIManager({
86
+ messageManager,
87
+ toolManager,
88
+ logger: this.logger,
89
+ workdir: this.workdir,
90
+ systemPrompt: configuration.systemPrompt,
91
+ gatewayConfig: this.gatewayConfig,
92
+ modelConfig: {
93
+ ...this.modelConfig,
94
+ agentModel: modelToUse,
95
+ },
96
+ tokenLimit: this.tokenLimit,
97
+ });
98
+ const instance = {
99
+ subagentId,
100
+ configuration,
101
+ aiManager,
102
+ messageManager,
103
+ toolManager,
104
+ status: "initializing",
105
+ taskDescription,
106
+ messages: [],
107
+ };
108
+ this.instances.set(subagentId, instance);
109
+ // Create subagent block in parent message manager
110
+ this.parentMessageManager.addSubagentBlock(subagentId, configuration.name, "active", []);
111
+ return instance;
112
+ }
113
+ /**
114
+ * Execute task using subagent instance
115
+ *
116
+ * IMPORTANT: This method automatically filters out the Task tool from allowedTools
117
+ * to prevent subagents from spawning other subagents (infinite recursion protection)
118
+ */
119
+ async executeTask(instance, prompt) {
120
+ try {
121
+ // Set status to active and update parent
122
+ this.updateInstanceStatus(instance.subagentId, "active");
123
+ this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
124
+ status: "active",
125
+ });
126
+ // Add the user's prompt as a message
127
+ instance.messageManager.addUserMessage(prompt);
128
+ // Create allowed tools list - always exclude Task tool to prevent subagent recursion
129
+ let allowedTools = instance.configuration.tools;
130
+ // Always filter out the Task tool to prevent subagents from creating sub-subagents
131
+ if (allowedTools) {
132
+ allowedTools = allowedTools.filter((tool) => tool !== "Task");
133
+ }
134
+ else {
135
+ // If no tools specified, get all tools except Task
136
+ const allTools = instance.toolManager.list().map((tool) => tool.name);
137
+ allowedTools = allTools.filter((tool) => tool !== "Task");
138
+ }
139
+ // Execute the AI request with tool restrictions
140
+ await instance.aiManager.sendAIMessage({
141
+ allowedTools,
142
+ model: instance.configuration.model !== "inherit"
143
+ ? instance.configuration.model
144
+ : undefined,
145
+ });
146
+ // Get the latest messages to extract the response
147
+ const messages = instance.messageManager.getMessages();
148
+ const lastAssistantMessage = messages
149
+ .filter((msg) => msg.role === "assistant")
150
+ .pop();
151
+ if (!lastAssistantMessage) {
152
+ throw new Error("No response from subagent");
153
+ }
154
+ // Extract text content from the last assistant message
155
+ const textBlocks = lastAssistantMessage.blocks.filter((block) => block.type === "text");
156
+ const response = textBlocks.map((block) => block.content).join("\n");
157
+ // Update status to completed and update parent with final messages
158
+ this.updateInstanceStatus(instance.subagentId, "completed");
159
+ this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
160
+ status: "completed",
161
+ messages: messages,
162
+ });
163
+ return response || "Task completed with no text response";
164
+ }
165
+ catch (error) {
166
+ this.updateInstanceStatus(instance.subagentId, "error");
167
+ this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
168
+ status: "error",
169
+ });
170
+ throw error;
171
+ }
172
+ }
173
+ /**
174
+ * Get instance by subagent ID
175
+ */
176
+ getInstance(subagentId) {
177
+ return this.instances.get(subagentId) || null;
178
+ }
179
+ /**
180
+ * Update instance status
181
+ */
182
+ updateInstanceStatus(subagentId, status) {
183
+ const instance = this.instances.get(subagentId);
184
+ if (instance) {
185
+ instance.status = status;
186
+ }
187
+ }
188
+ /**
189
+ * Add message to instance
190
+ */
191
+ addMessageToInstance(subagentId, message) {
192
+ const instance = this.instances.get(subagentId);
193
+ if (instance) {
194
+ instance.messages.push(message);
195
+ }
196
+ }
197
+ /**
198
+ * Abort a running subagent instance
199
+ */
200
+ abortInstance(subagentId) {
201
+ const instance = this.instances.get(subagentId);
202
+ if (!instance) {
203
+ return false;
204
+ }
205
+ // Only abort active or initializing instances
206
+ if (instance.status !== "active" && instance.status !== "initializing") {
207
+ return false;
208
+ }
209
+ try {
210
+ // Abort the AI manager operations
211
+ instance.aiManager.abortAIMessage();
212
+ // Update status
213
+ this.updateInstanceStatus(subagentId, "aborted");
214
+ this.parentMessageManager.updateSubagentBlock(subagentId, {
215
+ status: "aborted",
216
+ messages: instance.messages,
217
+ });
218
+ this.logger?.info(`Aborted subagent instance: ${subagentId}`);
219
+ return true;
220
+ }
221
+ catch (error) {
222
+ this.logger?.error(`Failed to abort subagent instance ${subagentId}:`, error);
223
+ return false;
224
+ }
225
+ }
226
+ /**
227
+ * Abort all active subagent instances
228
+ */
229
+ abortAllInstances() {
230
+ const activeInstances = this.getActiveInstances();
231
+ for (const instance of activeInstances) {
232
+ this.abortInstance(instance.subagentId);
233
+ }
234
+ }
235
+ /**
236
+ * Clean up completed, errored, or aborted instances
237
+ */
238
+ cleanupInstance(subagentId) {
239
+ const instance = this.instances.get(subagentId);
240
+ if (instance &&
241
+ (instance.status === "completed" ||
242
+ instance.status === "error" ||
243
+ instance.status === "aborted")) {
244
+ this.instances.delete(subagentId);
245
+ }
246
+ }
247
+ /**
248
+ * Get all active instances
249
+ */
250
+ getActiveInstances() {
251
+ return Array.from(this.instances.values()).filter((instance) => instance.status === "active" || instance.status === "initializing");
252
+ }
253
+ /**
254
+ * Clean up all instances (for session end)
255
+ */
256
+ cleanup() {
257
+ // Abort all active instances before cleanup
258
+ this.abortAllInstances();
259
+ this.instances.clear();
260
+ }
261
+ }
@@ -2,6 +2,8 @@ import type { ToolContext, ToolPlugin, ToolResult } from "../tools/types.js";
2
2
  import { McpManager } from "./mcpManager.js";
3
3
  import { ChatCompletionFunctionTool } from "openai/resources.js";
4
4
  import type { Logger } from "../types.js";
5
+ import type { SubagentManager } from "./subagentManager.js";
6
+ import type { SkillManager } from "./skillManager.js";
5
7
  export interface ToolManagerOptions {
6
8
  mcpManager: McpManager;
7
9
  logger?: Logger;
@@ -14,7 +16,37 @@ declare class ToolManager {
14
16
  private mcpManager;
15
17
  private logger?;
16
18
  constructor(options: ToolManagerOptions);
17
- private initializeBuiltInTools;
19
+ /**
20
+ * Register a new tool
21
+ */
22
+ register(tool: ToolPlugin): void;
23
+ /**
24
+ * Initialize built-in tools. Can be called with dependencies for tools that require them.
25
+ *
26
+ * This method can be called multiple times safely. When called without dependencies,
27
+ * it registers basic tools (Bash, Read, Write, TodoWrite, etc.). When called with
28
+ * dependencies, it also registers tools that require managers (Task, Skill).
29
+ *
30
+ * @param deps Optional dependencies for advanced tools
31
+ * @param deps.subagentManager SubagentManager instance for Task tool
32
+ * @param deps.skillManager SkillManager instance for Skill tool
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * // Initialize basic tools only
37
+ * toolManager.initializeBuiltInTools();
38
+ *
39
+ * // Initialize all tools including those requiring dependencies
40
+ * toolManager.initializeBuiltInTools({
41
+ * subagentManager: mySubagentManager,
42
+ * skillManager: mySkillManager
43
+ * });
44
+ * ```
45
+ */
46
+ initializeBuiltInTools(deps?: {
47
+ subagentManager?: SubagentManager;
48
+ skillManager?: SkillManager;
49
+ }): void;
18
50
  execute(name: string, args: Record<string, unknown>, context: ToolContext): Promise<ToolResult>;
19
51
  list(): ToolPlugin[];
20
52
  getToolsConfig(): ChatCompletionFunctionTool[];
@@ -1 +1 @@
1
- {"version":3,"file":"toolManager.d.ts","sourceRoot":"","sources":["../../src/managers/toolManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAY7E,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,cAAM,WAAW;IACf,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,OAAO,EAAE,kBAAkB;IAQvC,OAAO,CAAC,sBAAsB;IAqBxB,OAAO,CACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC;IA2BtB,IAAI,IAAI,UAAU,EAAE;IAMpB,cAAc,IAAI,0BAA0B,EAAE;CAO/C;AAGD,OAAO,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"toolManager.d.ts","sourceRoot":"","sources":["../../src/managers/toolManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAc7E,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,cAAM,WAAW;IACf,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,OAAO,EAAE,kBAAkB;IAKvC;;OAEG;IACI,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAIvC;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACI,sBAAsB,CAAC,IAAI,CAAC,EAAE;QACnC,eAAe,CAAC,EAAE,eAAe,CAAC;QAClC,YAAY,CAAC,EAAE,YAAY,CAAC;KAC7B,GAAG,IAAI;IAgCF,OAAO,CACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC;IA2BtB,IAAI,IAAI,UAAU,EAAE;IAMpB,cAAc,IAAI,0BAA0B,EAAE;CAO/C;AAGD,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -8,7 +8,9 @@ import { globTool } from "../tools/globTool.js";
8
8
  import { grepTool } from "../tools/grepTool.js";
9
9
  import { lsTool } from "../tools/lsTool.js";
10
10
  import { readTool } from "../tools/readTool.js";
11
- import { SkillManager } from "./skillManager.js";
11
+ import { todoWriteTool } from "../tools/todoWriteTool.js";
12
+ import { createTaskTool } from "../tools/taskTool.js";
13
+ import { createSkillTool } from "../tools/skillTool.js";
12
14
  /**
13
15
  * Tool Manager
14
16
  */
@@ -17,10 +19,37 @@ class ToolManager {
17
19
  this.tools = new Map();
18
20
  this.mcpManager = options.mcpManager;
19
21
  this.logger = options.logger;
20
- // Initialize built-in tools
21
- this.initializeBuiltInTools();
22
22
  }
23
- initializeBuiltInTools() {
23
+ /**
24
+ * Register a new tool
25
+ */
26
+ register(tool) {
27
+ this.tools.set(tool.name, tool);
28
+ }
29
+ /**
30
+ * Initialize built-in tools. Can be called with dependencies for tools that require them.
31
+ *
32
+ * This method can be called multiple times safely. When called without dependencies,
33
+ * it registers basic tools (Bash, Read, Write, TodoWrite, etc.). When called with
34
+ * dependencies, it also registers tools that require managers (Task, Skill).
35
+ *
36
+ * @param deps Optional dependencies for advanced tools
37
+ * @param deps.subagentManager SubagentManager instance for Task tool
38
+ * @param deps.skillManager SkillManager instance for Skill tool
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * // Initialize basic tools only
43
+ * toolManager.initializeBuiltInTools();
44
+ *
45
+ * // Initialize all tools including those requiring dependencies
46
+ * toolManager.initializeBuiltInTools({
47
+ * subagentManager: mySubagentManager,
48
+ * skillManager: mySkillManager
49
+ * });
50
+ * ```
51
+ */
52
+ initializeBuiltInTools(deps) {
24
53
  const builtInTools = [
25
54
  bashTool,
26
55
  bashOutputTool,
@@ -33,11 +62,20 @@ class ToolManager {
33
62
  grepTool,
34
63
  lsTool,
35
64
  readTool,
36
- new SkillManager({ logger: this.logger }).createTool(),
65
+ todoWriteTool,
37
66
  ];
38
67
  for (const tool of builtInTools) {
39
68
  this.tools.set(tool.name, tool);
40
69
  }
70
+ // Register tools that require dependencies
71
+ if (deps?.subagentManager) {
72
+ const taskTool = createTaskTool(deps.subagentManager);
73
+ this.tools.set(taskTool.name, taskTool);
74
+ }
75
+ if (deps?.skillManager) {
76
+ const skillTool = createSkillTool(deps.skillManager);
77
+ this.tools.set(skillTool.name, skillTool);
78
+ }
41
79
  }
42
80
  async execute(name, args, context) {
43
81
  // Check if it's an MCP tool first
@@ -1,6 +1,9 @@
1
1
  import { ChatCompletionMessageToolCall } from "openai/resources";
2
2
  import { ChatCompletionMessageParam, ChatCompletionFunctionTool } from "openai/resources.js";
3
+ import type { GatewayConfig, ModelConfig } from "../types.js";
3
4
  export interface CallAgentOptions {
5
+ gatewayConfig: GatewayConfig;
6
+ modelConfig: ModelConfig;
4
7
  messages: ChatCompletionMessageParam[];
5
8
  sessionId?: string;
6
9
  abortSignal?: AbortSignal;
@@ -21,6 +24,8 @@ export interface CallAgentResult {
21
24
  }
22
25
  export declare function callAgent(options: CallAgentOptions): Promise<CallAgentResult>;
23
26
  export interface CompressMessagesOptions {
27
+ gatewayConfig: GatewayConfig;
28
+ modelConfig: ModelConfig;
24
29
  messages: ChatCompletionMessageParam[];
25
30
  abortSignal?: AbortSignal;
26
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"aiService.d.ts","sourceRoot":"","sources":["../../src/services/aiService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAEL,0BAA0B,EAC1B,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAuC7B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,0BAA0B,EAAE,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,0BAA0B,EAAE,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,6BAA6B,EAAE,CAAC;IAC7C,KAAK,CAAC,EAAE;QACN,aAAa,EAAE,MAAM,CAAC;QACtB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CA2F1B;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,0BAA0B,EAAE,CAAC;IACvC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,MAAM,CAAC,CAmFjB"}
1
+ {"version":3,"file":"aiService.d.ts","sourceRoot":"","sources":["../../src/services/aiService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAEL,0BAA0B,EAC1B,0BAA0B,EAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA4D9D,MAAM,WAAW,gBAAgB;IAE/B,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,EAAE,WAAW,CAAC;IAGzB,QAAQ,EAAE,0BAA0B,EAAE,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,0BAA0B,EAAE,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,6BAA6B,EAAE,CAAC;IAC7C,KAAK,CAAC,EAAE;QACN,aAAa,EAAE,MAAM,CAAC;QACtB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CA6G1B;AAED,MAAM,WAAW,uBAAuB;IAEtC,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,EAAE,WAAW,CAAC;IAGzB,QAAQ,EAAE,0BAA0B,EAAE,CAAC;IACvC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,MAAM,CAAC,CAyFjB"}
@@ -1,5 +1,29 @@
1
1
  import OpenAI from "openai";
2
- import { FAST_MODEL_ID, AGENT_MODEL_ID } from "../utils/constants.js";
2
+ import * as os from "os";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+ /**
6
+ * Check if a directory is a git repository
7
+ * @param dirPath Directory path to check
8
+ * @returns "Yes" if it's a git repo, "No" otherwise
9
+ */
10
+ function isGitRepository(dirPath) {
11
+ try {
12
+ // Check if .git directory exists in current directory or any parent directory
13
+ let currentPath = path.resolve(dirPath);
14
+ while (currentPath !== path.dirname(currentPath)) {
15
+ const gitPath = path.join(currentPath, ".git");
16
+ if (fs.existsSync(gitPath)) {
17
+ return "Yes";
18
+ }
19
+ currentPath = path.dirname(currentPath);
20
+ }
21
+ return "No";
22
+ }
23
+ catch {
24
+ return "No";
25
+ }
26
+ }
3
27
  /**
4
28
  * Get specific configuration parameters based on model name
5
29
  * @param modelName Model name
@@ -19,31 +43,32 @@ function getModelConfig(modelName, baseConfig = {}) {
19
43
  }
20
44
  return config;
21
45
  }
22
- // Initialize OpenAI client with environment variables
23
- const openai = new OpenAI({
24
- apiKey: process.env.AIGW_TOKEN,
25
- baseURL: process.env.AIGW_URL,
26
- });
27
46
  export async function callAgent(options) {
28
- const { messages, abortSignal, memory, workdir, tools, model, systemPrompt } = options;
47
+ const { gatewayConfig, modelConfig, messages, abortSignal, memory, workdir, tools, model, systemPrompt, } = options;
29
48
  try {
49
+ // Create OpenAI client with injected configuration
50
+ const openai = new OpenAI({
51
+ apiKey: gatewayConfig.apiKey,
52
+ baseURL: gatewayConfig.baseURL,
53
+ });
30
54
  // Build system prompt content
31
- let systemContent;
32
- if (systemPrompt) {
33
- // Use custom system prompt if provided
34
- systemContent = systemPrompt;
35
- }
36
- else {
37
- // Use default system prompt
38
- systemContent = `You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
55
+ let systemContent = systemPrompt ||
56
+ `You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.`;
57
+ // Always add environment information
58
+ systemContent += `
39
59
 
40
- ## Current Working Directory
41
- ${workdir}
60
+ Here is useful information about the environment you are running in:
61
+ <env>
62
+ Working directory: ${workdir}
63
+ Is directory a git repo: ${isGitRepository(workdir)}
64
+ Platform: ${os.platform()}
65
+ OS Version: ${os.type()} ${os.release()}
66
+ Today's date: ${new Date().toISOString().split("T")[0]}
67
+ </env>
42
68
  `;
43
- // If there is memory content, add it to the system prompt
44
- if (memory && memory.trim()) {
45
- systemContent += `\n\n## Memory Context\n\nThe following is important context and memory from previous interactions:\n\n${memory}`;
46
- }
69
+ // If there is memory content, add it to the system prompt
70
+ if (memory && memory.trim()) {
71
+ systemContent += `\n## Memory Context\n\nThe following is important context and memory from previous interactions:\n\n${memory}`;
47
72
  }
48
73
  // Add system prompt
49
74
  const systemMessage = {
@@ -52,14 +77,14 @@ ${workdir}
52
77
  };
53
78
  // ChatCompletionMessageParam[] is already in OpenAI format, add system prompt to the beginning
54
79
  const openaiMessages = [systemMessage, ...messages];
55
- // Get model configuration
56
- const modelConfig = getModelConfig(model || AGENT_MODEL_ID, {
80
+ // Get model configuration - use injected modelConfig with optional override
81
+ const openaiModelConfig = getModelConfig(model || modelConfig.agentModel, {
57
82
  temperature: 0,
58
83
  max_completion_tokens: 32768,
59
84
  });
60
85
  // Prepare API call parameters
61
86
  const createParams = {
62
- ...modelConfig,
87
+ ...openaiModelConfig,
63
88
  messages: openaiMessages,
64
89
  };
65
90
  // Only add tools if they exist
@@ -102,15 +127,20 @@ ${workdir}
102
127
  }
103
128
  }
104
129
  export async function compressMessages(options) {
105
- const { messages, abortSignal } = options;
106
- // Get model configuration
107
- const modelConfig = getModelConfig(FAST_MODEL_ID, {
130
+ const { gatewayConfig, modelConfig, messages, abortSignal } = options;
131
+ // Create OpenAI client with injected configuration
132
+ const openai = new OpenAI({
133
+ apiKey: gatewayConfig.apiKey,
134
+ baseURL: gatewayConfig.baseURL,
135
+ });
136
+ // Get model configuration - use injected fast model
137
+ const openaiModelConfig = getModelConfig(modelConfig.fastModel, {
108
138
  temperature: 0.1,
109
139
  max_tokens: 1500,
110
140
  });
111
141
  try {
112
142
  const response = await openai.chat.completions.create({
113
- ...modelConfig,
143
+ ...openaiModelConfig,
114
144
  messages: [
115
145
  {
116
146
  role: "system",
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/services/session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAkBD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG5D;AAcD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,MAAM,EACf,iBAAiB,GAAE,MAAU,EAC7B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CA+Bf;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAmB7B;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAa7B;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,kBAAkB,UAAQ,GACzB,OAAO,CAAC,eAAe,EAAE,CAAC,CA2C5B;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYvE;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B7E;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASvE"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/services/session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAkBD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG5D;AAcD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,MAAM,EACf,iBAAiB,GAAE,MAAU,EAC7B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAmB7B;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAa7B;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,kBAAkB,UAAQ,GACzB,OAAO,CAAC,eAAe,EAAE,CAAC,CA2C5B;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYvE;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B7E;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASvE"}
@@ -42,6 +42,10 @@ export async function saveSession(sessionId, messages, workdir, latestTotalToken
42
42
  if (process.env.NODE_ENV === "test") {
43
43
  return;
44
44
  }
45
+ // Do not save if there are no messages
46
+ if (messages.length === 0) {
47
+ return;
48
+ }
45
49
  await ensureSessionDir();
46
50
  // Filter out diff blocks before saving
47
51
  const filteredMessages = filterDiffBlocks(messages);
@@ -1 +1 @@
1
- {"version":3,"file":"grepTool.d.ts","sourceRoot":"","sources":["../../src/tools/grepTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAMtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UA0QtB,CAAC"}
1
+ {"version":3,"file":"grepTool.d.ts","sourceRoot":"","sources":["../../src/tools/grepTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAMtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UA6QtB,CAAC"}