knockagent 0.1.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/README.md ADDED
@@ -0,0 +1,345 @@
1
+ # KnockAgent
2
+
3
+ [中文文档](./README.zh_CN.md)
4
+
5
+ > **Configuration-over-convention** agent framework — define AI agents with Markdown files.
6
+
7
+ KnockAgent is built on top of the [`@openai/agents`](https://github.com/openai/openai-agents-js) framework. It lets you build complex multi-agent systems with minimal code — just write Markdown files with YAML front matter to define each agent's model, temperature, system prompt, tools, and collaboration behaviour. The framework reads these `.md` files and automatically wires everything together.
8
+
9
+ ## ✨ Key Features
10
+
11
+ - 📝 **Markdown-as-Configuration** — Each agent is a `.md` file: front matter for settings, body for system prompt.
12
+ - 🔌 **Multi-Provider Support** — Supports a wide range of models via [Vercel AI SDK](https://ai-sdk.dev/) providers (OpenAI, Google, Anthropic, and more).
13
+ - 🧩 **Liquid Templates** — Use [LiquidJS](https://liquidjs.com/) template syntax in system prompts with full runtime context.
14
+ - 🤝 **Multi-Agent Collaboration** — Multiple agents can work together via delegation, task transfer, or tool invocation — all configured declaratively.
15
+ - 🛡️ **Type-Safe** — Written in TypeScript with full type inference for providers and models.
16
+ - 🧪 **VirtualFS** — Pluggable file-system interface, allowing you to embed agent definitions directly in code instead of reading from disk.
17
+
18
+ ## 📦 Installation
19
+
20
+ ```bash
21
+ npm install knockagent
22
+ # or
23
+ pnpm add knockagent
24
+ ```
25
+
26
+ ### Requirements
27
+
28
+ - Node.js `>=20.19.0` or `>=22.12.0`
29
+ - At least one [Vercel AI SDK provider](https://ai-sdk.dev/docs/foundations/providers-and-models) (e.g. `@ai-sdk/openai`)
30
+
31
+ ## 🚀 Quick Start
32
+
33
+ ### 1. Create project structure
34
+
35
+ ```
36
+ my-project/
37
+ ├── agents/
38
+ │ ├── main.md # Entry agent (required)
39
+ │ └── translator.md # Sub-agent
40
+ ├── index.ts
41
+ └── package.json
42
+ ```
43
+
44
+ ### 2. Define agents in Markdown
45
+
46
+ **`agents/main.md`** — the entry agent (must be named `main.md`):
47
+
48
+ ```markdown
49
+ ---
50
+ name: main
51
+ desc: A helpful assistant that can translate text
52
+ model: openai/gpt-4o
53
+ temperature: 0.7
54
+ handoffs: translator
55
+ ---
56
+
57
+ You are a helpful assistant. When the user asks you to translate text,
58
+ hand off the task to the translator agent.
59
+ ```
60
+
61
+ **`agents/translator.md`** — a handoff target:
62
+
63
+ ```markdown
64
+ ---
65
+ name: translator
66
+ desc: Translates text between languages
67
+ model: openai/gpt-4o-mini
68
+ temperature: 0.3
69
+ ---
70
+
71
+ You are a professional translator. Translate the user's text accurately
72
+ while preserving the original meaning and tone.
73
+ ```
74
+
75
+ ### 3. Wire it up in code
76
+
77
+ ```typescript
78
+ import KnockAgent, { createAiProvider } from "knockagent";
79
+ import { openai } from "@ai-sdk/openai";
80
+
81
+ const agent = new KnockAgent({
82
+ rootDir: "./agents",
83
+ providers: {
84
+ openai: createAiProvider(openai),
85
+ },
86
+ defaultModel: "openai/gpt-4o",
87
+ });
88
+ ```
89
+
90
+ The `KnockAgent` instance exposes the built `@openai/agents` `Agent` object. You can use the standard `Runner` API from `@openai/agents` to run conversations.
91
+
92
+ ---
93
+
94
+ ## 📖 Reference
95
+
96
+ ### Agent Markdown File Format
97
+
98
+ Each agent is a Markdown file (`.md`) consisting of two parts:
99
+
100
+ ```markdown
101
+ ---
102
+ <YAML front matter – agent configuration>
103
+ ---
104
+
105
+ <Markdown body – system prompt>
106
+ ```
107
+
108
+ The **front matter** controls agent behaviour; the **body** becomes the system prompt (rendered through the Liquid template engine at runtime).
109
+
110
+ ### Front Matter Fields
111
+
112
+ | Field | Type | Default | Description |
113
+ |---|---|---|---|
114
+ | `name` | `string` | File path as name | Display name of the agent |
115
+ | `desc` / `description` | `string` | `""` | Description shown when this agent is used as a handoff target or tool |
116
+ | `model` | `string` | `defaultModel` from config | Model identifier in `provider/model` format, e.g. `openai/gpt-4o` |
117
+ | `temperature` | `number` | `defaultTemperature` (default `1.0`) | Sampling temperature |
118
+ | `handoffs` | `string` (comma-separated) | – | Comma-separated list of agent paths to use as handoff targets |
119
+ | `agents` | `string` (comma-separated) | – | Comma-separated list of agent paths to mount as callable tools |
120
+ | `tools` | `string` (comma-separated) | – | Comma-separated list of tool names (must be registered via `KnockAgentConfig.tools`) |
121
+ | `reasoning_effort` | `"low"` \| `"medium"` \| `"high"` | – | Reasoning effort level (for supported models) |
122
+ | `reasoning_summary` | `string` | – | Reasoning summary configuration |
123
+ | `verbosity` | `string` | – | Text verbosity setting |
124
+ | `prefix` | `string` | – | Text prepended to every user message |
125
+ | `suffix` | `string` | – | Text appended to every user message |
126
+
127
+ #### Example: Full front matter
128
+
129
+ ```yaml
130
+ ---
131
+ name: researcher
132
+ desc: Researches topics using web search
133
+ model: openai/o4-mini
134
+ temperature: 0.5
135
+ handoffs: writer, reviewer
136
+ agents: summarizer
137
+ tools: search
138
+ reasoning_effort: medium
139
+ prefix: "Please research the following:"
140
+ suffix: "Provide sources for your claims."
141
+ ---
142
+ ```
143
+
144
+ ### System Prompt (Markdown Body)
145
+
146
+ The Markdown body after the front matter is the agent's system prompt. It is processed through **LiquidJS** at runtime, meaning you can use template variables and filters.
147
+
148
+ #### Template Variables
149
+
150
+ The Liquid render context is the `RunContext.context` object you pass when running the agent. For example:
151
+
152
+ ```markdown
153
+ ---
154
+ name: greeter
155
+ ---
156
+
157
+ Hello! You are assisting {{ username }}.
158
+
159
+ Today's tasks:
160
+ {% for task in tasks %}
161
+ - {{ task }}
162
+ {% endfor %}
163
+ ```
164
+
165
+ #### Built-in Filters
166
+
167
+ | Filter | Description | Example |
168
+ |---|---|---|
169
+ | `json` | Serializes a value to JSON string | `{{ data \| json }}` |
170
+
171
+ All standard [LiquidJS filters](https://liquidjs.com/filters/overview.html) are also available.
172
+
173
+ > ⚠️ **Important:** To include content from other files, use KnockAgent's dedicated `@(path)` import syntax (described below) instead of LiquidJS's built-in `{% render %}` or `{% include %}` tags. The LiquidJS file-inclusion tags are **not supported** — only `@(path)` is recognized for file imports.
174
+
175
+ ### Prompt Imports — `@(path)`
176
+
177
+ You can import the **content** (body only, not front matter) of another Markdown file using the `@(path)` syntax:
178
+
179
+ ```markdown
180
+ ---
181
+ name: agent_a
182
+ ---
183
+
184
+ # Agent A Instructions
185
+
186
+ @(./shared_rules)
187
+
188
+ Additional specific instructions here.
189
+ ```
190
+
191
+ This will inline the body of `shared_rules.md` at that position.
192
+
193
+ #### Import Path Resolution
194
+
195
+ | Path Format | Resolution |
196
+ |---|---|
197
+ | `@(./relative)` | Relative to the current file |
198
+ | `@(/absolute)` | Relative to the `rootDir` |
199
+
200
+ - The `.md` extension is automatically appended if omitted
201
+ - Circular imports are detected and will throw an error
202
+ - Only the **content** (Markdown body) is imported — front matter of the imported file is ignored
203
+
204
+ ### Entry Agent
205
+
206
+ KnockAgent requires a **`main.md`** agent file in the `rootDir`. This is the entry point for the agent system. If `main.md` does not exist, the constructor will throw an error.
207
+
208
+ ---
209
+
210
+ ## 🔧 API Reference
211
+
212
+ ### `KnockAgent<Context, ProviderNames>`
213
+
214
+ The main class that loads and wires all agents.
215
+
216
+ #### Constructor
217
+
218
+ ```typescript
219
+ new KnockAgent(config: KnockAgentConfig<ProviderNames>)
220
+ ```
221
+
222
+ **`KnockAgentConfig<ProviderNames>`**:
223
+
224
+ | Property | Type | Required | Description |
225
+ |---|---|---|---|
226
+ | `rootDir` | `string` | ✅ | Root directory containing agent `.md` files |
227
+ | `providers` | `Record<ProviderNames, AiProvider>` | ✅ | Map of provider name → provider instance |
228
+ | `defaultModel` | `` `${ProviderNames}/${string}` `` | ✅ | Default model in `provider/model` format |
229
+ | `defaultTemperature` | `number` | ❌ | Default temperature (defaults to `1.0`) |
230
+ | `tools` | `Tool[]` | ❌ | Array of tools available to agents |
231
+ | `fs` | `VirtualFS` | ❌ | Custom file-system implementation (for testing/embedding) |
232
+
233
+ #### Methods
234
+
235
+ ##### `getAgent(path: string): Agent<Context> | null`
236
+
237
+ Retrieves (or lazily creates) an agent by its file path relative to `rootDir`.
238
+
239
+ ```typescript
240
+ const agent = knockAgent.getAgent("main");
241
+ const subAgent = knockAgent.getAgent("subfolder/helper");
242
+ ```
243
+
244
+ ### `createAiProvider(baseProvider, mapModelSettings?)`
245
+
246
+ A helper function that wraps any AI SDK provider into a `KnockAgent`-compatible `AiProvider`.
247
+
248
+ ```typescript
249
+ import { createAiProvider } from "knockagent";
250
+ import { openai } from "@ai-sdk/openai";
251
+ import { google } from "@ai-sdk/google";
252
+
253
+ const providers = {
254
+ openai: createAiProvider(openai),
255
+ google: createAiProvider(google),
256
+ };
257
+ ```
258
+
259
+ **Parameters**:
260
+
261
+ | Parameter | Type | Description |
262
+ |---|---|---|
263
+ | `baseProvider` | `BaseAiProvider` | Any object that implements `languageModel(modelName: string)` (standard AI SDK providers do) |
264
+ | `mapModelSettings` | `(settings: ModelSettings, modelName: string) => ModelSettings` | Optional function to transform model settings before they are passed to the model |
265
+
266
+ ### `VirtualFS`
267
+
268
+ Interface for a pluggable file system. This is primarily designed for projects that prefer to embed agent prompt definitions directly in code rather than reading from disk files.
269
+
270
+ ```typescript
271
+ interface VirtualFS {
272
+ existsSync(path: string): boolean;
273
+ readFileSync(path: string, encoding?: BufferEncoding): string;
274
+ statSync(path: string): { isFile(): boolean };
275
+ }
276
+ ```
277
+
278
+ ---
279
+
280
+ ## 🤝 Handoffs vs Agents-as-Tools
281
+
282
+ KnockAgent supports two patterns for multi-agent collaboration:
283
+
284
+ ### Handoffs (`handoffs` field)
285
+
286
+ Handoffs **transfer control** from one agent to another. When an agent hands off, the new agent takes over the conversation entirely.
287
+
288
+ ```yaml
289
+ handoffs: translator, researcher
290
+ ```
291
+
292
+ ### Agents-as-Tools (`agents` field)
293
+
294
+ Agents declared under `agents` are mounted as **callable tools**. The parent agent remains in control and can invoke the sub-agent to perform a specific task, receiving the result back.
295
+
296
+ ```yaml
297
+ agents: summarizer, fact_checker
298
+ ```
299
+
300
+ The sub-agent tool will be named `agent_<name>` and described with the sub-agent's `desc` field.
301
+
302
+ ---
303
+
304
+ ## 📂 Project Structure Example
305
+
306
+ ```
307
+ agents/
308
+ ├── main.md # Entry agent (required)
309
+ ├── researcher.md # Handoff target
310
+ ├── writer.md # Handoff target
311
+ ├── shared/
312
+ │ ├── rules.md # Shared prompt fragment
313
+ │ └── format.md # Shared output format
314
+ └── tools/
315
+ └── summarizer.md # Agent used as a tool
316
+ ```
317
+
318
+ Each path used in `handoffs`, `agents`, or `@(...)` imports is relative to `rootDir`:
319
+
320
+ ```yaml
321
+ # In main.md
322
+ handoffs: researcher, writer
323
+ agents: tools/summarizer
324
+ ```
325
+
326
+ ```markdown
327
+ # In researcher.md
328
+ @(/shared/rules)
329
+ ```
330
+
331
+ ---
332
+
333
+ ## 🧪 Testing
334
+
335
+ Run the built-in test suite:
336
+
337
+ ```bash
338
+ pnpm test
339
+ ```
340
+
341
+ ---
342
+
343
+ ## 📄 License
344
+
345
+ [MIT](./LICENSE)
@@ -0,0 +1,343 @@
1
+ # KnockAgent
2
+
3
+ [English](./README.md)
4
+
5
+ > **配置大于约定** 的 Agent 框架 — 用 Markdown 文件定义 AI Agent。
6
+
7
+ KnockAgent 基于 [`@openai/agents`](https://github.com/openai/openai-agents-js) 框架打造,让你只需极少量代码即可构建复杂的多 Agent 系统 — 编写带有 YAML front matter 的 Markdown 文件来定义每个 Agent 的模型、温度、系统提示词、工具和协作方式。框架会读取这些 `.md` 文件并自动完成所有接线工作。
8
+
9
+ ## ✨ 核心特性
10
+
11
+ - 📝 **Markdown 即配置** — 每个 Agent 是一个 `.md` 文件:front matter 用于配置,正文作为系统提示词。
12
+ - 🔌 **多模型供应商** — 通过 [Vercel AI SDK](https://ai-sdk.dev/) 支持多种模型供应商(OpenAI、Google、Anthropic 等)。
13
+ - 🧩 **Liquid 模板** — 在系统提示词中使用 [LiquidJS](https://liquidjs.com/) 模板语法,支持完整运行时上下文。
14
+ - 🤝 **多 Agent 协作** — 多个 Agent 可通过任务委派、控制转移或工具调用等方式协同工作,全部通过声明式配置完成。
15
+ - ️ **类型安全** — TypeScript 编写,对供应商和模型提供完整类型推断。
16
+ - 🧪 **虚拟文件系统** — 可插拔的文件系统接口,支持将 Agent 定义直接嵌入代码中,无需从磁盘读取文件。
17
+
18
+ ## 📦 安装
19
+
20
+ ```bash
21
+ npm install knockagent
22
+ # 或
23
+ pnpm add knockagent
24
+ ```
25
+
26
+ ### 环境要求
27
+
28
+ - Node.js `>=20.19.0` 或 `>=22.12.0`
29
+ - 至少一个 [Vercel AI SDK 供应商](https://ai-sdk.dev/docs/foundations/providers-and-models)(如 `@ai-sdk/openai`)
30
+
31
+ ## 🚀 快速开始
32
+
33
+ ### 1. 创建项目结构
34
+
35
+ ```
36
+ my-project/
37
+ ├── agents/
38
+ │ ├── main.md # 入口 Agent(必需)
39
+ │ └── translator.md # 子 Agent
40
+ ├── index.ts
41
+ └── package.json
42
+ ```
43
+
44
+ ### 2. 用 Markdown 定义 Agent
45
+
46
+ **`agents/main.md`** — 入口 Agent(文件必须命名为 `main.md`):
47
+
48
+ ```markdown
49
+ ---
50
+ name: main
51
+ desc: 一个可以翻译文本的助手
52
+ model: openai/gpt-4o
53
+ temperature: 0.7
54
+ handoffs: translator
55
+ ---
56
+
57
+ 你是一个有用的助手。当用户要求你翻译时,将任务移交给翻译 Agent。
58
+ ```
59
+
60
+ **`agents/translator.md`** — 任务移交目标:
61
+
62
+ ```markdown
63
+ ---
64
+ name: translator
65
+ desc: 在语言之间翻译文本
66
+ model: openai/gpt-4o-mini
67
+ temperature: 0.3
68
+ ---
69
+
70
+ 你是一位专业翻译。准确翻译用户的文本,同时保持原文的含义和语气。
71
+ ```
72
+
73
+ ### 3. 在代码中接线
74
+
75
+ ```typescript
76
+ import KnockAgent, { createAiProvider } from "knockagent";
77
+ import { openai } from "@ai-sdk/openai";
78
+
79
+ const agent = new KnockAgent({
80
+ rootDir: "./agents",
81
+ providers: {
82
+ openai: createAiProvider(openai),
83
+ },
84
+ defaultModel: "openai/gpt-4o",
85
+ });
86
+ ```
87
+
88
+ `KnockAgent` 实例会构建 `@openai/agents` 的 `Agent` 对象。你可以使用 `@openai/agents` 标准的 `Runner` API 来运行对话。
89
+
90
+ ---
91
+
92
+ ## 📖 参考文档
93
+
94
+ ### Agent Markdown 文件格式
95
+
96
+ 每个 Agent 是一个 Markdown 文件(`.md`),由两部分组成:
97
+
98
+ ```markdown
99
+ ---
100
+ <YAML front matter – Agent 配置>
101
+ ---
102
+
103
+ <Markdown 正文 – 系统提示词>
104
+ ```
105
+
106
+ **Front matter** 控制 Agent 行为;**正文**成为系统提示词(运行时通过 Liquid 模板引擎渲染)。
107
+
108
+ ### Front Matter 字段
109
+
110
+ | 字段 | 类型 | 默认值 | 说明 |
111
+ |---|---|---|---|
112
+ | `name` | `string` | 文件路径作为名称 | Agent 的显示名称 |
113
+ | `desc` / `description` | `string` | `""` | 当此 Agent 被用作移交目标或工具时显示的描述 |
114
+ | `model` | `string` | 配置中的 `defaultModel` | 模型标识符,格式为 `供应商/模型名`,如 `openai/gpt-4o` |
115
+ | `temperature` | `number` | `defaultTemperature`(默认 `1.0`) | 采样温度 |
116
+ | `handoffs` | `string`(逗号分隔) | – | 逗号分隔的 Agent 路径列表,用于任务移交 |
117
+ | `agents` | `string`(逗号分隔) | – | 逗号分隔的 Agent 路径列表,作为可调用工具挂载 |
118
+ | `tools` | `string`(逗号分隔) | – | 逗号分隔的工具名称列表(必须通过 `KnockAgentConfig.tools` 注册) |
119
+ | `reasoning_effort` | `"low"` \| `"medium"` \| `"high"` | – | 推理努力程度(支持的模型可用) |
120
+ | `reasoning_summary` | `string` | – | 推理摘要配置 |
121
+ | `verbosity` | `string` | – | 文本详细程度设置 |
122
+ | `prefix` | `string` | – | 在每条用户消息前添加的文本 |
123
+ | `suffix` | `string` | – | 在每条用户消息后追加的文本 |
124
+
125
+ #### 示例:完整的 front matter
126
+
127
+ ```yaml
128
+ ---
129
+ name: researcher
130
+ desc: 使用网络搜索研究主题
131
+ model: openai/o4-mini
132
+ temperature: 0.5
133
+ handoffs: writer, reviewer
134
+ agents: summarizer
135
+ tools: search
136
+ reasoning_effort: medium
137
+ prefix: "请研究以下内容:"
138
+ suffix: "请提供你的信息来源。"
139
+ ---
140
+ ```
141
+
142
+ ### 系统提示词(Markdown 正文)
143
+
144
+ Front matter 之后的 Markdown 正文即为 Agent 的系统提示词。它在运行时通过 **LiquidJS** 处理,你可以使用模板变量和过滤器。
145
+
146
+ #### 模板变量
147
+
148
+ Liquid 的渲染上下文是运行 Agent 时传入的 `RunContext.context` 对象。例如:
149
+
150
+ ```markdown
151
+ ---
152
+ name: greeter
153
+ ---
154
+
155
+ 你好!你正在为 {{ username }} 提供帮助。
156
+
157
+ 今日任务:
158
+ {% for task in tasks %}
159
+ - {{ task }}
160
+ {% endfor %}
161
+ ```
162
+
163
+ #### 内置过滤器
164
+
165
+ | 过滤器 | 说明 | 示例 |
166
+ |---|---|---|
167
+ | `json` | 将值序列化为 JSON 字符串 | `{{ data \| json }}` |
168
+
169
+ 所有标准的 [LiquidJS 过滤器](https://liquidjs.com/filters/overview.html) 均可使用。
170
+
171
+ > ⚠️ **注意:** 如需引入其他文件内容,请使用 KnockAgent 专有的 `@(path)` 导入语法(见下文),**不要**使用 LiquidJS 内置的 `{% render %}` 或 `{% include %}` 标签。LiquidJS 的文件引入标签**不受支持** — 仅 `@(path)` 可用于文件导入。
172
+
173
+ ### 提示词导入 — `@(path)`
174
+
175
+ 你可以使用 `@(path)` 语法导入另一个 Markdown 文件的**内容**(仅正文,不包含 front matter):
176
+
177
+ ```markdown
178
+ ---
179
+ name: agent_a
180
+ ---
181
+
182
+ # Agent A 的指令
183
+
184
+ @(./shared_rules)
185
+
186
+ 此处为额外的具体指令。
187
+ ```
188
+
189
+ 这会将 `shared_rules.md` 的正文内联到该位置。
190
+
191
+ #### 导入路径解析
192
+
193
+ | 路径格式 | 解析方式 |
194
+ |---|---|
195
+ | `@(./relative)` | 相对于当前文件 |
196
+ | `@(/absolute)` | 相对于 `rootDir` |
197
+
198
+ - `.md` 扩展名省略时会自动添加
199
+ - 循环导入会被检测并抛出错误
200
+ - 仅导入**内容**(Markdown 正文)— 被导入文件的 front matter 会被忽略
201
+
202
+ ### 入口 Agent
203
+
204
+ KnockAgent 要求 `rootDir` 中必须有一个 **`main.md`** 文件作为 Agent 系统的入口。如果 `main.md` 不存在,构造函数将抛出错误。
205
+
206
+ ---
207
+
208
+ ## 🔧 API 参考
209
+
210
+ ### `KnockAgent<Context, ProviderNames>`
211
+
212
+ 加载并接线所有 Agent 的主类。
213
+
214
+ #### 构造函数
215
+
216
+ ```typescript
217
+ new KnockAgent(config: KnockAgentConfig<ProviderNames>)
218
+ ```
219
+
220
+ **`KnockAgentConfig<ProviderNames>`**:
221
+
222
+ | 属性 | 类型 | 必需 | 说明 |
223
+ |---|---|---|---|
224
+ | `rootDir` | `string` | ✅ | 包含 Agent `.md` 文件的根目录 |
225
+ | `providers` | `Record<ProviderNames, AiProvider>` | ✅ | 供应商名称 → 供应商实例的映射 |
226
+ | `defaultModel` | `` `${ProviderNames}/${string}` `` | ✅ | 默认模型,格式为 `供应商/模型名` |
227
+ | `defaultTemperature` | `number` | ❌ | 默认温度(默认为 `1.0`) |
228
+ | `tools` | `Tool[]` | ❌ | 可供 Agent 使用的工具数组 |
229
+ | `fs` | `VirtualFS` | ❌ | 自定义文件系统实现(用于测试/嵌入) |
230
+
231
+ #### 方法
232
+
233
+ ##### `getAgent(path: string): Agent<Context> | null`
234
+
235
+ 根据相对于 `rootDir` 的文件路径获取(或惰性创建)Agent。
236
+
237
+ ```typescript
238
+ const agent = knockAgent.getAgent("main");
239
+ const subAgent = knockAgent.getAgent("subfolder/helper");
240
+ ```
241
+
242
+ ### `createAiProvider(baseProvider, mapModelSettings?)`
243
+
244
+ 辅助函数,将任意 AI SDK 供应商包装为 KnockAgent 兼容的 `AiProvider`。
245
+
246
+ ```typescript
247
+ import { createAiProvider } from "knockagent";
248
+ import { openai } from "@ai-sdk/openai";
249
+ import { google } from "@ai-sdk/google";
250
+
251
+ const providers = {
252
+ openai: createAiProvider(openai),
253
+ google: createAiProvider(google),
254
+ };
255
+ ```
256
+
257
+ **参数**:
258
+
259
+ | 参数 | 类型 | 说明 |
260
+ |---|---|---|
261
+ | `baseProvider` | `BaseAiProvider` | 任意实现了 `languageModel(modelName: string)` 的对象(标准 AI SDK 供应商均满足) |
262
+ | `mapModelSettings` | `(settings: ModelSettings, modelName: string) => ModelSettings` | 可选函数,在将模型设置传递给模型前进行转换 |
263
+
264
+ ### `VirtualFS`
265
+
266
+ 可插拔文件系统接口。主要用于将 Agent 提示词定义直接嵌入到代码中,而非从磁盘文件读取。
267
+
268
+ ```typescript
269
+ interface VirtualFS {
270
+ existsSync(path: string): boolean;
271
+ readFileSync(path: string, encoding?: BufferEncoding): string;
272
+ statSync(path: string): { isFile(): boolean };
273
+ }
274
+ ```
275
+
276
+ ---
277
+
278
+ ## 🤝 任务移交 vs Agent 作为工具
279
+
280
+ KnockAgent 支持两种多 Agent 协作模式:
281
+
282
+ ### 任务移交(`handoffs` 字段)
283
+
284
+ 任务移交将**控制权转移**给另一个 Agent。当 Agent 执行移交后,新 Agent 将完全接管对话。
285
+
286
+ ```yaml
287
+ handoffs: translator, researcher
288
+ ```
289
+
290
+ ### Agent 作为工具(`agents` 字段)
291
+
292
+ 在 `agents` 下声明的 Agent 被挂载为**可调用工具**。父 Agent 保持控制权,可以调用子 Agent 执行特定任务,并接收返回结果。
293
+
294
+ ```yaml
295
+ agents: summarizer, fact_checker
296
+ ```
297
+
298
+ 子 Agent 工具将命名为 `agent_<name>`,并以子 Agent 的 `desc` 字段作为描述。
299
+
300
+ ---
301
+
302
+ ## 📂 项目结构示例
303
+
304
+ ```
305
+ agents/
306
+ ├── main.md # 入口 Agent(必需)
307
+ ├── researcher.md # 移交目标
308
+ ├── writer.md # 移交目标
309
+ ├── shared/
310
+ │ ├── rules.md # 共享提示词片段
311
+ │ └── format.md # 共享输出格式
312
+ └── tools/
313
+ └── summarizer.md # 作为工具的 Agent
314
+ ```
315
+
316
+ 在 `handoffs`、`agents` 或 `@(...)` 导入中使用的路径均相对于 `rootDir`:
317
+
318
+ ```yaml
319
+ # 在 main.md 中
320
+ handoffs: researcher, writer
321
+ agents: tools/summarizer
322
+ ```
323
+
324
+ ```markdown
325
+ # 在 researcher.md 中
326
+ @(/shared/rules)
327
+ ```
328
+
329
+ ---
330
+
331
+ ## 🧪 测试
332
+
333
+ 运行内置测试套件:
334
+
335
+ ```bash
336
+ pnpm test
337
+ ```
338
+
339
+ ---
340
+
341
+ ## 📄 许可证
342
+
343
+ [MIT](./LICENSE)
@@ -0,0 +1,25 @@
1
+ import { VirtualFS } from "./Loader.ts";
2
+ import { AiSdkModel } from "@openai/agents-extensions";
3
+ import { Agent, ModelSettings, Runner, Tool } from "@openai/agents";
4
+ export type AiSdkModelWithMapModelSettings = AiSdkModel & {
5
+ mapModelSettings?(modelSetting: ModelSettings): ModelSettings;
6
+ };
7
+ export interface AiProvider {
8
+ getModel(modelName: string): AiSdkModelWithMapModelSettings;
9
+ }
10
+ export interface KnockAgentConfig<ProviderNames extends string> {
11
+ rootDir: string;
12
+ fs?: VirtualFS;
13
+ providers: Record<ProviderNames, AiProvider>;
14
+ defaultModel: `${ProviderNames}/${string}`;
15
+ defaultTemperature?: number;
16
+ tools?: Tool[];
17
+ }
18
+ type RunInput<T> = Parameters<typeof Runner.prototype.run<Agent<T>, T>>[1];
19
+ export default class KnockAgent<Context extends object, ProviderNames extends string> {
20
+ #private;
21
+ constructor(config: KnockAgentConfig<ProviderNames>);
22
+ run(input: RunInput<Context>, context?: Context): Promise<import("@openai/agents").StreamedRunResult<Context, Agent<Context, "text">>>;
23
+ runAgent(agentPath: string, input: RunInput<Context>, context?: Context): Promise<import("@openai/agents").StreamedRunResult<Context, Agent<Context, "text">>>;
24
+ }
25
+ export {};