grok-dev 1.0.0-rc2 → 1.0.0-rc3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/project-overview.mdc +2 -2
- package/README.md +12 -3
- package/dist/agent/agent.d.ts +42 -3
- package/dist/agent/agent.js +276 -137
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/compaction.d.ts +35 -0
- package/dist/agent/compaction.js +364 -0
- package/dist/agent/compaction.js.map +1 -0
- package/dist/agent/compaction.test.d.ts +1 -0
- package/dist/agent/compaction.test.js.map +1 -0
- package/dist/headless/output.d.ts +67 -0
- package/dist/headless/output.js +176 -0
- package/dist/headless/output.js.map +1 -0
- package/dist/headless/output.test.d.ts +1 -0
- package/dist/headless/output.test.js.map +1 -0
- package/dist/index.js +38 -33
- package/dist/index.js.map +1 -1
- package/dist/mcp/parse-headers.test.d.ts +1 -0
- package/dist/mcp/parse-headers.test.js.map +1 -0
- package/dist/storage/index.d.ts +2 -1
- package/dist/storage/index.js +2 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/migrations.js +31 -1
- package/dist/storage/migrations.js.map +1 -1
- package/dist/storage/transcript-view.d.ts +14 -0
- package/dist/storage/transcript-view.js +23 -0
- package/dist/storage/transcript-view.js.map +1 -0
- package/dist/storage/transcript.d.ts +8 -2
- package/dist/storage/transcript.js +72 -18
- package/dist/storage/transcript.js.map +1 -1
- package/dist/telegram/limits.test.d.ts +1 -0
- package/dist/telegram/limits.test.js.map +1 -0
- package/dist/ui/app.js +39 -10
- package/dist/ui/app.js.map +1 -1
- package/dist/utils/instructions.js +0 -8
- package/dist/utils/instructions.js.map +1 -1
- package/dist/utils/instructions.test.d.ts +1 -0
- package/dist/utils/instructions.test.js.map +1 -0
- package/package.json +5 -2
|
@@ -37,7 +37,7 @@ src/
|
|
|
37
37
|
├── utils/
|
|
38
38
|
│ ├── settings.ts # User and project settings
|
|
39
39
|
│ ├── git-root.ts # Resolve git repository root for AGENTS.md discovery
|
|
40
|
-
│ └── instructions.ts # AGENTS.md (ecosystem)
|
|
40
|
+
│ └── instructions.ts # AGENTS.md (ecosystem) custom instructions
|
|
41
41
|
└── types/
|
|
42
42
|
└── index.ts # Shared TypeScript types
|
|
43
43
|
```
|
|
@@ -48,7 +48,7 @@ src/
|
|
|
48
48
|
- **Bash-only tools**: The agent uses bash for everything (file editing, searching, git, builds, etc.).
|
|
49
49
|
- **X Search & Web Search**: Integrated via the xAI Responses API for real-time information.
|
|
50
50
|
- **Settings hierarchy**: Environment variables → User-level (`~/.grok/user-settings.json`) → Project-level (`.grok/settings.json`).
|
|
51
|
-
- **Custom instructions**: `~/.grok/AGENTS.md`, then `AGENTS.override.md` / `AGENTS.md` per directory from git root through the workspace cwd (Codex-style merge)
|
|
51
|
+
- **Custom instructions**: `~/.grok/AGENTS.md`, then `AGENTS.override.md` / `AGENTS.md` per directory from git root through the workspace cwd (Codex-style merge).
|
|
52
52
|
- **ESM only**: The project uses `"type": "module"` — all imports use `.js` extensions for compiled output.
|
|
53
53
|
|
|
54
54
|
## Latest Grok Models
|
package/README.md
CHANGED
|
@@ -46,6 +46,7 @@ grok -d /path/to/your/repo
|
|
|
46
46
|
grok --prompt "run the test suite and summarize failures"
|
|
47
47
|
grok -p "show me package.json" --directory /path/to/project
|
|
48
48
|
grok --prompt "refactor X" --max-tool-rounds 30
|
|
49
|
+
grok --prompt "summarize the repo state" --format json
|
|
49
50
|
```
|
|
50
51
|
|
|
51
52
|
**Continue a saved session:**
|
|
@@ -57,6 +58,15 @@ grok -s <session-id>
|
|
|
57
58
|
|
|
58
59
|
Works in interactive mode too—same flag.
|
|
59
60
|
|
|
61
|
+
**Structured headless output:**
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
grok --prompt "summarize the repo state" --format json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`--format json` emits newline-delimited `StreamChunk` objects instead of the
|
|
68
|
+
default human-readable text stream.
|
|
69
|
+
|
|
60
70
|
**List Grok models and pricing hints:**
|
|
61
71
|
|
|
62
72
|
```bash
|
|
@@ -136,13 +146,12 @@ Treat the bot token like a password.
|
|
|
136
146
|
## Instructions & project brain
|
|
137
147
|
|
|
138
148
|
- **`AGENTS.md`** — merged from git root down to your cwd (Codex-style; see repo docs). **`AGENTS.override.md`** wins per directory when present.
|
|
139
|
-
- **`.grok/GROK.md`** or **`~/.grok/GROK.md`** — Grok-only rules, applied last.
|
|
140
149
|
|
|
141
150
|
---
|
|
142
151
|
|
|
143
|
-
##
|
|
152
|
+
## Project settings
|
|
144
153
|
|
|
145
|
-
Project file: **`.grok/settings.json`** — e.g. current model
|
|
154
|
+
Project file: **`.grok/settings.json`** — e.g. the current model for this project.
|
|
146
155
|
|
|
147
156
|
---
|
|
148
157
|
|
package/dist/agent/agent.d.ts
CHANGED
|
@@ -1,8 +1,44 @@
|
|
|
1
|
-
import type { AgentMode, ChatEntry, SessionInfo, SessionSnapshot, StreamChunk, SubagentStatus, TaskRequest, ToolResult } from "../types/index";
|
|
1
|
+
import type { AgentMode, ChatEntry, SessionInfo, SessionSnapshot, StreamChunk, SubagentStatus, TaskRequest, ToolCall, ToolResult } from "../types/index";
|
|
2
2
|
interface AgentOptions {
|
|
3
3
|
persistSession?: boolean;
|
|
4
4
|
session?: string;
|
|
5
5
|
}
|
|
6
|
+
type ProcessMessageFinishReason = "stop" | "length" | "content-filter" | "tool-calls" | "error" | "other";
|
|
7
|
+
export interface ProcessMessageUsage {
|
|
8
|
+
inputTokens?: number;
|
|
9
|
+
outputTokens?: number;
|
|
10
|
+
totalTokens?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface ProcessMessageStepStart {
|
|
13
|
+
stepNumber: number;
|
|
14
|
+
timestamp: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ProcessMessageStepFinish {
|
|
17
|
+
stepNumber: number;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
finishReason: ProcessMessageFinishReason;
|
|
20
|
+
usage: ProcessMessageUsage;
|
|
21
|
+
}
|
|
22
|
+
export interface ProcessMessageToolStart {
|
|
23
|
+
toolCall: ToolCall;
|
|
24
|
+
timestamp: number;
|
|
25
|
+
}
|
|
26
|
+
export interface ProcessMessageToolFinish {
|
|
27
|
+
toolCall: ToolCall;
|
|
28
|
+
toolResult: ToolResult;
|
|
29
|
+
timestamp: number;
|
|
30
|
+
}
|
|
31
|
+
export interface ProcessMessageError {
|
|
32
|
+
message: string;
|
|
33
|
+
timestamp: number;
|
|
34
|
+
}
|
|
35
|
+
export interface ProcessMessageObserver {
|
|
36
|
+
onStepStart?(info: ProcessMessageStepStart): void;
|
|
37
|
+
onStepFinish?(info: ProcessMessageStepFinish): void;
|
|
38
|
+
onToolStart?(info: ProcessMessageToolStart): void;
|
|
39
|
+
onToolFinish?(info: ProcessMessageToolFinish): void;
|
|
40
|
+
onError?(info: ProcessMessageError): void;
|
|
41
|
+
}
|
|
6
42
|
export declare class Agent {
|
|
7
43
|
private provider;
|
|
8
44
|
private apiKey;
|
|
@@ -13,7 +49,7 @@ export declare class Agent {
|
|
|
13
49
|
private workspace;
|
|
14
50
|
private session;
|
|
15
51
|
private messages;
|
|
16
|
-
private
|
|
52
|
+
private messageSeqs;
|
|
17
53
|
private abortController;
|
|
18
54
|
private maxToolRounds;
|
|
19
55
|
private mode;
|
|
@@ -56,7 +92,10 @@ export declare class Agent {
|
|
|
56
92
|
private runDelegation;
|
|
57
93
|
private readDelegation;
|
|
58
94
|
private listDelegations;
|
|
59
|
-
|
|
95
|
+
private getCompactionSettings;
|
|
96
|
+
private compactForContext;
|
|
97
|
+
private appendCompletedTurn;
|
|
98
|
+
processMessage(userMessage: string, observer?: ProcessMessageObserver): AsyncGenerator<StreamChunk, void, unknown>;
|
|
60
99
|
private requireProvider;
|
|
61
100
|
}
|
|
62
101
|
export {};
|
package/dist/agent/agent.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { stepCountIs, streamText } from "ai";
|
|
2
2
|
import { createProvider, generateTitle as genTitle } from "../grok/client";
|
|
3
|
+
import { getModelInfo } from "../grok/models";
|
|
3
4
|
import { createTools } from "../grok/tools";
|
|
4
5
|
import { buildMcpToolSet } from "../mcp/runtime";
|
|
5
|
-
import { appendMessages, appendSystemMessage, buildChatEntries, getSessionTotalTokens, loadTranscript, recordUsageEvent, SessionStore, } from "../storage/index";
|
|
6
|
+
import { appendCompaction, appendMessages, appendSystemMessage, buildChatEntries, getNextMessageSequence, getSessionTotalTokens, loadTranscript, loadTranscriptState, recordUsageEvent, SessionStore, } from "../storage/index";
|
|
6
7
|
import { BashTool } from "../tools/bash";
|
|
7
8
|
import { loadCustomInstructions } from "../utils/instructions";
|
|
8
9
|
import { loadMcpServers } from "../utils/settings";
|
|
9
10
|
import { discoverSkills, formatSkillsForPrompt } from "../utils/skills";
|
|
11
|
+
import { createCompactionSummaryMessage, DEFAULT_KEEP_RECENT_TOKENS, DEFAULT_RESERVE_TOKENS, estimateConversationTokens, generateCompactionSummary, prepareCompaction, relaxCompactionSettings, shouldCompactContext, } from "./compaction";
|
|
10
12
|
import { DelegationManager } from "./delegations";
|
|
11
13
|
const MAX_TOOL_ROUNDS = 400;
|
|
12
14
|
const ENVIRONMENT = `ENVIRONMENT:
|
|
@@ -156,7 +158,7 @@ export class Agent {
|
|
|
156
158
|
workspace = null;
|
|
157
159
|
session = null;
|
|
158
160
|
messages = [];
|
|
159
|
-
|
|
161
|
+
messageSeqs = [];
|
|
160
162
|
abortController = null;
|
|
161
163
|
maxToolRounds;
|
|
162
164
|
mode = "agent";
|
|
@@ -180,8 +182,9 @@ export class Agent {
|
|
|
180
182
|
this.workspace = this.sessionStore.getWorkspace();
|
|
181
183
|
this.session = this.sessionStore.openSession(options.session, this.modelId, this.mode, this.bash.getCwd());
|
|
182
184
|
this.mode = this.session.mode;
|
|
183
|
-
|
|
184
|
-
this.
|
|
185
|
+
const transcript = loadTranscriptState(this.session.id);
|
|
186
|
+
this.messages = transcript.messages;
|
|
187
|
+
this.messageSeqs = transcript.seqs;
|
|
185
188
|
this.sessionStore.setModel(this.session.id, this.modelId);
|
|
186
189
|
}
|
|
187
190
|
}
|
|
@@ -223,8 +226,7 @@ export class Agent {
|
|
|
223
226
|
}
|
|
224
227
|
getContextStats(contextWindow, inFlightText = "") {
|
|
225
228
|
const system = buildSystemPrompt(this.bash.getCwd(), this.mode, this.planContext);
|
|
226
|
-
const
|
|
227
|
-
const usedTokens = Math.min(contextWindow, Math.max(estimatedTokens, this.recordedTokens));
|
|
229
|
+
const usedTokens = Math.min(contextWindow, estimateConversationTokens(system, this.messages, inFlightText));
|
|
228
230
|
const remainingTokens = Math.max(0, contextWindow - usedTokens);
|
|
229
231
|
return {
|
|
230
232
|
contextWindow,
|
|
@@ -257,14 +259,14 @@ export class Agent {
|
|
|
257
259
|
startNewSession() {
|
|
258
260
|
if (!this.sessionStore) {
|
|
259
261
|
this.messages = [];
|
|
260
|
-
this.
|
|
262
|
+
this.messageSeqs = [];
|
|
261
263
|
return null;
|
|
262
264
|
}
|
|
263
265
|
this.sessionStore = new SessionStore(this.bash.getCwd());
|
|
264
266
|
this.workspace = this.sessionStore.getWorkspace();
|
|
265
267
|
this.session = this.sessionStore.createSession(this.modelId, this.mode, this.bash.getCwd());
|
|
266
268
|
this.messages = [];
|
|
267
|
-
this.
|
|
269
|
+
this.messageSeqs = [];
|
|
268
270
|
return this.getSessionSnapshot();
|
|
269
271
|
}
|
|
270
272
|
getSessionInfo() {
|
|
@@ -307,15 +309,12 @@ export class Agent {
|
|
|
307
309
|
const idx = this.messages.lastIndexOf(userMessage);
|
|
308
310
|
if (idx >= 0) {
|
|
309
311
|
this.messages.splice(idx, 1);
|
|
312
|
+
this.messageSeqs.splice(idx, 1);
|
|
310
313
|
}
|
|
311
314
|
}
|
|
312
315
|
recordUsage(usage, source = "message", model = this.modelId) {
|
|
313
316
|
if (!usage)
|
|
314
317
|
return;
|
|
315
|
-
const total = usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
|
|
316
|
-
if (Number.isFinite(total) && total > 0) {
|
|
317
|
-
this.recordedTokens += total;
|
|
318
|
-
}
|
|
319
318
|
if (this.session) {
|
|
320
319
|
recordUsageEvent(this.session.id, source, model, usage);
|
|
321
320
|
}
|
|
@@ -325,9 +324,11 @@ export class Agent {
|
|
|
325
324
|
const notifications = await this.delegations.consumeNotifications();
|
|
326
325
|
for (const notification of notifications) {
|
|
327
326
|
this.messages.push({ role: "system", content: notification.message });
|
|
327
|
+
let seq = null;
|
|
328
328
|
if (this.session) {
|
|
329
|
-
appendSystemMessage(this.session.id, notification.message);
|
|
329
|
+
seq = appendSystemMessage(this.session.id, notification.message);
|
|
330
330
|
}
|
|
331
|
+
this.messageSeqs.push(seq);
|
|
331
332
|
}
|
|
332
333
|
return notifications.map((notification) => notification.message);
|
|
333
334
|
}
|
|
@@ -498,143 +499,234 @@ export class Agent {
|
|
|
498
499
|
};
|
|
499
500
|
}
|
|
500
501
|
}
|
|
501
|
-
|
|
502
|
+
getCompactionSettings() {
|
|
503
|
+
return {
|
|
504
|
+
reserveTokens: Math.max(this.maxTokens, DEFAULT_RESERVE_TOKENS),
|
|
505
|
+
keepRecentTokens: DEFAULT_KEEP_RECENT_TOKENS,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
async compactForContext(provider, system, contextWindow, signal, settings = this.getCompactionSettings(), force = false) {
|
|
509
|
+
if (!this.session)
|
|
510
|
+
return false;
|
|
511
|
+
const preparation = prepareCompaction(this.messages, system, settings);
|
|
512
|
+
if (!preparation)
|
|
513
|
+
return false;
|
|
514
|
+
if (!force && !shouldCompactContext(preparation.tokensBefore, contextWindow, settings)) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
const keptSeqs = this.messageSeqs.slice(preparation.firstKeptIndex);
|
|
518
|
+
const firstKeptSeq = keptSeqs.find((seq) => seq !== null) ?? getNextMessageSequence(this.session.id);
|
|
519
|
+
const summary = await generateCompactionSummary(provider, this.modelId, preparation, undefined, signal);
|
|
520
|
+
appendCompaction(this.session.id, firstKeptSeq, summary, preparation.tokensBefore);
|
|
521
|
+
this.messages = [createCompactionSummaryMessage(summary), ...preparation.keptMessages];
|
|
522
|
+
this.messageSeqs = [null, ...keptSeqs];
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
525
|
+
appendCompletedTurn(userMessage, newMessages) {
|
|
526
|
+
if (newMessages.length === 0)
|
|
527
|
+
return;
|
|
528
|
+
const userIndex = this.messages.lastIndexOf(userMessage);
|
|
529
|
+
if (!this.sessionStore || !this.session) {
|
|
530
|
+
if (userIndex >= 0 && this.messageSeqs[userIndex] == null) {
|
|
531
|
+
this.messageSeqs[userIndex] = null;
|
|
532
|
+
}
|
|
533
|
+
this.messages.push(...newMessages);
|
|
534
|
+
this.messageSeqs.push(...newMessages.map(() => null));
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const insertedSeqs = appendMessages(this.session.id, [userMessage, ...newMessages]);
|
|
538
|
+
if (userIndex >= 0) {
|
|
539
|
+
this.messageSeqs[userIndex] = insertedSeqs[0] ?? this.messageSeqs[userIndex];
|
|
540
|
+
}
|
|
541
|
+
this.messages.push(...newMessages);
|
|
542
|
+
this.messageSeqs.push(...insertedSeqs.slice(1));
|
|
543
|
+
this.sessionStore.touchSession(this.session.id, this.bash.getCwd());
|
|
544
|
+
this.session = this.sessionStore.getRequiredSession(this.session.id);
|
|
545
|
+
}
|
|
546
|
+
async *processMessage(userMessage, observer) {
|
|
502
547
|
this.abortController = new AbortController();
|
|
503
548
|
const signal = this.abortController.signal;
|
|
504
549
|
this.emitSubagentStatus(null);
|
|
505
550
|
await this.consumeBackgroundNotifications();
|
|
506
551
|
const userModelMessage = { role: "user", content: userMessage };
|
|
507
552
|
this.messages.push(userModelMessage);
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
553
|
+
this.messageSeqs.push(null);
|
|
554
|
+
const provider = this.requireProvider();
|
|
555
|
+
const system = buildSystemPrompt(this.bash.getCwd(), this.mode, this.planContext);
|
|
556
|
+
const modelInfo = getModelInfo(this.modelId);
|
|
557
|
+
this.planContext = null;
|
|
558
|
+
let attemptedOverflowRecovery = false;
|
|
511
559
|
try {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
tools = { ...baseTools, ...mcpBundle.tools };
|
|
524
|
-
if (mcpBundle.errors.length > 0) {
|
|
525
|
-
yield { type: "content", content: `MCP unavailable: ${mcpBundle.errors.join(" | ")}\n\n` };
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
const system = buildSystemPrompt(this.bash.getCwd(), this.mode, this.planContext);
|
|
529
|
-
this.planContext = null;
|
|
530
|
-
const result = streamText({
|
|
531
|
-
model: provider(this.modelId),
|
|
532
|
-
system,
|
|
533
|
-
messages: this.messages,
|
|
534
|
-
tools,
|
|
535
|
-
stopWhen: stepCountIs(this.maxToolRounds),
|
|
536
|
-
maxRetries: 0,
|
|
537
|
-
abortSignal: signal,
|
|
538
|
-
temperature: 0.7,
|
|
539
|
-
maxOutputTokens: this.maxTokens,
|
|
540
|
-
onFinish: ({ totalUsage }) => {
|
|
541
|
-
this.recordUsage(totalUsage, "message");
|
|
542
|
-
},
|
|
543
|
-
});
|
|
544
|
-
for await (const part of result.fullStream) {
|
|
545
|
-
if (signal.aborted) {
|
|
546
|
-
yield { type: "content", content: "\n\n[Cancelled]" };
|
|
547
|
-
break;
|
|
548
|
-
}
|
|
549
|
-
switch (part.type) {
|
|
550
|
-
case "text-delta":
|
|
551
|
-
assistantText += part.text;
|
|
552
|
-
yield { type: "content", content: part.text };
|
|
553
|
-
break;
|
|
554
|
-
case "reasoning-delta":
|
|
555
|
-
yield { type: "reasoning", content: part.text };
|
|
556
|
-
break;
|
|
557
|
-
case "tool-call": {
|
|
558
|
-
const tc = toToolCall(part);
|
|
559
|
-
yield { type: "tool_calls", toolCalls: [tc] };
|
|
560
|
-
break;
|
|
560
|
+
while (true) {
|
|
561
|
+
let assistantText = "";
|
|
562
|
+
let streamOk = false;
|
|
563
|
+
let closeMcp;
|
|
564
|
+
let stepNumber = -1;
|
|
565
|
+
try {
|
|
566
|
+
const settings = attemptedOverflowRecovery
|
|
567
|
+
? relaxCompactionSettings(this.getCompactionSettings())
|
|
568
|
+
: this.getCompactionSettings();
|
|
569
|
+
if (modelInfo) {
|
|
570
|
+
await this.compactForContext(provider, system, modelInfo.contextWindow, signal, settings, attemptedOverflowRecovery);
|
|
561
571
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
572
|
+
const baseTools = createTools(this.bash, provider, this.mode, {
|
|
573
|
+
runTask: (request, abortSignal) => this.runTask(request, combineAbortSignals(signal, abortSignal)),
|
|
574
|
+
runDelegation: (request, abortSignal) => this.runDelegation(request, combineAbortSignals(signal, abortSignal)),
|
|
575
|
+
readDelegation: (id) => this.readDelegation(id),
|
|
576
|
+
listDelegations: () => this.listDelegations(),
|
|
577
|
+
});
|
|
578
|
+
let tools = baseTools;
|
|
579
|
+
if (this.mode === "agent") {
|
|
580
|
+
const mcpBundle = await buildMcpToolSet(loadMcpServers());
|
|
581
|
+
closeMcp = mcpBundle.close;
|
|
582
|
+
tools = { ...baseTools, ...mcpBundle.tools };
|
|
583
|
+
if (mcpBundle.errors.length > 0) {
|
|
584
|
+
yield { type: "content", content: `MCP unavailable: ${mcpBundle.errors.join(" | ")}\n\n` };
|
|
585
|
+
}
|
|
571
586
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
587
|
+
const result = streamText({
|
|
588
|
+
model: provider(this.modelId),
|
|
589
|
+
system,
|
|
590
|
+
messages: this.messages,
|
|
591
|
+
tools,
|
|
592
|
+
stopWhen: stepCountIs(this.maxToolRounds),
|
|
593
|
+
maxRetries: 0,
|
|
594
|
+
abortSignal: signal,
|
|
595
|
+
temperature: 0.7,
|
|
596
|
+
maxOutputTokens: this.maxTokens,
|
|
597
|
+
experimental_onStepStart: (event) => {
|
|
598
|
+
stepNumber = getStepNumber(event, stepNumber + 1);
|
|
599
|
+
notifyObserver(observer?.onStepStart, {
|
|
600
|
+
stepNumber,
|
|
601
|
+
timestamp: Date.now(),
|
|
602
|
+
});
|
|
603
|
+
},
|
|
604
|
+
onStepFinish: (event) => {
|
|
605
|
+
const currentStep = getStepNumber(event, Math.max(stepNumber, 0));
|
|
606
|
+
stepNumber = Math.max(stepNumber, currentStep);
|
|
607
|
+
notifyObserver(observer?.onStepFinish, {
|
|
608
|
+
stepNumber: currentStep,
|
|
609
|
+
timestamp: Date.now(),
|
|
610
|
+
finishReason: getFinishReason(event),
|
|
611
|
+
usage: getUsage(event),
|
|
612
|
+
});
|
|
613
|
+
},
|
|
614
|
+
onFinish: ({ totalUsage }) => {
|
|
615
|
+
this.recordUsage(totalUsage, "message");
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
for await (const part of result.fullStream) {
|
|
619
|
+
if (signal.aborted) {
|
|
620
|
+
yield { type: "content", content: "\n\n[Cancelled]" };
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
switch (part.type) {
|
|
624
|
+
case "text-delta":
|
|
625
|
+
assistantText += part.text;
|
|
626
|
+
yield { type: "content", content: part.text };
|
|
627
|
+
break;
|
|
628
|
+
case "reasoning-delta":
|
|
629
|
+
yield { type: "reasoning", content: part.text };
|
|
630
|
+
break;
|
|
631
|
+
case "tool-call": {
|
|
632
|
+
const tc = toToolCall(part);
|
|
633
|
+
notifyObserver(observer?.onToolStart, {
|
|
634
|
+
toolCall: tc,
|
|
635
|
+
timestamp: Date.now(),
|
|
636
|
+
});
|
|
637
|
+
yield { type: "tool_calls", toolCalls: [tc] };
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
case "tool-result": {
|
|
641
|
+
const tc = {
|
|
642
|
+
id: part.toolCallId,
|
|
643
|
+
type: "function",
|
|
644
|
+
function: { name: part.toolName, arguments: JSON.stringify(part.input ?? {}) },
|
|
645
|
+
};
|
|
646
|
+
const tr = toToolResult(part.output);
|
|
647
|
+
notifyObserver(observer?.onToolFinish, {
|
|
648
|
+
toolCall: tc,
|
|
649
|
+
toolResult: tr,
|
|
650
|
+
timestamp: Date.now(),
|
|
651
|
+
});
|
|
652
|
+
yield { type: "tool_result", toolCall: tc, toolResult: tr };
|
|
653
|
+
break;
|
|
654
|
+
}
|
|
655
|
+
case "error": {
|
|
656
|
+
const message = String(part.error);
|
|
657
|
+
notifyObserver(observer?.onError, {
|
|
658
|
+
message,
|
|
659
|
+
timestamp: Date.now(),
|
|
660
|
+
});
|
|
661
|
+
yield { type: "error", content: message };
|
|
662
|
+
break;
|
|
663
|
+
}
|
|
664
|
+
case "abort":
|
|
665
|
+
yield { type: "content", content: "\n\n[Cancelled]" };
|
|
666
|
+
break;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (signal.aborted) {
|
|
670
|
+
this.discardAbortedTurn(userModelMessage);
|
|
671
|
+
yield { type: "done" };
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
try {
|
|
675
|
+
const response = await result.response;
|
|
676
|
+
if (!signal.aborted) {
|
|
677
|
+
this.appendCompletedTurn(userModelMessage, response.messages);
|
|
678
|
+
streamOk = true;
|
|
679
|
+
}
|
|
593
680
|
}
|
|
594
|
-
|
|
681
|
+
catch (responseError) {
|
|
682
|
+
if (!attemptedOverflowRecovery &&
|
|
683
|
+
!assistantText.trim() &&
|
|
684
|
+
modelInfo &&
|
|
685
|
+
isContextLimitError(responseError)) {
|
|
686
|
+
attemptedOverflowRecovery = true;
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
if (signal.aborted) {
|
|
691
|
+
this.discardAbortedTurn(userModelMessage);
|
|
692
|
+
yield { type: "done" };
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
if (!streamOk && assistantText.trim()) {
|
|
696
|
+
this.appendCompletedTurn(userModelMessage, [{ role: "assistant", content: assistantText }]);
|
|
697
|
+
}
|
|
698
|
+
yield { type: "done" };
|
|
699
|
+
return;
|
|
595
700
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
701
|
+
catch (err) {
|
|
702
|
+
if (signal.aborted) {
|
|
703
|
+
this.discardAbortedTurn(userModelMessage);
|
|
704
|
+
yield { type: "content", content: "\n\n[Cancelled]" };
|
|
705
|
+
yield { type: "done" };
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
if (!attemptedOverflowRecovery && !assistantText.trim() && modelInfo && isContextLimitError(err)) {
|
|
709
|
+
attemptedOverflowRecovery = true;
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
713
|
+
notifyObserver(observer?.onError, {
|
|
714
|
+
message: `Error: ${msg}`,
|
|
715
|
+
timestamp: Date.now(),
|
|
716
|
+
});
|
|
717
|
+
yield { type: "error", content: `Error: ${msg}` };
|
|
718
|
+
if (assistantText.trim()) {
|
|
719
|
+
this.appendCompletedTurn(userModelMessage, [{ role: "assistant", content: assistantText }]);
|
|
720
|
+
}
|
|
721
|
+
yield { type: "done" };
|
|
722
|
+
return;
|
|
612
723
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
}
|
|
616
|
-
catch (err) {
|
|
617
|
-
if (signal.aborted) {
|
|
618
|
-
this.discardAbortedTurn(userModelMessage);
|
|
619
|
-
yield { type: "content", content: "\n\n[Cancelled]" };
|
|
620
|
-
}
|
|
621
|
-
else {
|
|
622
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
623
|
-
yield { type: "error", content: `Error: ${msg}` };
|
|
624
|
-
}
|
|
625
|
-
if (!signal.aborted && assistantText.trim()) {
|
|
626
|
-
const fallbackMessage = { role: "assistant", content: assistantText };
|
|
627
|
-
this.messages.push(fallbackMessage);
|
|
628
|
-
if (this.sessionStore && this.session) {
|
|
629
|
-
appendMessages(this.session.id, [userModelMessage, fallbackMessage]);
|
|
630
|
-
this.sessionStore.touchSession(this.session.id, this.bash.getCwd());
|
|
631
|
-
this.session = this.sessionStore.getRequiredSession(this.session.id);
|
|
724
|
+
finally {
|
|
725
|
+
await closeMcp?.().catch(() => { });
|
|
632
726
|
}
|
|
633
727
|
}
|
|
634
|
-
yield { type: "done" };
|
|
635
728
|
}
|
|
636
729
|
finally {
|
|
637
|
-
await closeMcp?.().catch(() => { });
|
|
638
730
|
if (this.abortController?.signal === signal) {
|
|
639
731
|
this.abortController = null;
|
|
640
732
|
}
|
|
@@ -657,6 +749,52 @@ function toToolCall(part) {
|
|
|
657
749
|
},
|
|
658
750
|
};
|
|
659
751
|
}
|
|
752
|
+
function notifyObserver(listener, payload) {
|
|
753
|
+
if (!listener) {
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
try {
|
|
757
|
+
listener(payload);
|
|
758
|
+
}
|
|
759
|
+
catch {
|
|
760
|
+
// Observer failures should never break generation.
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
function getStepNumber(event, fallback) {
|
|
764
|
+
if (event && typeof event === "object" && "stepNumber" in event && typeof event.stepNumber === "number") {
|
|
765
|
+
return event.stepNumber;
|
|
766
|
+
}
|
|
767
|
+
return fallback;
|
|
768
|
+
}
|
|
769
|
+
function getFinishReason(event) {
|
|
770
|
+
if (event && typeof event === "object" && "finishReason" in event) {
|
|
771
|
+
switch (event.finishReason) {
|
|
772
|
+
case "stop":
|
|
773
|
+
case "length":
|
|
774
|
+
case "content-filter":
|
|
775
|
+
case "tool-calls":
|
|
776
|
+
case "error":
|
|
777
|
+
case "other":
|
|
778
|
+
return event.finishReason;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return "other";
|
|
782
|
+
}
|
|
783
|
+
function getUsage(event) {
|
|
784
|
+
if (!(event && typeof event === "object" && "usage" in event)) {
|
|
785
|
+
return {};
|
|
786
|
+
}
|
|
787
|
+
const usage = event.usage;
|
|
788
|
+
if (!usage || typeof usage !== "object") {
|
|
789
|
+
return {};
|
|
790
|
+
}
|
|
791
|
+
const u = usage;
|
|
792
|
+
return {
|
|
793
|
+
inputTokens: typeof u.inputTokens === "number" ? u.inputTokens : undefined,
|
|
794
|
+
outputTokens: typeof u.outputTokens === "number" ? u.outputTokens : undefined,
|
|
795
|
+
totalTokens: typeof u.totalTokens === "number" ? u.totalTokens : undefined,
|
|
796
|
+
};
|
|
797
|
+
}
|
|
660
798
|
function toToolResult(output) {
|
|
661
799
|
if (output && typeof output === "object" && "success" in output) {
|
|
662
800
|
const r = output;
|
|
@@ -704,9 +842,6 @@ function firstLine(text) {
|
|
|
704
842
|
function truncate(text, max) {
|
|
705
843
|
return text.length <= max ? text : `${text.slice(0, max - 1)}…`;
|
|
706
844
|
}
|
|
707
|
-
function estimateTokens(text) {
|
|
708
|
-
return Math.ceil(text.length / 4);
|
|
709
|
-
}
|
|
710
845
|
function combineAbortSignals(...signals) {
|
|
711
846
|
const activeSignals = signals.filter((signal) => Boolean(signal));
|
|
712
847
|
if (activeSignals.length === 0)
|
|
@@ -726,4 +861,8 @@ function combineAbortSignals(...signals) {
|
|
|
726
861
|
}
|
|
727
862
|
return controller.signal;
|
|
728
863
|
}
|
|
864
|
+
function isContextLimitError(error) {
|
|
865
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
866
|
+
return /(context|token|prompt).*(limit|length|large|window|overflow)|too many tokens|maximum context/i.test(message);
|
|
867
|
+
}
|
|
729
868
|
//# sourceMappingURL=agent.js.map
|