@compilr-dev/agents 0.3.11 → 0.3.13
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 +42 -1
- package/dist/agent.js +116 -17
- package/dist/anchors/manager.js +3 -2
- package/dist/context/delegated-result-store.d.ts +67 -0
- package/dist/context/delegated-result-store.js +99 -0
- package/dist/context/delegation-types.d.ts +82 -0
- package/dist/context/delegation-types.js +18 -0
- package/dist/context/file-tracker.d.ts +59 -1
- package/dist/context/file-tracker.js +96 -1
- package/dist/context/file-tracking-hook.js +9 -4
- package/dist/context/index.d.ts +7 -1
- package/dist/context/index.js +4 -0
- package/dist/context/manager.js +12 -32
- package/dist/context/tool-result-delegator.d.ts +63 -0
- package/dist/context/tool-result-delegator.js +314 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +9 -3
- package/dist/memory/loader.js +2 -1
- package/dist/memory/types.d.ts +1 -1
- package/dist/providers/claude.d.ts +1 -5
- package/dist/providers/claude.js +6 -29
- package/dist/providers/gemini-native.d.ts +1 -1
- package/dist/providers/gemini-native.js +10 -24
- package/dist/providers/mock.d.ts +1 -1
- package/dist/providers/mock.js +3 -24
- package/dist/providers/openai-compatible.d.ts +1 -5
- package/dist/providers/openai-compatible.js +14 -28
- package/dist/providers/types.d.ts +5 -0
- package/dist/rate-limit/provider-wrapper.d.ts +1 -1
- package/dist/rate-limit/provider-wrapper.js +3 -27
- package/dist/tools/builtin/index.d.ts +2 -0
- package/dist/tools/builtin/index.js +2 -0
- package/dist/tools/builtin/recall-result.d.ts +29 -0
- package/dist/tools/builtin/recall-result.js +48 -0
- package/dist/tools/builtin/task.js +1 -0
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js +2 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/tokenizer.d.ts +19 -0
- package/dist/utils/tokenizer.js +93 -0
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -31,16 +31,16 @@ export { PerplexityProvider, createPerplexityProvider } from './providers/index.
|
|
|
31
31
|
export type { PerplexityProviderConfig } from './providers/index.js';
|
|
32
32
|
export { OpenRouterProvider, createOpenRouterProvider } from './providers/index.js';
|
|
33
33
|
export type { OpenRouterProviderConfig } from './providers/index.js';
|
|
34
|
-
export type { Tool, ToolHandler, ToolRegistry, ToolInputSchema, ToolExecutionResult, ToolRegistryOptions, ToolFallbackHandler, 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';
|
|
34
|
+
export type { Tool, ToolHandler, ToolRegistry, ToolInputSchema, ToolExecutionResult, ToolRegistryOptions, ToolFallbackHandler, DefineToolOptions, ReadFileInput, WriteFileInput, BashInput, BashResult, FifoDetectionResult, GrepInput, GlobInput, EditInput, TodoWriteInput, TodoReadInput, TodoItem, TodoStatus, TodoContextCleanupOptions, TaskInput, TaskResult, AgentTypeConfig, TaskToolOptions, ContextMode, ThoroughnessLevel, SubAgentEventInfo, SuggestInput, SuggestToolOptions, RecallResultInput, RecallResultToolOptions, } from './tools/index.js';
|
|
35
35
|
export { defineTool, createSuccessResult, createErrorResult, wrapToolExecute, DefaultToolRegistry, createToolRegistry, } from './tools/index.js';
|
|
36
|
-
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';
|
|
36
|
+
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, createRecallResultTool, builtinTools, allBuiltinTools, TOOL_NAMES, TOOL_SETS, } from './tools/index.js';
|
|
37
37
|
export { userMessage, assistantMessage, systemMessage, textBlock, toolUseBlock, toolResultBlock, getTextContent, getToolUses, getToolResults, hasToolUses, validateToolUseResultPairing, repairToolPairing, ensureMessageContent, normalizeMessages, } from './messages/index.js';
|
|
38
38
|
export type { ToolPairingValidation } from './messages/index.js';
|
|
39
|
-
export { generateId, sleep, retry, truncate, withRetryGenerator, calculateBackoffDelay, DEFAULT_RETRY_CONFIG, } from './utils/index.js';
|
|
39
|
+
export { generateId, sleep, retry, truncate, withRetryGenerator, calculateBackoffDelay, DEFAULT_RETRY_CONFIG, countTokens, countMessageTokens, } from './utils/index.js';
|
|
40
40
|
export type { RetryConfig as LLMRetryConfig, WithRetryOptions } from './utils/index.js';
|
|
41
41
|
export { AgentError, ProviderError, ToolError, ToolTimeoutError, ToolLoopError, ValidationError, MaxIterationsError, AbortError, ContextOverflowError, isAgentError, isProviderError, isToolError, isToolTimeoutError, isToolLoopError, isContextOverflowError, wrapError, } from './errors.js';
|
|
42
|
-
export { ContextManager, DEFAULT_CONTEXT_CONFIG, FileAccessTracker, createFileTrackingHook, TRACKED_TOOLS, } from './context/index.js';
|
|
43
|
-
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';
|
|
42
|
+
export { ContextManager, DEFAULT_CONTEXT_CONFIG, FileAccessTracker, createFileTrackingHook, TRACKED_TOOLS, DelegatedResultStore, ToolResultDelegator, DELEGATION_SYSTEM_PROMPT, DEFAULT_DELEGATION_CONFIG, } from './context/index.js';
|
|
43
|
+
export type { ContextManagerOptions, ContextCategory, BudgetAllocation, CategoryBudgetInfo, PreflightResult, VerbosityLevel, VerbosityConfig, ContextConfig, FilteringConfig, CompactionConfig, SummarizationConfig, CompactionResult, SummarizationResult, FilteringResult, ContextEvent, ContextEventHandler, ContextStats, FileAccessType, FileAccess, FileAccessTrackerOptions, FormatHintsOptions, FileAccessStats, RestorationHintMessage, DelegatedResultStoreStats, ToolResultDelegatorOptions, DelegationConfig, StoredResult, DelegationEvent, } from './context/index.js';
|
|
44
44
|
export { SkillRegistry, defineSkill, createSkillRegistry, builtinSkills, getDefaultSkillRegistry, resetDefaultSkillRegistry, } from './skills/index.js';
|
|
45
45
|
export type { Skill, SkillInvocationResult, SkillInvokeOptions } from './skills/index.js';
|
|
46
46
|
export { JsonSerializer, CompactJsonSerializer, defaultSerializer, MemoryCheckpointer, FileCheckpointer, StateError, StateErrorCode, CURRENT_STATE_VERSION, } from './state/index.js';
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,9 @@ export { readFileTool, createReadFileTool, writeFileTool, createWriteFileTool, b
|
|
|
29
29
|
// Task tool (sub-agent spawning)
|
|
30
30
|
createTaskTool, defaultAgentTypes,
|
|
31
31
|
// Suggest tool (next action suggestions)
|
|
32
|
-
suggestTool, createSuggestTool,
|
|
32
|
+
suggestTool, createSuggestTool,
|
|
33
|
+
// Recall result tool (delegation)
|
|
34
|
+
createRecallResultTool, builtinTools, allBuiltinTools,
|
|
33
35
|
// Tool names - single source of truth
|
|
34
36
|
TOOL_NAMES, TOOL_SETS, } from './tools/index.js';
|
|
35
37
|
// Message utilities
|
|
@@ -37,11 +39,15 @@ export { userMessage, assistantMessage, systemMessage, textBlock, toolUseBlock,
|
|
|
37
39
|
// Utilities
|
|
38
40
|
export { generateId, sleep,
|
|
39
41
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- Kept for backward compatibility
|
|
40
|
-
retry, truncate, withRetryGenerator, calculateBackoffDelay, DEFAULT_RETRY_CONFIG,
|
|
42
|
+
retry, truncate, withRetryGenerator, calculateBackoffDelay, DEFAULT_RETRY_CONFIG,
|
|
43
|
+
// Token counting (tiktoken-based)
|
|
44
|
+
countTokens, countMessageTokens, } from './utils/index.js';
|
|
41
45
|
// Errors
|
|
42
46
|
export { AgentError, ProviderError, ToolError, ToolTimeoutError, ToolLoopError, ValidationError, MaxIterationsError, AbortError, ContextOverflowError, isAgentError, isProviderError, isToolError, isToolTimeoutError, isToolLoopError, isContextOverflowError, wrapError, } from './errors.js';
|
|
43
47
|
// Context management
|
|
44
|
-
export { ContextManager, DEFAULT_CONTEXT_CONFIG, FileAccessTracker, createFileTrackingHook, TRACKED_TOOLS,
|
|
48
|
+
export { ContextManager, DEFAULT_CONTEXT_CONFIG, FileAccessTracker, createFileTrackingHook, TRACKED_TOOLS,
|
|
49
|
+
// Tool result delegation
|
|
50
|
+
DelegatedResultStore, ToolResultDelegator, DELEGATION_SYSTEM_PROMPT, DEFAULT_DELEGATION_CONFIG, } from './context/index.js';
|
|
45
51
|
// Skills system
|
|
46
52
|
export { SkillRegistry, defineSkill, createSkillRegistry, builtinSkills, getDefaultSkillRegistry, resetDefaultSkillRegistry, } from './skills/index.js';
|
|
47
53
|
// State management
|
package/dist/memory/loader.js
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import * as fs from 'fs/promises';
|
|
27
27
|
import * as path from 'path';
|
|
28
|
+
import { countTokens } from '../utils/tokenizer.js';
|
|
28
29
|
/**
|
|
29
30
|
* Built-in patterns for various LLM providers
|
|
30
31
|
*/
|
|
@@ -268,7 +269,7 @@ export class ProjectMemoryLoader {
|
|
|
268
269
|
files,
|
|
269
270
|
content,
|
|
270
271
|
rootDir: absoluteRoot,
|
|
271
|
-
estimatedTokens:
|
|
272
|
+
estimatedTokens: countTokens(content),
|
|
272
273
|
};
|
|
273
274
|
this.emit({ type: 'memory:search_complete', memory });
|
|
274
275
|
return memory;
|
package/dist/memory/types.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export interface ProjectMemory {
|
|
|
41
41
|
content: string;
|
|
42
42
|
/** The root directory where search started */
|
|
43
43
|
rootDir: string;
|
|
44
|
-
/** Total token estimate (
|
|
44
|
+
/** Total token estimate (tiktoken cl100k_base) */
|
|
45
45
|
estimatedTokens: number;
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
@@ -61,11 +61,7 @@ export declare class ClaudeProvider implements LLMProvider {
|
|
|
61
61
|
*/
|
|
62
62
|
chat(messages: Message[], options?: ChatOptions): AsyncIterable<StreamChunk>;
|
|
63
63
|
/**
|
|
64
|
-
* Count tokens in messages
|
|
65
|
-
*
|
|
66
|
-
* Note: Token counting API is available via Anthropic's beta endpoints
|
|
67
|
-
* but not yet exposed in the stable SDK. For now, this provides an
|
|
68
|
-
* approximation based on character count.
|
|
64
|
+
* Count tokens in messages using tiktoken (cl100k_base encoding)
|
|
69
65
|
*/
|
|
70
66
|
countTokens(messages: Message[]): Promise<number>;
|
|
71
67
|
/**
|
package/dist/providers/claude.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* ```
|
|
12
12
|
*/
|
|
13
13
|
import Anthropic from '@anthropic-ai/sdk';
|
|
14
|
+
import { countMessageTokens } from '../utils/tokenizer.js';
|
|
14
15
|
import { ProviderError } from '../errors.js';
|
|
15
16
|
/**
|
|
16
17
|
* Default model for Claude API
|
|
@@ -73,7 +74,9 @@ export class ClaudeProvider {
|
|
|
73
74
|
if (thinking) {
|
|
74
75
|
Object.assign(params, { thinking });
|
|
75
76
|
}
|
|
76
|
-
|
|
77
|
+
// Pass abort signal to SDK for immediate cancellation
|
|
78
|
+
const requestOptions = options?.signal ? { signal: options.signal } : undefined;
|
|
79
|
+
const stream = this.client.messages.stream(params, requestOptions);
|
|
77
80
|
const model = options?.model ?? this.defaultModel;
|
|
78
81
|
let currentToolId = '';
|
|
79
82
|
let currentToolName = '';
|
|
@@ -122,36 +125,10 @@ export class ClaudeProvider {
|
|
|
122
125
|
}
|
|
123
126
|
}
|
|
124
127
|
/**
|
|
125
|
-
* Count tokens in messages
|
|
126
|
-
*
|
|
127
|
-
* Note: Token counting API is available via Anthropic's beta endpoints
|
|
128
|
-
* but not yet exposed in the stable SDK. For now, this provides an
|
|
129
|
-
* approximation based on character count.
|
|
128
|
+
* Count tokens in messages using tiktoken (cl100k_base encoding)
|
|
130
129
|
*/
|
|
131
130
|
countTokens(messages) {
|
|
132
|
-
|
|
133
|
-
let charCount = 0;
|
|
134
|
-
for (const msg of messages) {
|
|
135
|
-
if (typeof msg.content === 'string') {
|
|
136
|
-
charCount += msg.content.length;
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
for (const block of msg.content) {
|
|
140
|
-
switch (block.type) {
|
|
141
|
-
case 'text':
|
|
142
|
-
charCount += block.text.length;
|
|
143
|
-
break;
|
|
144
|
-
case 'tool_use':
|
|
145
|
-
charCount += JSON.stringify(block.input).length;
|
|
146
|
-
break;
|
|
147
|
-
case 'tool_result':
|
|
148
|
-
charCount += block.content.length;
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return Promise.resolve(Math.ceil(charCount / 4));
|
|
131
|
+
return Promise.resolve(countMessageTokens(messages));
|
|
155
132
|
}
|
|
156
133
|
/**
|
|
157
134
|
* Convert our Message format to Anthropic's format
|
|
@@ -52,7 +52,7 @@ export declare class GeminiNativeProvider implements LLMProvider {
|
|
|
52
52
|
*/
|
|
53
53
|
chat(messages: Message[], options?: ChatOptions): AsyncIterable<StreamChunk>;
|
|
54
54
|
/**
|
|
55
|
-
* Count tokens in messages (
|
|
55
|
+
* Count tokens in messages using tiktoken (cl100k_base encoding)
|
|
56
56
|
*/
|
|
57
57
|
countTokens(messages: Message[]): Promise<number>;
|
|
58
58
|
/**
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { GoogleGenAI } from '@google/genai';
|
|
17
17
|
import { ProviderError } from '../errors.js';
|
|
18
|
+
import { countMessageTokens } from '../utils/tokenizer.js';
|
|
18
19
|
/**
|
|
19
20
|
* Default model for Gemini API
|
|
20
21
|
*/
|
|
@@ -66,6 +67,10 @@ export class GeminiNativeProvider {
|
|
|
66
67
|
if (tools.length > 0) {
|
|
67
68
|
config.tools = [{ functionDeclarations: tools }];
|
|
68
69
|
}
|
|
70
|
+
// Check abort before starting the request
|
|
71
|
+
if (options?.signal?.aborted) {
|
|
72
|
+
throw new Error('Aborted');
|
|
73
|
+
}
|
|
69
74
|
// Request streaming response
|
|
70
75
|
const streamResponse = await this.client.models.generateContentStream({
|
|
71
76
|
model,
|
|
@@ -81,6 +86,9 @@ export class GeminiNativeProvider {
|
|
|
81
86
|
let lastUsageMetadata;
|
|
82
87
|
// Process stream chunks
|
|
83
88
|
for await (const chunk of streamResponse) {
|
|
89
|
+
// Check abort between chunks
|
|
90
|
+
if (options?.signal?.aborted)
|
|
91
|
+
break;
|
|
84
92
|
const streamChunks = this.processChunk(chunk, currentToolId, currentToolName, toolInputJson, inThinkingBlock);
|
|
85
93
|
for (const streamChunk of streamChunks) {
|
|
86
94
|
// Update tracking state
|
|
@@ -137,32 +145,10 @@ export class GeminiNativeProvider {
|
|
|
137
145
|
}
|
|
138
146
|
}
|
|
139
147
|
/**
|
|
140
|
-
* Count tokens in messages (
|
|
148
|
+
* Count tokens in messages using tiktoken (cl100k_base encoding)
|
|
141
149
|
*/
|
|
142
150
|
countTokens(messages) {
|
|
143
|
-
|
|
144
|
-
let charCount = 0;
|
|
145
|
-
for (const msg of messages) {
|
|
146
|
-
if (typeof msg.content === 'string') {
|
|
147
|
-
charCount += msg.content.length;
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
for (const block of msg.content) {
|
|
151
|
-
switch (block.type) {
|
|
152
|
-
case 'text':
|
|
153
|
-
charCount += block.text.length;
|
|
154
|
-
break;
|
|
155
|
-
case 'tool_use':
|
|
156
|
-
charCount += JSON.stringify(block.input).length;
|
|
157
|
-
break;
|
|
158
|
-
case 'tool_result':
|
|
159
|
-
charCount += block.content.length;
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return Promise.resolve(Math.ceil(charCount / 4));
|
|
151
|
+
return Promise.resolve(countMessageTokens(messages));
|
|
166
152
|
}
|
|
167
153
|
/**
|
|
168
154
|
* Convert our Message format to Google's format
|
package/dist/providers/mock.d.ts
CHANGED
|
@@ -122,7 +122,7 @@ export declare class MockProvider implements LLMProvider {
|
|
|
122
122
|
*/
|
|
123
123
|
chat(messages: Message[], options?: ChatOptions): AsyncIterable<StreamChunk>;
|
|
124
124
|
/**
|
|
125
|
-
* Count tokens (
|
|
125
|
+
* Count tokens using tiktoken (cl100k_base encoding)
|
|
126
126
|
*/
|
|
127
127
|
countTokens(messages: Message[]): Promise<number>;
|
|
128
128
|
private sleep;
|
package/dist/providers/mock.js
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
27
|
import { ProviderError } from '../errors.js';
|
|
28
|
+
import { countMessageTokens } from '../utils/tokenizer.js';
|
|
28
29
|
/**
|
|
29
30
|
* MockProvider for testing agents without API calls.
|
|
30
31
|
*
|
|
@@ -171,32 +172,10 @@ export class MockProvider {
|
|
|
171
172
|
yield { type: 'done' };
|
|
172
173
|
}
|
|
173
174
|
/**
|
|
174
|
-
* Count tokens (
|
|
175
|
+
* Count tokens using tiktoken (cl100k_base encoding)
|
|
175
176
|
*/
|
|
176
177
|
countTokens(messages) {
|
|
177
|
-
|
|
178
|
-
let charCount = 0;
|
|
179
|
-
for (const msg of messages) {
|
|
180
|
-
if (typeof msg.content === 'string') {
|
|
181
|
-
charCount += msg.content.length;
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
for (const block of msg.content) {
|
|
185
|
-
if (block.type === 'text') {
|
|
186
|
-
charCount += block.text.length;
|
|
187
|
-
}
|
|
188
|
-
else if (block.type === 'tool_result') {
|
|
189
|
-
// Count tool result content (always a string per our type definition)
|
|
190
|
-
charCount += block.content.length;
|
|
191
|
-
}
|
|
192
|
-
else if (block.type === 'tool_use') {
|
|
193
|
-
// Count tool use input
|
|
194
|
-
charCount += JSON.stringify(block.input).length;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return Promise.resolve(Math.ceil(charCount / 4));
|
|
178
|
+
return Promise.resolve(countMessageTokens(messages));
|
|
200
179
|
}
|
|
201
180
|
sleep(ms) {
|
|
202
181
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -186,11 +186,7 @@ export declare abstract class OpenAICompatibleProvider implements LLMProvider {
|
|
|
186
186
|
arguments: string;
|
|
187
187
|
}>): StreamChunk[];
|
|
188
188
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* @remarks
|
|
192
|
-
* Most providers don't have a native token counting endpoint.
|
|
193
|
-
* This uses a rough approximation of ~4 characters per token.
|
|
189
|
+
* Count tokens in messages using tiktoken (cl100k_base encoding)
|
|
194
190
|
*/
|
|
195
191
|
countTokens(messages: Message[]): Promise<number>;
|
|
196
192
|
}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
24
|
import { ProviderError } from '../errors.js';
|
|
25
|
+
import { countMessageTokens } from '../utils/tokenizer.js';
|
|
25
26
|
// Default configuration
|
|
26
27
|
const DEFAULT_MAX_TOKENS = 4096;
|
|
27
28
|
const DEFAULT_TIMEOUT = 120000;
|
|
@@ -98,6 +99,17 @@ export class OpenAICompatibleProvider {
|
|
|
98
99
|
let usage;
|
|
99
100
|
try {
|
|
100
101
|
const controller = new AbortController();
|
|
102
|
+
// Chain user abort signal to our controller
|
|
103
|
+
if (options?.signal) {
|
|
104
|
+
if (options.signal.aborted) {
|
|
105
|
+
controller.abort();
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
options.signal.addEventListener('abort', () => {
|
|
109
|
+
controller.abort();
|
|
110
|
+
}, { once: true });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
101
113
|
const timeoutId = setTimeout(() => {
|
|
102
114
|
controller.abort();
|
|
103
115
|
}, this.timeout);
|
|
@@ -349,35 +361,9 @@ export class OpenAICompatibleProvider {
|
|
|
349
361
|
return results;
|
|
350
362
|
}
|
|
351
363
|
/**
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
* @remarks
|
|
355
|
-
* Most providers don't have a native token counting endpoint.
|
|
356
|
-
* This uses a rough approximation of ~4 characters per token.
|
|
364
|
+
* Count tokens in messages using tiktoken (cl100k_base encoding)
|
|
357
365
|
*/
|
|
358
366
|
countTokens(messages) {
|
|
359
|
-
|
|
360
|
-
for (const msg of messages) {
|
|
361
|
-
if (typeof msg.content === 'string') {
|
|
362
|
-
charCount += msg.content.length;
|
|
363
|
-
}
|
|
364
|
-
else if (Array.isArray(msg.content)) {
|
|
365
|
-
for (const block of msg.content) {
|
|
366
|
-
if (block.type === 'text') {
|
|
367
|
-
charCount += block.text.length;
|
|
368
|
-
}
|
|
369
|
-
else if (block.type === 'tool_use') {
|
|
370
|
-
charCount += JSON.stringify(block.input).length;
|
|
371
|
-
}
|
|
372
|
-
else if (block.type === 'tool_result') {
|
|
373
|
-
charCount +=
|
|
374
|
-
typeof block.content === 'string'
|
|
375
|
-
? block.content.length
|
|
376
|
-
: JSON.stringify(block.content).length;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
return Promise.resolve(Math.ceil(charCount / 4));
|
|
367
|
+
return Promise.resolve(countMessageTokens(messages));
|
|
382
368
|
}
|
|
383
369
|
}
|
|
@@ -147,6 +147,11 @@ export interface ChatOptions {
|
|
|
147
147
|
* ```
|
|
148
148
|
*/
|
|
149
149
|
thinking?: ThinkingConfig;
|
|
150
|
+
/**
|
|
151
|
+
* AbortSignal for cancelling the LLM request.
|
|
152
|
+
* When aborted, the provider should stop streaming and throw/return immediately.
|
|
153
|
+
*/
|
|
154
|
+
signal?: AbortSignal;
|
|
150
155
|
/**
|
|
151
156
|
* Enable prompt caching for system prompt and tools (Claude-specific)
|
|
152
157
|
*
|
|
@@ -45,7 +45,7 @@ export declare class RateLimitedProvider implements LLMProvider {
|
|
|
45
45
|
*/
|
|
46
46
|
countTokens(messages: Message[]): Promise<number>;
|
|
47
47
|
/**
|
|
48
|
-
* Estimate tokens from messages
|
|
48
|
+
* Estimate tokens from messages using tiktoken
|
|
49
49
|
*/
|
|
50
50
|
private estimateTokens;
|
|
51
51
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { createRateLimiter } from './limiter.js';
|
|
7
7
|
import { withRetry } from './retry.js';
|
|
8
|
+
import { countMessageTokens } from '../utils/tokenizer.js';
|
|
8
9
|
/**
|
|
9
10
|
* Wrapper that adds rate limiting and retry to any LLMProvider
|
|
10
11
|
*
|
|
@@ -105,35 +106,10 @@ export class RateLimitedProvider {
|
|
|
105
106
|
return withRetry(() => countTokensFn(messages), this.retryConfig);
|
|
106
107
|
}
|
|
107
108
|
/**
|
|
108
|
-
* Estimate tokens from messages
|
|
109
|
+
* Estimate tokens from messages using tiktoken
|
|
109
110
|
*/
|
|
110
111
|
estimateTokens(messages) {
|
|
111
|
-
|
|
112
|
-
for (const msg of messages) {
|
|
113
|
-
if (typeof msg.content === 'string') {
|
|
114
|
-
charCount += msg.content.length;
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
for (const block of msg.content) {
|
|
118
|
-
switch (block.type) {
|
|
119
|
-
case 'text':
|
|
120
|
-
charCount += block.text.length;
|
|
121
|
-
break;
|
|
122
|
-
case 'tool_use':
|
|
123
|
-
charCount += JSON.stringify(block.input).length;
|
|
124
|
-
break;
|
|
125
|
-
case 'tool_result':
|
|
126
|
-
charCount += block.content.length;
|
|
127
|
-
break;
|
|
128
|
-
case 'thinking':
|
|
129
|
-
charCount += block.thinking.length;
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
// Rough estimate: 4 characters per token
|
|
136
|
-
return Math.ceil(charCount / 4);
|
|
112
|
+
return countMessageTokens(messages);
|
|
137
113
|
}
|
|
138
114
|
}
|
|
139
115
|
/**
|
|
@@ -33,6 +33,8 @@ export { askUserTool, createAskUserTool } from './ask-user.js';
|
|
|
33
33
|
export type { AskUserInput, AskUserResult, AskUserQuestion, AskUserOption, AskUserToolOptions, } from './ask-user.js';
|
|
34
34
|
export { askUserSimpleTool, createAskUserSimpleTool } from './ask-user-simple.js';
|
|
35
35
|
export type { AskUserSimpleInput, AskUserSimpleResult, AskUserSimpleToolOptions, } from './ask-user-simple.js';
|
|
36
|
+
export { createRecallResultTool } from './recall-result.js';
|
|
37
|
+
export type { RecallResultInput, RecallResultToolOptions } from './recall-result.js';
|
|
36
38
|
export { backlogReadTool, backlogWriteTool, createBacklogTools } from './backlog.js';
|
|
37
39
|
export type { BacklogItem, BacklogStatus, BacklogItemType, BacklogPriority, BacklogReadInput, BacklogReadResult, BacklogWriteInput, BacklogWriteResult, BacklogToolOptions, } from './backlog.js';
|
|
38
40
|
export declare const builtinTools: {
|
|
@@ -32,6 +32,8 @@ export { suggestTool, createSuggestTool } from './suggest.js';
|
|
|
32
32
|
// Ask user tools (user interaction)
|
|
33
33
|
export { askUserTool, createAskUserTool } from './ask-user.js';
|
|
34
34
|
export { askUserSimpleTool, createAskUserSimpleTool } from './ask-user-simple.js';
|
|
35
|
+
// Recall result tool (tool result delegation)
|
|
36
|
+
export { createRecallResultTool } from './recall-result.js';
|
|
35
37
|
// Backlog tools (file-based project backlog)
|
|
36
38
|
export { backlogReadTool, backlogWriteTool, createBacklogTools } from './backlog.js';
|
|
37
39
|
/**
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recall_full_result tool
|
|
3
|
+
*
|
|
4
|
+
* Retrieves the full output of a previously delegated tool result.
|
|
5
|
+
* Use when a summary is insufficient and you need the complete data.
|
|
6
|
+
*/
|
|
7
|
+
import type { Tool } from '../types.js';
|
|
8
|
+
import type { DelegatedResultStore } from '../../context/delegated-result-store.js';
|
|
9
|
+
import type { DelegationEvent } from '../../context/delegation-types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Input for the recall_full_result tool.
|
|
12
|
+
*/
|
|
13
|
+
export interface RecallResultInput {
|
|
14
|
+
/** Delegation ID from a previously delegated result (e.g., "dr_1707900000_0") */
|
|
15
|
+
id: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Options for creating the recall_full_result tool.
|
|
19
|
+
*/
|
|
20
|
+
export interface RecallResultToolOptions {
|
|
21
|
+
/** The delegation store to retrieve results from */
|
|
22
|
+
store: DelegatedResultStore;
|
|
23
|
+
/** Optional event callback for recall events */
|
|
24
|
+
onEvent?: (event: DelegationEvent) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a recall_full_result tool that retrieves delegated results from the store.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createRecallResultTool(options: RecallResultToolOptions): Tool<RecallResultInput>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recall_full_result tool
|
|
3
|
+
*
|
|
4
|
+
* Retrieves the full output of a previously delegated tool result.
|
|
5
|
+
* Use when a summary is insufficient and you need the complete data.
|
|
6
|
+
*/
|
|
7
|
+
import { defineTool, createSuccessResult, createErrorResult } from '../define.js';
|
|
8
|
+
/**
|
|
9
|
+
* Create a recall_full_result tool that retrieves delegated results from the store.
|
|
10
|
+
*/
|
|
11
|
+
export function createRecallResultTool(options) {
|
|
12
|
+
const { store, onEvent } = options;
|
|
13
|
+
return defineTool({
|
|
14
|
+
name: 'recall_full_result',
|
|
15
|
+
description: 'Retrieve the full output of a previously delegated tool result. ' +
|
|
16
|
+
'Use when a summary is insufficient and you need the complete data. ' +
|
|
17
|
+
'Results expire after 10 minutes.',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
id: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Delegation ID (e.g., "dr_1707900000_0")',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ['id'],
|
|
27
|
+
},
|
|
28
|
+
execute: (input) => {
|
|
29
|
+
const stored = store.get(input.id);
|
|
30
|
+
onEvent?.({
|
|
31
|
+
type: 'delegation:recall',
|
|
32
|
+
delegationId: input.id,
|
|
33
|
+
found: stored !== undefined,
|
|
34
|
+
});
|
|
35
|
+
if (!stored) {
|
|
36
|
+
return Promise.resolve(createErrorResult('Delegation ID not found or expired. Re-run the original tool to get the result.'));
|
|
37
|
+
}
|
|
38
|
+
return Promise.resolve(createSuccessResult({
|
|
39
|
+
delegationId: stored.id,
|
|
40
|
+
toolName: stored.toolName,
|
|
41
|
+
fullContent: stored.fullContent,
|
|
42
|
+
fullTokens: stored.fullTokens,
|
|
43
|
+
}));
|
|
44
|
+
},
|
|
45
|
+
parallel: true,
|
|
46
|
+
silent: true,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -183,6 +183,7 @@ export function createTaskTool(options) {
|
|
|
183
183
|
};
|
|
184
184
|
}
|
|
185
185
|
const resultPromise = parentAgent.runSubAgent(subAgentName, prompt, {
|
|
186
|
+
signal: context?.abortSignal,
|
|
186
187
|
onEvent: eventHandler,
|
|
187
188
|
});
|
|
188
189
|
const result = await Promise.race([resultPromise, timeoutPromise]);
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export { defineTool, createSuccessResult, createErrorResult, wrapToolExecute } f
|
|
|
6
6
|
export type { DefineToolOptions } from './define.js';
|
|
7
7
|
export { DefaultToolRegistry, createToolRegistry } from './registry.js';
|
|
8
8
|
export type { ToolRegistryOptions } from './registry.js';
|
|
9
|
-
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 './builtin/index.js';
|
|
10
|
-
export type { ReadFileInput, WriteFileInput, BashInput, BashResult, FifoDetectionResult, BashOutputInput, BashOutputResult, KillShellInput, KillShellResult, ShellStatus, BackgroundShell, ShellOutput, ShellManagerOptions, GrepInput, GlobInput, EditInput, TodoWriteInput, TodoReadInput, TodoItem, TodoStatus, TodoContextCleanupOptions, WebFetchInput, WebFetchResult, WebFetchOptions, TaskInput, TaskResult, AgentTypeConfig, TaskToolOptions, ContextMode, ThoroughnessLevel, SubAgentEventInfo, SuggestInput, SuggestToolOptions, } from './builtin/index.js';
|
|
9
|
+
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, createRecallResultTool, builtinTools, allBuiltinTools, TOOL_NAMES, TOOL_SETS, } from './builtin/index.js';
|
|
10
|
+
export type { ReadFileInput, WriteFileInput, BashInput, BashResult, FifoDetectionResult, BashOutputInput, BashOutputResult, KillShellInput, KillShellResult, ShellStatus, BackgroundShell, ShellOutput, ShellManagerOptions, GrepInput, GlobInput, EditInput, TodoWriteInput, TodoReadInput, TodoItem, TodoStatus, TodoContextCleanupOptions, WebFetchInput, WebFetchResult, WebFetchOptions, TaskInput, TaskResult, AgentTypeConfig, TaskToolOptions, ContextMode, ThoroughnessLevel, SubAgentEventInfo, SuggestInput, SuggestToolOptions, RecallResultInput, RecallResultToolOptions, } from './builtin/index.js';
|
package/dist/tools/index.js
CHANGED
|
@@ -35,6 +35,8 @@ webFetchTool, createWebFetchTool,
|
|
|
35
35
|
createTaskTool, defaultAgentTypes,
|
|
36
36
|
// Suggest (next action suggestions)
|
|
37
37
|
suggestTool, createSuggestTool,
|
|
38
|
+
// Recall result (delegation)
|
|
39
|
+
createRecallResultTool,
|
|
38
40
|
// Collections
|
|
39
41
|
builtinTools, allBuiltinTools,
|
|
40
42
|
// Tool names - single source of truth
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token counting utility using tiktoken (cl100k_base encoding)
|
|
3
|
+
*
|
|
4
|
+
* Replaces the rough `Math.ceil(charCount / 4)` heuristic with actual
|
|
5
|
+
* BPE tokenization for accurate context window management.
|
|
6
|
+
*/
|
|
7
|
+
import type { Message } from '../providers/types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Count tokens in a text string using tiktoken.
|
|
10
|
+
* Falls back to chars/4 heuristic for very large or pathologically repetitive strings.
|
|
11
|
+
*/
|
|
12
|
+
export declare function countTokens(text: string): number;
|
|
13
|
+
/**
|
|
14
|
+
* Count tokens across an array of messages
|
|
15
|
+
*
|
|
16
|
+
* Extracts all text content from messages (text blocks, tool inputs/results,
|
|
17
|
+
* thinking blocks) and counts tokens using tiktoken.
|
|
18
|
+
*/
|
|
19
|
+
export declare function countMessageTokens(messages: Message[]): number;
|