@compilr-dev/agents 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +82 -1
- package/dist/agent.js +162 -23
- package/dist/context/manager.d.ts +8 -0
- package/dist/context/manager.js +25 -2
- package/dist/errors.d.ts +20 -1
- package/dist/errors.js +44 -2
- package/dist/index.d.ts +6 -1
- package/dist/index.js +7 -1
- package/dist/messages/index.d.ts +12 -5
- package/dist/messages/index.js +53 -15
- package/dist/providers/gemini-native.d.ts +86 -0
- package/dist/providers/gemini-native.js +339 -0
- package/dist/providers/index.d.ts +7 -2
- package/dist/providers/index.js +7 -2
- package/dist/providers/ollama.d.ts +2 -2
- package/dist/providers/ollama.js +3 -3
- package/dist/providers/types.d.ts +11 -0
- package/dist/skills/index.js +474 -56
- package/dist/state/agent-state.d.ts +1 -0
- package/dist/state/agent-state.js +2 -0
- package/dist/state/serializer.js +20 -2
- package/dist/state/types.d.ts +5 -0
- package/dist/utils/index.d.ts +119 -4
- package/dist/utils/index.js +164 -13
- package/package.json +4 -1
package/dist/agent.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { ContextManager } from './context/manager.js';
|
|
|
16
16
|
import { FileAccessTracker } from './context/file-tracker.js';
|
|
17
17
|
import { AnchorManager } from './anchors/manager.js';
|
|
18
18
|
import { GuardrailManager } from './guardrails/manager.js';
|
|
19
|
+
import { type RetryConfig } from './utils/index.js';
|
|
19
20
|
/**
|
|
20
21
|
* Event types emitted during agent execution
|
|
21
22
|
*/
|
|
@@ -146,6 +147,18 @@ export type AgentEvent = {
|
|
|
146
147
|
type: 'iteration_limit_extended';
|
|
147
148
|
newMaxIterations: number;
|
|
148
149
|
addedIterations: number;
|
|
150
|
+
} | {
|
|
151
|
+
type: 'llm_retry';
|
|
152
|
+
attempt: number;
|
|
153
|
+
maxAttempts: number;
|
|
154
|
+
error: string;
|
|
155
|
+
delayMs: number;
|
|
156
|
+
provider: string;
|
|
157
|
+
} | {
|
|
158
|
+
type: 'llm_retry_exhausted';
|
|
159
|
+
attempts: number;
|
|
160
|
+
error: string;
|
|
161
|
+
provider: string;
|
|
149
162
|
};
|
|
150
163
|
/**
|
|
151
164
|
* Event handler function type
|
|
@@ -268,6 +281,29 @@ export interface AgentConfig {
|
|
|
268
281
|
* Event handler for monitoring agent execution
|
|
269
282
|
*/
|
|
270
283
|
onEvent?: AgentEventHandler;
|
|
284
|
+
/**
|
|
285
|
+
* Configuration for automatic retry on transient LLM errors.
|
|
286
|
+
* Enabled by default with sensible defaults (10 attempts, exponential backoff).
|
|
287
|
+
*
|
|
288
|
+
* Retryable errors include:
|
|
289
|
+
* - Rate limit (429)
|
|
290
|
+
* - Server errors (5xx)
|
|
291
|
+
* - Connection/network errors
|
|
292
|
+
* - Anthropic overloaded (529)
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```typescript
|
|
296
|
+
* const agent = new Agent({
|
|
297
|
+
* provider,
|
|
298
|
+
* retry: {
|
|
299
|
+
* maxAttempts: 5, // Max 5 retries
|
|
300
|
+
* baseDelayMs: 2000, // Start with 2s delay
|
|
301
|
+
* maxDelayMs: 60000, // Cap at 60s
|
|
302
|
+
* }
|
|
303
|
+
* });
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
retry?: RetryConfig;
|
|
271
307
|
/**
|
|
272
308
|
* Checkpointer for persisting agent state.
|
|
273
309
|
* If provided, enables checkpoint() and resume() functionality.
|
|
@@ -377,6 +413,15 @@ export interface AgentConfig {
|
|
|
377
413
|
* ```
|
|
378
414
|
*/
|
|
379
415
|
permissions?: PermissionManagerOptions;
|
|
416
|
+
/**
|
|
417
|
+
* Pre-existing PermissionManager instance.
|
|
418
|
+
*
|
|
419
|
+
* Use this to share a PermissionManager between agents (e.g., parent and sub-agents).
|
|
420
|
+
* When provided, takes precedence over `permissions` options.
|
|
421
|
+
*
|
|
422
|
+
* This is primarily used internally for sub-agent permission inheritance.
|
|
423
|
+
*/
|
|
424
|
+
permissionManager?: PermissionManager;
|
|
380
425
|
/**
|
|
381
426
|
* Pre-loaded project memory to prepend to system prompt.
|
|
382
427
|
*
|
|
@@ -649,6 +694,20 @@ export interface SubAgentConfig {
|
|
|
649
694
|
* Default: false (uses shared store)
|
|
650
695
|
*/
|
|
651
696
|
stateIsolation?: boolean;
|
|
697
|
+
/**
|
|
698
|
+
* Inherit parent's permission manager.
|
|
699
|
+
*
|
|
700
|
+
* When true (default), the sub-agent uses the parent's PermissionManager,
|
|
701
|
+
* sharing session grants and permission rules. This ensures:
|
|
702
|
+
* - Sub-agents follow the same permission rules as parent
|
|
703
|
+
* - Session grants from parent are available to sub-agents
|
|
704
|
+
* - User sees permission prompts for sub-agent tool usage
|
|
705
|
+
*
|
|
706
|
+
* Set to false to allow sub-agents to bypass permissions (use with caution).
|
|
707
|
+
*
|
|
708
|
+
* Default: true
|
|
709
|
+
*/
|
|
710
|
+
inheritPermissions?: boolean;
|
|
652
711
|
}
|
|
653
712
|
/**
|
|
654
713
|
* Result from a sub-agent execution
|
|
@@ -712,6 +771,7 @@ export declare class Agent {
|
|
|
712
771
|
private readonly autoContextManagement;
|
|
713
772
|
private readonly onEvent?;
|
|
714
773
|
private readonly onIterationLimitReached?;
|
|
774
|
+
private readonly retryConfig;
|
|
715
775
|
private readonly checkpointer?;
|
|
716
776
|
private readonly _sessionId;
|
|
717
777
|
private readonly autoCheckpoint;
|
|
@@ -1136,8 +1196,14 @@ export declare class Agent {
|
|
|
1136
1196
|
/**
|
|
1137
1197
|
* Set the conversation history (for manual compaction/restoration)
|
|
1138
1198
|
* Also updates the context manager's token count if configured.
|
|
1199
|
+
*
|
|
1200
|
+
* @param messages - The message history to restore
|
|
1201
|
+
* @param options - Optional restore options
|
|
1202
|
+
* @param options.turnCount - The turn count to restore (important for compaction)
|
|
1139
1203
|
*/
|
|
1140
|
-
setHistory(messages: Message[]
|
|
1204
|
+
setHistory(messages: Message[], options?: {
|
|
1205
|
+
turnCount?: number;
|
|
1206
|
+
}): Promise<this>;
|
|
1141
1207
|
/**
|
|
1142
1208
|
* Get the context manager (if configured)
|
|
1143
1209
|
*/
|
|
@@ -1454,9 +1520,24 @@ export declare class Agent {
|
|
|
1454
1520
|
* Process stream chunks into text, tool uses, and usage data
|
|
1455
1521
|
*/
|
|
1456
1522
|
private processChunks;
|
|
1523
|
+
/**
|
|
1524
|
+
* Wrap provider.chat() with automatic retry on transient errors.
|
|
1525
|
+
*
|
|
1526
|
+
* Retries the entire stream on failure with exponential backoff.
|
|
1527
|
+
* Emits llm_retry events before each retry attempt.
|
|
1528
|
+
*
|
|
1529
|
+
* @param messages - Messages to send
|
|
1530
|
+
* @param options - Chat options
|
|
1531
|
+
* @param emit - Event emitter function
|
|
1532
|
+
* @param signal - Optional abort signal
|
|
1533
|
+
*/
|
|
1534
|
+
private chatWithRetry;
|
|
1457
1535
|
/**
|
|
1458
1536
|
* Generate a summary of messages using the LLM provider.
|
|
1459
1537
|
* Used for context summarization when approaching limits.
|
|
1538
|
+
*
|
|
1539
|
+
* If anchors are configured, the summary will prioritize keeping
|
|
1540
|
+
* information related to anchor content (anchor-weighted summarization).
|
|
1460
1541
|
*/
|
|
1461
1542
|
private generateSummary;
|
|
1462
1543
|
/**
|
package/dist/agent.js
CHANGED
|
@@ -11,10 +11,11 @@ import { FileAccessTracker } from './context/file-tracker.js';
|
|
|
11
11
|
import { createFileTrackingHook } from './context/file-tracking-hook.js';
|
|
12
12
|
import { AnchorManager } from './anchors/manager.js';
|
|
13
13
|
import { GuardrailManager } from './guardrails/manager.js';
|
|
14
|
-
import { MaxIterationsError, ToolLoopError } from './errors.js';
|
|
14
|
+
import { MaxIterationsError, ToolLoopError, ProviderError } from './errors.js';
|
|
15
15
|
import { generateSessionId, createAgentState, deserializeTodos } from './state/agent-state.js';
|
|
16
16
|
import { getDefaultTodoStore, createIsolatedTodoStore } from './tools/builtin/todo.js';
|
|
17
17
|
import { repairToolPairing } from './messages/index.js';
|
|
18
|
+
import { DEFAULT_RETRY_CONFIG, withRetryGenerator } from './utils/index.js';
|
|
18
19
|
/**
|
|
19
20
|
* Agent class - orchestrates LLM interactions with tool use
|
|
20
21
|
*
|
|
@@ -44,6 +45,8 @@ export class Agent {
|
|
|
44
45
|
autoContextManagement;
|
|
45
46
|
onEvent;
|
|
46
47
|
onIterationLimitReached;
|
|
48
|
+
// Retry configuration
|
|
49
|
+
retryConfig;
|
|
47
50
|
// State management
|
|
48
51
|
checkpointer;
|
|
49
52
|
_sessionId;
|
|
@@ -120,7 +123,12 @@ export class Agent {
|
|
|
120
123
|
this.guardrailManager = new GuardrailManager(config.guardrails);
|
|
121
124
|
}
|
|
122
125
|
// Permission management
|
|
123
|
-
if (
|
|
126
|
+
// Use pre-existing permissionManager if provided (for sub-agent inheritance)
|
|
127
|
+
// Otherwise create one from options
|
|
128
|
+
if (config.permissionManager !== undefined) {
|
|
129
|
+
this.permissionManager = config.permissionManager;
|
|
130
|
+
}
|
|
131
|
+
else if (config.permissions !== undefined) {
|
|
124
132
|
this.permissionManager = new PermissionManager(config.permissions);
|
|
125
133
|
}
|
|
126
134
|
// Project memory - store and prepend to system prompt
|
|
@@ -183,6 +191,13 @@ export class Agent {
|
|
|
183
191
|
// Hooks manager without file tracking
|
|
184
192
|
this.hooksManager = new HooksManager({ hooks: config.hooks });
|
|
185
193
|
}
|
|
194
|
+
// Retry configuration with defaults
|
|
195
|
+
this.retryConfig = {
|
|
196
|
+
enabled: config.retry?.enabled ?? DEFAULT_RETRY_CONFIG.enabled,
|
|
197
|
+
maxAttempts: config.retry?.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts,
|
|
198
|
+
baseDelayMs: config.retry?.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs,
|
|
199
|
+
maxDelayMs: config.retry?.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs,
|
|
200
|
+
};
|
|
186
201
|
}
|
|
187
202
|
// ==========================================================================
|
|
188
203
|
// Static Factory Methods
|
|
@@ -710,11 +725,28 @@ export class Agent {
|
|
|
710
725
|
/**
|
|
711
726
|
* Set the conversation history (for manual compaction/restoration)
|
|
712
727
|
* Also updates the context manager's token count if configured.
|
|
728
|
+
*
|
|
729
|
+
* @param messages - The message history to restore
|
|
730
|
+
* @param options - Optional restore options
|
|
731
|
+
* @param options.turnCount - The turn count to restore (important for compaction)
|
|
713
732
|
*/
|
|
714
|
-
async setHistory(messages) {
|
|
715
|
-
|
|
733
|
+
async setHistory(messages, options) {
|
|
734
|
+
// Repair tool_use/tool_result pairing to fix any corrupted messages
|
|
735
|
+
// This is especially important after resuming from a saved session
|
|
736
|
+
const repairedMessages = repairToolPairing(messages);
|
|
737
|
+
this.conversationHistory = [...repairedMessages];
|
|
716
738
|
if (this.contextManager) {
|
|
717
|
-
await this.contextManager.updateTokenCount(
|
|
739
|
+
await this.contextManager.updateTokenCount(repairedMessages);
|
|
740
|
+
// Restore turn count if provided
|
|
741
|
+
if (options?.turnCount !== undefined) {
|
|
742
|
+
this.contextManager.setTurnCount(options.turnCount);
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
745
|
+
// Infer turn count from messages as a fallback
|
|
746
|
+
// Count user messages as a proxy for turns
|
|
747
|
+
const inferredTurnCount = repairedMessages.filter((m) => m.role === 'user').length;
|
|
748
|
+
this.contextManager.setTurnCount(inferredTurnCount);
|
|
749
|
+
}
|
|
718
750
|
}
|
|
719
751
|
return this;
|
|
720
752
|
}
|
|
@@ -926,6 +958,7 @@ export class Agent {
|
|
|
926
958
|
messages: this.conversationHistory,
|
|
927
959
|
todos: todoStore.getAll(),
|
|
928
960
|
currentIteration: this._currentIteration,
|
|
961
|
+
turnCount: this.contextManager?.getTurnCount() ?? 0,
|
|
929
962
|
totalTokensUsed: this._totalTokensUsed,
|
|
930
963
|
createdAt: this._createdAt,
|
|
931
964
|
});
|
|
@@ -1054,6 +1087,11 @@ export class Agent {
|
|
|
1054
1087
|
agent._createdAt = state.createdAt;
|
|
1055
1088
|
agent._totalTokensUsed = state.totalTokensUsed;
|
|
1056
1089
|
agent._currentIteration = state.currentIteration;
|
|
1090
|
+
// Restore turn count to context manager if configured
|
|
1091
|
+
// Note: turnCount is guaranteed to exist - deserializer ensures backward compatibility
|
|
1092
|
+
if (agent.contextManager) {
|
|
1093
|
+
agent.contextManager.setTurnCount(state.turnCount);
|
|
1094
|
+
}
|
|
1057
1095
|
// Restore todos
|
|
1058
1096
|
if (state.todos.length > 0) {
|
|
1059
1097
|
const todoStore = getDefaultTodoStore();
|
|
@@ -1118,6 +1156,9 @@ export class Agent {
|
|
|
1118
1156
|
for (const tool of toolsToRegister) {
|
|
1119
1157
|
subAgentToolRegistry.register(tool);
|
|
1120
1158
|
}
|
|
1159
|
+
// Determine if sub-agent should inherit parent's permissions
|
|
1160
|
+
// Default: true (sub-agents follow same permission rules as parent)
|
|
1161
|
+
const inheritPermissions = config.inheritPermissions ?? true;
|
|
1121
1162
|
// Create the sub-agent
|
|
1122
1163
|
const subAgent = new Agent({
|
|
1123
1164
|
provider: this.provider,
|
|
@@ -1128,6 +1169,12 @@ export class Agent {
|
|
|
1128
1169
|
contextManager: subAgentContextManager,
|
|
1129
1170
|
autoContextManagement: true,
|
|
1130
1171
|
onEvent: this.onEvent, // Forward events to parent
|
|
1172
|
+
// Sub-agents should summarize their findings when hitting iteration limit
|
|
1173
|
+
// rather than throwing an error with no response
|
|
1174
|
+
iterationLimitBehavior: 'summarize',
|
|
1175
|
+
// Inherit parent's permission manager if enabled
|
|
1176
|
+
// This shares session grants and permission rules with sub-agents
|
|
1177
|
+
permissionManager: inheritPermissions ? this.permissionManager : undefined,
|
|
1131
1178
|
});
|
|
1132
1179
|
// Store the sub-agent
|
|
1133
1180
|
this.subAgents.set(config.name, { config, agent: subAgent });
|
|
@@ -1390,22 +1437,34 @@ export class Agent {
|
|
|
1390
1437
|
// Build messages: system prompt + history + new user message
|
|
1391
1438
|
let messages = [];
|
|
1392
1439
|
// Add system message if present
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
});
|
|
1398
|
-
}
|
|
1399
|
-
// Inject anchors (critical information that survives context compaction)
|
|
1440
|
+
// NOTE: Anchors are now appended to the system prompt (not a separate message)
|
|
1441
|
+
// to avoid multiple system messages which can confuse Claude's role identity
|
|
1442
|
+
let systemContent = this.systemPrompt;
|
|
1443
|
+
// Inject anchors into the system prompt (not as separate message)
|
|
1400
1444
|
if (this.anchorManager && this.anchorManager.size > 0) {
|
|
1401
1445
|
const anchorsContent = this.anchorManager.format();
|
|
1402
1446
|
if (anchorsContent) {
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1447
|
+
// Insert anchors BEFORE the role ending (if present) so role reinforcement stays at the end
|
|
1448
|
+
const roleEndingMarker = '## YOUR ASSIGNED ROLE:';
|
|
1449
|
+
const roleEndingIndex = systemContent.indexOf(roleEndingMarker);
|
|
1450
|
+
if (roleEndingIndex > 0) {
|
|
1451
|
+
// Insert anchors before the role ending
|
|
1452
|
+
const beforeRole = systemContent.substring(0, roleEndingIndex);
|
|
1453
|
+
const roleEnding = systemContent.substring(roleEndingIndex);
|
|
1454
|
+
systemContent = `${beforeRole}\n\n---\n\n## Active Anchors (Critical Information)\n\n${anchorsContent}\n\n---\n\n${roleEnding}`;
|
|
1455
|
+
}
|
|
1456
|
+
else {
|
|
1457
|
+
// No role ending, just append anchors
|
|
1458
|
+
systemContent = `${systemContent}\n\n---\n\n## Active Anchors (Critical Information)\n\n${anchorsContent}`;
|
|
1459
|
+
}
|
|
1407
1460
|
}
|
|
1408
1461
|
}
|
|
1462
|
+
if (systemContent) {
|
|
1463
|
+
messages.push({
|
|
1464
|
+
role: 'system',
|
|
1465
|
+
content: systemContent,
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1409
1468
|
// Add conversation history
|
|
1410
1469
|
messages.push(...this.conversationHistory);
|
|
1411
1470
|
// Add new user message
|
|
@@ -1514,10 +1573,10 @@ export class Agent {
|
|
|
1514
1573
|
const llmStartTime = Date.now();
|
|
1515
1574
|
const chunks = [];
|
|
1516
1575
|
try {
|
|
1517
|
-
for await (const chunk of this.
|
|
1576
|
+
for await (const chunk of this.chatWithRetry(messages, {
|
|
1518
1577
|
...chatOptions,
|
|
1519
1578
|
tools: tools.length > 0 ? tools : undefined,
|
|
1520
|
-
})) {
|
|
1579
|
+
}, emit, signal)) {
|
|
1521
1580
|
// Check for abort during streaming
|
|
1522
1581
|
if (signal?.aborted) {
|
|
1523
1582
|
aborted = true;
|
|
@@ -1615,6 +1674,7 @@ export class Agent {
|
|
|
1615
1674
|
id: tu.id,
|
|
1616
1675
|
name: tu.name,
|
|
1617
1676
|
input: tu.input,
|
|
1677
|
+
signature: tu.signature, // Gemini 3 thought signature (required for multi-turn)
|
|
1618
1678
|
})),
|
|
1619
1679
|
],
|
|
1620
1680
|
};
|
|
@@ -2111,6 +2171,7 @@ export class Agent {
|
|
|
2111
2171
|
id: chunk.toolUse.id,
|
|
2112
2172
|
name: chunk.toolUse.name,
|
|
2113
2173
|
inputJson: '',
|
|
2174
|
+
signature: chunk.toolUse.signature, // Capture Gemini 3 thought signature
|
|
2114
2175
|
};
|
|
2115
2176
|
}
|
|
2116
2177
|
break;
|
|
@@ -2129,6 +2190,7 @@ export class Agent {
|
|
|
2129
2190
|
id: currentToolUse.id,
|
|
2130
2191
|
name: currentToolUse.name,
|
|
2131
2192
|
input,
|
|
2193
|
+
signature: currentToolUse.signature, // Pass through the signature
|
|
2132
2194
|
});
|
|
2133
2195
|
}
|
|
2134
2196
|
catch {
|
|
@@ -2146,27 +2208,100 @@ export class Agent {
|
|
|
2146
2208
|
}
|
|
2147
2209
|
return { text, toolUses, usage, model };
|
|
2148
2210
|
}
|
|
2211
|
+
/**
|
|
2212
|
+
* Wrap provider.chat() with automatic retry on transient errors.
|
|
2213
|
+
*
|
|
2214
|
+
* Retries the entire stream on failure with exponential backoff.
|
|
2215
|
+
* Emits llm_retry events before each retry attempt.
|
|
2216
|
+
*
|
|
2217
|
+
* @param messages - Messages to send
|
|
2218
|
+
* @param options - Chat options
|
|
2219
|
+
* @param emit - Event emitter function
|
|
2220
|
+
* @param signal - Optional abort signal
|
|
2221
|
+
*/
|
|
2222
|
+
chatWithRetry(messages, options, emit, signal) {
|
|
2223
|
+
// If retry is disabled, return the raw provider stream
|
|
2224
|
+
if (!this.retryConfig.enabled) {
|
|
2225
|
+
return this.provider.chat(messages, options);
|
|
2226
|
+
}
|
|
2227
|
+
const providerName = this.provider.name;
|
|
2228
|
+
const { maxAttempts, baseDelayMs, maxDelayMs } = this.retryConfig;
|
|
2229
|
+
return withRetryGenerator(() => this.provider.chat(messages, options), {
|
|
2230
|
+
maxAttempts,
|
|
2231
|
+
baseDelayMs,
|
|
2232
|
+
maxDelayMs,
|
|
2233
|
+
isRetryable: (error) => {
|
|
2234
|
+
// Use the ProviderError's built-in retryable check
|
|
2235
|
+
return error instanceof ProviderError && error.isRetryable();
|
|
2236
|
+
},
|
|
2237
|
+
onRetry: (attempt, max, error, delayMs) => {
|
|
2238
|
+
emit({
|
|
2239
|
+
type: 'llm_retry',
|
|
2240
|
+
attempt,
|
|
2241
|
+
maxAttempts: max,
|
|
2242
|
+
error: error.message,
|
|
2243
|
+
delayMs,
|
|
2244
|
+
provider: providerName,
|
|
2245
|
+
});
|
|
2246
|
+
},
|
|
2247
|
+
onExhausted: (attempts, error) => {
|
|
2248
|
+
emit({
|
|
2249
|
+
type: 'llm_retry_exhausted',
|
|
2250
|
+
attempts,
|
|
2251
|
+
error: error.message,
|
|
2252
|
+
provider: providerName,
|
|
2253
|
+
});
|
|
2254
|
+
},
|
|
2255
|
+
signal,
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
2149
2258
|
/**
|
|
2150
2259
|
* Generate a summary of messages using the LLM provider.
|
|
2151
2260
|
* Used for context summarization when approaching limits.
|
|
2261
|
+
*
|
|
2262
|
+
* If anchors are configured, the summary will prioritize keeping
|
|
2263
|
+
* information related to anchor content (anchor-weighted summarization).
|
|
2152
2264
|
*/
|
|
2153
2265
|
async generateSummary(messages) {
|
|
2266
|
+
// Build anchor context if available (for weighted summarization)
|
|
2267
|
+
let anchorContext = '';
|
|
2268
|
+
if (this.anchorManager && this.anchorManager.size > 0) {
|
|
2269
|
+
const anchors = this.anchorManager.getAll();
|
|
2270
|
+
if (anchors.length > 0) {
|
|
2271
|
+
const anchorItems = anchors.map((a) => `- [${a.priority}] ${a.content}`).join('\n');
|
|
2272
|
+
anchorContext = `
|
|
2273
|
+
## PRIORITY CONTEXT (Anchors)
|
|
2274
|
+
|
|
2275
|
+
The following are critical anchors that should be preserved in context. When summarizing,
|
|
2276
|
+
PRIORITIZE keeping information that relates to these anchors:
|
|
2277
|
+
|
|
2278
|
+
${anchorItems}
|
|
2279
|
+
|
|
2280
|
+
Ensure the summary captures any conversation details related to these anchors.
|
|
2281
|
+
`;
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2154
2284
|
const summaryPrompt = `Please provide a concise summary of the following conversation. Focus on:
|
|
2155
2285
|
1. Key decisions made
|
|
2156
2286
|
2. Important context established
|
|
2157
2287
|
3. Tasks completed or in progress
|
|
2158
2288
|
4. Any relevant file paths or code snippets mentioned
|
|
2159
|
-
|
|
2289
|
+
${anchorContext ? '5. Information related to the priority anchors listed below' : ''}
|
|
2290
|
+
${anchorContext}
|
|
2160
2291
|
Keep the summary under 500 words.
|
|
2161
2292
|
|
|
2162
2293
|
Conversation to summarize:
|
|
2163
2294
|
${messages.map((m) => `${m.role}: ${typeof m.content === 'string' ? m.content : JSON.stringify(m.content)}`).join('\n\n')}`;
|
|
2164
2295
|
const summaryMessages = [{ role: 'user', content: summaryPrompt }];
|
|
2296
|
+
// Create emit function for retry events (uses main event handler)
|
|
2297
|
+
const emit = (event) => {
|
|
2298
|
+
this.onEvent?.(event);
|
|
2299
|
+
};
|
|
2165
2300
|
let summary = '';
|
|
2166
|
-
for await (const chunk of this.
|
|
2301
|
+
for await (const chunk of this.chatWithRetry(summaryMessages, {
|
|
2167
2302
|
...this.chatOptions,
|
|
2168
2303
|
maxTokens: this.contextManager?.getConfig().summarization.summaryMaxTokens ?? 2000,
|
|
2169
|
-
})) {
|
|
2304
|
+
}, emit)) {
|
|
2170
2305
|
if (chunk.type === 'text' && chunk.text) {
|
|
2171
2306
|
summary += chunk.text;
|
|
2172
2307
|
}
|
|
@@ -2205,11 +2340,15 @@ ${messages
|
|
|
2205
2340
|
.map((m) => `${m.role}: ${typeof m.content === 'string' ? m.content.slice(0, 500) : '[complex content]'}`)
|
|
2206
2341
|
.join('\n\n')}`;
|
|
2207
2342
|
const summaryMessages = [{ role: 'user', content: summaryPrompt }];
|
|
2343
|
+
// Create emit function for retry events (uses main event handler)
|
|
2344
|
+
const emit = (event) => {
|
|
2345
|
+
this.onEvent?.(event);
|
|
2346
|
+
};
|
|
2208
2347
|
let summary = '';
|
|
2209
|
-
for await (const chunk of this.
|
|
2348
|
+
for await (const chunk of this.chatWithRetry(summaryMessages, {
|
|
2210
2349
|
...this.chatOptions,
|
|
2211
2350
|
maxTokens: 1000, // Keep summary concise
|
|
2212
|
-
})) {
|
|
2351
|
+
}, emit)) {
|
|
2213
2352
|
if (chunk.type === 'text' && chunk.text) {
|
|
2214
2353
|
summary += chunk.text;
|
|
2215
2354
|
}
|
|
@@ -98,6 +98,14 @@ export declare class ContextManager {
|
|
|
98
98
|
* Increment turn count (call after each assistant response)
|
|
99
99
|
*/
|
|
100
100
|
incrementTurn(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Get the current turn count
|
|
103
|
+
*/
|
|
104
|
+
getTurnCount(): number;
|
|
105
|
+
/**
|
|
106
|
+
* Set the turn count (for restoring from saved state)
|
|
107
|
+
*/
|
|
108
|
+
setTurnCount(count: number): void;
|
|
101
109
|
/**
|
|
102
110
|
* Check if compaction is needed
|
|
103
111
|
*/
|
package/dist/context/manager.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* }
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
|
+
import { repairToolPairing } from '../messages/index.js';
|
|
20
21
|
/**
|
|
21
22
|
* Default budget allocation
|
|
22
23
|
*/
|
|
@@ -176,6 +177,23 @@ export class ContextManager {
|
|
|
176
177
|
incrementTurn() {
|
|
177
178
|
this.turnCount++;
|
|
178
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Get the current turn count
|
|
182
|
+
*/
|
|
183
|
+
getTurnCount() {
|
|
184
|
+
return this.turnCount;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Set the turn count (for restoring from saved state)
|
|
188
|
+
*/
|
|
189
|
+
setTurnCount(count) {
|
|
190
|
+
this.turnCount = count;
|
|
191
|
+
// If we're restoring state, assume last compaction was at turn 0
|
|
192
|
+
// to prevent immediate compaction after restore
|
|
193
|
+
if (this.lastCompactionTurn === 0 && count > 0) {
|
|
194
|
+
this.lastCompactionTurn = count;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
179
197
|
/**
|
|
180
198
|
* Check if compaction is needed
|
|
181
199
|
*/
|
|
@@ -588,12 +606,15 @@ export class ContextManager {
|
|
|
588
606
|
}
|
|
589
607
|
// Reconstruct messages in original order
|
|
590
608
|
// System messages come first, then summary (if any), then tool results, then recent
|
|
591
|
-
|
|
609
|
+
let finalMessages = [
|
|
592
610
|
...categorized.system,
|
|
593
611
|
...compactedHistory,
|
|
594
612
|
...compactedToolResults,
|
|
595
613
|
...categorized.recentMessages,
|
|
596
614
|
];
|
|
615
|
+
// Repair tool_use/tool_result pairing after compaction
|
|
616
|
+
// This fixes orphaned blocks that cause API errors
|
|
617
|
+
finalMessages = repairToolPairing(finalMessages);
|
|
597
618
|
// If history was summarized, add assistant acknowledgment after summary
|
|
598
619
|
if (categoryStats.history.action === 'summarized' && compactedHistory.length > 0) {
|
|
599
620
|
// Insert assistant acknowledgment after the summary message
|
|
@@ -894,7 +915,9 @@ export class ContextManager {
|
|
|
894
915
|
compactedOld.push({ ...msg, content: compactedBlocks });
|
|
895
916
|
}
|
|
896
917
|
}
|
|
897
|
-
|
|
918
|
+
// Repair tool_use/tool_result pairing after compaction
|
|
919
|
+
// This fixes orphaned blocks that cause API errors
|
|
920
|
+
const compactedMessages = repairToolPairing([...compactedOld, ...recentMessages]);
|
|
898
921
|
const tokensAfter = await this.countTokens(compactedMessages);
|
|
899
922
|
this.compactionCount++;
|
|
900
923
|
this.lastCompactionTurn = this.turnCount;
|
package/dist/errors.d.ts
CHANGED
|
@@ -43,7 +43,26 @@ export declare class ProviderError extends AgentError {
|
|
|
43
43
|
*/
|
|
44
44
|
isServerError(): boolean;
|
|
45
45
|
/**
|
|
46
|
-
* Check if this
|
|
46
|
+
* Check if this is a connection/network error.
|
|
47
|
+
* These errors typically have no status code but are retryable.
|
|
48
|
+
*/
|
|
49
|
+
isConnectionError(): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Check if this is an Anthropic overloaded error (529)
|
|
52
|
+
*/
|
|
53
|
+
isOverloadedError(): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Check if this error is retryable.
|
|
56
|
+
* Retryable errors include:
|
|
57
|
+
* - Rate limit (429)
|
|
58
|
+
* - Server errors (5xx)
|
|
59
|
+
* - Connection/network errors
|
|
60
|
+
* - Anthropic overloaded (529)
|
|
61
|
+
*
|
|
62
|
+
* Non-retryable errors include:
|
|
63
|
+
* - Authentication errors (401, 403)
|
|
64
|
+
* - Bad request (400)
|
|
65
|
+
* - Not found (404)
|
|
47
66
|
*/
|
|
48
67
|
isRetryable(): boolean;
|
|
49
68
|
}
|
package/dist/errors.js
CHANGED
|
@@ -62,10 +62,52 @@ export class ProviderError extends AgentError {
|
|
|
62
62
|
return this.statusCode !== undefined && this.statusCode >= 500 && this.statusCode < 600;
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
* Check if this
|
|
65
|
+
* Check if this is a connection/network error.
|
|
66
|
+
* These errors typically have no status code but are retryable.
|
|
67
|
+
*/
|
|
68
|
+
isConnectionError() {
|
|
69
|
+
if (this.statusCode !== undefined) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const msg = this.message.toLowerCase();
|
|
73
|
+
return (msg.includes('connection') ||
|
|
74
|
+
msg.includes('econnrefused') ||
|
|
75
|
+
msg.includes('econnreset') ||
|
|
76
|
+
msg.includes('etimedout') ||
|
|
77
|
+
msg.includes('enotfound') ||
|
|
78
|
+
msg.includes('network') ||
|
|
79
|
+
msg.includes('socket') ||
|
|
80
|
+
msg.includes('dns'));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if this is an Anthropic overloaded error (529)
|
|
84
|
+
*/
|
|
85
|
+
isOverloadedError() {
|
|
86
|
+
return this.statusCode === 529;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Check if this error is retryable.
|
|
90
|
+
* Retryable errors include:
|
|
91
|
+
* - Rate limit (429)
|
|
92
|
+
* - Server errors (5xx)
|
|
93
|
+
* - Connection/network errors
|
|
94
|
+
* - Anthropic overloaded (529)
|
|
95
|
+
*
|
|
96
|
+
* Non-retryable errors include:
|
|
97
|
+
* - Authentication errors (401, 403)
|
|
98
|
+
* - Bad request (400)
|
|
99
|
+
* - Not found (404)
|
|
66
100
|
*/
|
|
67
101
|
isRetryable() {
|
|
68
|
-
|
|
102
|
+
// Never retry auth errors
|
|
103
|
+
if (this.isAuthError()) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
// Retry transient errors
|
|
107
|
+
return (this.isRateLimitError() ||
|
|
108
|
+
this.isServerError() ||
|
|
109
|
+
this.isConnectionError() ||
|
|
110
|
+
this.isOverloadedError());
|
|
69
111
|
}
|
|
70
112
|
}
|
|
71
113
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,10 @@ export { OpenAIProvider, createOpenAIProvider } from './providers/index.js';
|
|
|
15
15
|
export type { OpenAIProviderConfig } from './providers/index.js';
|
|
16
16
|
export { GeminiProvider, createGeminiProvider } from './providers/index.js';
|
|
17
17
|
export type { GeminiProviderConfig } from './providers/index.js';
|
|
18
|
+
export { GeminiNativeProvider, createGeminiNativeProvider } from './providers/index.js';
|
|
19
|
+
export type { GeminiNativeProviderConfig } from './providers/index.js';
|
|
20
|
+
export { GeminiLegacyProvider, createGeminiLegacyProvider } from './providers/index.js';
|
|
21
|
+
export type { GeminiLegacyProviderConfig } from './providers/index.js';
|
|
18
22
|
export { OpenAICompatibleProvider } from './providers/index.js';
|
|
19
23
|
export type { OpenAICompatibleConfig } from './providers/index.js';
|
|
20
24
|
export type { Tool, ToolHandler, ToolRegistry, ToolInputSchema, ToolExecutionResult, ToolRegistryOptions, DefineToolOptions, ReadFileInput, WriteFileInput, BashInput, BashResult, FifoDetectionResult, GrepInput, GlobInput, EditInput, TodoWriteInput, TodoReadInput, TodoItem, TodoStatus, TodoContextCleanupOptions, TaskInput, TaskResult, AgentTypeConfig, TaskToolOptions, ContextMode, ThoroughnessLevel, SubAgentEventInfo, SuggestInput, SuggestToolOptions, } from './tools/index.js';
|
|
@@ -22,7 +26,8 @@ export { defineTool, createSuccessResult, createErrorResult, wrapToolExecute, De
|
|
|
22
26
|
export { readFileTool, createReadFileTool, writeFileTool, createWriteFileTool, bashTool, createBashTool, execStream, detectFifoUsage, bashOutputTool, createBashOutputTool, killShellTool, createKillShellTool, ShellManager, getDefaultShellManager, setDefaultShellManager, grepTool, createGrepTool, globTool, createGlobTool, editTool, createEditTool, todoWriteTool, todoReadTool, createTodoTools, TodoStore, resetDefaultTodoStore, getDefaultTodoStore, createIsolatedTodoStore, cleanupTodoContextMessages, getTodoContextStats, webFetchTool, createWebFetchTool, createTaskTool, defaultAgentTypes, suggestTool, createSuggestTool, builtinTools, allBuiltinTools, TOOL_NAMES, TOOL_SETS, } from './tools/index.js';
|
|
23
27
|
export { userMessage, assistantMessage, systemMessage, textBlock, toolUseBlock, toolResultBlock, getTextContent, getToolUses, getToolResults, hasToolUses, validateToolUseResultPairing, repairToolPairing, ensureMessageContent, normalizeMessages, } from './messages/index.js';
|
|
24
28
|
export type { ToolPairingValidation } from './messages/index.js';
|
|
25
|
-
export { generateId, sleep, retry, truncate } from './utils/index.js';
|
|
29
|
+
export { generateId, sleep, retry, truncate, withRetryGenerator, calculateBackoffDelay, DEFAULT_RETRY_CONFIG, } from './utils/index.js';
|
|
30
|
+
export type { RetryConfig as LLMRetryConfig, WithRetryOptions } from './utils/index.js';
|
|
26
31
|
export { AgentError, ProviderError, ToolError, ToolTimeoutError, ToolLoopError, ValidationError, MaxIterationsError, AbortError, ContextOverflowError, isAgentError, isProviderError, isToolError, isToolTimeoutError, isToolLoopError, isContextOverflowError, wrapError, } from './errors.js';
|
|
27
32
|
export { ContextManager, DEFAULT_CONTEXT_CONFIG, FileAccessTracker, createFileTrackingHook, TRACKED_TOOLS, } from './context/index.js';
|
|
28
33
|
export type { ContextManagerOptions, ContextCategory, BudgetAllocation, CategoryBudgetInfo, PreflightResult, VerbosityLevel, VerbosityConfig, ContextConfig, FilteringConfig, CompactionConfig, SummarizationConfig, CompactionResult, SummarizationResult, FilteringResult, ContextEvent, ContextEventHandler, ContextStats, FileAccessType, FileAccess, FileAccessTrackerOptions, FormatHintsOptions, FileAccessStats, } from './context/index.js';
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,10 @@ export { ClaudeProvider, createClaudeProvider } from './providers/index.js';
|
|
|
11
11
|
export { OllamaProvider, createOllamaProvider } from './providers/index.js';
|
|
12
12
|
export { OpenAIProvider, createOpenAIProvider } from './providers/index.js';
|
|
13
13
|
export { GeminiProvider, createGeminiProvider } from './providers/index.js';
|
|
14
|
+
// Also export native Gemini provider explicitly for clarity
|
|
15
|
+
export { GeminiNativeProvider, createGeminiNativeProvider } from './providers/index.js';
|
|
16
|
+
// Legacy Gemini provider (OpenAI-compatible endpoint)
|
|
17
|
+
export { GeminiLegacyProvider, createGeminiLegacyProvider } from './providers/index.js';
|
|
14
18
|
export { OpenAICompatibleProvider } from './providers/index.js';
|
|
15
19
|
// Tool utilities
|
|
16
20
|
export { defineTool, createSuccessResult, createErrorResult, wrapToolExecute, DefaultToolRegistry, createToolRegistry, } from './tools/index.js';
|
|
@@ -25,7 +29,9 @@ TOOL_NAMES, TOOL_SETS, } from './tools/index.js';
|
|
|
25
29
|
// Message utilities
|
|
26
30
|
export { userMessage, assistantMessage, systemMessage, textBlock, toolUseBlock, toolResultBlock, getTextContent, getToolUses, getToolResults, hasToolUses, validateToolUseResultPairing, repairToolPairing, ensureMessageContent, normalizeMessages, } from './messages/index.js';
|
|
27
31
|
// Utilities
|
|
28
|
-
export { generateId, sleep,
|
|
32
|
+
export { generateId, sleep,
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- Kept for backward compatibility
|
|
34
|
+
retry, truncate, withRetryGenerator, calculateBackoffDelay, DEFAULT_RETRY_CONFIG, } from './utils/index.js';
|
|
29
35
|
// Errors
|
|
30
36
|
export { AgentError, ProviderError, ToolError, ToolTimeoutError, ToolLoopError, ValidationError, MaxIterationsError, AbortError, ContextOverflowError, isAgentError, isProviderError, isToolError, isToolTimeoutError, isToolLoopError, isContextOverflowError, wrapError, } from './errors.js';
|
|
31
37
|
// Context management
|