@codeany/open-agent-sdk 0.1.0 → 0.2.1
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/README.md +144 -31
- package/dist/agent.d.ts +113 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +446 -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 +494 -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/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 +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 +423 -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 +7 -1
- package/src/agent.ts +106 -15
- package/src/engine.ts +169 -59
- package/src/index.ts +51 -1
- package/src/providers/anthropic.ts +60 -0
- package/src/providers/index.ts +34 -0
- package/src/providers/openai.ts +315 -0
- package/src/providers/types.ts +85 -0
- package/src/session.ts +5 -5
- package/src/skills/bundled/commit.ts +38 -0
- package/src/skills/bundled/debug.ts +48 -0
- package/src/skills/bundled/index.ts +28 -0
- package/src/skills/bundled/review.ts +41 -0
- package/src/skills/bundled/simplify.ts +51 -0
- package/src/skills/bundled/test.ts +43 -0
- package/src/skills/index.ts +25 -0
- package/src/skills/registry.ts +133 -0
- package/src/skills/types.ts +99 -0
- package/src/tools/agent-tool.ts +13 -2
- package/src/tools/index.ts +8 -0
- package/src/tools/skill-tool.ts +133 -0
- package/src/tools/types.ts +7 -3
- package/src/types.ts +35 -8
- package/src/utils/compact.ts +18 -17
- package/src/utils/messages.ts +12 -13
- package/src/utils/tokens.ts +29 -6
- 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/web/index.html +0 -365
- package/examples/web/server.ts +0 -157
- package/tsconfig.json +0 -19
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills Module - Public API
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Types
|
|
6
|
+
export type {
|
|
7
|
+
SkillDefinition,
|
|
8
|
+
SkillContentBlock,
|
|
9
|
+
SkillResult,
|
|
10
|
+
} from './types.js'
|
|
11
|
+
|
|
12
|
+
// Registry
|
|
13
|
+
export {
|
|
14
|
+
registerSkill,
|
|
15
|
+
getSkill,
|
|
16
|
+
getAllSkills,
|
|
17
|
+
getUserInvocableSkills,
|
|
18
|
+
hasSkill,
|
|
19
|
+
unregisterSkill,
|
|
20
|
+
clearSkills,
|
|
21
|
+
formatSkillsForPrompt,
|
|
22
|
+
} from './registry.js'
|
|
23
|
+
|
|
24
|
+
// Bundled skills
|
|
25
|
+
export { initBundledSkills } from './bundled/index.js'
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Registry
|
|
3
|
+
*
|
|
4
|
+
* Central registry for managing skill definitions.
|
|
5
|
+
* Skills can be registered programmatically or loaded from bundled definitions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { SkillDefinition } from './types.js'
|
|
9
|
+
|
|
10
|
+
/** Internal skill store */
|
|
11
|
+
const skills: Map<string, SkillDefinition> = new Map()
|
|
12
|
+
|
|
13
|
+
/** Alias -> skill name mapping */
|
|
14
|
+
const aliases: Map<string, string> = new Map()
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Register a skill definition.
|
|
18
|
+
*/
|
|
19
|
+
export function registerSkill(definition: SkillDefinition): void {
|
|
20
|
+
skills.set(definition.name, definition)
|
|
21
|
+
|
|
22
|
+
// Register aliases
|
|
23
|
+
if (definition.aliases) {
|
|
24
|
+
for (const alias of definition.aliases) {
|
|
25
|
+
aliases.set(alias, definition.name)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get a skill by name or alias.
|
|
32
|
+
*/
|
|
33
|
+
export function getSkill(name: string): SkillDefinition | undefined {
|
|
34
|
+
// Direct lookup
|
|
35
|
+
const direct = skills.get(name)
|
|
36
|
+
if (direct) return direct
|
|
37
|
+
|
|
38
|
+
// Alias lookup
|
|
39
|
+
const resolved = aliases.get(name)
|
|
40
|
+
if (resolved) return skills.get(resolved)
|
|
41
|
+
|
|
42
|
+
return undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get all registered skills.
|
|
47
|
+
*/
|
|
48
|
+
export function getAllSkills(): SkillDefinition[] {
|
|
49
|
+
return Array.from(skills.values())
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get all user-invocable skills (for /command listing).
|
|
54
|
+
*/
|
|
55
|
+
export function getUserInvocableSkills(): SkillDefinition[] {
|
|
56
|
+
return getAllSkills().filter(
|
|
57
|
+
(s) => s.userInvocable !== false && (!s.isEnabled || s.isEnabled()),
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Check if a skill exists.
|
|
63
|
+
*/
|
|
64
|
+
export function hasSkill(name: string): boolean {
|
|
65
|
+
return skills.has(name) || aliases.has(name)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Remove a skill.
|
|
70
|
+
*/
|
|
71
|
+
export function unregisterSkill(name: string): boolean {
|
|
72
|
+
const skill = skills.get(name)
|
|
73
|
+
if (!skill) return false
|
|
74
|
+
|
|
75
|
+
// Remove aliases
|
|
76
|
+
if (skill.aliases) {
|
|
77
|
+
for (const alias of skill.aliases) {
|
|
78
|
+
aliases.delete(alias)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return skills.delete(name)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Clear all skills (for testing).
|
|
87
|
+
*/
|
|
88
|
+
export function clearSkills(): void {
|
|
89
|
+
skills.clear()
|
|
90
|
+
aliases.clear()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Format skills listing for system prompt injection.
|
|
95
|
+
*
|
|
96
|
+
* Uses a budget system: skills listing gets a limited character budget
|
|
97
|
+
* to avoid bloating the context window.
|
|
98
|
+
*/
|
|
99
|
+
export function formatSkillsForPrompt(
|
|
100
|
+
contextWindowTokens?: number,
|
|
101
|
+
): string {
|
|
102
|
+
const invocable = getUserInvocableSkills()
|
|
103
|
+
if (invocable.length === 0) return ''
|
|
104
|
+
|
|
105
|
+
// Budget: 1% of context window in characters (4 chars per token)
|
|
106
|
+
const CHARS_PER_TOKEN = 4
|
|
107
|
+
const DEFAULT_BUDGET = 8000
|
|
108
|
+
const MAX_DESC_CHARS = 250
|
|
109
|
+
const budget = contextWindowTokens
|
|
110
|
+
? Math.floor(contextWindowTokens * 0.01 * CHARS_PER_TOKEN)
|
|
111
|
+
: DEFAULT_BUDGET
|
|
112
|
+
|
|
113
|
+
const lines: string[] = []
|
|
114
|
+
let used = 0
|
|
115
|
+
|
|
116
|
+
for (const skill of invocable) {
|
|
117
|
+
const desc = skill.description.length > MAX_DESC_CHARS
|
|
118
|
+
? skill.description.slice(0, MAX_DESC_CHARS) + '...'
|
|
119
|
+
: skill.description
|
|
120
|
+
|
|
121
|
+
const trigger = skill.whenToUse
|
|
122
|
+
? ` TRIGGER when: ${skill.whenToUse}`
|
|
123
|
+
: ''
|
|
124
|
+
|
|
125
|
+
const line = `- ${skill.name}: ${desc}${trigger}`
|
|
126
|
+
|
|
127
|
+
if (used + line.length > budget) break
|
|
128
|
+
lines.push(line)
|
|
129
|
+
used += line.length
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return lines.join('\n')
|
|
133
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill System Types
|
|
3
|
+
*
|
|
4
|
+
* Skills are reusable prompt templates that extend agent capabilities.
|
|
5
|
+
* They can be invoked by the model via the Skill tool or by users via /skillname.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ToolContext } from '../types.js'
|
|
9
|
+
import type { HookConfig } from '../hooks.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Content block for skill prompts (compatible with Anthropic API).
|
|
13
|
+
*/
|
|
14
|
+
export type SkillContentBlock =
|
|
15
|
+
| { type: 'text'; text: string }
|
|
16
|
+
| { type: 'image'; source: { type: 'base64'; media_type: string; data: string } }
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Bundled skill definition.
|
|
20
|
+
*
|
|
21
|
+
* Inspired by Claude Code's skill system. Skills provide specialized
|
|
22
|
+
* capabilities by injecting context-specific prompts with optional
|
|
23
|
+
* tool restrictions and model overrides.
|
|
24
|
+
*/
|
|
25
|
+
export interface SkillDefinition {
|
|
26
|
+
/** Unique skill name (e.g., 'simplify', 'commit') */
|
|
27
|
+
name: string
|
|
28
|
+
|
|
29
|
+
/** Human-readable description */
|
|
30
|
+
description: string
|
|
31
|
+
|
|
32
|
+
/** Alternative names for the skill */
|
|
33
|
+
aliases?: string[]
|
|
34
|
+
|
|
35
|
+
/** When the model should invoke this skill (used in system prompt) */
|
|
36
|
+
whenToUse?: string
|
|
37
|
+
|
|
38
|
+
/** Hint for expected arguments */
|
|
39
|
+
argumentHint?: string
|
|
40
|
+
|
|
41
|
+
/** Tools the skill is allowed to use (empty = all tools) */
|
|
42
|
+
allowedTools?: string[]
|
|
43
|
+
|
|
44
|
+
/** Model override for this skill */
|
|
45
|
+
model?: string
|
|
46
|
+
|
|
47
|
+
/** Whether the skill can be invoked by users via /command */
|
|
48
|
+
userInvocable?: boolean
|
|
49
|
+
|
|
50
|
+
/** Runtime check for availability */
|
|
51
|
+
isEnabled?: () => boolean
|
|
52
|
+
|
|
53
|
+
/** Hook overrides while skill is active */
|
|
54
|
+
hooks?: HookConfig
|
|
55
|
+
|
|
56
|
+
/** Execution context: 'inline' runs in current context, 'fork' spawns a subagent */
|
|
57
|
+
context?: 'inline' | 'fork'
|
|
58
|
+
|
|
59
|
+
/** Subagent type for forked execution */
|
|
60
|
+
agent?: string
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Generate the prompt content blocks for this skill.
|
|
64
|
+
*
|
|
65
|
+
* @param args - User-provided arguments (e.g., from "/simplify focus on error handling")
|
|
66
|
+
* @param context - Tool execution context (cwd, etc.)
|
|
67
|
+
* @returns Content blocks to inject into the conversation
|
|
68
|
+
*/
|
|
69
|
+
getPrompt: (
|
|
70
|
+
args: string,
|
|
71
|
+
context: ToolContext,
|
|
72
|
+
) => Promise<SkillContentBlock[]>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Result of executing a skill.
|
|
77
|
+
*/
|
|
78
|
+
export interface SkillResult {
|
|
79
|
+
/** Whether execution succeeded */
|
|
80
|
+
success: boolean
|
|
81
|
+
|
|
82
|
+
/** Skill name that was executed */
|
|
83
|
+
skillName: string
|
|
84
|
+
|
|
85
|
+
/** Execution status */
|
|
86
|
+
status: 'inline' | 'forked'
|
|
87
|
+
|
|
88
|
+
/** Allowed tools override (for inline execution) */
|
|
89
|
+
allowedTools?: string[]
|
|
90
|
+
|
|
91
|
+
/** Model override */
|
|
92
|
+
model?: string
|
|
93
|
+
|
|
94
|
+
/** Result text (for forked execution) */
|
|
95
|
+
result?: string
|
|
96
|
+
|
|
97
|
+
/** Error message */
|
|
98
|
+
error?: string
|
|
99
|
+
}
|
package/src/tools/agent-tool.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import type { ToolDefinition, ToolContext, ToolResult, AgentDefinition } from '../types.js'
|
|
9
9
|
import { QueryEngine } from '../engine.js'
|
|
10
10
|
import { getAllBaseTools, filterTools } from './index.js'
|
|
11
|
-
import {
|
|
11
|
+
import { createProvider, type ApiType } from '../providers/index.js'
|
|
12
12
|
|
|
13
13
|
// Store for registered agent definitions
|
|
14
14
|
let registeredAgents: Record<string, AgentDefinition> = {}
|
|
@@ -101,10 +101,21 @@ export const AgentTool: ToolDefinition = {
|
|
|
101
101
|
const systemPrompt = agentDef?.prompt ||
|
|
102
102
|
'You are a helpful assistant. Complete the given task using the available tools.'
|
|
103
103
|
|
|
104
|
+
// Inherit provider and model from parent agent context, fall back to env vars
|
|
105
|
+
const subModel = input.model || context.model || process.env.CODEANY_MODEL || 'claude-sonnet-4-6'
|
|
106
|
+
const provider = context.provider ?? createProvider(
|
|
107
|
+
(context.apiType || process.env.CODEANY_API_TYPE as ApiType) || 'anthropic-messages',
|
|
108
|
+
{
|
|
109
|
+
apiKey: process.env.CODEANY_API_KEY,
|
|
110
|
+
baseURL: process.env.CODEANY_BASE_URL,
|
|
111
|
+
},
|
|
112
|
+
)
|
|
113
|
+
|
|
104
114
|
// Create subagent engine
|
|
105
115
|
const engine = new QueryEngine({
|
|
106
116
|
cwd: context.cwd,
|
|
107
|
-
model:
|
|
117
|
+
model: subModel,
|
|
118
|
+
provider,
|
|
108
119
|
tools,
|
|
109
120
|
systemPrompt,
|
|
110
121
|
maxTurns: agentDef?.maxTurns || 10,
|
package/src/tools/index.ts
CHANGED
|
@@ -62,6 +62,9 @@ import { ConfigTool } from './config-tool.js'
|
|
|
62
62
|
// Todo
|
|
63
63
|
import { TodoWriteTool } from './todo-tool.js'
|
|
64
64
|
|
|
65
|
+
// Skill
|
|
66
|
+
import { SkillTool } from './skill-tool.js'
|
|
67
|
+
|
|
65
68
|
/**
|
|
66
69
|
* All built-in tools (30+).
|
|
67
70
|
*/
|
|
@@ -125,6 +128,9 @@ const ALL_TOOLS: ToolDefinition[] = [
|
|
|
125
128
|
|
|
126
129
|
// Todo
|
|
127
130
|
TodoWriteTool,
|
|
131
|
+
|
|
132
|
+
// Skill
|
|
133
|
+
SkillTool,
|
|
128
134
|
]
|
|
129
135
|
|
|
130
136
|
/**
|
|
@@ -226,6 +232,8 @@ export {
|
|
|
226
232
|
ConfigTool,
|
|
227
233
|
// Todo
|
|
228
234
|
TodoWriteTool,
|
|
235
|
+
// Skill
|
|
236
|
+
SkillTool,
|
|
229
237
|
}
|
|
230
238
|
|
|
231
239
|
// Re-export helpers
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Tool
|
|
3
|
+
*
|
|
4
|
+
* Allows the model to invoke registered skills by name.
|
|
5
|
+
* Skills are prompt templates that provide specialized capabilities.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ToolDefinition, ToolResult, ToolContext } from '../types.js'
|
|
9
|
+
import { getSkill, getUserInvocableSkills } from '../skills/registry.js'
|
|
10
|
+
|
|
11
|
+
export const SkillTool: ToolDefinition = {
|
|
12
|
+
name: 'Skill',
|
|
13
|
+
description:
|
|
14
|
+
'Execute a skill within the current conversation. ' +
|
|
15
|
+
'Skills provide specialized capabilities and domain knowledge. ' +
|
|
16
|
+
'Use this tool with the skill name and optional arguments. ' +
|
|
17
|
+
'Available skills are listed in system-reminder messages.',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
skill: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'The skill name to execute (e.g., "commit", "review", "simplify")',
|
|
24
|
+
},
|
|
25
|
+
args: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
description: 'Optional arguments for the skill',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
required: ['skill'],
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
isReadOnly: () => false,
|
|
34
|
+
isConcurrencySafe: () => false,
|
|
35
|
+
isEnabled: () => getUserInvocableSkills().length > 0,
|
|
36
|
+
|
|
37
|
+
async prompt(): Promise<string> {
|
|
38
|
+
const skills = getUserInvocableSkills()
|
|
39
|
+
if (skills.length === 0) return ''
|
|
40
|
+
|
|
41
|
+
const lines = skills.map((s) => {
|
|
42
|
+
const desc =
|
|
43
|
+
s.description.length > 200
|
|
44
|
+
? s.description.slice(0, 200) + '...'
|
|
45
|
+
: s.description
|
|
46
|
+
return `- ${s.name}: ${desc}`
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
'Execute a skill within the main conversation.\n\n' +
|
|
51
|
+
'Available skills:\n' +
|
|
52
|
+
lines.join('\n') +
|
|
53
|
+
'\n\nWhen a skill matches the user\'s request, invoke it using the Skill tool.'
|
|
54
|
+
)
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
async call(input: any, context: ToolContext): Promise<ToolResult> {
|
|
58
|
+
const skillName: string = input.skill
|
|
59
|
+
const args: string = input.args || ''
|
|
60
|
+
|
|
61
|
+
if (!skillName) {
|
|
62
|
+
return {
|
|
63
|
+
type: 'tool_result',
|
|
64
|
+
tool_use_id: '',
|
|
65
|
+
content: 'Error: skill name is required',
|
|
66
|
+
is_error: true,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const skill = getSkill(skillName)
|
|
71
|
+
if (!skill) {
|
|
72
|
+
const available = getUserInvocableSkills()
|
|
73
|
+
.map((s) => s.name)
|
|
74
|
+
.join(', ')
|
|
75
|
+
return {
|
|
76
|
+
type: 'tool_result',
|
|
77
|
+
tool_use_id: '',
|
|
78
|
+
content: `Error: Unknown skill "${skillName}". Available skills: ${available || 'none'}`,
|
|
79
|
+
is_error: true,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Check if skill is enabled
|
|
84
|
+
if (skill.isEnabled && !skill.isEnabled()) {
|
|
85
|
+
return {
|
|
86
|
+
type: 'tool_result',
|
|
87
|
+
tool_use_id: '',
|
|
88
|
+
content: `Error: Skill "${skillName}" is currently disabled`,
|
|
89
|
+
is_error: true,
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// Get skill prompt
|
|
95
|
+
const contentBlocks = await skill.getPrompt(args, context)
|
|
96
|
+
|
|
97
|
+
// Convert content blocks to text
|
|
98
|
+
const promptText = contentBlocks
|
|
99
|
+
.filter((b): b is { type: 'text'; text: string } => b.type === 'text')
|
|
100
|
+
.map((b) => b.text)
|
|
101
|
+
.join('\n\n')
|
|
102
|
+
|
|
103
|
+
// Build result with metadata
|
|
104
|
+
const result: Record<string, unknown> = {
|
|
105
|
+
success: true,
|
|
106
|
+
commandName: skill.name,
|
|
107
|
+
status: skill.context === 'fork' ? 'forked' : 'inline',
|
|
108
|
+
prompt: promptText,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (skill.allowedTools) {
|
|
112
|
+
result.allowedTools = skill.allowedTools
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (skill.model) {
|
|
116
|
+
result.model = skill.model
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
type: 'tool_result',
|
|
121
|
+
tool_use_id: '',
|
|
122
|
+
content: JSON.stringify(result),
|
|
123
|
+
}
|
|
124
|
+
} catch (err: any) {
|
|
125
|
+
return {
|
|
126
|
+
type: 'tool_result',
|
|
127
|
+
tool_use_id: '',
|
|
128
|
+
content: `Error executing skill "${skillName}": ${err.message}`,
|
|
129
|
+
is_error: true,
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
}
|
package/src/tools/types.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ToolDefinition, ToolInputSchema, ToolContext, ToolResult } from '../types.js'
|
|
6
|
-
import type Anthropic from '@anthropic-ai/sdk'
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* Helper to create a tool definition with sensible defaults.
|
|
@@ -52,11 +51,16 @@ export function defineTool(config: {
|
|
|
52
51
|
|
|
53
52
|
/**
|
|
54
53
|
* Convert a ToolDefinition to API-compatible tool format.
|
|
54
|
+
* Returns the normalized tool format used by providers.
|
|
55
55
|
*/
|
|
56
|
-
export function toApiTool(tool: ToolDefinition):
|
|
56
|
+
export function toApiTool(tool: ToolDefinition): {
|
|
57
|
+
name: string
|
|
58
|
+
description: string
|
|
59
|
+
input_schema: ToolInputSchema
|
|
60
|
+
} {
|
|
57
61
|
return {
|
|
58
62
|
name: tool.name,
|
|
59
63
|
description: tool.description,
|
|
60
|
-
input_schema: tool.inputSchema
|
|
64
|
+
input_schema: tool.inputSchema,
|
|
61
65
|
}
|
|
62
66
|
}
|
package/src/types.ts
CHANGED
|
@@ -2,7 +2,17 @@
|
|
|
2
2
|
* Core type definitions for the Agent SDK
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
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 |
|
|
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:
|
|
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:
|
|
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 |
|
|
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:
|
|
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
|
-
|
|
446
|
-
|
|
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
|
}
|
package/src/utils/compact.ts
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* 3. Session memory compaction: consolidates across sessions
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import
|
|
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:
|
|
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
|
-
|
|
61
|
+
provider: LLMProvider,
|
|
61
62
|
model: string,
|
|
62
|
-
messages:
|
|
63
|
+
messages: any[],
|
|
63
64
|
state: AutoCompactState,
|
|
64
65
|
): Promise<{
|
|
65
|
-
compactedMessages:
|
|
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
|
|
77
|
+
const response = await provider.createMessage({
|
|
77
78
|
model,
|
|
78
|
-
|
|
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)
|
|
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:
|
|
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:
|
|
131
|
-
):
|
|
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:
|
|
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:
|
|
183
|
+
messages: any[],
|
|
183
184
|
maxToolResultChars: number = 50000,
|
|
184
|
-
):
|
|
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
|
|