@kalenkevich/agent_007 0.0.1

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 (247) hide show
  1. package/dist/agent/agent.d.ts +17 -0
  2. package/dist/agent/agent.js +6 -0
  3. package/dist/agent/agent.js.map +1 -0
  4. package/dist/agent/agent_event.d.ts +108 -0
  5. package/dist/agent/agent_event.js +56 -0
  6. package/dist/agent/agent_event.js.map +1 -0
  7. package/dist/agent/agent_event_utils.d.ts +5 -0
  8. package/dist/agent/agent_event_utils.js +66 -0
  9. package/dist/agent/agent_event_utils.js.map +1 -0
  10. package/dist/agent/cli_agent/cli_agent.d.ts +41 -0
  11. package/dist/agent/cli_agent/cli_agent.js +324 -0
  12. package/dist/agent/cli_agent/cli_agent.js.map +1 -0
  13. package/dist/agent/cli_agent/system_prompt.d.ts +1 -0
  14. package/dist/agent/cli_agent/system_prompt.js +58 -0
  15. package/dist/agent/cli_agent/system_prompt.js.map +1 -0
  16. package/dist/agent/cli_agent.d.ts +34 -0
  17. package/dist/agent/cli_agent.js +91 -0
  18. package/dist/agent/cli_agent.js.map +1 -0
  19. package/dist/agent/planner_agent/planner_agent.d.ts +28 -0
  20. package/dist/agent/planner_agent/planner_agent.js +102 -0
  21. package/dist/agent/planner_agent/planner_agent.js.map +1 -0
  22. package/dist/agent/request_processor/basic_request_processor.d.ts +17 -0
  23. package/dist/agent/request_processor/basic_request_processor.js +28 -0
  24. package/dist/agent/request_processor/basic_request_processor.js.map +1 -0
  25. package/dist/agent/request_processor/compaction_processor.d.ts +17 -0
  26. package/dist/agent/request_processor/compaction_processor.js +118 -0
  27. package/dist/agent/request_processor/compaction_processor.js.map +1 -0
  28. package/dist/agent/request_processor/request_processor.d.ts +11 -0
  29. package/dist/agent/request_processor/request_processor.js +2 -0
  30. package/dist/agent/request_processor/request_processor.js.map +1 -0
  31. package/dist/cli/init_project_command_handler.d.ts +3 -0
  32. package/dist/cli/init_project_command_handler.js +58 -0
  33. package/dist/cli/init_project_command_handler.js.map +1 -0
  34. package/dist/cli/loader.d.ts +6 -0
  35. package/dist/cli/loader.js +27 -0
  36. package/dist/cli/loader.js.map +1 -0
  37. package/dist/cli/prompt_utils.d.ts +11 -0
  38. package/dist/cli/prompt_utils.js +18 -0
  39. package/dist/cli/prompt_utils.js.map +1 -0
  40. package/dist/cli/run_command.d.ts +6 -0
  41. package/dist/cli/run_command.js +72 -0
  42. package/dist/cli/run_command.js.map +1 -0
  43. package/dist/cli/run_interactive_command.d.ts +6 -0
  44. package/dist/cli/run_interactive_command.js +282 -0
  45. package/dist/cli/run_interactive_command.js.map +1 -0
  46. package/dist/cli/run_noninteractive_command.d.ts +6 -0
  47. package/dist/cli/run_noninteractive_command.js +60 -0
  48. package/dist/cli/run_noninteractive_command.js.map +1 -0
  49. package/dist/cli_entrypoint.d.ts +2 -0
  50. package/dist/cli_entrypoint.js +110 -0
  51. package/dist/cli_entrypoint.js.map +1 -0
  52. package/dist/command/commnad_handler.d.ts +3 -0
  53. package/dist/command/commnad_handler.js +2 -0
  54. package/dist/command/commnad_handler.js.map +1 -0
  55. package/dist/command/init_project_command_handler.d.ts +4 -0
  56. package/dist/command/init_project_command_handler.js +58 -0
  57. package/dist/command/init_project_command_handler.js.map +1 -0
  58. package/dist/config/app_dir.d.ts +1 -0
  59. package/dist/config/app_dir.js +4 -0
  60. package/dist/config/app_dir.js.map +1 -0
  61. package/dist/config/config.d.ts +21 -0
  62. package/dist/config/config.js +2 -0
  63. package/dist/config/config.js.map +1 -0
  64. package/dist/config/config_loader.d.ts +2 -0
  65. package/dist/config/config_loader.js +47 -0
  66. package/dist/config/config_loader.js.map +1 -0
  67. package/dist/config/config_store.d.ts +10 -0
  68. package/dist/config/config_store.js +44 -0
  69. package/dist/config/config_store.js.map +1 -0
  70. package/dist/content.d.ts +51 -0
  71. package/dist/content.js +16 -0
  72. package/dist/content.js.map +1 -0
  73. package/dist/core/functions.d.ts +1 -0
  74. package/dist/core/functions.js +6 -0
  75. package/dist/core/functions.js.map +1 -0
  76. package/dist/core/loop.d.ts +20 -0
  77. package/dist/core/loop.js +121 -0
  78. package/dist/core/loop.js.map +1 -0
  79. package/dist/core/project_service.d.ts +11 -0
  80. package/dist/core/project_service.js +26 -0
  81. package/dist/core/project_service.js.map +1 -0
  82. package/dist/core/run.d.ts +6 -0
  83. package/dist/core/run.js +25 -0
  84. package/dist/core/run.js.map +1 -0
  85. package/dist/index.d.ts +1 -0
  86. package/dist/index.js +2 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/logger.d.ts +27 -0
  89. package/dist/logger.js +98 -0
  90. package/dist/logger.js.map +1 -0
  91. package/dist/model/adaptive_model.d.ts +16 -0
  92. package/dist/model/adaptive_model.js +57 -0
  93. package/dist/model/adaptive_model.js.map +1 -0
  94. package/dist/model/google/gemini_model.d.ts +15 -0
  95. package/dist/model/google/gemini_model.js +131 -0
  96. package/dist/model/google/gemini_model.js.map +1 -0
  97. package/dist/model/google/gemini_response_utils.d.ts +3 -0
  98. package/dist/model/google/gemini_response_utils.js +36 -0
  99. package/dist/model/google/gemini_response_utils.js.map +1 -0
  100. package/dist/model/google/gemini_streaming_utils.d.ts +28 -0
  101. package/dist/model/google/gemini_streaming_utils.js +235 -0
  102. package/dist/model/google/gemini_streaming_utils.js.map +1 -0
  103. package/dist/model/google/gen_ai_convert_utils.d.ts +6 -0
  104. package/dist/model/google/gen_ai_convert_utils.js +117 -0
  105. package/dist/model/google/gen_ai_convert_utils.js.map +1 -0
  106. package/dist/model/model.d.ts +11 -0
  107. package/dist/model/model.js +2 -0
  108. package/dist/model/model.js.map +1 -0
  109. package/dist/model/registry.d.ts +19 -0
  110. package/dist/model/registry.js +47 -0
  111. package/dist/model/registry.js.map +1 -0
  112. package/dist/model/request.d.ts +13 -0
  113. package/dist/model/request.js +2 -0
  114. package/dist/model/request.js.map +1 -0
  115. package/dist/model/request_builder_utils.d.ts +19 -0
  116. package/dist/model/request_builder_utils.js +43 -0
  117. package/dist/model/request_builder_utils.js.map +1 -0
  118. package/dist/model/response.d.ts +60 -0
  119. package/dist/model/response.js +2 -0
  120. package/dist/model/response.js.map +1 -0
  121. package/dist/model/util_llm.d.ts +10 -0
  122. package/dist/model/util_llm.js +149 -0
  123. package/dist/model/util_llm.js.map +1 -0
  124. package/dist/session/session.d.ts +14 -0
  125. package/dist/session/session.js +2 -0
  126. package/dist/session/session.js.map +1 -0
  127. package/dist/session/session_file_service.d.ts +23 -0
  128. package/dist/session/session_file_service.js +147 -0
  129. package/dist/session/session_file_service.js.map +1 -0
  130. package/dist/skills/skill.d.ts +23 -0
  131. package/dist/skills/skill.js +12 -0
  132. package/dist/skills/skill.js.map +1 -0
  133. package/dist/tools/build_in/find.d.ts +3 -0
  134. package/dist/tools/build_in/find.js +71 -0
  135. package/dist/tools/build_in/find.js.map +1 -0
  136. package/dist/tools/build_in/grep.d.ts +3 -0
  137. package/dist/tools/build_in/grep.js +97 -0
  138. package/dist/tools/build_in/grep.js.map +1 -0
  139. package/dist/tools/build_in/index.d.ts +1 -0
  140. package/dist/tools/build_in/index.js +13 -0
  141. package/dist/tools/build_in/index.js.map +1 -0
  142. package/dist/tools/build_in/list_dir.d.ts +3 -0
  143. package/dist/tools/build_in/list_dir.js +46 -0
  144. package/dist/tools/build_in/list_dir.js.map +1 -0
  145. package/dist/tools/build_in/view_file.d.ts +3 -0
  146. package/dist/tools/build_in/view_file.js +44 -0
  147. package/dist/tools/build_in/view_file.js.map +1 -0
  148. package/dist/tools/build_in/write_file.d.ts +3 -0
  149. package/dist/tools/build_in/write_file.js +50 -0
  150. package/dist/tools/build_in/write_file.js.map +1 -0
  151. package/dist/tools/functional_tool.d.ts +18 -0
  152. package/dist/tools/functional_tool.js +20 -0
  153. package/dist/tools/functional_tool.js.map +1 -0
  154. package/dist/tools/schema.d.ts +86 -0
  155. package/dist/tools/schema.js +37 -0
  156. package/dist/tools/schema.js.map +1 -0
  157. package/dist/tools/tool.d.ts +30 -0
  158. package/dist/tools/tool.js +9 -0
  159. package/dist/tools/tool.js.map +1 -0
  160. package/dist/tools/tool_call_policy.d.ts +4 -0
  161. package/dist/tools/tool_call_policy.js +4 -0
  162. package/dist/tools/tool_call_policy.js.map +1 -0
  163. package/dist/tools/tool_policy.d.ts +4 -0
  164. package/dist/tools/tool_policy.js +4 -0
  165. package/dist/tools/tool_policy.js.map +1 -0
  166. package/dist/ui/ui.d.ts +1 -0
  167. package/dist/ui/ui.js +2 -0
  168. package/dist/ui/ui.js.map +1 -0
  169. package/dist/user_input.d.ts +20 -0
  170. package/dist/user_input.js +21 -0
  171. package/dist/user_input.js.map +1 -0
  172. package/package.json +44 -0
  173. package/src/agent/agent.ts +18 -0
  174. package/src/agent/agent_event.ts +171 -0
  175. package/src/agent/agent_event_utils.ts +87 -0
  176. package/src/agent/cli_agent/cli_agent.ts +418 -0
  177. package/src/agent/cli_agent/system_prompt.ts +57 -0
  178. package/src/agent/planner_agent/planner_agent.ts +136 -0
  179. package/src/agent/request_processor/basic_request_processor.ts +46 -0
  180. package/src/agent/request_processor/compaction_processor.ts +164 -0
  181. package/src/agent/request_processor/request_processor.ts +13 -0
  182. package/src/cli/loader.ts +27 -0
  183. package/src/cli/prompt_utils.ts +19 -0
  184. package/src/cli/run_interactive_command.ts +337 -0
  185. package/src/cli/run_noninteractive_command.ts +74 -0
  186. package/src/cli_entrypoint.ts +128 -0
  187. package/src/command/commnad_handler.ts +3 -0
  188. package/src/command/init_project_command_handler.ts +66 -0
  189. package/src/config/app_dir.ts +4 -0
  190. package/src/config/config.ts +24 -0
  191. package/src/config/config_loader.ts +57 -0
  192. package/src/config/config_store.ts +50 -0
  193. package/src/content.ts +87 -0
  194. package/src/core/functions.ts +7 -0
  195. package/src/core/loop.ts +165 -0
  196. package/src/core/project_service.ts +38 -0
  197. package/src/core/run.ts +36 -0
  198. package/src/index.ts +1 -0
  199. package/src/logger.ts +128 -0
  200. package/src/model/adaptive_model.ts +77 -0
  201. package/src/model/google/gemini_model.ts +194 -0
  202. package/src/model/google/gemini_response_utils.ts +46 -0
  203. package/src/model/google/gemini_streaming_utils.ts +294 -0
  204. package/src/model/google/gen_ai_convert_utils.ts +149 -0
  205. package/src/model/model.ts +18 -0
  206. package/src/model/registry.ts +61 -0
  207. package/src/model/request.ts +15 -0
  208. package/src/model/request_builder_utils.ts +79 -0
  209. package/src/model/response.ts +66 -0
  210. package/src/model/util_llm.ts +167 -0
  211. package/src/session/session.ts +16 -0
  212. package/src/session/session_file_service.ts +207 -0
  213. package/src/skills/skill.ts +38 -0
  214. package/src/tools/build_in/find.ts +80 -0
  215. package/src/tools/build_in/grep.ts +101 -0
  216. package/src/tools/build_in/index.ts +13 -0
  217. package/src/tools/build_in/list_dir.ts +50 -0
  218. package/src/tools/build_in/view_file.ts +47 -0
  219. package/src/tools/build_in/write_file.ts +53 -0
  220. package/src/tools/functional_tool.ts +59 -0
  221. package/src/tools/schema.ts +87 -0
  222. package/src/tools/tool.ts +68 -0
  223. package/src/tools/tool_call_policy.ts +7 -0
  224. package/src/ui/ui.ts +0 -0
  225. package/src/user_input.ts +51 -0
  226. package/tests/integration/util_llm_test.ts +42 -0
  227. package/tests/unit/adaptive_model_test.ts +122 -0
  228. package/tests/unit/agent/request_processor/compaction_processor_test.ts +121 -0
  229. package/tests/unit/cli/prompt_utils_test.ts +47 -0
  230. package/tests/unit/cli_agent_test.ts +476 -0
  231. package/tests/unit/content_test.ts +56 -0
  232. package/tests/unit/logger_test.ts +109 -0
  233. package/tests/unit/loop_test.ts +141 -0
  234. package/tests/unit/model/gemini_model_test.ts +111 -0
  235. package/tests/unit/planner_agent_test.ts +52 -0
  236. package/tests/unit/project_service_test.ts +102 -0
  237. package/tests/unit/session_file_service_test.ts +160 -0
  238. package/tests/unit/tools/find_test.ts +40 -0
  239. package/tests/unit/tools/grep_test.ts +43 -0
  240. package/tests/unit/tools/list_dir_test.ts +32 -0
  241. package/tests/unit/tools/view_file_test.ts +32 -0
  242. package/tests/unit/tools/write_file_test.ts +44 -0
  243. package/tests/unit/user_input_test.ts +55 -0
  244. package/tests/unit/util_llm_test.ts +61 -0
  245. package/todo.md +29 -0
  246. package/tsconfig.json +33 -0
  247. package/vitest.config.ts +33 -0
@@ -0,0 +1,418 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import * as fs from "node:fs/promises";
3
+ import type { Agent } from "../agent.js";
4
+ import type { LlmModel } from "../../model/model.js";
5
+ import type { Skill } from "../../skills/skill.js";
6
+ import type { Tool } from "../../tools/tool.js";
7
+ import {
8
+ type AgentEvent,
9
+ AgentEventType,
10
+ AgentEndReason,
11
+ type ToolCallEvent,
12
+ isUserInputResponseEvent,
13
+ } from "../agent_event.js";
14
+ import type { Content } from "../../content.js";
15
+ import {
16
+ type UserInput,
17
+ isUserCommand,
18
+ toContentParts,
19
+ UserCommandType,
20
+ } from "../../user_input.js";
21
+ import type { ThinkingConfig } from "../../model/request.js";
22
+ import {
23
+ getContentFromAgentEvent,
24
+ llmResponseToAgentEvents,
25
+ } from "../agent_event_utils.js";
26
+ import { logger } from "../../logger.js";
27
+ import { CLI_AGENT_SYSTEM_PROMPT } from "./system_prompt.js";
28
+ import { BUILD_IN_TOOLS } from "../../tools/build_in/index.js";
29
+ import { PlannerAgent } from "../planner_agent/planner_agent.js";
30
+ import {
31
+ type ToolCallPolicy,
32
+ DEFAULT_POLICY,
33
+ } from "../../tools/tool_call_policy.js";
34
+ import type { CompactionConfig } from "../../config/config.js";
35
+ import { BasicRequestProcessor } from "../request_processor/basic_request_processor.js";
36
+ import { CompactionProcessor } from "../request_processor/compaction_processor.js";
37
+ import type { AgentState } from "../request_processor/request_processor.js";
38
+
39
+ export interface CliAgentOptions {
40
+ model: LlmModel;
41
+ history?: AgentEvent[];
42
+ skills?: Skill[];
43
+ thinkingConfig?: ThinkingConfig;
44
+ compactionConfig?: CompactionConfig;
45
+ toolPolicies?: Record<string, ToolCallPolicy>;
46
+ tools?: Tool[];
47
+ instructions?: string;
48
+ }
49
+
50
+ export class CliAgent implements Agent {
51
+ readonly id = "cli_agent";
52
+ readonly name = "Agent 007";
53
+ readonly description = "Agent 007";
54
+ readonly instructions: string;
55
+ readonly tools: Tool[];
56
+ readonly skills?: Skill[];
57
+
58
+ readonly model: LlmModel;
59
+ private streamId?: string;
60
+ private history: AgentEvent[] = [];
61
+ private historyContent: Content[] = [];
62
+ private thinkingConfig?: ThinkingConfig;
63
+ private toolPolicies: Record<string, ToolCallPolicy>;
64
+ private compactionConfig?: CompactionConfig;
65
+ private abortController?: AbortController;
66
+
67
+ constructor(options: CliAgentOptions) {
68
+ this.model = options.model;
69
+ this.thinkingConfig = options.thinkingConfig;
70
+ this.skills = options.skills;
71
+ this.history = options.history || [];
72
+ this.historyContent = this.history
73
+ .map((c) => getContentFromAgentEvent(c))
74
+ .filter(Boolean) as Content[];
75
+ this.toolPolicies = options.toolPolicies || {};
76
+ this.tools = options.tools || BUILD_IN_TOOLS;
77
+ this.compactionConfig = options.compactionConfig;
78
+ this.instructions = options.instructions || CLI_AGENT_SYSTEM_PROMPT;
79
+ }
80
+
81
+ async *run(userInput: UserInput): AsyncGenerator<AgentEvent, void, unknown> {
82
+ for await (const agentEvent of this.runInternal(userInput)) {
83
+ this.history.push(agentEvent);
84
+ const content = getContentFromAgentEvent(agentEvent);
85
+ if (content) {
86
+ this.historyContent.push(content);
87
+ }
88
+
89
+ yield agentEvent;
90
+ }
91
+ }
92
+
93
+ private async *runInternal(
94
+ userInput: UserInput,
95
+ ): AsyncGenerator<AgentEvent, void, unknown> {
96
+ if (isUserCommand(userInput)) {
97
+ if (userInput.command === UserCommandType.PLAN) {
98
+ const planner = new PlannerAgent({
99
+ model: this.model,
100
+ tools: this.tools,
101
+ skills: this.skills,
102
+ });
103
+ yield* planner.run(userInput.task);
104
+ }
105
+ return;
106
+ }
107
+
108
+ logger.debug("[CliAgent] runInternal started");
109
+
110
+ const lastEvent = this.history[this.history.length - 1];
111
+ let skipInitialEvents = false;
112
+
113
+ if (lastEvent && lastEvent.type === AgentEventType.USER_INPUT_REQUEST) {
114
+ logger.debug("[CliAgent] Resuming from USER_INPUT_REQUEST");
115
+ this.streamId = lastEvent.streamId;
116
+ skipInitialEvents = true;
117
+
118
+ const requestId = lastEvent.requestId;
119
+ if ((lastEvent.requestSchema as any)?.type === "plan_approval") {
120
+ const isAccepted =
121
+ isUserInputResponseEvent(userInput) && userInput.action === "accept";
122
+
123
+ if (isAccepted) {
124
+ const planFilePath = (lastEvent.requestSchema as any)
125
+ .planFilePath as string;
126
+ try {
127
+ const planContent = await fs.readFile(planFilePath, "utf-8");
128
+ yield this.createEvent(AgentEventType.MESSAGE, {
129
+ role: "user",
130
+ parts: [
131
+ {
132
+ type: "text",
133
+ text: `Plan approved. Please execute the following plan:\n\n${planContent}`,
134
+ },
135
+ ],
136
+ });
137
+ } catch (error: any) {
138
+ logger.error(`Failed to read plan file: ${error.message}`);
139
+ yield this.createEvent(AgentEventType.MESSAGE, {
140
+ role: "user",
141
+ parts: [
142
+ {
143
+ type: "text",
144
+ text: `Plan approved, but failed to read plan file: ${error.message}. Please proceed if you know the plan.`,
145
+ },
146
+ ],
147
+ });
148
+ }
149
+ } else {
150
+ yield this.createEvent(AgentEventType.MESSAGE, {
151
+ role: "user",
152
+ parts: [{ type: "text", text: "Plan declined." }],
153
+ });
154
+ }
155
+ } else {
156
+ const toolCall = this.history.find(
157
+ (e) =>
158
+ e.type === AgentEventType.TOOL_CALL && e.requestId === requestId,
159
+ ) as ToolCallEvent;
160
+
161
+ if (toolCall) {
162
+ const isAccepted =
163
+ isUserInputResponseEvent(userInput as any) &&
164
+ (userInput as any).action === "accept";
165
+
166
+ if (isAccepted) {
167
+ const tool = this.tools.find((t) => t.name === toolCall.name);
168
+ if (tool) {
169
+ try {
170
+ logger.debug(
171
+ `[CliAgent] Executing tool ${toolCall.name} after confirmation`,
172
+ );
173
+ const result = await tool.execute(toolCall.args);
174
+ yield this.createEvent(AgentEventType.TOOL_RESPONSE, {
175
+ role: "user",
176
+ requestId: toolCall.requestId,
177
+ name: toolCall.name,
178
+ result: result as Record<string, unknown> | string,
179
+ parts: [
180
+ {
181
+ type: "function_response",
182
+ id: toolCall.requestId,
183
+ name: toolCall.name,
184
+ response:
185
+ typeof result === "object"
186
+ ? (result as Record<string, unknown>)
187
+ : { result },
188
+ },
189
+ ],
190
+ });
191
+ } catch (error: any) {
192
+ logger.error(
193
+ `[CliAgent] Tool execution failed: ${error.message}`,
194
+ );
195
+ yield this.createEvent(AgentEventType.TOOL_RESPONSE, {
196
+ role: "user",
197
+ requestId: toolCall.requestId,
198
+ name: toolCall.name,
199
+ error: error.message,
200
+ result: {},
201
+ parts: [
202
+ {
203
+ type: "function_response",
204
+ id: toolCall.requestId,
205
+ name: toolCall.name,
206
+ response: { error: error.message },
207
+ },
208
+ ],
209
+ });
210
+ }
211
+ }
212
+ } else {
213
+ logger.debug(
214
+ `[CliAgent] Tool ${toolCall.name} execution declined by user`,
215
+ );
216
+ yield this.createEvent(AgentEventType.TOOL_RESPONSE, {
217
+ role: "user",
218
+ requestId: toolCall.requestId,
219
+ name: toolCall.name,
220
+ error: "User declined tool execution",
221
+ result: {},
222
+ parts: [
223
+ {
224
+ type: "function_response",
225
+ id: toolCall.requestId,
226
+ name: toolCall.name,
227
+ response: { error: "User declined tool execution" },
228
+ },
229
+ ],
230
+ });
231
+ }
232
+ } else {
233
+ if (isUserInputResponseEvent(userInput)) {
234
+ yield this.createEvent(userInput.type, userInput);
235
+ }
236
+ }
237
+ }
238
+ }
239
+
240
+ if (!skipInitialEvents) {
241
+ const userContent = toContentParts(userInput as any);
242
+ this.abortController = new AbortController();
243
+ this.streamId = randomUUID();
244
+
245
+ yield this.createEvent(AgentEventType.START);
246
+ yield this.createEvent(AgentEventType.MESSAGE, {
247
+ role: "user",
248
+ parts: userContent,
249
+ });
250
+ }
251
+
252
+ let continueTurn = true;
253
+
254
+ while (continueTurn) {
255
+ const basicProcessor = new BasicRequestProcessor({
256
+ agentName: this.name,
257
+ description: this.description,
258
+ instructions: this.instructions,
259
+ tools: this.tools,
260
+ skills: this.skills,
261
+ thinkingConfig: this.thinkingConfig,
262
+ });
263
+
264
+ const compactionProcessor = new CompactionProcessor({
265
+ model: this.model,
266
+ compactionConfig: this.compactionConfig,
267
+ requestBuilderOptions: {
268
+ agentName: this.name,
269
+ description: this.description,
270
+ instructions: this.instructions,
271
+ tools: this.tools,
272
+ skills: this.skills,
273
+ thinkingConfig: this.thinkingConfig,
274
+ },
275
+ streamId: this.streamId!,
276
+ });
277
+
278
+ let state: AgentState = {
279
+ historyContent: this.historyContent,
280
+ events: [],
281
+ };
282
+
283
+ state = await basicProcessor.process(state);
284
+ state = await compactionProcessor.process(state);
285
+
286
+ this.historyContent = state.historyContent;
287
+
288
+ for (const event of state.events) {
289
+ yield event;
290
+ }
291
+
292
+ const llmRequest = state.llmRequest;
293
+ if (!llmRequest) {
294
+ throw new Error("LlmRequest is missing after processors");
295
+ }
296
+
297
+ logger.debug("[CliAgent] calling model.run");
298
+
299
+ const toolCalls: ToolCallEvent[] = [];
300
+
301
+ for await (const modelResponse of this.model.run(llmRequest, {
302
+ stream: true,
303
+ abortSignal: this.abortController?.signal,
304
+ })) {
305
+ for (const agentEvent of llmResponseToAgentEvents(modelResponse)) {
306
+ logger.debug("[CliAgent] yielding event:", agentEvent.type);
307
+ yield this.createEvent(agentEvent.type!, agentEvent);
308
+
309
+ if (
310
+ agentEvent.type === AgentEventType.TOOL_CALL &&
311
+ !agentEvent.partial
312
+ ) {
313
+ toolCalls.push(agentEvent as ToolCallEvent);
314
+ }
315
+ }
316
+ }
317
+
318
+ if (toolCalls.length === 0) {
319
+ continueTurn = false;
320
+ break;
321
+ }
322
+
323
+ for (const toolCall of toolCalls) {
324
+ const tool = this.tools.find((t) => t.name === toolCall.name);
325
+ if (!tool) {
326
+ logger.error(`[CliAgent] Tool not found: ${toolCall.name}`);
327
+ yield this.createEvent(AgentEventType.TOOL_RESPONSE, {
328
+ role: "user",
329
+ requestId: toolCall.requestId,
330
+ name: toolCall.name,
331
+ error: `Tool ${toolCall.name} not found`,
332
+ result: {},
333
+ });
334
+ continue;
335
+ }
336
+
337
+ const policy = this.toolPolicies[toolCall.name] || DEFAULT_POLICY;
338
+ if (policy.confirmationRequired) {
339
+ logger.debug(
340
+ `[CliAgent] Tool ${toolCall.name} requires confirmation`,
341
+ );
342
+ yield this.createEvent(AgentEventType.USER_INPUT_REQUEST, {
343
+ role: "agent",
344
+ requestId: toolCall.requestId,
345
+ message: `Do you want to allow execution of tool ${toolCall.name}?`,
346
+ });
347
+ return;
348
+ }
349
+
350
+ try {
351
+ logger.debug(`[CliAgent] Executing tool ${toolCall.name}`);
352
+ const result = await tool.execute(toolCall.args);
353
+ yield this.createEvent(AgentEventType.TOOL_RESPONSE, {
354
+ role: "user",
355
+ requestId: toolCall.requestId,
356
+ name: toolCall.name,
357
+ result: result as Record<string, unknown> | string,
358
+ parts: [
359
+ {
360
+ type: "function_response",
361
+ id: toolCall.requestId,
362
+ name: toolCall.name,
363
+ response:
364
+ typeof result === "object"
365
+ ? (result as Record<string, unknown>)
366
+ : { result },
367
+ },
368
+ ],
369
+ });
370
+ } catch (error: any) {
371
+ logger.error(`[CliAgent] Tool execution failed: ${error.message}`);
372
+ yield this.createEvent(AgentEventType.TOOL_RESPONSE, {
373
+ role: "user",
374
+ requestId: toolCall.requestId,
375
+ name: toolCall.name,
376
+ error: error.message,
377
+ result: {},
378
+ parts: [
379
+ {
380
+ type: "function_response",
381
+ id: toolCall.requestId,
382
+ name: toolCall.name,
383
+ response: { error: error.message },
384
+ },
385
+ ],
386
+ });
387
+ }
388
+ }
389
+ }
390
+
391
+ yield this.createEvent(AgentEventType.END, {
392
+ role: "agent",
393
+ type: AgentEventType.END,
394
+ reason: AgentEndReason.COMPLETED,
395
+ });
396
+ }
397
+
398
+ private createEvent(
399
+ type: AgentEventType,
400
+ data: Partial<AgentEvent> = {},
401
+ ): AgentEvent {
402
+ return {
403
+ type,
404
+ id: randomUUID(),
405
+ streamId: this.streamId!,
406
+ timestamp: new Date().toISOString(),
407
+ ...data,
408
+ } as AgentEvent;
409
+ }
410
+
411
+ getHistory(): AgentEvent[] {
412
+ return [...this.history];
413
+ }
414
+
415
+ async abort(): Promise<void> {
416
+ this.abortController?.abort();
417
+ }
418
+ }
@@ -0,0 +1,57 @@
1
+ export const CLI_AGENT_SYSTEM_PROMPT = `
2
+ You are Agent 007, an advanced AI coding assistant specializing in software engineering tasks. Your primary goal is to help users safely and effectively develop, debug, and maintain codebases.
3
+
4
+ ## Core Mandates
5
+
6
+ ### Security & System Integrity
7
+ - **Credential Protection:** Never log, print, or commit secrets, API keys, or sensitive credentials. Rigorously protect \`.env\` files, \`.git\`, and system configuration folders.
8
+ - **Source Control:** Do not stage or commit changes unless specifically requested by the user.
9
+
10
+ ### Context Efficiency
11
+ Be strategic in your use of the available tools to minimize unnecessary context usage while still providing the best answer that you can.
12
+ - **Minimize Turns:** Combine turns whenever possible by utilizing parallel searching and reading.
13
+ - **Search First:** Prefer using search tools (e.g., grep, glob) to identify points of interest instead of reading lots of files individually.
14
+ - **Conservative Limits:** Provide conservative limits and scopes to tools to reduce the impact on context, as long as it doesn't result in extra turns to recover missing data.
15
+
16
+ ### Conventions & Style
17
+ - **Workspace Precedence:** Rigorously adhere to existing workspace conventions, architectural patterns, and style (naming, formatting, typing, commenting).
18
+ - **Surgical Updates:** Analyze surrounding files, tests, and configuration to ensure your changes are seamless, idiomatic, and consistent with the local context.
19
+
20
+ ### Technical Integrity & Quality
21
+ - **No Hacks:** NEVER use hacks like disabling or suppressing warnings, bypassing the type system, or employing "hidden" logic unless explicitly instructed. Use explicit and idiomatic language features.
22
+ - **Library Verification:** NEVER assume a library/framework is available. Verify its established usage within the project (e.g., check \`package.json\`, \`Cargo.toml\`) before employing it.
23
+ - **Lifecycle Responsibility:** You are responsible for the entire lifecycle: implementation, testing, and validation.
24
+ - **Testing Mandate:** ALWAYS search for and update related tests after making a code change. You must add a new test case to the existing test file or create a new one to verify your changes.
25
+ - **Bug Reproduction:** For bug fixes, you must empirically reproduce the failure with a new test case or reproduction script before applying the fix.
26
+
27
+ ### Expertise & Intent Alignment
28
+ - **Directives vs Inquiries:** Distinguish between **Directives** (unambiguous requests for action) and **Inquiries** (requests for analysis, advice, or observations).
29
+ - **Default to Inquiry:** Assume all requests are Inquiries unless they contain an explicit instruction to perform a task.
30
+ - **Scope Limitation:** For Inquiries, your scope is strictly limited to research and analysis. Propose solutions but DO NOT modify files until a corresponding Directive is issued.
31
+ - **Autonomy:** For Directives, work autonomously. Only seek user intervention if you have exhausted all possible routes or if a proposed solution diverges significantly from the established architecture.
32
+
33
+ ## Development Lifecycle
34
+
35
+ Operate using a **Research -> Strategy -> Execution** lifecycle. For the Execution phase, resolve each sub-task through an iterative **Plan -> Act -> Validate** cycle.
36
+
37
+ 1. **Research:** Systematically map the codebase and validate assumptions. Use search tools extensively to understand file structures and conventions. Prioritize empirical reproduction of reported issues.
38
+ 2. **Strategy:** Formulate a grounded plan based on your research. Share a concise summary of your strategy with the user before proceeding to execution.
39
+ 3. **Execution:** For each sub-task:
40
+ - **Plan:** Define the specific implementation approach and the testing strategy to verify the change.
41
+ - **Act:** Apply targeted, surgical changes. Ensure changes are idiomatically complete and follow all workspace standards.
42
+ - **Validate:** Run tests and workspace standards to confirm the success of the specific change and ensure no regressions were introduced. Validation is the only path to finality.
43
+
44
+ ## Operational Guidelines
45
+
46
+ ### Tone and Style
47
+ - **Role:** A senior software engineer and collaborative peer programmer.
48
+ - **High-Signal Output:** Focus exclusively on **intent** and **technical rationale**. Avoid conversational filler, apologies, and mechanical tool-use narration.
49
+ - **Concise & Direct:** Adopt a professional, direct, and concise tone suitable for a CLI environment. Aim for minimal text output per response whenever practical.
50
+ - **Formatting:** Use GitHub-flavored Markdown.
51
+
52
+ ### Tool Usage
53
+ - **Parallelism:** Tools execute in parallel by default. Execute multiple independent tool calls in parallel when feasible (e.g., searching or reading different files).
54
+ - **Sequencing:** If a tool depends on the output of a previous tool in the same turn, you MUST ensure sequential execution (e.g., setting specific flags if the system supports it).
55
+ - **File Collisions:** Do NOT make multiple calls to edit tools for the SAME file in a single turn to prevent race conditions.
56
+ - **Explain Critical Commands:** Before executing commands that modify the file system or system state, provide a brief explanation of the command's purpose and potential impact.
57
+ `;
@@ -0,0 +1,136 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import type { Agent } from "../agent.js";
3
+ import type { LlmModel } from "../../model/model.js";
4
+ import type { Tool } from "../../tools/tool.js";
5
+ import type { Skill } from "../../skills/skill.js";
6
+ import { type AgentEvent, AgentEventType } from "../agent_event.js";
7
+ import { type UserInput } from "../../user_input.js";
8
+ import { buildLlmRequest } from "../../model/request_builder_utils.js";
9
+ import { llmResponseToAgentEvents } from "../agent_event_utils.js";
10
+ import * as fs from "node:fs/promises";
11
+ import * as os from "node:os";
12
+ import * as path from "node:path";
13
+
14
+ export interface PlannerAgentOptions {
15
+ model: LlmModel;
16
+ tools?: Tool[];
17
+ skills?: Skill[];
18
+ }
19
+
20
+ export class PlannerAgent implements Agent {
21
+ readonly id = "planner_agent";
22
+ readonly name = "Planner Agent";
23
+ readonly description = "Generates plans for tasks.";
24
+ readonly instructions =
25
+ "You are a planning assistant. Your job is to create a plan for the given task.";
26
+ readonly model: LlmModel;
27
+ readonly tools?: Tool[];
28
+ readonly skills?: Skill[];
29
+
30
+ private streamId?: string;
31
+ private history: AgentEvent[] = [];
32
+ private abortController?: AbortController;
33
+
34
+ constructor(options: PlannerAgentOptions) {
35
+ this.model = options.model;
36
+ this.tools = options.tools;
37
+ this.skills = options.skills;
38
+ }
39
+
40
+ async *run(userInput: UserInput): AsyncGenerator<AgentEvent, void, unknown> {
41
+ this.abortController = new AbortController();
42
+ this.streamId = randomUUID();
43
+
44
+ yield this.createEvent(AgentEventType.START);
45
+
46
+ const task =
47
+ typeof userInput === "string" ? userInput : JSON.stringify(userInput);
48
+
49
+ const planningPrompt = `Generate a plan for the following task: "${task}".
50
+ The plan should be in free-form markdown.
51
+ Respond ONLY with the plan.`;
52
+
53
+ const llmRequest = buildLlmRequest({
54
+ agentName: this.name,
55
+ content: {
56
+ role: "user",
57
+ parts: [{ type: "text", text: planningPrompt }],
58
+ },
59
+ historyContent: [],
60
+ tools: this.tools || [],
61
+ skills: this.skills,
62
+ description: this.description,
63
+ instructions: this.instructions,
64
+ });
65
+
66
+ let planContent = "";
67
+ for await (const modelResponse of this.model.run(llmRequest, {
68
+ stream: true,
69
+ abortSignal: this.abortController?.signal,
70
+ })) {
71
+ for (const agentEvent of llmResponseToAgentEvents(modelResponse)) {
72
+ yield this.createEvent(agentEvent.type!, agentEvent);
73
+ if (agentEvent.type === AgentEventType.MESSAGE && agentEvent.parts) {
74
+ for (const part of agentEvent.parts) {
75
+ if ("text" in part && part.text) {
76
+ planContent += part.text;
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+
83
+ const requestId = randomUUID();
84
+ const tempFilePath = path.join(os.tmpdir(), `plan_${requestId}.md`);
85
+
86
+ try {
87
+ await fs.writeFile(tempFilePath, planContent, "utf-8");
88
+ yield this.createEvent(AgentEventType.MESSAGE, {
89
+ role: "agent",
90
+ parts: [{ type: "text", text: `\nPlan written to ${tempFilePath}` }],
91
+ });
92
+ } catch (error: any) {
93
+ yield this.createEvent(AgentEventType.MESSAGE, {
94
+ role: "agent",
95
+ parts: [
96
+ {
97
+ type: "text",
98
+ text: `\nFailed to write plan to ${tempFilePath}: ${error.message}`,
99
+ },
100
+ ],
101
+ });
102
+ }
103
+
104
+ yield this.createEvent(AgentEventType.USER_INPUT_REQUEST, {
105
+ role: "agent",
106
+ requestId,
107
+ message: "Do you approve this plan?",
108
+ requestSchema: { type: "plan_approval", planFilePath: tempFilePath },
109
+ });
110
+
111
+ return;
112
+ }
113
+
114
+ private createEvent(
115
+ type: AgentEventType,
116
+ data: Partial<AgentEvent> = {},
117
+ ): AgentEvent {
118
+ const event = {
119
+ type,
120
+ id: randomUUID(),
121
+ streamId: this.streamId!,
122
+ timestamp: new Date().toISOString(),
123
+ ...data,
124
+ } as AgentEvent;
125
+ this.history.push(event);
126
+ return event;
127
+ }
128
+
129
+ getHistory(): AgentEvent[] {
130
+ return [...this.history];
131
+ }
132
+
133
+ async abort(): Promise<void> {
134
+ this.abortController?.abort();
135
+ }
136
+ }
@@ -0,0 +1,46 @@
1
+ import type {
2
+ RequestProcessor,
3
+ AgentState,
4
+ } from "./request_processor.js";
5
+ import { buildLlmRequest } from "../../model/request_builder_utils.js";
6
+ import type { Tool } from "../../tools/tool.js";
7
+ import type { Skill } from "../../skills/skill.js";
8
+ import type { ThinkingConfig } from "../../model/request.js";
9
+
10
+ export interface BasicRequestProcessorOptions {
11
+ agentName: string;
12
+ description: string;
13
+ instructions: string;
14
+ tools: Tool[];
15
+ skills?: Skill[];
16
+ thinkingConfig?: ThinkingConfig;
17
+ }
18
+
19
+ export class BasicRequestProcessor implements RequestProcessor {
20
+ constructor(private options: BasicRequestProcessorOptions) {}
21
+
22
+ async process(state: AgentState): Promise<AgentState> {
23
+ if (state.historyContent.length === 0) {
24
+ return state;
25
+ }
26
+
27
+ const lastContent = state.historyContent[state.historyContent.length - 1];
28
+ const historyForRequest = state.historyContent.slice(0, -1);
29
+
30
+ const llmRequest = buildLlmRequest({
31
+ agentName: this.options.agentName,
32
+ content: lastContent,
33
+ historyContent: historyForRequest,
34
+ tools: this.options.tools,
35
+ skills: this.options.skills,
36
+ description: this.options.description,
37
+ instructions: this.options.instructions,
38
+ thinkingConfig: this.options.thinkingConfig,
39
+ });
40
+
41
+ return {
42
+ ...state,
43
+ llmRequest,
44
+ };
45
+ }
46
+ }