grok-dev 1.0.0-rc1

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 (112) hide show
  1. package/.cursor/rules/development-workflow.mdc +66 -0
  2. package/.cursor/rules/project-overview.mdc +66 -0
  3. package/.cursor/rules/react-ink-components.mdc +45 -0
  4. package/.cursor/rules/tools-and-agent.mdc +62 -0
  5. package/.cursor/rules/typescript-conventions.mdc +54 -0
  6. package/.grok/settings.json +3 -0
  7. package/.husky/pre-commit +1 -0
  8. package/LICENSE +21 -0
  9. package/README.md +526 -0
  10. package/biome.json +51 -0
  11. package/dist/agent/agent.d.ts +62 -0
  12. package/dist/agent/agent.js +701 -0
  13. package/dist/agent/agent.js.map +1 -0
  14. package/dist/agent/delegations.d.ts +42 -0
  15. package/dist/agent/delegations.js +273 -0
  16. package/dist/agent/delegations.js.map +1 -0
  17. package/dist/grok/client.d.ts +12 -0
  18. package/dist/grok/client.js +37 -0
  19. package/dist/grok/client.js.map +1 -0
  20. package/dist/grok/models.d.ts +5 -0
  21. package/dist/grok/models.js +73 -0
  22. package/dist/grok/models.js.map +1 -0
  23. package/dist/grok/tools.d.ts +12 -0
  24. package/dist/grok/tools.js +230 -0
  25. package/dist/grok/tools.js.map +1 -0
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.js +192 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/storage/db.d.ts +18 -0
  30. package/dist/storage/db.js +71 -0
  31. package/dist/storage/db.js.map +1 -0
  32. package/dist/storage/index.d.ts +4 -0
  33. package/dist/storage/index.js +5 -0
  34. package/dist/storage/index.js.map +1 -0
  35. package/dist/storage/migrations.d.ts +2 -0
  36. package/dist/storage/migrations.js +92 -0
  37. package/dist/storage/migrations.js.map +1 -0
  38. package/dist/storage/sessions.d.ts +15 -0
  39. package/dist/storage/sessions.js +135 -0
  40. package/dist/storage/sessions.js.map +1 -0
  41. package/dist/storage/transcript.d.ts +6 -0
  42. package/dist/storage/transcript.js +261 -0
  43. package/dist/storage/transcript.js.map +1 -0
  44. package/dist/storage/usage.d.ts +9 -0
  45. package/dist/storage/usage.js +58 -0
  46. package/dist/storage/usage.js.map +1 -0
  47. package/dist/storage/workspaces.d.ts +9 -0
  48. package/dist/storage/workspaces.js +60 -0
  49. package/dist/storage/workspaces.js.map +1 -0
  50. package/dist/telegram/bridge.d.ts +39 -0
  51. package/dist/telegram/bridge.js +164 -0
  52. package/dist/telegram/bridge.js.map +1 -0
  53. package/dist/telegram/index.d.ts +3 -0
  54. package/dist/telegram/index.js +4 -0
  55. package/dist/telegram/index.js.map +1 -0
  56. package/dist/telegram/limits.d.ts +3 -0
  57. package/dist/telegram/limits.js +12 -0
  58. package/dist/telegram/limits.js.map +1 -0
  59. package/dist/telegram/pairing.d.ts +9 -0
  60. package/dist/telegram/pairing.js +30 -0
  61. package/dist/telegram/pairing.js.map +1 -0
  62. package/dist/telegram/preview-stream.d.ts +22 -0
  63. package/dist/telegram/preview-stream.js +181 -0
  64. package/dist/telegram/preview-stream.js.map +1 -0
  65. package/dist/telegram/turn-coordinator.d.ts +7 -0
  66. package/dist/telegram/turn-coordinator.js +14 -0
  67. package/dist/telegram/turn-coordinator.js.map +1 -0
  68. package/dist/telegram/typing-refresh.d.ts +3 -0
  69. package/dist/telegram/typing-refresh.js +12 -0
  70. package/dist/telegram/typing-refresh.js.map +1 -0
  71. package/dist/tools/bash.d.ts +27 -0
  72. package/dist/tools/bash.js +261 -0
  73. package/dist/tools/bash.js.map +1 -0
  74. package/dist/tools/file.d.ts +15 -0
  75. package/dist/tools/file.js +94 -0
  76. package/dist/tools/file.js.map +1 -0
  77. package/dist/types/index.d.ts +151 -0
  78. package/dist/types/index.js +6 -0
  79. package/dist/types/index.js.map +1 -0
  80. package/dist/ui/app.d.ts +15 -0
  81. package/dist/ui/app.js +1720 -0
  82. package/dist/ui/app.js.map +1 -0
  83. package/dist/ui/markdown.d.ts +5 -0
  84. package/dist/ui/markdown.js +38 -0
  85. package/dist/ui/markdown.js.map +1 -0
  86. package/dist/ui/plan.d.ts +24 -0
  87. package/dist/ui/plan.js +122 -0
  88. package/dist/ui/plan.js.map +1 -0
  89. package/dist/ui/terminal-selection-text.d.ts +23 -0
  90. package/dist/ui/terminal-selection-text.js +59 -0
  91. package/dist/ui/terminal-selection-text.js.map +1 -0
  92. package/dist/ui/theme.d.ts +53 -0
  93. package/dist/ui/theme.js +53 -0
  94. package/dist/ui/theme.js.map +1 -0
  95. package/dist/utils/git-root.d.ts +1 -0
  96. package/dist/utils/git-root.js +16 -0
  97. package/dist/utils/git-root.js.map +1 -0
  98. package/dist/utils/host-clipboard.d.ts +4 -0
  99. package/dist/utils/host-clipboard.js +32 -0
  100. package/dist/utils/host-clipboard.js.map +1 -0
  101. package/dist/utils/instructions.d.ts +1 -0
  102. package/dist/utils/instructions.js +73 -0
  103. package/dist/utils/instructions.js.map +1 -0
  104. package/dist/utils/settings.d.ts +33 -0
  105. package/dist/utils/settings.js +88 -0
  106. package/dist/utils/settings.js.map +1 -0
  107. package/dist/utils/skills.d.ts +17 -0
  108. package/dist/utils/skills.js +161 -0
  109. package/dist/utils/skills.js.map +1 -0
  110. package/package.json +67 -0
  111. package/skills-lock.json +10 -0
  112. package/tmp/large_class.py +633 -0
@@ -0,0 +1,701 @@
1
+ import { stepCountIs, streamText } from "ai";
2
+ import { createProvider, generateTitle as genTitle } from "../grok/client";
3
+ import { createTools } from "../grok/tools";
4
+ import { appendMessages, appendSystemMessage, buildChatEntries, getSessionTotalTokens, loadTranscript, recordUsageEvent, SessionStore, } from "../storage/index";
5
+ import { BashTool } from "../tools/bash";
6
+ import { loadCustomInstructions } from "../utils/instructions";
7
+ import { discoverSkills, formatSkillsForPrompt } from "../utils/skills";
8
+ import { DelegationManager } from "./delegations";
9
+ const MAX_TOOL_ROUNDS = 400;
10
+ const ENVIRONMENT = `ENVIRONMENT:
11
+ You are running inside a terminal (CLI). Your text output is rendered in a plain terminal — not a browser, not a rich text editor.
12
+ - Use plain text only. No markdown tables, no HTML, no images, no colored text.
13
+ - Use simple markers like dashes (-) or asterisks (*) for lists.
14
+ - Use indentation and blank lines for structure.
15
+ - Keep lines under 100 characters when possible.
16
+ - Use backticks for inline code and triple backticks for code blocks — these are rendered.
17
+ - Never use unicode box-drawing, fancy borders, or ASCII art in your responses.`;
18
+ const MODE_PROMPTS = {
19
+ agent: `You are Grok CLI in Agent mode — a powerful AI coding agent. You execute tasks directly using tools.
20
+
21
+ ${ENVIRONMENT}
22
+
23
+ TOOLS:
24
+ - read_file: Read file contents with start_line/end_line for iterative reading. Use for examining code.
25
+ - write_file: Create new files or overwrite existing ones with full content.
26
+ - edit_file: Replace a unique string in a file with new content. The old_string must be unique — include enough context lines.
27
+ - bash: Execute shell commands. Set background=true for long-running processes (dev servers, watchers, builds). Returns a process ID immediately.
28
+ - process_logs: View recent output from a background process by ID.
29
+ - process_stop: Stop a background process by ID.
30
+ - process_list: List all background processes with status and uptime.
31
+ - task: Delegate a focused foreground task to a sub-agent. Use general for multi-step execution and explore for fast read-only research.
32
+ - delegate: Launch a read-only background agent for longer research while you continue working.
33
+ - delegation_read: Retrieve a completed background delegation result by ID.
34
+ - delegation_list: List running and completed background delegations. Do not poll it repeatedly.
35
+ - search_web: Search the web for current information, documentation, APIs, tutorials, etc.
36
+ - search_x: Search X/Twitter for real-time posts, discussions, opinions, and trends.
37
+
38
+ WORKFLOW:
39
+ 1. Understand the request
40
+ 2. Decide whether a sub-agent should handle the first investigation pass
41
+ 3. Use read_file and bash to explore the codebase directly when the task is small or tightly scoped
42
+ 4. Use bash with background=true for dev servers, watchers, or any long-running process — then continue working
43
+ 5. Use delegate for read-only work that can run in parallel, then continue productive work
44
+ 6. Use edit_file for targeted changes, write_file for new files or full rewrites
45
+ 7. Verify changes by reading modified files
46
+ 8. Run tests or builds with bash to confirm correctness
47
+ 9. Use search_web or search_x when you need up-to-date information
48
+
49
+ DEFAULT DELEGATION POLICY:
50
+ - Prefer the task tool by default for code review, code quality analysis, architecture research, root-cause investigation, bug triage, or any request that likely needs reading multiple files before acting.
51
+ - Prefer delegate for longer-running read-only exploration when you can keep making progress without blocking.
52
+ - Use the explore sub-agent for read-only investigation, reviews, research, and "how does this work?" tasks.
53
+ - Use the general sub-agent for delegated work that may need editing files, running commands, or producing a concrete implementation.
54
+ - Never use delegate for tasks that should edit files or make shell changes.
55
+ - When a background delegation is running, do not wait idly and do not spam delegation_list(). Continue useful work.
56
+ - Do not wait for the user to explicitly ask for a sub-agent when delegation would clearly help.
57
+ - Skip delegation only when the task is trivial, single-file, or you already have the exact answer.
58
+
59
+ EXAMPLES:
60
+ - "review this change" -> delegate to explore first
61
+ - "research how auth works" -> delegate to explore first
62
+ - "investigate why this test fails" -> delegate to explore first, then continue with findings
63
+ - "refactor this module" -> delegate a focused part to general when helpful
64
+
65
+ IMPORTANT:
66
+ - Prefer edit_file for surgical changes to existing files — it shows a clean diff.
67
+ - Use write_file only for new files or when most of the file is changing.
68
+ - Use read_file instead of cat/head/tail for reading files.
69
+
70
+ Be direct. Execute, don't just describe. Show results, not plans.`,
71
+ plan: `You are Grok CLI in Plan mode — you analyze and plan but DO NOT execute changes.
72
+
73
+ ${ENVIRONMENT}
74
+
75
+ TOOLS:
76
+ - read_file: Read file contents for analysis.
77
+ - bash: ONLY for searching (find, grep, ls) — NEVER modify files.
78
+ - generate_plan: ALWAYS use this to present your plan. Creates an interactive UI with steps and questions.
79
+
80
+ BEHAVIOR:
81
+ - Explore the codebase first using read_file and bash to understand the current state
82
+ - ALWAYS call generate_plan to present your plan — never just describe it in text
83
+ - Include clear, ordered steps with affected file paths
84
+ - Include questions when you need user input on approach, trade-offs, or preferences
85
+ - Use "select" questions for single-choice decisions, "multiselect" for picking multiple options, and "text" for free-form input
86
+ - Highlight potential risks, edge cases, and dependencies in the plan summary
87
+ - NEVER create, modify, or delete files — only read and analyze`,
88
+ ask: `You are Grok CLI in Ask mode — you answer questions clearly and thoroughly.
89
+
90
+ ${ENVIRONMENT}
91
+
92
+ TOOLS:
93
+ - read_file: Read file contents for context.
94
+ - bash: ONLY for searching (find, grep, ls) — NEVER modify.
95
+
96
+ BEHAVIOR:
97
+ - Answer the user's question directly and thoroughly
98
+ - Use tools to gather context when needed
99
+ - Provide code examples when helpful
100
+ - NEVER create, modify, or delete files
101
+ - Focus on explanation, not execution`,
102
+ };
103
+ function buildSystemPrompt(cwd, mode, planContext) {
104
+ const custom = loadCustomInstructions(cwd);
105
+ const customSection = custom
106
+ ? `\n\nCUSTOM INSTRUCTIONS:\n${custom}\n\nFollow the above alongside standard instructions.\n`
107
+ : "";
108
+ const skillsText = formatSkillsForPrompt(discoverSkills(cwd));
109
+ const skillsSection = skillsText ? `\n\n${skillsText}\n` : "";
110
+ const planSection = planContext
111
+ ? `\n\nAPPROVED PLAN:\nThe following plan has been approved by the user. Execute it now.\n${planContext}\n`
112
+ : "";
113
+ return `${MODE_PROMPTS[mode]}${customSection}${skillsSection}${planSection}
114
+
115
+ Current working directory: ${cwd}`;
116
+ }
117
+ function buildSubagentPrompt(request, cwd) {
118
+ const mode = request.agent === "explore" ? "ask" : "agent";
119
+ const role = request.agent === "explore"
120
+ ? "You are the Explore sub-agent. You are read-only and focus on fast codebase research."
121
+ : "You are the General sub-agent. You can investigate, edit files, and run commands to complete delegated work.";
122
+ const rules = request.agent === "explore"
123
+ ? [
124
+ "Do not create, modify, or delete files.",
125
+ "Prefer `read_file` and search commands over broad shell exploration.",
126
+ "Return concise findings for the parent agent.",
127
+ ]
128
+ : [
129
+ "Work only on the delegated task below.",
130
+ "Use tools directly instead of narrating your intent.",
131
+ "Return a concise summary for the parent agent with key outcomes and any open risks.",
132
+ ];
133
+ return [
134
+ role,
135
+ "",
136
+ "You are helping a parent agent. Do not address the end user directly.",
137
+ "Focus tightly on the delegated scope and summarize what matters back to the parent agent.",
138
+ "",
139
+ ...rules,
140
+ "",
141
+ `Delegated task: ${request.description}`,
142
+ "",
143
+ buildSystemPrompt(cwd, mode),
144
+ ].join("\n");
145
+ }
146
+ export class Agent {
147
+ provider = null;
148
+ apiKey = null;
149
+ baseURL = null;
150
+ bash;
151
+ delegations;
152
+ sessionStore = null;
153
+ workspace = null;
154
+ session = null;
155
+ messages = [];
156
+ recordedTokens = 0;
157
+ abortController = null;
158
+ maxToolRounds;
159
+ mode = "agent";
160
+ modelId;
161
+ maxTokens;
162
+ planContext = null;
163
+ subagentStatusListeners = new Set();
164
+ constructor(apiKey, baseURL, model, maxToolRounds, options = {}) {
165
+ this.baseURL = baseURL || null;
166
+ if (apiKey) {
167
+ this.setApiKey(apiKey, baseURL);
168
+ }
169
+ this.bash = new BashTool();
170
+ this.delegations = new DelegationManager(() => this.bash.getCwd());
171
+ this.modelId = model || "grok-4-1-fast";
172
+ this.maxToolRounds = maxToolRounds || MAX_TOOL_ROUNDS;
173
+ const envMax = Number(process.env.GROK_MAX_TOKENS);
174
+ this.maxTokens = Number.isFinite(envMax) && envMax > 0 ? envMax : 16_384;
175
+ if (options.persistSession !== false) {
176
+ this.sessionStore = new SessionStore(this.bash.getCwd());
177
+ this.workspace = this.sessionStore.getWorkspace();
178
+ this.session = this.sessionStore.openSession(options.session, this.modelId, this.mode, this.bash.getCwd());
179
+ this.mode = this.session.mode;
180
+ this.messages = loadTranscript(this.session.id);
181
+ this.recordedTokens = getSessionTotalTokens(this.session.id);
182
+ this.sessionStore.setModel(this.session.id, this.modelId);
183
+ }
184
+ }
185
+ getModel() {
186
+ return this.modelId;
187
+ }
188
+ setModel(model) {
189
+ this.modelId = model;
190
+ if (this.sessionStore && this.session) {
191
+ this.sessionStore.setModel(this.session.id, model);
192
+ this.session = this.sessionStore.getRequiredSession(this.session.id);
193
+ }
194
+ }
195
+ getMode() {
196
+ return this.mode;
197
+ }
198
+ setMode(mode) {
199
+ if (mode !== this.mode) {
200
+ this.mode = mode;
201
+ if (this.sessionStore && this.session) {
202
+ this.sessionStore.setMode(this.session.id, mode);
203
+ this.session = this.sessionStore.getRequiredSession(this.session.id);
204
+ }
205
+ }
206
+ }
207
+ setPlanContext(ctx) {
208
+ this.planContext = ctx;
209
+ }
210
+ hasApiKey() {
211
+ return !!this.apiKey;
212
+ }
213
+ setApiKey(apiKey, baseURL = this.baseURL ?? undefined) {
214
+ this.apiKey = apiKey;
215
+ this.baseURL = baseURL || null;
216
+ this.provider = createProvider(apiKey, baseURL);
217
+ }
218
+ getCwd() {
219
+ return this.bash.getCwd();
220
+ }
221
+ getContextStats(contextWindow, inFlightText = "") {
222
+ const system = buildSystemPrompt(this.bash.getCwd(), this.mode, this.planContext);
223
+ const estimatedTokens = estimateTokens(`${system}\n${JSON.stringify(this.messages)}\n${inFlightText}`);
224
+ const usedTokens = Math.min(contextWindow, Math.max(estimatedTokens, this.recordedTokens));
225
+ const remainingTokens = Math.max(0, contextWindow - usedTokens);
226
+ return {
227
+ contextWindow,
228
+ usedTokens,
229
+ remainingTokens,
230
+ ratioUsed: usedTokens / contextWindow,
231
+ ratioRemaining: remainingTokens / contextWindow,
232
+ };
233
+ }
234
+ async generateTitle(userMessage) {
235
+ const provider = this.provider;
236
+ if (!provider) {
237
+ return "New session";
238
+ }
239
+ const generated = await genTitle(provider, userMessage);
240
+ this.recordUsage(generated.usage, "title", "grok-3-mini-fast");
241
+ if (this.sessionStore && this.session && !this.session.title && generated.title) {
242
+ this.sessionStore.setTitle(this.session.id, generated.title);
243
+ this.session = this.sessionStore.getRequiredSession(this.session.id);
244
+ }
245
+ return generated.title;
246
+ }
247
+ abort() {
248
+ this.abortController?.abort();
249
+ this.emitSubagentStatus(null);
250
+ }
251
+ clearHistory() {
252
+ this.startNewSession();
253
+ }
254
+ startNewSession() {
255
+ if (!this.sessionStore) {
256
+ this.messages = [];
257
+ this.recordedTokens = 0;
258
+ return null;
259
+ }
260
+ this.sessionStore = new SessionStore(this.bash.getCwd());
261
+ this.workspace = this.sessionStore.getWorkspace();
262
+ this.session = this.sessionStore.createSession(this.modelId, this.mode, this.bash.getCwd());
263
+ this.messages = [];
264
+ this.recordedTokens = 0;
265
+ return this.getSessionSnapshot();
266
+ }
267
+ getSessionInfo() {
268
+ return this.session;
269
+ }
270
+ getSessionId() {
271
+ return this.session?.id || null;
272
+ }
273
+ getSessionTitle() {
274
+ return this.session?.title || null;
275
+ }
276
+ getChatEntries() {
277
+ if (!this.session)
278
+ return [];
279
+ return buildChatEntries(this.session.id);
280
+ }
281
+ getSessionSnapshot() {
282
+ if (!this.session || !this.workspace)
283
+ return null;
284
+ return {
285
+ workspace: this.workspace,
286
+ session: this.session,
287
+ messages: loadTranscript(this.session.id),
288
+ entries: buildChatEntries(this.session.id),
289
+ totalTokens: getSessionTotalTokens(this.session.id),
290
+ };
291
+ }
292
+ onSubagentStatus(listener) {
293
+ this.subagentStatusListeners.add(listener);
294
+ return () => {
295
+ this.subagentStatusListeners.delete(listener);
296
+ };
297
+ }
298
+ emitSubagentStatus(status) {
299
+ for (const listener of this.subagentStatusListeners) {
300
+ listener(status);
301
+ }
302
+ }
303
+ discardAbortedTurn(userMessage) {
304
+ const idx = this.messages.lastIndexOf(userMessage);
305
+ if (idx >= 0) {
306
+ this.messages.splice(idx, 1);
307
+ }
308
+ }
309
+ recordUsage(usage, source = "message", model = this.modelId) {
310
+ if (!usage)
311
+ return;
312
+ const total = usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
313
+ if (Number.isFinite(total) && total > 0) {
314
+ this.recordedTokens += total;
315
+ }
316
+ if (this.session) {
317
+ recordUsageEvent(this.session.id, source, model, usage);
318
+ }
319
+ }
320
+ async consumeBackgroundNotifications() {
321
+ try {
322
+ const notifications = await this.delegations.consumeNotifications();
323
+ for (const notification of notifications) {
324
+ this.messages.push({ role: "system", content: notification.message });
325
+ if (this.session) {
326
+ appendSystemMessage(this.session.id, notification.message);
327
+ }
328
+ }
329
+ return notifications.map((notification) => notification.message);
330
+ }
331
+ catch {
332
+ return [];
333
+ }
334
+ }
335
+ async runTaskRequest(request, onActivity, abortSignal) {
336
+ const provider = this.requireProvider();
337
+ const signal = abortSignal;
338
+ const childMode = request.agent === "explore" ? "ask" : "agent";
339
+ const childBash = new BashTool(this.bash.getCwd());
340
+ const childTools = createTools(childBash, provider, childMode);
341
+ const initialDetail = request.agent === "explore" ? "Scanning the codebase" : "Planning delegated work";
342
+ let assistantText = "";
343
+ let lastActivity = initialDetail;
344
+ onActivity?.(initialDetail);
345
+ try {
346
+ const result = streamText({
347
+ model: provider(request.agent === "explore" ? "grok-4-1-fast" : this.modelId),
348
+ system: buildSubagentPrompt(request, childBash.getCwd()),
349
+ messages: [{ role: "user", content: request.prompt }],
350
+ tools: childTools,
351
+ stopWhen: stepCountIs(Math.min(this.maxToolRounds, request.agent === "explore" ? 60 : 120)),
352
+ maxRetries: 0,
353
+ abortSignal: signal,
354
+ temperature: request.agent === "explore" ? 0.2 : 0.5,
355
+ maxOutputTokens: Math.min(this.maxTokens, 8_192),
356
+ onFinish: ({ totalUsage }) => {
357
+ this.recordUsage(totalUsage, "task");
358
+ },
359
+ });
360
+ for await (const part of result.fullStream) {
361
+ if (signal?.aborted) {
362
+ break;
363
+ }
364
+ if (part.type === "text-delta") {
365
+ assistantText += part.text;
366
+ continue;
367
+ }
368
+ if (part.type === "tool-call") {
369
+ lastActivity = formatSubagentActivity(part.toolName, part.input);
370
+ onActivity?.(lastActivity);
371
+ }
372
+ }
373
+ if (signal?.aborted) {
374
+ return { success: false, output: "[Cancelled]" };
375
+ }
376
+ await result.response;
377
+ const output = assistantText.trim() || `Task completed. Last action: ${lastActivity}`;
378
+ return {
379
+ success: true,
380
+ output,
381
+ task: {
382
+ agent: request.agent,
383
+ description: request.description,
384
+ summary: firstLine(output),
385
+ activity: lastActivity,
386
+ },
387
+ };
388
+ }
389
+ catch (err) {
390
+ if (signal?.aborted)
391
+ throw err;
392
+ const msg = err instanceof Error ? err.message : String(err);
393
+ const output = `Task failed: ${msg}`;
394
+ return {
395
+ success: false,
396
+ output,
397
+ task: {
398
+ agent: request.agent,
399
+ description: request.description,
400
+ summary: output,
401
+ activity: lastActivity,
402
+ },
403
+ };
404
+ }
405
+ }
406
+ async runTask(request, abortSignal) {
407
+ try {
408
+ return await this.runTaskRequest(request, (detail) => {
409
+ if (abortSignal?.aborted)
410
+ return;
411
+ this.emitSubagentStatus({
412
+ agent: request.agent,
413
+ description: request.description,
414
+ detail,
415
+ });
416
+ }, abortSignal);
417
+ }
418
+ finally {
419
+ this.emitSubagentStatus(null);
420
+ }
421
+ }
422
+ async runDelegation(request, abortSignal) {
423
+ try {
424
+ if (abortSignal?.aborted) {
425
+ return { success: false, output: "[Cancelled]" };
426
+ }
427
+ return await this.delegations.start(request, {
428
+ model: this.modelId,
429
+ maxToolRounds: this.maxToolRounds,
430
+ maxTokens: this.maxTokens,
431
+ });
432
+ }
433
+ catch (err) {
434
+ if (abortSignal?.aborted)
435
+ throw err;
436
+ const msg = err instanceof Error ? err.message : String(err);
437
+ return {
438
+ success: false,
439
+ output: `Delegation failed: ${msg}`,
440
+ };
441
+ }
442
+ }
443
+ async readDelegation(id) {
444
+ try {
445
+ return {
446
+ success: true,
447
+ output: await this.delegations.read(id),
448
+ };
449
+ }
450
+ catch (err) {
451
+ const msg = err instanceof Error ? err.message : String(err);
452
+ return {
453
+ success: false,
454
+ output: `Failed to read delegation: ${msg}`,
455
+ };
456
+ }
457
+ }
458
+ async listDelegations() {
459
+ try {
460
+ const delegations = await this.delegations.list();
461
+ if (delegations.length === 0) {
462
+ return {
463
+ success: true,
464
+ output: "No delegations found for this project.",
465
+ };
466
+ }
467
+ const lines = delegations.map((delegation) => {
468
+ const title = delegation.description || delegation.id;
469
+ return `- \`${delegation.id}\` [${delegation.status}] ${title}\n ${delegation.summary}`;
470
+ });
471
+ return {
472
+ success: true,
473
+ output: `## Delegations\n\n${lines.join("\n")}`,
474
+ };
475
+ }
476
+ catch (err) {
477
+ const msg = err instanceof Error ? err.message : String(err);
478
+ return {
479
+ success: false,
480
+ output: `Failed to list delegations: ${msg}`,
481
+ };
482
+ }
483
+ }
484
+ async *processMessage(userMessage) {
485
+ this.abortController = new AbortController();
486
+ const signal = this.abortController.signal;
487
+ this.emitSubagentStatus(null);
488
+ await this.consumeBackgroundNotifications();
489
+ const userModelMessage = { role: "user", content: userMessage };
490
+ this.messages.push(userModelMessage);
491
+ let assistantText = "";
492
+ let streamOk = false;
493
+ try {
494
+ const provider = this.requireProvider();
495
+ const tools = createTools(this.bash, provider, this.mode, {
496
+ runTask: (request, abortSignal) => this.runTask(request, combineAbortSignals(signal, abortSignal)),
497
+ runDelegation: (request, abortSignal) => this.runDelegation(request, combineAbortSignals(signal, abortSignal)),
498
+ readDelegation: (id) => this.readDelegation(id),
499
+ listDelegations: () => this.listDelegations(),
500
+ });
501
+ const system = buildSystemPrompt(this.bash.getCwd(), this.mode, this.planContext);
502
+ this.planContext = null;
503
+ const result = streamText({
504
+ model: provider(this.modelId),
505
+ system,
506
+ messages: this.messages,
507
+ tools,
508
+ stopWhen: stepCountIs(this.maxToolRounds),
509
+ maxRetries: 0,
510
+ abortSignal: signal,
511
+ temperature: 0.7,
512
+ maxOutputTokens: this.maxTokens,
513
+ onFinish: ({ totalUsage }) => {
514
+ this.recordUsage(totalUsage, "message");
515
+ },
516
+ });
517
+ for await (const part of result.fullStream) {
518
+ if (signal.aborted) {
519
+ yield { type: "content", content: "\n\n[Cancelled]" };
520
+ break;
521
+ }
522
+ switch (part.type) {
523
+ case "text-delta":
524
+ assistantText += part.text;
525
+ yield { type: "content", content: part.text };
526
+ break;
527
+ case "reasoning-delta":
528
+ yield { type: "reasoning", content: part.text };
529
+ break;
530
+ case "tool-call": {
531
+ const tc = toToolCall(part);
532
+ yield { type: "tool_calls", toolCalls: [tc] };
533
+ break;
534
+ }
535
+ case "tool-result": {
536
+ const tc = {
537
+ id: part.toolCallId,
538
+ type: "function",
539
+ function: { name: part.toolName, arguments: JSON.stringify(part.input ?? {}) },
540
+ };
541
+ const tr = toToolResult(part.output);
542
+ yield { type: "tool_result", toolCall: tc, toolResult: tr };
543
+ break;
544
+ }
545
+ case "error":
546
+ yield { type: "error", content: String(part.error) };
547
+ break;
548
+ case "abort":
549
+ yield { type: "content", content: "\n\n[Cancelled]" };
550
+ break;
551
+ }
552
+ }
553
+ if (signal.aborted) {
554
+ this.discardAbortedTurn(userModelMessage);
555
+ yield { type: "done" };
556
+ return;
557
+ }
558
+ try {
559
+ const response = await result.response;
560
+ if (!signal.aborted) {
561
+ this.messages.push(...response.messages);
562
+ if (this.sessionStore && this.session) {
563
+ appendMessages(this.session.id, [userModelMessage, ...response.messages]);
564
+ this.sessionStore.touchSession(this.session.id, this.bash.getCwd());
565
+ this.session = this.sessionStore.getRequiredSession(this.session.id);
566
+ }
567
+ streamOk = true;
568
+ }
569
+ }
570
+ catch {
571
+ // response promise can fail after stream errors — fall back to manual message
572
+ }
573
+ if (signal.aborted) {
574
+ this.discardAbortedTurn(userModelMessage);
575
+ yield { type: "done" };
576
+ return;
577
+ }
578
+ if (!streamOk && assistantText.trim()) {
579
+ const fallbackMessage = { role: "assistant", content: assistantText };
580
+ this.messages.push(fallbackMessage);
581
+ if (this.sessionStore && this.session) {
582
+ appendMessages(this.session.id, [userModelMessage, fallbackMessage]);
583
+ this.sessionStore.touchSession(this.session.id, this.bash.getCwd());
584
+ this.session = this.sessionStore.getRequiredSession(this.session.id);
585
+ }
586
+ }
587
+ yield { type: "done" };
588
+ }
589
+ catch (err) {
590
+ if (signal.aborted) {
591
+ this.discardAbortedTurn(userModelMessage);
592
+ yield { type: "content", content: "\n\n[Cancelled]" };
593
+ }
594
+ else {
595
+ const msg = err instanceof Error ? err.message : String(err);
596
+ yield { type: "error", content: `Error: ${msg}` };
597
+ }
598
+ if (!signal.aborted && assistantText.trim()) {
599
+ const fallbackMessage = { role: "assistant", content: assistantText };
600
+ this.messages.push(fallbackMessage);
601
+ if (this.sessionStore && this.session) {
602
+ appendMessages(this.session.id, [userModelMessage, fallbackMessage]);
603
+ this.sessionStore.touchSession(this.session.id, this.bash.getCwd());
604
+ this.session = this.sessionStore.getRequiredSession(this.session.id);
605
+ }
606
+ }
607
+ yield { type: "done" };
608
+ }
609
+ finally {
610
+ if (this.abortController?.signal === signal) {
611
+ this.abortController = null;
612
+ }
613
+ }
614
+ }
615
+ requireProvider() {
616
+ if (!this.provider) {
617
+ throw new Error("API key required. Add an API key to continue.");
618
+ }
619
+ return this.provider;
620
+ }
621
+ }
622
+ function toToolCall(part) {
623
+ return {
624
+ id: part.toolCallId,
625
+ type: "function",
626
+ function: {
627
+ name: part.toolName,
628
+ arguments: JSON.stringify(part.input ?? part.args ?? {}),
629
+ },
630
+ };
631
+ }
632
+ function toToolResult(output) {
633
+ if (output && typeof output === "object" && "success" in output) {
634
+ const r = output;
635
+ return {
636
+ success: r.success,
637
+ output: r.output,
638
+ error: r.success ? undefined : r.output,
639
+ diff: r.diff,
640
+ plan: r.plan,
641
+ task: r.task,
642
+ delegation: r.delegation,
643
+ backgroundProcess: r.backgroundProcess,
644
+ };
645
+ }
646
+ return { success: true, output: String(output) };
647
+ }
648
+ function formatSubagentActivity(toolName, args) {
649
+ const parsed = parseToolArgs(args);
650
+ if (toolName === "read_file")
651
+ return `Read ${parsed.path || "file"}`;
652
+ if (toolName === "write_file")
653
+ return `Write ${parsed.path || "file"}`;
654
+ if (toolName === "edit_file")
655
+ return `Edit ${parsed.path || "file"}`;
656
+ if (toolName === "search_web")
657
+ return `Web search "${truncate(parsed.query || "", 50)}"`;
658
+ if (toolName === "search_x")
659
+ return `X search "${truncate(parsed.query || "", 50)}"`;
660
+ if (toolName === "bash")
661
+ return truncate(parsed.command || "Run command", 70);
662
+ return truncate(`${toolName}`, 70);
663
+ }
664
+ function parseToolArgs(args) {
665
+ if (!args || typeof args !== "object")
666
+ return {};
667
+ const result = {};
668
+ for (const [key, value] of Object.entries(args)) {
669
+ result[key] = typeof value === "string" ? value : JSON.stringify(value);
670
+ }
671
+ return result;
672
+ }
673
+ function firstLine(text) {
674
+ return text.trim().split("\n").find(Boolean)?.trim() || "Task completed.";
675
+ }
676
+ function truncate(text, max) {
677
+ return text.length <= max ? text : `${text.slice(0, max - 1)}…`;
678
+ }
679
+ function estimateTokens(text) {
680
+ return Math.ceil(text.length / 4);
681
+ }
682
+ function combineAbortSignals(...signals) {
683
+ const activeSignals = signals.filter((signal) => Boolean(signal));
684
+ if (activeSignals.length === 0)
685
+ return undefined;
686
+ if (activeSignals.length === 1)
687
+ return activeSignals[0];
688
+ if (typeof AbortSignal.any === "function") {
689
+ return AbortSignal.any(activeSignals);
690
+ }
691
+ const controller = new AbortController();
692
+ for (const signal of activeSignals) {
693
+ if (signal.aborted) {
694
+ controller.abort();
695
+ break;
696
+ }
697
+ signal.addEventListener("abort", () => controller.abort(), { once: true });
698
+ }
699
+ return controller.signal;
700
+ }
701
+ //# sourceMappingURL=agent.js.map