@codeany/open-agent-sdk 0.1.0 → 0.2.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/src/types.ts CHANGED
@@ -2,7 +2,17 @@
2
2
  * Core type definitions for the Agent SDK
3
3
  */
4
4
 
5
- import type Anthropic from '@anthropic-ai/sdk'
5
+ // Content block types (provider-agnostic, compatible with Anthropic format)
6
+ export type ContentBlockParam =
7
+ | { type: 'text'; text: string }
8
+ | { type: 'image'; source: any }
9
+ | { type: 'tool_use'; id: string; name: string; input: any }
10
+ | { type: 'tool_result'; tool_use_id: string; content: string | any[]; is_error?: boolean }
11
+
12
+ export type ContentBlock =
13
+ | { type: 'text'; text: string }
14
+ | { type: 'tool_use'; id: string; name: string; input: any }
15
+ | { type: 'thinking'; thinking: string }
6
16
 
7
17
  // --------------------------------------------------------------------------
8
18
  // Message Types
@@ -12,7 +22,7 @@ export type MessageRole = 'user' | 'assistant'
12
22
 
13
23
  export interface ConversationMessage {
14
24
  role: MessageRole
15
- content: string | Anthropic.ContentBlockParam[]
25
+ content: string | ContentBlockParam[]
16
26
  }
17
27
 
18
28
  export interface UserMessage {
@@ -26,7 +36,7 @@ export interface AssistantMessage {
26
36
  type: 'assistant'
27
37
  message: {
28
38
  role: 'assistant'
29
- content: Anthropic.ContentBlock[]
39
+ content: ContentBlock[]
30
40
  }
31
41
  uuid: string
32
42
  timestamp: string
@@ -57,7 +67,7 @@ export interface SDKAssistantMessage {
57
67
  session_id?: string
58
68
  message: {
59
69
  role: 'assistant'
60
- content: Anthropic.ContentBlock[]
70
+ content: ContentBlock[]
61
71
  }
62
72
  parent_tool_use_id?: string | null
63
73
  }
@@ -181,12 +191,18 @@ export interface ToolInputSchema {
181
191
  export interface ToolContext {
182
192
  cwd: string
183
193
  abortSignal?: AbortSignal
194
+ /** Parent agent's LLM provider (inherited by subagents) */
195
+ provider?: import('./providers/types.js').LLMProvider
196
+ /** Parent agent's model ID */
197
+ model?: string
198
+ /** Parent agent's API type */
199
+ apiType?: import('./providers/types.js').ApiType
184
200
  }
185
201
 
186
202
  export interface ToolResult {
187
203
  type: 'tool_result'
188
204
  tool_use_id: string
189
- content: string | Anthropic.ToolResultBlockParam['content']
205
+ content: string | any[]
190
206
  is_error?: boolean
191
207
  }
192
208
 
@@ -202,8 +218,10 @@ export type PermissionMode =
202
218
  | 'dontAsk'
203
219
  | 'auto'
204
220
 
221
+ export type PermissionBehavior = 'allow' | 'deny'
222
+
205
223
  export type CanUseToolResult = {
206
- behavior: 'allow' | 'deny'
224
+ behavior: PermissionBehavior
207
225
  updatedInput?: unknown
208
226
  message?: string
209
227
  }
@@ -326,6 +344,11 @@ export interface ModelInfo {
326
344
  export interface AgentOptions {
327
345
  /** LLM model ID */
328
346
  model?: string
347
+ /**
348
+ * API type: 'anthropic-messages' or 'openai-completions'.
349
+ * Falls back to CODEANY_API_TYPE env var. Default: 'anthropic-messages'.
350
+ */
351
+ apiType?: import('./providers/types.js').ApiType
329
352
  /** API key. Falls back to CODEANY_API_KEY env var. */
330
353
  apiKey?: string
331
354
  /** API base URL override */
@@ -442,8 +465,8 @@ export interface QueryResult {
442
465
  export interface QueryEngineConfig {
443
466
  cwd: string
444
467
  model: string
445
- apiKey?: string
446
- baseURL?: string
468
+ /** LLM provider instance (created from apiType) */
469
+ provider: import('./providers/types.js').LLMProvider
447
470
  tools: ToolDefinition[]
448
471
  systemPrompt?: string
449
472
  appendSystemPrompt?: string
@@ -456,4 +479,8 @@ export interface QueryEngineConfig {
456
479
  includePartialMessages: boolean
457
480
  abortSignal?: AbortSignal
458
481
  agents?: Record<string, AgentDefinition>
482
+ /** Hook registry for lifecycle events */
483
+ hookRegistry?: import('./hooks.js').HookRegistry
484
+ /** Session ID for hook context */
485
+ sessionId?: string
459
486
  }
@@ -8,7 +8,8 @@
8
8
  * 3. Session memory compaction: consolidates across sessions
9
9
  */
10
10
 
11
- import Anthropic from '@anthropic-ai/sdk'
11
+ import type { LLMProvider } from '../providers/types.js'
12
+ import type { NormalizedMessageParam } from '../providers/types.js'
12
13
  import {
13
14
  estimateMessagesTokens,
14
15
  getAutoCompactThreshold,
@@ -38,7 +39,7 @@ export function createAutoCompactState(): AutoCompactState {
38
39
  * Check if auto-compaction should trigger.
39
40
  */
40
41
  export function shouldAutoCompact(
41
- messages: Anthropic.MessageParam[],
42
+ messages: any[],
42
43
  model: string,
43
44
  state: AutoCompactState,
44
45
  ): boolean {
@@ -57,12 +58,12 @@ export function shouldAutoCompact(
57
58
  * then replaces the history with a compact summary.
58
59
  */
59
60
  export async function compactConversation(
60
- client: Anthropic,
61
+ provider: LLMProvider,
61
62
  model: string,
62
- messages: Anthropic.MessageParam[],
63
+ messages: any[],
63
64
  state: AutoCompactState,
64
65
  ): Promise<{
65
- compactedMessages: Anthropic.MessageParam[]
66
+ compactedMessages: NormalizedMessageParam[]
66
67
  summary: string
67
68
  state: AutoCompactState
68
69
  }> {
@@ -73,9 +74,9 @@ export async function compactConversation(
73
74
  // Build compaction prompt
74
75
  const compactionPrompt = buildCompactionPrompt(strippedMessages)
75
76
 
76
- const response = await client.messages.create({
77
+ const response = await provider.createMessage({
77
78
  model,
78
- max_tokens: 8192,
79
+ maxTokens: 8192,
79
80
  system: 'You are a conversation summarizer. Create a detailed summary of the conversation that preserves all important context, decisions made, files modified, tool outputs, and current state. The summary should allow the conversation to continue seamlessly.',
80
81
  messages: [
81
82
  {
@@ -86,12 +87,12 @@ export async function compactConversation(
86
87
  })
87
88
 
88
89
  const summary = response.content
89
- .filter((b): b is Anthropic.TextBlock => b.type === 'text')
90
- .map((b) => b.text)
90
+ .filter((b) => b.type === 'text')
91
+ .map((b) => (b as { type: 'text'; text: string }).text)
91
92
  .join('\n')
92
93
 
93
94
  // Replace messages with summary
94
- const compactedMessages: Anthropic.MessageParam[] = [
95
+ const compactedMessages: NormalizedMessageParam[] = [
95
96
  {
96
97
  role: 'user',
97
98
  content: `[Previous conversation summary]\n\n${summary}\n\n[End of summary - conversation continues below]`,
@@ -127,9 +128,9 @@ export async function compactConversation(
127
128
  * Strip images from messages for compaction safety.
128
129
  */
129
130
  function stripImagesFromMessages(
130
- messages: Anthropic.MessageParam[],
131
- ): Anthropic.MessageParam[] {
132
- return messages.map((msg) => {
131
+ messages: any[],
132
+ ): any[] {
133
+ return messages.map((msg: any) => {
133
134
  if (typeof msg.content === 'string') return msg
134
135
 
135
136
  const filtered = (msg.content as any[]).filter((block: any) => {
@@ -143,7 +144,7 @@ function stripImagesFromMessages(
143
144
  /**
144
145
  * Build compaction prompt from messages.
145
146
  */
146
- function buildCompactionPrompt(messages: Anthropic.MessageParam[]): string {
147
+ function buildCompactionPrompt(messages: any[]): string {
147
148
  const parts: string[] = ['Please summarize this conversation:\n']
148
149
 
149
150
  for (const msg of messages) {
@@ -179,10 +180,10 @@ function buildCompactionPrompt(messages: Anthropic.MessageParam[]): string {
179
180
  * to fit within token budgets.
180
181
  */
181
182
  export function microCompactMessages(
182
- messages: Anthropic.MessageParam[],
183
+ messages: any[],
183
184
  maxToolResultChars: number = 50000,
184
- ): Anthropic.MessageParam[] {
185
- return messages.map((msg) => {
185
+ ): any[] {
186
+ return messages.map((msg: any) => {
186
187
  if (typeof msg.content === 'string') return msg
187
188
  if (!Array.isArray(msg.content)) return msg
188
189
 
@@ -5,14 +5,13 @@
5
5
  * synthetic placeholders, and content processing.
6
6
  */
7
7
 
8
- import type Anthropic from '@anthropic-ai/sdk'
9
8
  import type { Message, UserMessage, AssistantMessage, TokenUsage } from '../types.js'
10
9
 
11
10
  /**
12
11
  * Create a user message.
13
12
  */
14
13
  export function createUserMessage(
15
- content: string | Anthropic.ContentBlockParam[],
14
+ content: string | any[],
16
15
  options?: {
17
16
  uuid?: string
18
17
  isMeta?: boolean
@@ -34,7 +33,7 @@ export function createUserMessage(
34
33
  * Create an assistant message.
35
34
  */
36
35
  export function createAssistantMessage(
37
- content: Anthropic.ContentBlock[],
36
+ content: any[],
38
37
  usage?: TokenUsage,
39
38
  ): AssistantMessage {
40
39
  return {
@@ -55,9 +54,9 @@ export function createAssistantMessage(
55
54
  * and fixes tool result pairing.
56
55
  */
57
56
  export function normalizeMessagesForAPI(
58
- messages: Anthropic.MessageParam[],
59
- ): Anthropic.MessageParam[] {
60
- const normalized: Anthropic.MessageParam[] = []
57
+ messages: Array<{ role: string; content: any }>,
58
+ ): Array<{ role: string; content: any }> {
59
+ const normalized: Array<{ role: string; content: any }> = []
61
60
 
62
61
  for (let i = 0; i < messages.length; i++) {
63
62
  const msg = messages[i]
@@ -96,9 +95,9 @@ export function normalizeMessagesForAPI(
96
95
  * matching tool_use in the previous assistant message.
97
96
  */
98
97
  function fixToolResultPairing(
99
- messages: Anthropic.MessageParam[],
100
- ): Anthropic.MessageParam[] {
101
- const result: Anthropic.MessageParam[] = []
98
+ messages: Array<{ role: string; content: any }>,
99
+ ): Array<{ role: string; content: any }> {
100
+ const result: Array<{ role: string; content: any }> = []
102
101
 
103
102
  for (let i = 0; i < messages.length; i++) {
104
103
  const msg = messages[i]
@@ -145,8 +144,8 @@ function fixToolResultPairing(
145
144
  * Strip images from messages (for compaction).
146
145
  */
147
146
  export function stripImagesFromMessages(
148
- messages: Anthropic.MessageParam[],
149
- ): Anthropic.MessageParam[] {
147
+ messages: Array<{ role: string; content: any }>,
148
+ ): Array<{ role: string; content: any }> {
150
149
  return messages.map((msg) => {
151
150
  if (typeof msg.content === 'string') return msg
152
151
  if (!Array.isArray(msg.content)) return msg
@@ -166,7 +165,7 @@ export function stripImagesFromMessages(
166
165
  * Extract text from message content blocks.
167
166
  */
168
167
  export function extractTextFromContent(
169
- content: Anthropic.ContentBlock[] | string,
168
+ content: any[] | string,
170
169
  ): string {
171
170
  if (typeof content === 'string') return content
172
171
 
@@ -179,7 +178,7 @@ export function extractTextFromContent(
179
178
  /**
180
179
  * Create a system message for compact boundary.
181
180
  */
182
- export function createCompactBoundaryMessage(): Anthropic.MessageParam {
181
+ export function createCompactBoundaryMessage(): { role: string; content: string } {
183
182
  return {
184
183
  role: 'user',
185
184
  content: '[Previous context has been summarized above. Continuing conversation.]',
@@ -5,8 +5,6 @@
5
5
  * API-based exact counting when available.
6
6
  */
7
7
 
8
- import Anthropic from '@anthropic-ai/sdk'
9
-
10
8
  /**
11
9
  * Rough token estimation: ~4 chars per token (conservative).
12
10
  */
@@ -18,7 +16,7 @@ export function estimateTokens(text: string): number {
18
16
  * Estimate tokens for a message array.
19
17
  */
20
18
  export function estimateMessagesTokens(
21
- messages: Anthropic.MessageParam[],
19
+ messages: Array<{ role: string; content: any }>,
22
20
  ): number {
23
21
  let total = 0
24
22
  for (const msg of messages) {
@@ -68,15 +66,26 @@ export function getTokenCountFromUsage(usage: {
68
66
  * Get the context window size for a model.
69
67
  */
70
68
  export function getContextWindowSize(model: string): number {
71
- // Model context windows
69
+ // Anthropic model context windows
72
70
  if (model.includes('opus-4') && model.includes('1m')) return 1_000_000
73
71
  if (model.includes('opus-4')) return 200_000
74
72
  if (model.includes('sonnet-4')) return 200_000
75
73
  if (model.includes('haiku-4')) return 200_000
76
-
77
-
78
74
  if (model.includes('claude-3')) return 200_000
79
75
 
76
+ // OpenAI model context windows
77
+ if (model.includes('gpt-4o')) return 128_000
78
+ if (model.includes('gpt-4-turbo')) return 128_000
79
+ if (model.includes('gpt-4-1')) return 1_000_000
80
+ if (model.includes('gpt-4')) return 128_000
81
+ if (model.includes('gpt-3.5')) return 16_385
82
+ if (model.includes('o1')) return 200_000
83
+ if (model.includes('o3')) return 200_000
84
+ if (model.includes('o4')) return 200_000
85
+
86
+ // DeepSeek models
87
+ if (model.includes('deepseek')) return 128_000
88
+
80
89
  // Default
81
90
  return 200_000
82
91
  }
@@ -97,6 +106,7 @@ export function getAutoCompactThreshold(model: string): number {
97
106
  * Model pricing (USD per token).
98
107
  */
99
108
  export const MODEL_PRICING: Record<string, { input: number; output: number }> = {
109
+ // Anthropic models
100
110
  'claude-opus-4-6': { input: 15 / 1_000_000, output: 75 / 1_000_000 },
101
111
  'claude-opus-4-5': { input: 15 / 1_000_000, output: 75 / 1_000_000 },
102
112
  'claude-sonnet-4-6': { input: 3 / 1_000_000, output: 15 / 1_000_000 },
@@ -105,6 +115,19 @@ export const MODEL_PRICING: Record<string, { input: number; output: number }> =
105
115
  'claude-3-5-sonnet': { input: 3 / 1_000_000, output: 15 / 1_000_000 },
106
116
  'claude-3-5-haiku': { input: 0.8 / 1_000_000, output: 4 / 1_000_000 },
107
117
  'claude-3-opus': { input: 15 / 1_000_000, output: 75 / 1_000_000 },
118
+
119
+ // OpenAI models
120
+ 'gpt-4o': { input: 2.5 / 1_000_000, output: 10 / 1_000_000 },
121
+ 'gpt-4o-mini': { input: 0.15 / 1_000_000, output: 0.6 / 1_000_000 },
122
+ 'gpt-4-turbo': { input: 10 / 1_000_000, output: 30 / 1_000_000 },
123
+ 'gpt-4-1': { input: 2 / 1_000_000, output: 8 / 1_000_000 },
124
+ 'o1': { input: 15 / 1_000_000, output: 60 / 1_000_000 },
125
+ 'o3': { input: 10 / 1_000_000, output: 40 / 1_000_000 },
126
+ 'o4-mini': { input: 1.1 / 1_000_000, output: 4.4 / 1_000_000 },
127
+
128
+ // DeepSeek models
129
+ 'deepseek-chat': { input: 0.27 / 1_000_000, output: 1.1 / 1_000_000 },
130
+ 'deepseek-reasoner': { input: 0.55 / 1_000_000, output: 2.19 / 1_000_000 },
108
131
  }
109
132
 
110
133
  /**