@codeany/open-agent-sdk 0.2.2 → 0.2.4
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 +113 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +453 -0
- package/dist/agent.js.map +1 -0
- package/dist/engine.d.ts +62 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +496 -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 +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +133 -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 +212 -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/{src/skills/bundled/debug.ts → dist/skills/bundled/debug.js} +20 -22
- 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/{src/skills/bundled/review.ts → dist/skills/bundled/review.js} +18 -21
- 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/{src/skills/bundled/simplify.ts → dist/skills/bundled/simplify.js} +16 -19
- 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/{src/skills/bundled/test.ts → dist/skills/bundled/test.js} +18 -21
- 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 +146 -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/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 +432 -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/tokens.d.ts +57 -0
- package/dist/utils/tokens.d.ts.map +1 -0
- package/dist/utils/tokens.js +134 -0
- package/dist/utils/tokens.js.map +1 -0
- package/package.json +6 -1
- package/.env.example +0 -8
- package/examples/01-simple-query.ts +0 -43
- package/examples/02-multi-tool.ts +0 -44
- package/examples/03-multi-turn.ts +0 -39
- package/examples/04-prompt-api.ts +0 -29
- package/examples/05-custom-system-prompt.ts +0 -26
- package/examples/06-mcp-server.ts +0 -49
- package/examples/07-custom-tools.ts +0 -87
- package/examples/08-official-api-compat.ts +0 -38
- package/examples/09-subagents.ts +0 -48
- package/examples/10-permissions.ts +0 -40
- package/examples/11-custom-mcp-tools.ts +0 -101
- package/examples/12-skills.ts +0 -88
- package/examples/13-hooks.ts +0 -88
- package/examples/14-openai-compat.ts +0 -71
- package/examples/web/index.html +0 -365
- package/examples/web/server.ts +0 -157
- package/src/agent.ts +0 -516
- package/src/engine.ts +0 -633
- package/src/hooks.ts +0 -261
- package/src/index.ts +0 -426
- package/src/mcp/client.ts +0 -150
- package/src/providers/anthropic.ts +0 -60
- package/src/providers/index.ts +0 -34
- package/src/providers/openai.ts +0 -315
- package/src/providers/types.ts +0 -85
- package/src/sdk-mcp-server.ts +0 -78
- package/src/session.ts +0 -227
- package/src/skills/bundled/commit.ts +0 -38
- package/src/skills/bundled/index.ts +0 -28
- package/src/skills/index.ts +0 -25
- package/src/skills/registry.ts +0 -133
- package/src/skills/types.ts +0 -99
- package/src/tool-helper.ts +0 -127
- package/src/tools/agent-tool.ts +0 -164
- package/src/tools/ask-user.ts +0 -79
- package/src/tools/bash.ts +0 -75
- package/src/tools/config-tool.ts +0 -89
- package/src/tools/cron-tools.ts +0 -153
- package/src/tools/edit.ts +0 -74
- package/src/tools/glob.ts +0 -77
- package/src/tools/grep.ts +0 -168
- package/src/tools/index.ts +0 -240
- package/src/tools/lsp-tool.ts +0 -163
- package/src/tools/mcp-resource-tools.ts +0 -125
- package/src/tools/notebook-edit.ts +0 -93
- package/src/tools/plan-tools.ts +0 -88
- package/src/tools/read.ts +0 -73
- package/src/tools/send-message.ts +0 -96
- package/src/tools/skill-tool.ts +0 -133
- package/src/tools/task-tools.ts +0 -290
- package/src/tools/team-tools.ts +0 -128
- package/src/tools/todo-tool.ts +0 -112
- package/src/tools/tool-search.ts +0 -87
- package/src/tools/types.ts +0 -66
- package/src/tools/web-fetch.ts +0 -66
- package/src/tools/web-search.ts +0 -86
- package/src/tools/worktree-tools.ts +0 -140
- package/src/tools/write.ts +0 -42
- package/src/types.ts +0 -486
- package/src/utils/compact.ts +0 -207
- package/src/utils/context.ts +0 -191
- package/src/utils/fileCache.ts +0 -148
- package/src/utils/messages.ts +0 -195
- package/src/utils/retry.ts +0 -140
- package/src/utils/tokens.ts +0 -145
- package/tsconfig.json +0 -19
package/src/engine.ts
DELETED
|
@@ -1,633 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* QueryEngine - Core agentic loop
|
|
3
|
-
*
|
|
4
|
-
* Manages the full conversation lifecycle:
|
|
5
|
-
* 1. Take user prompt
|
|
6
|
-
* 2. Build system prompt with context (git status, project context, tools)
|
|
7
|
-
* 3. Call LLM API with tools (via provider abstraction)
|
|
8
|
-
* 4. Stream response
|
|
9
|
-
* 5. Execute tool calls (concurrent for read-only, serial for mutations)
|
|
10
|
-
* 6. Send results back, repeat until done
|
|
11
|
-
* 7. Auto-compact when context exceeds threshold
|
|
12
|
-
* 8. Retry with exponential backoff on transient errors
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type {
|
|
16
|
-
SDKMessage,
|
|
17
|
-
QueryEngineConfig,
|
|
18
|
-
ToolDefinition,
|
|
19
|
-
ToolResult,
|
|
20
|
-
ToolContext,
|
|
21
|
-
TokenUsage,
|
|
22
|
-
} from './types.js'
|
|
23
|
-
import type {
|
|
24
|
-
LLMProvider,
|
|
25
|
-
CreateMessageResponse,
|
|
26
|
-
NormalizedMessageParam,
|
|
27
|
-
NormalizedTool,
|
|
28
|
-
} from './providers/types.js'
|
|
29
|
-
import {
|
|
30
|
-
estimateMessagesTokens,
|
|
31
|
-
estimateCost,
|
|
32
|
-
getAutoCompactThreshold,
|
|
33
|
-
} from './utils/tokens.js'
|
|
34
|
-
import {
|
|
35
|
-
shouldAutoCompact,
|
|
36
|
-
compactConversation,
|
|
37
|
-
microCompactMessages,
|
|
38
|
-
createAutoCompactState,
|
|
39
|
-
type AutoCompactState,
|
|
40
|
-
} from './utils/compact.js'
|
|
41
|
-
import {
|
|
42
|
-
withRetry,
|
|
43
|
-
isPromptTooLongError,
|
|
44
|
-
} from './utils/retry.js'
|
|
45
|
-
import { getSystemContext, getUserContext } from './utils/context.js'
|
|
46
|
-
import { normalizeMessagesForAPI } from './utils/messages.js'
|
|
47
|
-
import type { HookRegistry, HookInput, HookOutput } from './hooks.js'
|
|
48
|
-
|
|
49
|
-
// ============================================================================
|
|
50
|
-
// Tool format conversion
|
|
51
|
-
// ============================================================================
|
|
52
|
-
|
|
53
|
-
/** Convert a ToolDefinition to the normalized provider tool format. */
|
|
54
|
-
function toProviderTool(tool: ToolDefinition): NormalizedTool {
|
|
55
|
-
return {
|
|
56
|
-
name: tool.name,
|
|
57
|
-
description: tool.description,
|
|
58
|
-
input_schema: tool.inputSchema,
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ============================================================================
|
|
63
|
-
// ToolUseBlock (internal type for extracted tool_use blocks)
|
|
64
|
-
// ============================================================================
|
|
65
|
-
|
|
66
|
-
interface ToolUseBlock {
|
|
67
|
-
type: 'tool_use'
|
|
68
|
-
id: string
|
|
69
|
-
name: string
|
|
70
|
-
input: any
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// ============================================================================
|
|
74
|
-
// System Prompt Builder
|
|
75
|
-
// ============================================================================
|
|
76
|
-
|
|
77
|
-
async function buildSystemPrompt(config: QueryEngineConfig): Promise<string> {
|
|
78
|
-
if (config.systemPrompt) {
|
|
79
|
-
const base = config.systemPrompt
|
|
80
|
-
return config.appendSystemPrompt
|
|
81
|
-
? base + '\n\n' + config.appendSystemPrompt
|
|
82
|
-
: base
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const parts: string[] = []
|
|
86
|
-
|
|
87
|
-
parts.push(
|
|
88
|
-
'You are an AI assistant with access to tools. Use the tools provided to help the user accomplish their tasks.',
|
|
89
|
-
'You should use tools when they would help you complete the task more accurately or efficiently.',
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
// List available tools with descriptions
|
|
93
|
-
parts.push('\n# Available Tools\n')
|
|
94
|
-
for (const tool of config.tools) {
|
|
95
|
-
parts.push(`- **${tool.name}**: ${tool.description}`)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Add agent definitions
|
|
99
|
-
if (config.agents && Object.keys(config.agents).length > 0) {
|
|
100
|
-
parts.push('\n# Available Subagents\n')
|
|
101
|
-
for (const [name, def] of Object.entries(config.agents)) {
|
|
102
|
-
parts.push(`- **${name}**: ${def.description}`)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// System context (git status, etc.)
|
|
107
|
-
try {
|
|
108
|
-
const sysCtx = await getSystemContext(config.cwd)
|
|
109
|
-
if (sysCtx) {
|
|
110
|
-
parts.push('\n# Environment\n')
|
|
111
|
-
parts.push(sysCtx)
|
|
112
|
-
}
|
|
113
|
-
} catch {
|
|
114
|
-
// Context is best-effort
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// User context (AGENT.md, date)
|
|
118
|
-
try {
|
|
119
|
-
const userCtx = await getUserContext(config.cwd)
|
|
120
|
-
if (userCtx) {
|
|
121
|
-
parts.push('\n# Project Context\n')
|
|
122
|
-
parts.push(userCtx)
|
|
123
|
-
}
|
|
124
|
-
} catch {
|
|
125
|
-
// Context is best-effort
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Working directory
|
|
129
|
-
parts.push(`\n# Working Directory\n${config.cwd}`)
|
|
130
|
-
|
|
131
|
-
if (config.appendSystemPrompt) {
|
|
132
|
-
parts.push('\n' + config.appendSystemPrompt)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return parts.join('\n')
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// ============================================================================
|
|
139
|
-
// QueryEngine
|
|
140
|
-
// ============================================================================
|
|
141
|
-
|
|
142
|
-
export class QueryEngine {
|
|
143
|
-
private config: QueryEngineConfig
|
|
144
|
-
private provider: LLMProvider
|
|
145
|
-
public messages: NormalizedMessageParam[] = []
|
|
146
|
-
private totalUsage: TokenUsage = { input_tokens: 0, output_tokens: 0 }
|
|
147
|
-
private totalCost = 0
|
|
148
|
-
private turnCount = 0
|
|
149
|
-
private compactState: AutoCompactState
|
|
150
|
-
private sessionId: string
|
|
151
|
-
private apiTimeMs = 0
|
|
152
|
-
private hookRegistry?: HookRegistry
|
|
153
|
-
|
|
154
|
-
constructor(config: QueryEngineConfig) {
|
|
155
|
-
this.config = config
|
|
156
|
-
this.provider = config.provider
|
|
157
|
-
this.compactState = createAutoCompactState()
|
|
158
|
-
this.sessionId = config.sessionId || crypto.randomUUID()
|
|
159
|
-
this.hookRegistry = config.hookRegistry
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Execute hooks for a lifecycle event.
|
|
164
|
-
* Returns hook outputs; never throws.
|
|
165
|
-
*/
|
|
166
|
-
private async executeHooks(
|
|
167
|
-
event: import('./hooks.js').HookEvent,
|
|
168
|
-
extra?: Partial<HookInput>,
|
|
169
|
-
): Promise<HookOutput[]> {
|
|
170
|
-
if (!this.hookRegistry?.hasHooks(event)) return []
|
|
171
|
-
try {
|
|
172
|
-
return await this.hookRegistry.execute(event, {
|
|
173
|
-
event,
|
|
174
|
-
sessionId: this.sessionId,
|
|
175
|
-
cwd: this.config.cwd,
|
|
176
|
-
...extra,
|
|
177
|
-
})
|
|
178
|
-
} catch {
|
|
179
|
-
return []
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Submit a user message and run the agentic loop.
|
|
185
|
-
* Yields SDKMessage events as the agent works.
|
|
186
|
-
*/
|
|
187
|
-
async *submitMessage(
|
|
188
|
-
prompt: string | any[],
|
|
189
|
-
): AsyncGenerator<SDKMessage> {
|
|
190
|
-
// Hook: SessionStart
|
|
191
|
-
await this.executeHooks('SessionStart')
|
|
192
|
-
|
|
193
|
-
// Hook: UserPromptSubmit
|
|
194
|
-
const userHookResults = await this.executeHooks('UserPromptSubmit', {
|
|
195
|
-
toolInput: prompt,
|
|
196
|
-
})
|
|
197
|
-
// Check if any hook blocks the submission
|
|
198
|
-
if (userHookResults.some((r) => r.block)) {
|
|
199
|
-
yield {
|
|
200
|
-
type: 'result',
|
|
201
|
-
subtype: 'error_during_execution',
|
|
202
|
-
is_error: true,
|
|
203
|
-
usage: this.totalUsage,
|
|
204
|
-
num_turns: 0,
|
|
205
|
-
cost: 0,
|
|
206
|
-
errors: ['Blocked by UserPromptSubmit hook'],
|
|
207
|
-
}
|
|
208
|
-
return
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Add user message
|
|
212
|
-
this.messages.push({ role: 'user', content: prompt as any })
|
|
213
|
-
|
|
214
|
-
// Build tool definitions for provider
|
|
215
|
-
const tools = this.config.tools.map(toProviderTool)
|
|
216
|
-
|
|
217
|
-
// Build system prompt
|
|
218
|
-
const systemPrompt = await buildSystemPrompt(this.config)
|
|
219
|
-
|
|
220
|
-
// Emit init system message
|
|
221
|
-
yield {
|
|
222
|
-
type: 'system',
|
|
223
|
-
subtype: 'init',
|
|
224
|
-
session_id: this.sessionId,
|
|
225
|
-
tools: this.config.tools.map(t => t.name),
|
|
226
|
-
model: this.config.model,
|
|
227
|
-
cwd: this.config.cwd,
|
|
228
|
-
mcp_servers: [],
|
|
229
|
-
permission_mode: 'bypassPermissions',
|
|
230
|
-
} as SDKMessage
|
|
231
|
-
|
|
232
|
-
// Agentic loop
|
|
233
|
-
let turnsRemaining = this.config.maxTurns
|
|
234
|
-
let budgetExceeded = false
|
|
235
|
-
let maxOutputRecoveryAttempts = 0
|
|
236
|
-
const MAX_OUTPUT_RECOVERY = 3
|
|
237
|
-
|
|
238
|
-
while (turnsRemaining > 0) {
|
|
239
|
-
if (this.config.abortSignal?.aborted) break
|
|
240
|
-
|
|
241
|
-
// Check budget
|
|
242
|
-
if (this.config.maxBudgetUsd && this.totalCost >= this.config.maxBudgetUsd) {
|
|
243
|
-
budgetExceeded = true
|
|
244
|
-
break
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Auto-compact if context is too large
|
|
248
|
-
if (shouldAutoCompact(this.messages as any[], this.config.model, this.compactState)) {
|
|
249
|
-
await this.executeHooks('PreCompact')
|
|
250
|
-
try {
|
|
251
|
-
const result = await compactConversation(
|
|
252
|
-
this.provider,
|
|
253
|
-
this.config.model,
|
|
254
|
-
this.messages as any[],
|
|
255
|
-
this.compactState,
|
|
256
|
-
)
|
|
257
|
-
this.messages = result.compactedMessages as NormalizedMessageParam[]
|
|
258
|
-
this.compactState = result.state
|
|
259
|
-
await this.executeHooks('PostCompact')
|
|
260
|
-
} catch {
|
|
261
|
-
// Continue with uncompacted messages
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Micro-compact: truncate large tool results
|
|
266
|
-
const apiMessages = microCompactMessages(
|
|
267
|
-
normalizeMessagesForAPI(this.messages as any[]),
|
|
268
|
-
) as NormalizedMessageParam[]
|
|
269
|
-
|
|
270
|
-
this.turnCount++
|
|
271
|
-
turnsRemaining--
|
|
272
|
-
|
|
273
|
-
// Make API call with retry via provider
|
|
274
|
-
let response: CreateMessageResponse
|
|
275
|
-
const apiStart = performance.now()
|
|
276
|
-
try {
|
|
277
|
-
response = await withRetry(
|
|
278
|
-
async () => {
|
|
279
|
-
return this.provider.createMessage({
|
|
280
|
-
model: this.config.model,
|
|
281
|
-
maxTokens: this.config.maxTokens,
|
|
282
|
-
system: systemPrompt,
|
|
283
|
-
messages: apiMessages,
|
|
284
|
-
tools: tools.length > 0 ? tools : undefined,
|
|
285
|
-
thinking:
|
|
286
|
-
this.config.thinking?.type === 'enabled' &&
|
|
287
|
-
this.config.thinking.budgetTokens
|
|
288
|
-
? {
|
|
289
|
-
type: 'enabled',
|
|
290
|
-
budget_tokens: this.config.thinking.budgetTokens,
|
|
291
|
-
}
|
|
292
|
-
: undefined,
|
|
293
|
-
})
|
|
294
|
-
},
|
|
295
|
-
undefined,
|
|
296
|
-
this.config.abortSignal,
|
|
297
|
-
)
|
|
298
|
-
} catch (err: any) {
|
|
299
|
-
// Handle prompt-too-long by compacting
|
|
300
|
-
if (isPromptTooLongError(err) && !this.compactState.compacted) {
|
|
301
|
-
try {
|
|
302
|
-
const result = await compactConversation(
|
|
303
|
-
this.provider,
|
|
304
|
-
this.config.model,
|
|
305
|
-
this.messages as any[],
|
|
306
|
-
this.compactState,
|
|
307
|
-
)
|
|
308
|
-
this.messages = result.compactedMessages as NormalizedMessageParam[]
|
|
309
|
-
this.compactState = result.state
|
|
310
|
-
turnsRemaining++ // Retry this turn
|
|
311
|
-
this.turnCount--
|
|
312
|
-
continue
|
|
313
|
-
} catch {
|
|
314
|
-
// Can't compact, give up
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const message = err?.message ? String(err.message) : String(err)
|
|
319
|
-
|
|
320
|
-
yield {
|
|
321
|
-
type: 'result',
|
|
322
|
-
subtype: 'error',
|
|
323
|
-
usage: this.totalUsage,
|
|
324
|
-
num_turns: this.turnCount,
|
|
325
|
-
cost: this.totalCost,
|
|
326
|
-
errors: [message],
|
|
327
|
-
}
|
|
328
|
-
return
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// Track API timing
|
|
332
|
-
this.apiTimeMs += performance.now() - apiStart
|
|
333
|
-
|
|
334
|
-
// Track usage (normalized by provider)
|
|
335
|
-
if (response.usage) {
|
|
336
|
-
this.totalUsage.input_tokens += response.usage.input_tokens
|
|
337
|
-
this.totalUsage.output_tokens += response.usage.output_tokens
|
|
338
|
-
if (response.usage.cache_creation_input_tokens) {
|
|
339
|
-
this.totalUsage.cache_creation_input_tokens =
|
|
340
|
-
(this.totalUsage.cache_creation_input_tokens || 0) +
|
|
341
|
-
response.usage.cache_creation_input_tokens
|
|
342
|
-
}
|
|
343
|
-
if (response.usage.cache_read_input_tokens) {
|
|
344
|
-
this.totalUsage.cache_read_input_tokens =
|
|
345
|
-
(this.totalUsage.cache_read_input_tokens || 0) +
|
|
346
|
-
response.usage.cache_read_input_tokens
|
|
347
|
-
}
|
|
348
|
-
this.totalCost += estimateCost(this.config.model, response.usage)
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Add assistant message to conversation
|
|
352
|
-
this.messages.push({ role: 'assistant', content: response.content as any })
|
|
353
|
-
|
|
354
|
-
// Yield assistant message
|
|
355
|
-
yield {
|
|
356
|
-
type: 'assistant',
|
|
357
|
-
message: {
|
|
358
|
-
role: 'assistant',
|
|
359
|
-
content: response.content as any,
|
|
360
|
-
},
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// Handle max_output_tokens recovery
|
|
364
|
-
if (
|
|
365
|
-
response.stopReason === 'max_tokens' &&
|
|
366
|
-
maxOutputRecoveryAttempts < MAX_OUTPUT_RECOVERY
|
|
367
|
-
) {
|
|
368
|
-
maxOutputRecoveryAttempts++
|
|
369
|
-
// Add continuation prompt
|
|
370
|
-
this.messages.push({
|
|
371
|
-
role: 'user',
|
|
372
|
-
content: 'Please continue from where you left off.',
|
|
373
|
-
})
|
|
374
|
-
continue
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Check for tool use
|
|
378
|
-
const toolUseBlocks = response.content.filter(
|
|
379
|
-
(block): block is ToolUseBlock => block.type === 'tool_use',
|
|
380
|
-
)
|
|
381
|
-
|
|
382
|
-
if (toolUseBlocks.length === 0) {
|
|
383
|
-
break // No tool calls - agent is done
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Reset max_output recovery counter on successful tool use
|
|
387
|
-
maxOutputRecoveryAttempts = 0
|
|
388
|
-
|
|
389
|
-
// Execute tools (concurrent read-only, serial mutations)
|
|
390
|
-
const toolResults = await this.executeTools(toolUseBlocks)
|
|
391
|
-
|
|
392
|
-
// Yield tool results
|
|
393
|
-
for (const result of toolResults) {
|
|
394
|
-
yield {
|
|
395
|
-
type: 'tool_result',
|
|
396
|
-
result: {
|
|
397
|
-
tool_use_id: result.tool_use_id,
|
|
398
|
-
tool_name: result.tool_name || '',
|
|
399
|
-
output:
|
|
400
|
-
typeof result.content === 'string'
|
|
401
|
-
? result.content
|
|
402
|
-
: JSON.stringify(result.content),
|
|
403
|
-
},
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Add tool results to conversation
|
|
408
|
-
this.messages.push({
|
|
409
|
-
role: 'user',
|
|
410
|
-
content: toolResults.map((r) => ({
|
|
411
|
-
type: 'tool_result' as const,
|
|
412
|
-
tool_use_id: r.tool_use_id,
|
|
413
|
-
content:
|
|
414
|
-
typeof r.content === 'string'
|
|
415
|
-
? r.content
|
|
416
|
-
: JSON.stringify(r.content),
|
|
417
|
-
is_error: r.is_error,
|
|
418
|
-
})),
|
|
419
|
-
})
|
|
420
|
-
|
|
421
|
-
if (response.stopReason === 'end_turn') break
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// Hook: Stop (end of agentic loop)
|
|
425
|
-
await this.executeHooks('Stop')
|
|
426
|
-
|
|
427
|
-
// Hook: SessionEnd
|
|
428
|
-
await this.executeHooks('SessionEnd')
|
|
429
|
-
|
|
430
|
-
// Yield enriched final result
|
|
431
|
-
const endSubtype = budgetExceeded
|
|
432
|
-
? 'error_max_budget_usd'
|
|
433
|
-
: turnsRemaining <= 0
|
|
434
|
-
? 'error_max_turns'
|
|
435
|
-
: 'success'
|
|
436
|
-
|
|
437
|
-
yield {
|
|
438
|
-
type: 'result',
|
|
439
|
-
subtype: endSubtype,
|
|
440
|
-
session_id: this.sessionId,
|
|
441
|
-
is_error: endSubtype !== 'success',
|
|
442
|
-
num_turns: this.turnCount,
|
|
443
|
-
total_cost_usd: this.totalCost,
|
|
444
|
-
duration_api_ms: Math.round(this.apiTimeMs),
|
|
445
|
-
usage: this.totalUsage,
|
|
446
|
-
model_usage: { [this.config.model]: { input_tokens: this.totalUsage.input_tokens, output_tokens: this.totalUsage.output_tokens } },
|
|
447
|
-
cost: this.totalCost,
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/**
|
|
452
|
-
* Execute tool calls with concurrency control.
|
|
453
|
-
*
|
|
454
|
-
* Read-only tools run concurrently (up to 10 at a time).
|
|
455
|
-
* Mutation tools run sequentially.
|
|
456
|
-
*/
|
|
457
|
-
private async executeTools(
|
|
458
|
-
toolUseBlocks: ToolUseBlock[],
|
|
459
|
-
): Promise<(ToolResult & { tool_name?: string })[]> {
|
|
460
|
-
const context: ToolContext = {
|
|
461
|
-
cwd: this.config.cwd,
|
|
462
|
-
abortSignal: this.config.abortSignal,
|
|
463
|
-
provider: this.provider,
|
|
464
|
-
model: this.config.model,
|
|
465
|
-
apiType: this.provider.apiType,
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
const MAX_CONCURRENCY = parseInt(
|
|
469
|
-
process.env.AGENT_SDK_MAX_TOOL_CONCURRENCY || '10',
|
|
470
|
-
)
|
|
471
|
-
|
|
472
|
-
// Partition into read-only (concurrent) and mutation (serial)
|
|
473
|
-
const readOnly: Array<{ block: ToolUseBlock; tool?: ToolDefinition }> = []
|
|
474
|
-
const mutations: Array<{ block: ToolUseBlock; tool?: ToolDefinition }> = []
|
|
475
|
-
|
|
476
|
-
for (const block of toolUseBlocks) {
|
|
477
|
-
const tool = this.config.tools.find((t) => t.name === block.name)
|
|
478
|
-
if (tool?.isReadOnly?.()) {
|
|
479
|
-
readOnly.push({ block, tool })
|
|
480
|
-
} else {
|
|
481
|
-
mutations.push({ block, tool })
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
const results: (ToolResult & { tool_name?: string })[] = []
|
|
486
|
-
|
|
487
|
-
// Execute read-only tools concurrently (batched by MAX_CONCURRENCY)
|
|
488
|
-
for (let i = 0; i < readOnly.length; i += MAX_CONCURRENCY) {
|
|
489
|
-
const batch = readOnly.slice(i, i + MAX_CONCURRENCY)
|
|
490
|
-
const batchResults = await Promise.all(
|
|
491
|
-
batch.map((item) =>
|
|
492
|
-
this.executeSingleTool(item.block, item.tool, context),
|
|
493
|
-
),
|
|
494
|
-
)
|
|
495
|
-
results.push(...batchResults)
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
// Execute mutation tools sequentially
|
|
499
|
-
for (const item of mutations) {
|
|
500
|
-
const result = await this.executeSingleTool(item.block, item.tool, context)
|
|
501
|
-
results.push(result)
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
return results
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/**
|
|
508
|
-
* Execute a single tool with permission checking.
|
|
509
|
-
*/
|
|
510
|
-
private async executeSingleTool(
|
|
511
|
-
block: ToolUseBlock,
|
|
512
|
-
tool: ToolDefinition | undefined,
|
|
513
|
-
context: ToolContext,
|
|
514
|
-
): Promise<ToolResult & { tool_name?: string }> {
|
|
515
|
-
if (!tool) {
|
|
516
|
-
return {
|
|
517
|
-
type: 'tool_result',
|
|
518
|
-
tool_use_id: block.id,
|
|
519
|
-
content: `Error: Unknown tool "${block.name}"`,
|
|
520
|
-
is_error: true,
|
|
521
|
-
tool_name: block.name,
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// Check enabled
|
|
526
|
-
if (tool.isEnabled && !tool.isEnabled()) {
|
|
527
|
-
return {
|
|
528
|
-
type: 'tool_result',
|
|
529
|
-
tool_use_id: block.id,
|
|
530
|
-
content: `Error: Tool "${block.name}" is not enabled`,
|
|
531
|
-
is_error: true,
|
|
532
|
-
tool_name: block.name,
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// Check permissions
|
|
537
|
-
if (this.config.canUseTool) {
|
|
538
|
-
try {
|
|
539
|
-
const permission = await this.config.canUseTool(tool, block.input)
|
|
540
|
-
if (permission.behavior === 'deny') {
|
|
541
|
-
return {
|
|
542
|
-
type: 'tool_result',
|
|
543
|
-
tool_use_id: block.id,
|
|
544
|
-
content: permission.message || `Permission denied for tool "${block.name}"`,
|
|
545
|
-
is_error: true,
|
|
546
|
-
tool_name: block.name,
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
if (permission.updatedInput !== undefined) {
|
|
550
|
-
block = { ...block, input: permission.updatedInput }
|
|
551
|
-
}
|
|
552
|
-
} catch (err: any) {
|
|
553
|
-
return {
|
|
554
|
-
type: 'tool_result',
|
|
555
|
-
tool_use_id: block.id,
|
|
556
|
-
content: `Permission check error: ${err.message}`,
|
|
557
|
-
is_error: true,
|
|
558
|
-
tool_name: block.name,
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// Hook: PreToolUse
|
|
564
|
-
const preHookResults = await this.executeHooks('PreToolUse', {
|
|
565
|
-
toolName: block.name,
|
|
566
|
-
toolInput: block.input,
|
|
567
|
-
toolUseId: block.id,
|
|
568
|
-
})
|
|
569
|
-
// Check if any hook blocks this tool
|
|
570
|
-
if (preHookResults.some((r) => r.block)) {
|
|
571
|
-
const msg = preHookResults.find((r) => r.message)?.message || 'Blocked by PreToolUse hook'
|
|
572
|
-
return {
|
|
573
|
-
type: 'tool_result',
|
|
574
|
-
tool_use_id: block.id,
|
|
575
|
-
content: msg,
|
|
576
|
-
is_error: true,
|
|
577
|
-
tool_name: block.name,
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// Execute the tool
|
|
582
|
-
try {
|
|
583
|
-
const result = await tool.call(block.input, context)
|
|
584
|
-
|
|
585
|
-
// Hook: PostToolUse
|
|
586
|
-
await this.executeHooks('PostToolUse', {
|
|
587
|
-
toolName: block.name,
|
|
588
|
-
toolInput: block.input,
|
|
589
|
-
toolOutput: typeof result.content === 'string' ? result.content : JSON.stringify(result.content),
|
|
590
|
-
toolUseId: block.id,
|
|
591
|
-
})
|
|
592
|
-
|
|
593
|
-
return { ...result, tool_use_id: block.id, tool_name: block.name }
|
|
594
|
-
} catch (err: any) {
|
|
595
|
-
// Hook: PostToolUseFailure
|
|
596
|
-
await this.executeHooks('PostToolUseFailure', {
|
|
597
|
-
toolName: block.name,
|
|
598
|
-
toolInput: block.input,
|
|
599
|
-
toolUseId: block.id,
|
|
600
|
-
error: err.message,
|
|
601
|
-
})
|
|
602
|
-
|
|
603
|
-
return {
|
|
604
|
-
type: 'tool_result',
|
|
605
|
-
tool_use_id: block.id,
|
|
606
|
-
content: `Tool execution error: ${err.message}`,
|
|
607
|
-
is_error: true,
|
|
608
|
-
tool_name: block.name,
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
/**
|
|
614
|
-
* Get current messages for session persistence.
|
|
615
|
-
*/
|
|
616
|
-
getMessages(): NormalizedMessageParam[] {
|
|
617
|
-
return [...this.messages]
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
/**
|
|
621
|
-
* Get total usage across all turns.
|
|
622
|
-
*/
|
|
623
|
-
getUsage(): TokenUsage {
|
|
624
|
-
return { ...this.totalUsage }
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* Get total cost.
|
|
629
|
-
*/
|
|
630
|
-
getCost(): number {
|
|
631
|
-
return this.totalCost
|
|
632
|
-
}
|
|
633
|
-
}
|