@claudebuddy/claudebuddy-agent-sdk 0.4.0
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/LICENSE +21 -0
- package/README.md +501 -0
- package/dist/agent.d.ts +137 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +573 -0
- package/dist/agent.js.map +1 -0
- package/dist/engine.d.ts +70 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +552 -0
- package/dist/engine.js.map +1 -0
- package/dist/hooks.d.ts +111 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +179 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +141 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +19 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +126 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/providers/anthropic.d.ts +17 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +47 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/index.d.ts +20 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +26 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai.d.ts +26 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +243 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/types.d.ts +84 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +11 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/sdk-mcp-server.d.ts +52 -0
- package/dist/sdk-mcp-server.d.ts.map +1 -0
- package/dist/sdk-mcp-server.js +57 -0
- package/dist/sdk-mcp-server.js.map +1 -0
- package/dist/session.d.ts +73 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +159 -0
- package/dist/session.js.map +1 -0
- package/dist/skills/bundled/commit.d.ts +7 -0
- package/dist/skills/bundled/commit.d.ts.map +1 -0
- package/dist/skills/bundled/commit.js +35 -0
- package/dist/skills/bundled/commit.js.map +1 -0
- package/dist/skills/bundled/debug.d.ts +7 -0
- package/dist/skills/bundled/debug.d.ts.map +1 -0
- package/dist/skills/bundled/debug.js +46 -0
- package/dist/skills/bundled/debug.js.map +1 -0
- package/dist/skills/bundled/index.d.ts +11 -0
- package/dist/skills/bundled/index.d.ts.map +1 -0
- package/dist/skills/bundled/index.js +26 -0
- package/dist/skills/bundled/index.js.map +1 -0
- package/dist/skills/bundled/review.d.ts +7 -0
- package/dist/skills/bundled/review.d.ts.map +1 -0
- package/dist/skills/bundled/review.js +38 -0
- package/dist/skills/bundled/review.js.map +1 -0
- package/dist/skills/bundled/simplify.d.ts +8 -0
- package/dist/skills/bundled/simplify.d.ts.map +1 -0
- package/dist/skills/bundled/simplify.js +48 -0
- package/dist/skills/bundled/simplify.js.map +1 -0
- package/dist/skills/bundled/test.d.ts +7 -0
- package/dist/skills/bundled/test.d.ts.map +1 -0
- package/dist/skills/bundled/test.js +40 -0
- package/dist/skills/bundled/test.js.map +1 -0
- package/dist/skills/index.d.ts +7 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +8 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/registry.d.ts +43 -0
- package/dist/skills/registry.d.ts.map +1 -0
- package/dist/skills/registry.js +111 -0
- package/dist/skills/registry.js.map +1 -0
- package/dist/skills/types.d.ts +83 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +8 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tool-helper.d.ts +73 -0
- package/dist/tool-helper.d.ts.map +1 -0
- package/dist/tool-helper.js +86 -0
- package/dist/tool-helper.js.map +1 -0
- package/dist/tools/agent-tool.d.ts +17 -0
- package/dist/tools/agent-tool.d.ts.map +1 -0
- package/dist/tools/agent-tool.js +150 -0
- package/dist/tools/agent-tool.js.map +1 -0
- package/dist/tools/ask-user.d.ts +18 -0
- package/dist/tools/ask-user.d.ts.map +1 -0
- package/dist/tools/ask-user.js +72 -0
- package/dist/tools/ask-user.js.map +1 -0
- package/dist/tools/bash.d.ts +5 -0
- package/dist/tools/bash.d.ts.map +1 -0
- package/dist/tools/bash.js +67 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/config-tool.d.ts +20 -0
- package/dist/tools/config-tool.d.ts.map +1 -0
- package/dist/tools/config-tool.js +83 -0
- package/dist/tools/config-tool.js.map +1 -0
- package/dist/tools/cron-tools.d.ts +33 -0
- package/dist/tools/cron-tools.d.ts.map +1 -0
- package/dist/tools/cron-tools.js +128 -0
- package/dist/tools/cron-tools.js.map +1 -0
- package/dist/tools/edit.d.ts +5 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +70 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/glob.d.ts +5 -0
- package/dist/tools/glob.d.ts.map +1 -0
- package/dist/tools/glob.js +75 -0
- package/dist/tools/glob.js.map +1 -0
- package/dist/tools/grep.d.ts +5 -0
- package/dist/tools/grep.d.ts.map +1 -0
- package/dist/tools/grep.js +168 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/index.d.ts +45 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +162 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/lsp-tool.d.ts +9 -0
- package/dist/tools/lsp-tool.d.ts.map +1 -0
- package/dist/tools/lsp-tool.js +137 -0
- package/dist/tools/lsp-tool.js.map +1 -0
- package/dist/tools/mcp-resource-tools.d.ts +14 -0
- package/dist/tools/mcp-resource-tools.d.ts.map +1 -0
- package/dist/tools/mcp-resource-tools.js +117 -0
- package/dist/tools/mcp-resource-tools.js.map +1 -0
- package/dist/tools/notebook-edit.d.ts +5 -0
- package/dist/tools/notebook-edit.d.ts.map +1 -0
- package/dist/tools/notebook-edit.js +85 -0
- package/dist/tools/notebook-edit.js.map +1 -0
- package/dist/tools/plan-tools.d.ts +12 -0
- package/dist/tools/plan-tools.d.ts.map +1 -0
- package/dist/tools/plan-tools.js +77 -0
- package/dist/tools/plan-tools.js.map +1 -0
- package/dist/tools/read.d.ts +5 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +66 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/send-message.d.ts +31 -0
- package/dist/tools/send-message.d.ts.map +1 -0
- package/dist/tools/send-message.js +77 -0
- package/dist/tools/send-message.js.map +1 -0
- package/dist/tools/skill-tool.d.ts +9 -0
- package/dist/tools/skill-tool.d.ts.map +1 -0
- package/dist/tools/skill-tool.js +115 -0
- package/dist/tools/skill-tool.js.map +1 -0
- package/dist/tools/task-tools.d.ts +48 -0
- package/dist/tools/task-tools.d.ts.map +1 -0
- package/dist/tools/task-tools.js +242 -0
- package/dist/tools/task-tools.js.map +1 -0
- package/dist/tools/team-tools.d.ts +34 -0
- package/dist/tools/team-tools.d.ts.map +1 -0
- package/dist/tools/team-tools.js +103 -0
- package/dist/tools/team-tools.js.map +1 -0
- package/dist/tools/todo-tool.d.ts +22 -0
- package/dist/tools/todo-tool.d.ts.map +1 -0
- package/dist/tools/todo-tool.js +93 -0
- package/dist/tools/todo-tool.js.map +1 -0
- package/dist/tools/tool-search.d.ts +13 -0
- package/dist/tools/tool-search.d.ts.map +1 -0
- package/dist/tools/tool-search.js +76 -0
- package/dist/tools/tool-search.js.map +1 -0
- package/dist/tools/types.d.ts +29 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +52 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/update-goal.d.ts +38 -0
- package/dist/tools/update-goal.d.ts.map +1 -0
- package/dist/tools/update-goal.js +109 -0
- package/dist/tools/update-goal.js.map +1 -0
- package/dist/tools/web-fetch.d.ts +5 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +60 -0
- package/dist/tools/web-fetch.js.map +1 -0
- package/dist/tools/web-search.d.ts +5 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +77 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/tools/worktree-tools.d.ts +10 -0
- package/dist/tools/worktree-tools.d.ts.map +1 -0
- package/dist/tools/worktree-tools.js +130 -0
- package/dist/tools/worktree-tools.js.map +1 -0
- package/dist/tools/write.d.ts +5 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +40 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/types.d.ts +485 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/compact.d.ts +44 -0
- package/dist/utils/compact.d.ts.map +1 -0
- package/dist/utils/compact.js +162 -0
- package/dist/utils/compact.js.map +1 -0
- package/dist/utils/context.d.ts +35 -0
- package/dist/utils/context.d.ts.map +1 -0
- package/dist/utils/context.js +174 -0
- package/dist/utils/context.js.map +1 -0
- package/dist/utils/fileCache.d.ts +64 -0
- package/dist/utils/fileCache.d.ts.map +1 -0
- package/dist/utils/fileCache.js +117 -0
- package/dist/utils/fileCache.js.map +1 -0
- package/dist/utils/messages.d.ts +57 -0
- package/dist/utils/messages.d.ts.map +1 -0
- package/dist/utils/messages.js +152 -0
- package/dist/utils/messages.js.map +1 -0
- package/dist/utils/retry.d.ts +48 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +111 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/spill.d.ts +100 -0
- package/dist/utils/spill.d.ts.map +1 -0
- package/dist/utils/spill.js +126 -0
- package/dist/utils/spill.js.map +1 -0
- package/dist/utils/tokens.d.ts +60 -0
- package/dist/utils/tokens.d.ts.map +1 -0
- package/dist/utils/tokens.js +140 -0
- package/dist/utils/tokens.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message Utilities
|
|
3
|
+
*
|
|
4
|
+
* Message creation factories, normalization for API,
|
|
5
|
+
* synthetic placeholders, and content processing.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Create a user message.
|
|
9
|
+
*/
|
|
10
|
+
export function createUserMessage(content, options) {
|
|
11
|
+
return {
|
|
12
|
+
type: 'user',
|
|
13
|
+
message: {
|
|
14
|
+
role: 'user',
|
|
15
|
+
content,
|
|
16
|
+
},
|
|
17
|
+
uuid: options?.uuid || crypto.randomUUID(),
|
|
18
|
+
timestamp: new Date().toISOString(),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create an assistant message.
|
|
23
|
+
*/
|
|
24
|
+
export function createAssistantMessage(content, usage) {
|
|
25
|
+
return {
|
|
26
|
+
type: 'assistant',
|
|
27
|
+
message: {
|
|
28
|
+
role: 'assistant',
|
|
29
|
+
content,
|
|
30
|
+
},
|
|
31
|
+
uuid: crypto.randomUUID(),
|
|
32
|
+
timestamp: new Date().toISOString(),
|
|
33
|
+
usage,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Normalize messages for the LLM API.
|
|
38
|
+
* Ensures proper message format, strips internal metadata,
|
|
39
|
+
* and fixes tool result pairing.
|
|
40
|
+
*/
|
|
41
|
+
export function normalizeMessagesForAPI(messages) {
|
|
42
|
+
const normalized = [];
|
|
43
|
+
for (let i = 0; i < messages.length; i++) {
|
|
44
|
+
const msg = messages[i];
|
|
45
|
+
// Ensure alternating user/assistant messages
|
|
46
|
+
if (normalized.length > 0) {
|
|
47
|
+
const last = normalized[normalized.length - 1];
|
|
48
|
+
if (last.role === msg.role) {
|
|
49
|
+
// Merge same-role messages
|
|
50
|
+
if (msg.role === 'user') {
|
|
51
|
+
// Combine content
|
|
52
|
+
const lastContent = typeof last.content === 'string'
|
|
53
|
+
? [{ type: 'text', text: last.content }]
|
|
54
|
+
: last.content;
|
|
55
|
+
const newContent = typeof msg.content === 'string'
|
|
56
|
+
? [{ type: 'text', text: msg.content }]
|
|
57
|
+
: msg.content;
|
|
58
|
+
normalized[normalized.length - 1] = {
|
|
59
|
+
role: 'user',
|
|
60
|
+
content: [...lastContent, ...newContent],
|
|
61
|
+
};
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
normalized.push({ ...msg });
|
|
67
|
+
}
|
|
68
|
+
// Ensure tool results are properly paired with tool_use
|
|
69
|
+
return fixToolResultPairing(normalized);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Fix tool result pairing: ensure every tool_result has a
|
|
73
|
+
* matching tool_use in the previous assistant message.
|
|
74
|
+
*/
|
|
75
|
+
function fixToolResultPairing(messages) {
|
|
76
|
+
const result = [];
|
|
77
|
+
for (let i = 0; i < messages.length; i++) {
|
|
78
|
+
const msg = messages[i];
|
|
79
|
+
if (msg.role === 'user' && Array.isArray(msg.content)) {
|
|
80
|
+
// Check for tool_result blocks
|
|
81
|
+
const toolResults = msg.content.filter((block) => block.type === 'tool_result');
|
|
82
|
+
if (toolResults.length > 0 && result.length > 0) {
|
|
83
|
+
// Find the previous assistant message
|
|
84
|
+
const prevAssistant = result[result.length - 1];
|
|
85
|
+
if (prevAssistant.role === 'assistant' && Array.isArray(prevAssistant.content)) {
|
|
86
|
+
const toolUseIds = new Set(prevAssistant.content
|
|
87
|
+
.filter((b) => b.type === 'tool_use')
|
|
88
|
+
.map((b) => b.id));
|
|
89
|
+
// Filter out orphaned tool results
|
|
90
|
+
const validContent = msg.content.filter((block) => {
|
|
91
|
+
if (block.type === 'tool_result') {
|
|
92
|
+
return toolUseIds.has(block.tool_use_id);
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
});
|
|
96
|
+
if (validContent.length > 0) {
|
|
97
|
+
result.push({ ...msg, content: validContent });
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
result.push(msg);
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Strip images from messages (for compaction).
|
|
109
|
+
*/
|
|
110
|
+
export function stripImagesFromMessages(messages) {
|
|
111
|
+
return messages.map((msg) => {
|
|
112
|
+
if (typeof msg.content === 'string')
|
|
113
|
+
return msg;
|
|
114
|
+
if (!Array.isArray(msg.content))
|
|
115
|
+
return msg;
|
|
116
|
+
const filtered = msg.content.filter((block) => block.type !== 'image');
|
|
117
|
+
return {
|
|
118
|
+
...msg,
|
|
119
|
+
content: filtered.length > 0 ? filtered : '[content removed]',
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Extract text from message content blocks.
|
|
125
|
+
*/
|
|
126
|
+
export function extractTextFromContent(content) {
|
|
127
|
+
if (typeof content === 'string')
|
|
128
|
+
return content;
|
|
129
|
+
return content
|
|
130
|
+
.filter((b) => b.type === 'text')
|
|
131
|
+
.map((b) => b.text)
|
|
132
|
+
.join('');
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Create a system message for compact boundary.
|
|
136
|
+
*/
|
|
137
|
+
export function createCompactBoundaryMessage() {
|
|
138
|
+
return {
|
|
139
|
+
role: 'user',
|
|
140
|
+
content: '[Previous context has been summarized above. Continuing conversation.]',
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Truncate text to max length with ellipsis.
|
|
145
|
+
*/
|
|
146
|
+
export function truncateText(text, maxLength) {
|
|
147
|
+
if (text.length <= maxLength)
|
|
148
|
+
return text;
|
|
149
|
+
const half = Math.floor(maxLength / 2);
|
|
150
|
+
return text.slice(0, half) + '\n...(truncated)...\n' + text.slice(-half);
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/utils/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry Logic with Exponential Backoff
|
|
3
|
+
*
|
|
4
|
+
* Handles API retries for rate limits, overloaded servers,
|
|
5
|
+
* and transient failures.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Retry configuration.
|
|
9
|
+
*/
|
|
10
|
+
export interface RetryConfig {
|
|
11
|
+
maxRetries: number;
|
|
12
|
+
baseDelayMs: number;
|
|
13
|
+
maxDelayMs: number;
|
|
14
|
+
retryableStatusCodes: number[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Default retry configuration.
|
|
18
|
+
*/
|
|
19
|
+
export declare const DEFAULT_RETRY_CONFIG: RetryConfig;
|
|
20
|
+
/**
|
|
21
|
+
* Check if an error is retryable.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isRetryableError(err: any, config?: RetryConfig): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Calculate delay for exponential backoff.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getRetryDelay(attempt: number, config?: RetryConfig): number;
|
|
28
|
+
/**
|
|
29
|
+
* Execute a function with retries.
|
|
30
|
+
*/
|
|
31
|
+
export declare function withRetry<T>(fn: () => Promise<T>, config?: RetryConfig, abortSignal?: AbortSignal): Promise<T>;
|
|
32
|
+
/**
|
|
33
|
+
* Check if an error is a "prompt too long" error.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isPromptTooLongError(err: any): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Check if error is an auth error.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isAuthError(err: any): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Check if error is a rate limit error.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isRateLimitError(err: any): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Format an API error for display.
|
|
46
|
+
*/
|
|
47
|
+
export declare function formatApiError(err: any): string;
|
|
48
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,oBAAoB,EAAE,MAAM,EAAE,CAAA;CAC/B;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAKlC,CAAA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,GAAE,WAAkC,GAAG,OAAO,CAgB9F;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,WAAkC,GAAG,MAAM,CAKjG;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,GAAE,WAAkC,EAC1C,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,CAAC,CAAC,CA4BZ;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAQtD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAE7C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAElD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAc/C"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry Logic with Exponential Backoff
|
|
3
|
+
*
|
|
4
|
+
* Handles API retries for rate limits, overloaded servers,
|
|
5
|
+
* and transient failures.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Default retry configuration.
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_RETRY_CONFIG = {
|
|
11
|
+
maxRetries: 3,
|
|
12
|
+
baseDelayMs: 2000,
|
|
13
|
+
maxDelayMs: 30000,
|
|
14
|
+
retryableStatusCodes: [429, 500, 502, 503, 529],
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Check if an error is retryable.
|
|
18
|
+
*/
|
|
19
|
+
export function isRetryableError(err, config = DEFAULT_RETRY_CONFIG) {
|
|
20
|
+
if (err?.status && config.retryableStatusCodes.includes(err.status)) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
// Network errors
|
|
24
|
+
if (err?.code === 'ECONNRESET' || err?.code === 'ETIMEDOUT' || err?.code === 'ECONNREFUSED') {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
// API overloaded
|
|
28
|
+
if (err?.error?.type === 'overloaded_error') {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Calculate delay for exponential backoff.
|
|
35
|
+
*/
|
|
36
|
+
export function getRetryDelay(attempt, config = DEFAULT_RETRY_CONFIG) {
|
|
37
|
+
const delay = config.baseDelayMs * Math.pow(2, attempt);
|
|
38
|
+
// Add jitter (±25%)
|
|
39
|
+
const jitter = delay * 0.25 * (Math.random() * 2 - 1);
|
|
40
|
+
return Math.min(delay + jitter, config.maxDelayMs);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Execute a function with retries.
|
|
44
|
+
*/
|
|
45
|
+
export async function withRetry(fn, config = DEFAULT_RETRY_CONFIG, abortSignal) {
|
|
46
|
+
let lastError;
|
|
47
|
+
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
48
|
+
if (abortSignal?.aborted) {
|
|
49
|
+
throw new Error('Aborted');
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
return await fn();
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
lastError = err;
|
|
56
|
+
if (!isRetryableError(err, config)) {
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
if (attempt === config.maxRetries) {
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
// Wait before retry
|
|
63
|
+
const delay = getRetryDelay(attempt, config);
|
|
64
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
throw lastError;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if an error is a "prompt too long" error.
|
|
71
|
+
*/
|
|
72
|
+
export function isPromptTooLongError(err) {
|
|
73
|
+
if (err?.status === 400) {
|
|
74
|
+
const message = err?.error?.error?.message || err?.message || '';
|
|
75
|
+
return message.includes('prompt is too long') ||
|
|
76
|
+
message.includes('max_tokens') ||
|
|
77
|
+
message.includes('context length');
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Check if error is an auth error.
|
|
83
|
+
*/
|
|
84
|
+
export function isAuthError(err) {
|
|
85
|
+
return err?.status === 401 || err?.status === 403;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if error is a rate limit error.
|
|
89
|
+
*/
|
|
90
|
+
export function isRateLimitError(err) {
|
|
91
|
+
return err?.status === 429;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Format an API error for display.
|
|
95
|
+
*/
|
|
96
|
+
export function formatApiError(err) {
|
|
97
|
+
if (isAuthError(err)) {
|
|
98
|
+
return 'Authentication failed. Check your CLAUDEBUDDY_API_KEY.';
|
|
99
|
+
}
|
|
100
|
+
if (isRateLimitError(err)) {
|
|
101
|
+
return 'Rate limit exceeded. Please retry after a short wait.';
|
|
102
|
+
}
|
|
103
|
+
if (err?.status === 529) {
|
|
104
|
+
return 'API overloaded. Please retry later.';
|
|
105
|
+
}
|
|
106
|
+
if (isPromptTooLongError(err)) {
|
|
107
|
+
return 'Prompt too long. Auto-compacting conversation...';
|
|
108
|
+
}
|
|
109
|
+
return `API error: ${err.message || err}`;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spill — overflow text off to disk
|
|
3
|
+
*
|
|
4
|
+
* When a tool result is far larger than the context can afford, we do not
|
|
5
|
+
* truncate it inline (which loses data and wastes tokens on the tail anyway).
|
|
6
|
+
* Instead we "spill" the full text to a file on disk and hand the model a
|
|
7
|
+
* compact head/tail preview plus a locator the model (or a later spill-aware
|
|
8
|
+
* tool) can use to retrieve the full payload on demand.
|
|
9
|
+
*
|
|
10
|
+
* Design rules (mirroring DeepSeek's spill-policy):
|
|
11
|
+
* 1. Purely presentational — it is a post-processing layer, decoupled from
|
|
12
|
+
* the tool implementation. The underlying tool result is never mutated.
|
|
13
|
+
* 2. Best-effort — if spilling fails (disk full, no permission) the original
|
|
14
|
+
* successful result is returned unchanged. A spill failure must never turn
|
|
15
|
+
* a successful tool call into an error.
|
|
16
|
+
* 3. The replacement text must itself stay under the cap, with a reserved
|
|
17
|
+
* byte budget for the locator/notice so it can never overflow.
|
|
18
|
+
* 4. Skip spill for reading tools to avoid a read -> spill -> read cycle.
|
|
19
|
+
*/
|
|
20
|
+
/** A stored spill: an opaque locator plus a model-visible preview. */
|
|
21
|
+
export interface SpillEntry {
|
|
22
|
+
/** Opaque handle used to retrieve the stored full text later. */
|
|
23
|
+
locator: string;
|
|
24
|
+
/** File path the full text was written to (locator may reference it). */
|
|
25
|
+
path: string;
|
|
26
|
+
/** Byte size of the spilled content. */
|
|
27
|
+
size: number;
|
|
28
|
+
}
|
|
29
|
+
/** Configuration for the spill store. */
|
|
30
|
+
export interface SpillStoreOptions {
|
|
31
|
+
/** Directory to write spill files into. Defaults to <cwd>/.spill. */
|
|
32
|
+
spillDir?: string;
|
|
33
|
+
/** Maximum bytes stored per file before we still abort a spill attempt. */
|
|
34
|
+
maxSpillBytes?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Append-only spill store. Each spill gets its own file so there is no
|
|
38
|
+
* locking or ordering concern. The locator is the absolute file path — simple,
|
|
39
|
+
* unique per write, and trivially re-fetchable by any file tool.
|
|
40
|
+
*/
|
|
41
|
+
export declare class SpillStore {
|
|
42
|
+
private readonly spillDir;
|
|
43
|
+
private readonly maxSpillBytes;
|
|
44
|
+
private seq;
|
|
45
|
+
constructor(options?: SpillStoreOptions);
|
|
46
|
+
/** Lazily ensure the spill directory exists. */
|
|
47
|
+
private ensureDir;
|
|
48
|
+
/**
|
|
49
|
+
* Write `text` to a new spill file if it is non-empty and within limits.
|
|
50
|
+
* Never throws: any failure is reported via the `ok: false` shape.
|
|
51
|
+
*/
|
|
52
|
+
saveText(text: string, tag?: string): Promise<{
|
|
53
|
+
ok: true;
|
|
54
|
+
entry: SpillEntry;
|
|
55
|
+
} | {
|
|
56
|
+
ok: false;
|
|
57
|
+
error: string;
|
|
58
|
+
}>;
|
|
59
|
+
/** Read a spilled payload back by its locator (the absolute path). */
|
|
60
|
+
read(locator: string): Promise<string | undefined>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build the compact model-visible preview for a spilled blob: head + "…truncated…"
|
|
64
|
+
* + tail, sized so head+tail+notice fit within `previewBytes` with room to spare.
|
|
65
|
+
*/
|
|
66
|
+
export declare function buildPreview(text: string, previewBytes?: number): string;
|
|
67
|
+
/**
|
|
68
|
+
* Policy-level options controlling when a tool result is spilled.
|
|
69
|
+
*/
|
|
70
|
+
export interface SpillPolicyOptions {
|
|
71
|
+
/** Tool results above this many bytes are spilled. Default 20000. */
|
|
72
|
+
maxInlineBytes?: number;
|
|
73
|
+
/** Size of the head/tail preview given to the model. Default 4000. */
|
|
74
|
+
previewBytes?: number;
|
|
75
|
+
/** Tool names that should never be spilled (to avoid read->spill->read loops). */
|
|
76
|
+
neverSpillTools?: string[];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Apply the spill policy to a single tool result content string.
|
|
80
|
+
*
|
|
81
|
+
* Returns a tagged result so the caller can distinguish:
|
|
82
|
+
* - `{ kind: 'keep', content }` — unchanged (small, or tool excluded)
|
|
83
|
+
* - `{ kind: 'spill', content, entry }` — spilled; preview replaces content
|
|
84
|
+
* - `{ kind: 'failed', content }` — spill attempted but failed; keep original
|
|
85
|
+
*/
|
|
86
|
+
export declare function applySpillPolicy(text: string, store: SpillStore, options?: SpillPolicyOptions): Promise<{
|
|
87
|
+
kind: 'keep';
|
|
88
|
+
content: string;
|
|
89
|
+
} | {
|
|
90
|
+
kind: 'spill';
|
|
91
|
+
content: string;
|
|
92
|
+
entry: SpillEntry;
|
|
93
|
+
} | {
|
|
94
|
+
kind: 'failed';
|
|
95
|
+
content: string;
|
|
96
|
+
error: string;
|
|
97
|
+
}>;
|
|
98
|
+
/** Skip spill for a given tool name (avoid read -> spill -> read loops). */
|
|
99
|
+
export declare function shouldNeverSpill(toolName: string, neverSpillTools?: string[]): boolean;
|
|
100
|
+
//# sourceMappingURL=spill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spill.d.ts","sourceRoot":"","sources":["../../src/utils/spill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAA;IACf,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAA;CACb;AAED,yCAAyC;AACzC,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED;;;;GAIG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;IACtC,OAAO,CAAC,GAAG,CAAI;gBAEH,OAAO,GAAE,iBAAsB;IAK3C,gDAAgD;YAClC,SAAS;IAKvB;;;OAGG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAqBnH,sEAAsE;IAChE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAazD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,YAAY,GAAE,MAAa,GAC1B,MAAM,CAUR;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kFAAkF;IAClF,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CACN;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CACrD,CAgBA;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,eAAe,GAAE,MAAM,EAAO,GAC7B,OAAO,CAGT"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spill — overflow text off to disk
|
|
3
|
+
*
|
|
4
|
+
* When a tool result is far larger than the context can afford, we do not
|
|
5
|
+
* truncate it inline (which loses data and wastes tokens on the tail anyway).
|
|
6
|
+
* Instead we "spill" the full text to a file on disk and hand the model a
|
|
7
|
+
* compact head/tail preview plus a locator the model (or a later spill-aware
|
|
8
|
+
* tool) can use to retrieve the full payload on demand.
|
|
9
|
+
*
|
|
10
|
+
* Design rules (mirroring DeepSeek's spill-policy):
|
|
11
|
+
* 1. Purely presentational — it is a post-processing layer, decoupled from
|
|
12
|
+
* the tool implementation. The underlying tool result is never mutated.
|
|
13
|
+
* 2. Best-effort — if spilling fails (disk full, no permission) the original
|
|
14
|
+
* successful result is returned unchanged. A spill failure must never turn
|
|
15
|
+
* a successful tool call into an error.
|
|
16
|
+
* 3. The replacement text must itself stay under the cap, with a reserved
|
|
17
|
+
* byte budget for the locator/notice so it can never overflow.
|
|
18
|
+
* 4. Skip spill for reading tools to avoid a read -> spill -> read cycle.
|
|
19
|
+
*/
|
|
20
|
+
import { promises as fs } from 'node:fs';
|
|
21
|
+
import path from 'node:path';
|
|
22
|
+
/**
|
|
23
|
+
* Append-only spill store. Each spill gets its own file so there is no
|
|
24
|
+
* locking or ordering concern. The locator is the absolute file path — simple,
|
|
25
|
+
* unique per write, and trivially re-fetchable by any file tool.
|
|
26
|
+
*/
|
|
27
|
+
export class SpillStore {
|
|
28
|
+
spillDir;
|
|
29
|
+
maxSpillBytes;
|
|
30
|
+
seq = 0;
|
|
31
|
+
constructor(options = {}) {
|
|
32
|
+
this.spillDir = options.spillDir ?? '.spill';
|
|
33
|
+
this.maxSpillBytes = options.maxSpillBytes ?? 20 * 1024 * 1024;
|
|
34
|
+
}
|
|
35
|
+
/** Lazily ensure the spill directory exists. */
|
|
36
|
+
async ensureDir() {
|
|
37
|
+
await fs.mkdir(this.spillDir, { recursive: true });
|
|
38
|
+
return this.spillDir;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Write `text` to a new spill file if it is non-empty and within limits.
|
|
42
|
+
* Never throws: any failure is reported via the `ok: false` shape.
|
|
43
|
+
*/
|
|
44
|
+
async saveText(text, tag) {
|
|
45
|
+
try {
|
|
46
|
+
if (typeof text !== 'string' || text.length === 0) {
|
|
47
|
+
return { ok: false, error: 'nothing to spill' };
|
|
48
|
+
}
|
|
49
|
+
const bytes = Buffer.byteLength(text, 'utf8');
|
|
50
|
+
if (bytes > this.maxSpillBytes) {
|
|
51
|
+
return { ok: false, error: `spill exceeds maxSpillBytes (${bytes} > ${this.maxSpillBytes})` };
|
|
52
|
+
}
|
|
53
|
+
const dir = await this.ensureDir();
|
|
54
|
+
const seq = ++this.seq;
|
|
55
|
+
const safeTag = (tag ?? 'result').replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 40);
|
|
56
|
+
const fileName = `${Date.now()}-${seq}-${safeTag}.spill.txt`;
|
|
57
|
+
const filePath = path.join(dir, fileName);
|
|
58
|
+
await fs.writeFile(filePath, text, 'utf8');
|
|
59
|
+
return { ok: true, entry: { locator: filePath, path: filePath, size: bytes } };
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
return { ok: false, error: err?.message ? String(err.message) : String(err) };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Read a spilled payload back by its locator (the absolute path). */
|
|
66
|
+
async read(locator) {
|
|
67
|
+
try {
|
|
68
|
+
// Defensive: only allow reads of files under our spill directory.
|
|
69
|
+
const resolved = path.resolve(locator);
|
|
70
|
+
const dir = path.resolve(this.spillDir);
|
|
71
|
+
if (!resolved.startsWith(dir + path.sep) && resolved !== dir) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
return await fs.readFile(resolved, 'utf8');
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Build the compact model-visible preview for a spilled blob: head + "…truncated…"
|
|
83
|
+
* + tail, sized so head+tail+notice fit within `previewBytes` with room to spare.
|
|
84
|
+
*/
|
|
85
|
+
export function buildPreview(text, previewBytes = 4000) {
|
|
86
|
+
// Reserve ~10% for the locator notice so the replacement never overflows.
|
|
87
|
+
const headBudget = Math.floor((previewBytes * 0.9) / 2);
|
|
88
|
+
const tailBudget = Math.floor((previewBytes * 0.9) / 2);
|
|
89
|
+
const total = text.length;
|
|
90
|
+
if (total <= previewBytes * 0.9)
|
|
91
|
+
return text;
|
|
92
|
+
const head = text.slice(0, headBudget);
|
|
93
|
+
const tail = text.slice(total - tailBudget);
|
|
94
|
+
const omitted = total - headBudget - tailBudget;
|
|
95
|
+
return `${head}\n\n…[${omitted} chars omitted; full result spilled to disk]…\n\n${tail}`;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Apply the spill policy to a single tool result content string.
|
|
99
|
+
*
|
|
100
|
+
* Returns a tagged result so the caller can distinguish:
|
|
101
|
+
* - `{ kind: 'keep', content }` — unchanged (small, or tool excluded)
|
|
102
|
+
* - `{ kind: 'spill', content, entry }` — spilled; preview replaces content
|
|
103
|
+
* - `{ kind: 'failed', content }` — spill attempted but failed; keep original
|
|
104
|
+
*/
|
|
105
|
+
export async function applySpillPolicy(text, store, options = {}) {
|
|
106
|
+
const maxInlineBytes = options.maxInlineBytes ?? 20000;
|
|
107
|
+
const previewBytes = options.previewBytes ?? 4000;
|
|
108
|
+
const bytes = Buffer.byteLength(text, 'utf8');
|
|
109
|
+
if (bytes <= maxInlineBytes)
|
|
110
|
+
return { kind: 'keep', content: text };
|
|
111
|
+
const saved = await store.saveText(text);
|
|
112
|
+
if (!saved.ok) {
|
|
113
|
+
// Best-effort: never turn a success into an error, never lose data.
|
|
114
|
+
return { kind: 'failed', content: text, error: saved.error };
|
|
115
|
+
}
|
|
116
|
+
const preview = buildPreview(text, previewBytes);
|
|
117
|
+
const notice = `\n\n[Full ${bytes} bytes spilled to: ${saved.entry.locator}]`;
|
|
118
|
+
return { kind: 'spill', content: preview + notice, entry: saved.entry };
|
|
119
|
+
}
|
|
120
|
+
/** Skip spill for a given tool name (avoid read -> spill -> read loops). */
|
|
121
|
+
export function shouldNeverSpill(toolName, neverSpillTools = []) {
|
|
122
|
+
if (neverSpillTools.length === 0)
|
|
123
|
+
return false;
|
|
124
|
+
return neverSpillTools.some((n) => toolName === n || toolName.toLowerCase().includes(n.toLowerCase()));
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=spill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spill.js","sourceRoot":"","sources":["../../src/utils/spill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Estimation & Counting
|
|
3
|
+
*
|
|
4
|
+
* Provides rough token estimation (character-based) and
|
|
5
|
+
* API-based exact counting when available.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Rough token estimation: ~4 chars per token (conservative).
|
|
9
|
+
*/
|
|
10
|
+
export declare function estimateTokens(text: string): number;
|
|
11
|
+
/**
|
|
12
|
+
* Estimate tokens for a message array.
|
|
13
|
+
*/
|
|
14
|
+
export declare function estimateMessagesTokens(messages: Array<{
|
|
15
|
+
role: string;
|
|
16
|
+
content: any;
|
|
17
|
+
}>): number;
|
|
18
|
+
/**
|
|
19
|
+
* Estimate tokens for a system prompt.
|
|
20
|
+
*/
|
|
21
|
+
export declare function estimateSystemPromptTokens(systemPrompt: string): number;
|
|
22
|
+
/**
|
|
23
|
+
* Count tokens from API usage response.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getTokenCountFromUsage(usage: {
|
|
26
|
+
input_tokens: number;
|
|
27
|
+
output_tokens: number;
|
|
28
|
+
cache_creation_input_tokens?: number;
|
|
29
|
+
cache_read_input_tokens?: number;
|
|
30
|
+
}): number;
|
|
31
|
+
/**
|
|
32
|
+
* Get the context window size for a model.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getContextWindowSize(model: string, contextWindowSize?: number): number;
|
|
35
|
+
/**
|
|
36
|
+
* Auto-compact buffer: trigger compaction when within this many tokens of the limit.
|
|
37
|
+
*/
|
|
38
|
+
export declare const AUTOCOMPACT_BUFFER_TOKENS = 13000;
|
|
39
|
+
/**
|
|
40
|
+
* Get the auto-compact threshold for a model.
|
|
41
|
+
*/
|
|
42
|
+
export declare function getAutoCompactThreshold(model: string, contextWindowSize?: number): number;
|
|
43
|
+
/**
|
|
44
|
+
* Model pricing (USD per token).
|
|
45
|
+
*/
|
|
46
|
+
export declare const MODEL_PRICING: Record<string, {
|
|
47
|
+
input: number;
|
|
48
|
+
output: number;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Estimate cost from usage and model.
|
|
52
|
+
*/
|
|
53
|
+
export declare function estimateCost(model: string, usage: {
|
|
54
|
+
input_tokens: number;
|
|
55
|
+
output_tokens: number;
|
|
56
|
+
}, pricing?: {
|
|
57
|
+
input: number;
|
|
58
|
+
output: number;
|
|
59
|
+
}): number;
|
|
60
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC,GAC9C,MAAM,CAmBR;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,2BAA2B,CAAC,EAAE,MAAM,CAAA;IACpC,uBAAuB,CAAC,EAAE,MAAM,CAAA;CACjC,GAAG,MAAM,CAOT;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,iBAAiB,CAAC,EAAE,MAAM,GACzB,MAAM,CAwBR;AAED;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAS,CAAA;AAE/C;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,iBAAiB,CAAC,EAAE,MAAM,GACzB,MAAM,CAER;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAuB3E,CAAA;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,EACtD,OAAO,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C,MAAM,CAeR"}
|