@rong/agentscript 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/CHANGELOG.md +22 -0
- package/INSTALL.md +92 -0
- package/LICENSE +21 -0
- package/README.md +246 -0
- package/dist/ast/constants.js +1 -0
- package/dist/ast/format.js +41 -0
- package/dist/ast/types.js +1 -0
- package/dist/bin/agentscript.js +234 -0
- package/dist/bin/input.js +19 -0
- package/dist/bin/repl.js +290 -0
- package/dist/index.js +26 -0
- package/dist/parser/errors.js +8 -0
- package/dist/parser/parser.js +661 -0
- package/dist/parser/tokenizer.js +246 -0
- package/dist/providers/llm/anthropic.js +36 -0
- package/dist/providers/llm/index.js +3 -0
- package/dist/providers/llm/ollama.js +19 -0
- package/dist/providers/llm/openai.js +31 -0
- package/dist/providers/llm/protocol.js +45 -0
- package/dist/providers/llm/shared.js +147 -0
- package/dist/providers/llm/types.js +1 -0
- package/dist/providers/llm/uri.js +24 -0
- package/dist/providers/memory/file.js +44 -0
- package/dist/providers/memory/host.js +66 -0
- package/dist/providers/memory/index.js +1 -0
- package/dist/providers/memory/shared.js +56 -0
- package/dist/providers/memory/sqlite.js +98 -0
- package/dist/providers/mock/index.js +32 -0
- package/dist/providers/tools/env.js +11 -0
- package/dist/providers/tools/file.js +99 -0
- package/dist/providers/tools/host.js +34 -0
- package/dist/providers/tools/http.js +40 -0
- package/dist/providers/tools/index.js +2 -0
- package/dist/providers/tools/scheme.js +16 -0
- package/dist/providers/tools/shared.js +92 -0
- package/dist/providers/tools/shell.js +80 -0
- package/dist/runtime/context.js +160 -0
- package/dist/runtime/errors.js +14 -0
- package/dist/runtime/evaluator.js +276 -0
- package/dist/runtime/generate.js +175 -0
- package/dist/runtime/guards.js +39 -0
- package/dist/runtime/input.js +38 -0
- package/dist/runtime/interpreter.js +314 -0
- package/dist/runtime/json.js +59 -0
- package/dist/runtime/loader.js +146 -0
- package/dist/runtime/scope.js +47 -0
- package/dist/runtime/shape.js +132 -0
- package/dist/runtime/trace.js +54 -0
- package/dist/runtime/truth.js +13 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/uri.js +10 -0
- package/dist/semantic/analyzer.js +519 -0
- package/dist/semantic/diagnostics.js +16 -0
- package/dist/utils/assert.js +3 -0
- package/docs/cn/context-engineering.md +389 -0
- package/docs/cn/language.md +478 -0
- package/docs/design-history/v0-design.md +365 -0
- package/docs/design-history/v0-implement.md +274 -0
- package/docs/design-history/v1-design.md +323 -0
- package/docs/design-history/v1-implement.md +267 -0
- package/docs/design-history/v2-design.md +387 -0
- package/docs/design-history/v2-implement.md +399 -0
- package/docs/en/context-engineering.md +332 -0
- package/docs/en/language.md +478 -0
- package/examples/changelog.as +29 -0
- package/examples/extract.as +29 -0
- package/examples/review.as +38 -0
- package/examples/summarize.as +28 -0
- package/examples/translate.as +33 -0
- package/package.json +59 -0
- package/tutorials/cli.as +22 -0
- package/tutorials/helloworld.as +14 -0
- package/tutorials/memory.as +19 -0
- package/tutorials/plan-execute.as +155 -0
- package/tutorials/react.as +98 -0
- package/tutorials/repl.as +31 -0
- package/tutorials/self-improve.as +60 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
# AgentScript V0 Design
|
|
2
|
+
|
|
3
|
+
AgentScript 是一种用于构建 LLM Agent 的小型领域语言。V0 的目标是用最小语言面实现一个可运行、可审计、能管理上下文边界的 ReAct Agent。长期能力可以继续扩展,但 V0 只描述当前已经实现和测试覆盖的行为。
|
|
4
|
+
|
|
5
|
+
核心原则:
|
|
6
|
+
|
|
7
|
+
- Agent 是执行和 prompt 身份的基本单元。
|
|
8
|
+
- 所有函数必须定义在 `agent` 内;V0 没有全局函数。
|
|
9
|
+
- `{}` 作用域决定变量、`use` 上下文和 repeat 临时状态的生命周期。
|
|
10
|
+
- 未被 `use` 的普通变量不会进入 LLM prompt。
|
|
11
|
+
- trace 是调试和审计产物,不会自动进入 prompt。
|
|
12
|
+
- 关键词保持少量;能由作用域和普通变量表达的能力不增加专用关键词。
|
|
13
|
+
|
|
14
|
+
## 最小能力
|
|
15
|
+
|
|
16
|
+
V0 支持:
|
|
17
|
+
|
|
18
|
+
- `import llm` 和 `import tool` 资源声明。
|
|
19
|
+
- `main agent` 和 `main func` 显式入口。
|
|
20
|
+
- Agent 内函数、变量赋值、对象/列表字面量、成员访问、函数调用。
|
|
21
|
+
- `model`、`role`、`description` 作用域配置。
|
|
22
|
+
- `use` 上下文声明和 `< n` 上下文预算。
|
|
23
|
+
- `generate({ input, limit, attempts, debug }) { return { ... } }` LLM 调用。
|
|
24
|
+
- `if` / `else`,`==`、`!=`、`and`、`or`、`not`。
|
|
25
|
+
- `loop until condition < n` 有上限循环。
|
|
26
|
+
- `repeat * n` 有上限重复执行。
|
|
27
|
+
- 入口 input shape 和交互式补齐。
|
|
28
|
+
- 跨 Agent 调用:`Worker.run(input)`;`Worker(input)` 调用 `Worker` 的 `main func`。
|
|
29
|
+
|
|
30
|
+
V0 不支持:
|
|
31
|
+
|
|
32
|
+
- 全局函数。
|
|
33
|
+
- 用户自定义类型、类、继承、泛型。
|
|
34
|
+
- 通用异步、并发、事务或回滚。
|
|
35
|
+
- `context {}`、`include`、`exclude`、`retain`、`isolate` 等上下文关键词。
|
|
36
|
+
- RAG、长期 memory、harness/eval 编排。
|
|
37
|
+
- 通用异常捕获、事务或回滚。
|
|
38
|
+
|
|
39
|
+
## 程序入口
|
|
40
|
+
|
|
41
|
+
程序从 `main agent` 的 `main func` 启动。
|
|
42
|
+
|
|
43
|
+
```agentscript
|
|
44
|
+
main agent ResearchAgent {
|
|
45
|
+
model Qwen
|
|
46
|
+
role "Researcher"
|
|
47
|
+
description "Research with search observations."
|
|
48
|
+
|
|
49
|
+
main func(input {
|
|
50
|
+
question string
|
|
51
|
+
}) {
|
|
52
|
+
use input.question
|
|
53
|
+
return answer(input.question)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
func answer(question) {
|
|
57
|
+
use question
|
|
58
|
+
|
|
59
|
+
return generate({ input: "Answer the question" }) {
|
|
60
|
+
return {
|
|
61
|
+
ok boolean
|
|
62
|
+
text string
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
入口规则:
|
|
70
|
+
|
|
71
|
+
- 一个程序最多一个 `main agent`。
|
|
72
|
+
- 一个 Agent 最多一个 `main func`。
|
|
73
|
+
- 多 Agent 程序必须声明 `main agent`。
|
|
74
|
+
- `main agent { ... }` 可以省略 Agent 名,内部名为 `__main_agent`。
|
|
75
|
+
- `main func(input) { ... }` 可以省略函数名,内部名为 `__main`。
|
|
76
|
+
- `input` 不是关键词,只是入口参数的常用约定。
|
|
77
|
+
- 只有 `main func` 的第一个 `input` 参数可以声明 shape。
|
|
78
|
+
|
|
79
|
+
## 资源
|
|
80
|
+
|
|
81
|
+
```agentscript
|
|
82
|
+
import llm Qwen from "ollama://localhost:11434/qwen3.6"
|
|
83
|
+
import tool Search from "mcp://tools/search"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
LLM URI:
|
|
87
|
+
|
|
88
|
+
- `openai://gpt-4.1-mini`,需要 `OPENAI_API_KEY`。
|
|
89
|
+
- `anthropic://claude-sonnet-4-0`,需要 `ANTHROPIC_API_KEY`。
|
|
90
|
+
- `ollama://localhost:11434/qwen3.6`,显式 Ollama 地址。
|
|
91
|
+
|
|
92
|
+
工具由 host runtime 提供。工具调用输出会写入 trace,但不会自动进入后续 prompt。
|
|
93
|
+
|
|
94
|
+
## 作用域配置
|
|
95
|
+
|
|
96
|
+
`model`、`role`、`description` 是作用域配置。函数或块内可以覆盖父作用域配置。
|
|
97
|
+
|
|
98
|
+
```agentscript
|
|
99
|
+
agent A {
|
|
100
|
+
model Fast
|
|
101
|
+
role "Assistant"
|
|
102
|
+
description "Default behavior."
|
|
103
|
+
|
|
104
|
+
func careful(input) {
|
|
105
|
+
model Strong
|
|
106
|
+
description "Use a stronger model for this function."
|
|
107
|
+
|
|
108
|
+
return generate({ input: "Answer carefully" }) {
|
|
109
|
+
return {
|
|
110
|
+
text string
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
规则:
|
|
118
|
+
|
|
119
|
+
- `model` 必须引用 `import llm` 名称。
|
|
120
|
+
- `role` 和 `description` 必须是字符串。
|
|
121
|
+
- 执行 `generate` 时,当前作用域必须能解析到 `model`、`role`、`description`。
|
|
122
|
+
- 不调用 `generate` 的纯工具或纯计算函数不需要这些配置。
|
|
123
|
+
|
|
124
|
+
## 数据和 Shape
|
|
125
|
+
|
|
126
|
+
V0 运行时数据以 JSON 为核心:
|
|
127
|
+
|
|
128
|
+
- `string`
|
|
129
|
+
- `number`
|
|
130
|
+
- `boolean`
|
|
131
|
+
- `json`
|
|
132
|
+
- `list`
|
|
133
|
+
|
|
134
|
+
`generate` 返回 shape 使用轻量标注:
|
|
135
|
+
|
|
136
|
+
```agentscript
|
|
137
|
+
return generate({ input: "Extract facts" }) {
|
|
138
|
+
return {
|
|
139
|
+
facts list[string]
|
|
140
|
+
source string
|
|
141
|
+
meta json
|
|
142
|
+
ok boolean
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Shape 只用于入口 input 校验和 `generate` 输出校验,不是完整类型系统。
|
|
148
|
+
|
|
149
|
+
## 上下文
|
|
150
|
+
|
|
151
|
+
`use` 表示一个值允许进入当前作用域后续 `generate` 的 prompt context。
|
|
152
|
+
|
|
153
|
+
```agentscript
|
|
154
|
+
func compose(question, scratch) {
|
|
155
|
+
use question
|
|
156
|
+
use scratch.summary < 2k
|
|
157
|
+
|
|
158
|
+
return generate({ input: "Answer using only the context" }) {
|
|
159
|
+
return {
|
|
160
|
+
ok boolean
|
|
161
|
+
text string
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
规则:
|
|
168
|
+
|
|
169
|
+
- `use` 只能写在函数或执行块内。
|
|
170
|
+
- `use` 只能引用当前可见的普通运行时值。
|
|
171
|
+
- `llm`、`tool`、`agent` 资源绑定不能被 `use`。
|
|
172
|
+
- 子作用域继承父作用域的 `use`。
|
|
173
|
+
- `use value < n` 对该上下文项应用预算;`2k` 约等于 2000 字符。
|
|
174
|
+
- 未被 `use` 的变量、工具原始输出和 trace 不进入 prompt。
|
|
175
|
+
|
|
176
|
+
## Generate
|
|
177
|
+
|
|
178
|
+
`generate({ input, limit, attempts, debug }) { return { ... } }` 表示一次 LLM call。`input` 是本次 call 的最后用户指令,可以是字符串、对象或其它 JSON 值。`limit`、`attempts`、`debug` 都是可选参数。
|
|
179
|
+
|
|
180
|
+
```agentscript
|
|
181
|
+
answer = generate({
|
|
182
|
+
input: "Answer using collected facts"
|
|
183
|
+
limit: 800
|
|
184
|
+
attempts: 3
|
|
185
|
+
}) {
|
|
186
|
+
return {
|
|
187
|
+
ok boolean
|
|
188
|
+
text string
|
|
189
|
+
error string
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
规则:
|
|
195
|
+
|
|
196
|
+
- `generate` 是语法级内置表达式,不是普通函数。
|
|
197
|
+
- `generate` 参数必须是对象,且必须包含 `input` 字段。
|
|
198
|
+
- `limit` 是本次 LLM call 的预算,支持 `800` 或 `2k` 这类 budget 字面量。
|
|
199
|
+
- `attempts` 表示最多生成次数;它不是额外重试次数。
|
|
200
|
+
- `debug` 是 boolean,缺省值为 `false`;为 `true` 时 runtime 将完整 prompt 打印到 stderr。
|
|
201
|
+
- 块内 `return { ... }` 描述 LLM 输出 JSON shape,不会从外层函数返回。
|
|
202
|
+
- LLM 输出会先按 shape 做有限容错转换。
|
|
203
|
+
- 当输出不是 JSON 或转换后仍不符合 shape,且 `attempts > 1` 时,下一次调用会把上一次输出和错误信息附加到 `input` 后,请模型 repair。
|
|
204
|
+
- provider 网络、认证、超时、模型不存在等基础设施错误不会被 repair 重试。
|
|
205
|
+
|
|
206
|
+
## 控制流
|
|
207
|
+
|
|
208
|
+
### If
|
|
209
|
+
|
|
210
|
+
```agentscript
|
|
211
|
+
if answer.ok and not input.dry_run {
|
|
212
|
+
return answer
|
|
213
|
+
} else {
|
|
214
|
+
return failed(answer.error)
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
V0 条件表达式只支持:
|
|
219
|
+
|
|
220
|
+
- `==`
|
|
221
|
+
- `!=`
|
|
222
|
+
- `and`
|
|
223
|
+
- `or`
|
|
224
|
+
- `not`
|
|
225
|
+
|
|
226
|
+
`<` 不作为通用比较运算符;它只用于预算和循环上限。
|
|
227
|
+
|
|
228
|
+
### Loop
|
|
229
|
+
|
|
230
|
+
```agentscript
|
|
231
|
+
done = false
|
|
232
|
+
|
|
233
|
+
loop until done < 6 {
|
|
234
|
+
observation = observe(Search.search(query))
|
|
235
|
+
scratch.add(observation)
|
|
236
|
+
done = enough_evidence(scratch)
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
`loop until condition < n` 每轮开始先检查 `condition`。当条件为真或达到 `n` 次上限时结束。
|
|
241
|
+
|
|
242
|
+
### Repeat
|
|
243
|
+
|
|
244
|
+
```agentscript
|
|
245
|
+
insight = none
|
|
246
|
+
|
|
247
|
+
repeat * 3 {
|
|
248
|
+
scratch = []
|
|
249
|
+
answer = attempt(input.question, insight)
|
|
250
|
+
|
|
251
|
+
if answer.ok {
|
|
252
|
+
return answer
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
insight = reflect(answer.error, scratch.summary)
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
规则:
|
|
260
|
+
|
|
261
|
+
- 每次 repeat attempt 创建新的子作用域。
|
|
262
|
+
- repeat 块内新建变量在本次 attempt 结束后丢弃。
|
|
263
|
+
- repeat 外层已存在的变量在块内被赋值时会更新外层变量。
|
|
264
|
+
- 这允许保留短 `insight`,同时丢弃完整尝试过程。
|
|
265
|
+
|
|
266
|
+
## Agent 调用
|
|
267
|
+
|
|
268
|
+
```agentscript
|
|
269
|
+
result = Worker.run(input)
|
|
270
|
+
result = Worker(input)
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
规则:
|
|
274
|
+
|
|
275
|
+
- `Worker.run(input)` 调用 `Worker` 的 `run` 函数。
|
|
276
|
+
- `Worker(input)` 调用 `Worker` 的 `main func`。
|
|
277
|
+
- 跨 Agent 调用使用独立函数作用域;子 Agent 内部 trace 嵌套在顶层 `agent` trace 事件下。
|
|
278
|
+
|
|
279
|
+
## CLI
|
|
280
|
+
|
|
281
|
+
开发期命令:
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
npm run agentscript -- tutorials/react.as --input '{"question":"What is AgentScript?"}'
|
|
285
|
+
npm run agentscript -- tutorials/react.as --check
|
|
286
|
+
npm run agentscript -- tutorials/react.as --parse
|
|
287
|
+
npm run agentscript
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
构建后:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
node dist/bin/agentscript.js tutorials/react.as --input '{"question":"What is AgentScript?"}'
|
|
294
|
+
node dist/bin/agentscript.js
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
选项:
|
|
298
|
+
|
|
299
|
+
- `--input '<json>'`
|
|
300
|
+
- `--input-file input.json`
|
|
301
|
+
- `--agent AgentName`
|
|
302
|
+
- `--function functionName`
|
|
303
|
+
- `--check`
|
|
304
|
+
- `--parse`
|
|
305
|
+
- `--real-llm`
|
|
306
|
+
- `--trace trace.json`
|
|
307
|
+
- `--trace pretty`
|
|
308
|
+
- `--verbose`
|
|
309
|
+
- `--quiet`
|
|
310
|
+
|
|
311
|
+
无参数启动进入 REPL。REPL 以一个完整 `agent` 声明为最小粘贴单元。
|
|
312
|
+
|
|
313
|
+
```text
|
|
314
|
+
> :import llm Qwen from "ollama://localhost:11434/qwen3.6"
|
|
315
|
+
> :load tutorials/helloworld.as
|
|
316
|
+
> :check
|
|
317
|
+
> :run {}
|
|
318
|
+
> :trace pretty
|
|
319
|
+
> :exit
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## 保留词
|
|
323
|
+
|
|
324
|
+
V0 保留词:
|
|
325
|
+
|
|
326
|
+
- `import`
|
|
327
|
+
- `from`
|
|
328
|
+
- `main`
|
|
329
|
+
- `agent`
|
|
330
|
+
- `func`
|
|
331
|
+
- `use`
|
|
332
|
+
- `loop`
|
|
333
|
+
- `until`
|
|
334
|
+
- `repeat`
|
|
335
|
+
- `for`
|
|
336
|
+
- `in`
|
|
337
|
+
- `return`
|
|
338
|
+
- `if`
|
|
339
|
+
- `else`
|
|
340
|
+
- `and`
|
|
341
|
+
- `or`
|
|
342
|
+
- `not`
|
|
343
|
+
- `generate`
|
|
344
|
+
- `true`
|
|
345
|
+
- `false`
|
|
346
|
+
- `none`
|
|
347
|
+
- `string`
|
|
348
|
+
- `boolean`
|
|
349
|
+
- `json`
|
|
350
|
+
- `list`
|
|
351
|
+
|
|
352
|
+
以下不是关键词:`input`、`act`、`reason`、`observe`、`reflect`、`answer`、`scratch`、`done`、`task`、`output`、`context`、`include`、`exclude`、`retain`、`isolate`、`repair`。
|
|
353
|
+
|
|
354
|
+
`act` 只是普通函数名,没有入口或 Agent 调用约定。
|
|
355
|
+
|
|
356
|
+
## 示例
|
|
357
|
+
|
|
358
|
+
完整示例在:
|
|
359
|
+
|
|
360
|
+
- `tutorials/helloworld.as`
|
|
361
|
+
- `tutorials/react.as`
|
|
362
|
+
- `tutorials/cli.as`
|
|
363
|
+
- `examples/review.as`
|
|
364
|
+
- `examples/summarize.as`
|
|
365
|
+
- `examples/changelog.as`
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# AgentScript V0 Implement
|
|
2
|
+
|
|
3
|
+
本文档是 V0 阶段的历史实现快照。语言设计见 `v0-design.md`。当前 v1.0.0 的实现入口和模块概览见 `../en/language.md` 与 `../cn/language.md`。
|
|
4
|
+
|
|
5
|
+
## 执行管线
|
|
6
|
+
|
|
7
|
+
V0 采用解释执行:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
source
|
|
11
|
+
-> tokenizer
|
|
12
|
+
-> parser
|
|
13
|
+
-> AST
|
|
14
|
+
-> semantic analyzer
|
|
15
|
+
-> interpreter
|
|
16
|
+
-> trace + result
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
V0 不实现 IR、字节码或编译到其他 runtime。当前语言面很小,解释器足够验证作用域、`use`、`generate`、工具调用、`repeat` 和 trace 行为。
|
|
20
|
+
|
|
21
|
+
## 模块
|
|
22
|
+
|
|
23
|
+
V0 阶段的核心源码模块:
|
|
24
|
+
|
|
25
|
+
- `src/parser/tokenizer.ts`:分词。
|
|
26
|
+
- `src/parser/parser.ts`:递归下降 parser,输出 AST。
|
|
27
|
+
- `src/ast/types.ts`:AST 类型。
|
|
28
|
+
- `src/semantic/analyzer.ts`:静态语义检查。
|
|
29
|
+
- `src/runtime/interpreter.ts`:解释器入口、Agent/函数调用和语句执行。
|
|
30
|
+
- `src/runtime/evaluator.ts`:表达式求值、工具调用和 `use` source 解析。
|
|
31
|
+
- `src/runtime/generate.ts`:`generate` 执行、上下文构建调用、LLM 调用和输出校验。
|
|
32
|
+
- `src/runtime/scope.ts`:运行时变量、配置和 `use` 作用域。
|
|
33
|
+
- `src/runtime/context.ts`:`generate` prompt/context builder。
|
|
34
|
+
- `src/providers/llm/`:OpenAI、Anthropic、Ollama provider。
|
|
35
|
+
- `src/runtime/types.ts`:运行时值、provider 接口和执行选项类型。
|
|
36
|
+
- `src/runtime/guards.ts`:运行时值类型守卫。
|
|
37
|
+
- `src/runtime/json.ts`:JSON 解析和序列化工具。
|
|
38
|
+
- `src/runtime/truth.ts`:条件表达式 truthiness。
|
|
39
|
+
- `src/runtime/shape.ts`:shape 构建、校验和 `generate` 输出容错转换。
|
|
40
|
+
- `src/providers/mock/index.ts`:mock LLM/tool provider。
|
|
41
|
+
- `src/runtime/trace.ts`:trace 格式化。
|
|
42
|
+
- `src/bin/agentscript.ts`:CLI。
|
|
43
|
+
- `src/bin/repl.ts`:agent-level REPL。
|
|
44
|
+
|
|
45
|
+
后续 V1/V2 继续增加了 loader、memory、tools、输入处理、诊断和包入口等模块。当前代码库中与实现相关的主要补充模块包括:
|
|
46
|
+
|
|
47
|
+
- `src/index.ts`:包入口。
|
|
48
|
+
- `src/ast/format.ts`:AST 表达式源码格式化。
|
|
49
|
+
- `src/parser/errors.ts`:解析错误类型。
|
|
50
|
+
- `src/semantic/diagnostics.ts`:语义诊断格式化。
|
|
51
|
+
- `src/runtime/errors.ts`:运行时错误类型。
|
|
52
|
+
- `src/runtime/input.ts`:入口输入 shape 处理。
|
|
53
|
+
- `src/runtime/loader.ts`:跨文件 import 加载器。
|
|
54
|
+
- `src/providers/memory/`:File JSONL 和 SQLite memory provider。
|
|
55
|
+
- `src/providers/tools/`:host tool provider 实现。
|
|
56
|
+
- `src/bin/input.ts`:CLI 输入解析。
|
|
57
|
+
|
|
58
|
+
## AST 范围
|
|
59
|
+
|
|
60
|
+
V0 AST 节点:
|
|
61
|
+
|
|
62
|
+
- `Program`
|
|
63
|
+
- `ImportDecl`
|
|
64
|
+
- `AgentDecl`
|
|
65
|
+
- `ConfigDecl`
|
|
66
|
+
- `ConfigStmt`
|
|
67
|
+
- `FuncDecl`
|
|
68
|
+
- `FuncParam`
|
|
69
|
+
- `UseStmt`
|
|
70
|
+
- `AssignStmt`
|
|
71
|
+
- `ExprStmt`
|
|
72
|
+
- `IfStmt`
|
|
73
|
+
- `LoopUntilStmt`
|
|
74
|
+
- `RepeatStmt`
|
|
75
|
+
- `ReturnStmt`
|
|
76
|
+
- `IdentifierExpr`
|
|
77
|
+
- `StringExpr`
|
|
78
|
+
- `NumberExpr`
|
|
79
|
+
- `BooleanExpr`
|
|
80
|
+
- `NullExpr`
|
|
81
|
+
- `ListExpr`
|
|
82
|
+
- `ObjectExpr`
|
|
83
|
+
- `ShapeObjectExpr`
|
|
84
|
+
- `MemberExpr`
|
|
85
|
+
- `CallExpr`
|
|
86
|
+
- `UnaryExpr`
|
|
87
|
+
- `BinaryExpr`
|
|
88
|
+
- `GenerateExpr`
|
|
89
|
+
|
|
90
|
+
重要解析规则:
|
|
91
|
+
|
|
92
|
+
- `main agent { ... }` 映射为匿名入口 Agent,内部名 `__main_agent`。
|
|
93
|
+
- `main func(input) { ... }` 映射为匿名入口函数,内部名 `__main`。
|
|
94
|
+
- `AgentName(input)` 是普通 `CallExpr`,语义和运行时把它解析为目标 Agent 的 `main func` 调用。
|
|
95
|
+
- `generate({ input: "...", limit: 500 }) { return { ... } }` 把生成预算保存在 `GenerateExpr` options 中。
|
|
96
|
+
- `use value < 2k` 的预算在 `UseStmt` 上。
|
|
97
|
+
- `loop until done < 6` 的 `< 6` 是循环上限,不是比较表达式。
|
|
98
|
+
|
|
99
|
+
## 语义检查
|
|
100
|
+
|
|
101
|
+
当前 semantic analyzer 检查:
|
|
102
|
+
|
|
103
|
+
- import 名称重复。
|
|
104
|
+
- agent 名称重复。
|
|
105
|
+
- 多 Agent 程序必须有一个 `main agent`。
|
|
106
|
+
- `main agent`、`main func` 不能重复。
|
|
107
|
+
- 入口 Agent 必须有 main func;单 Agent 程序省略 `main agent` 时,该 Agent 仍必须有 main func。
|
|
108
|
+
- 同一 Agent 内函数名不能重复。
|
|
109
|
+
- 参数名不能重复。
|
|
110
|
+
- 只有 `main func` 的第一个 `input` 参数可以声明 shape。
|
|
111
|
+
- `model` 必须引用 `import llm`。
|
|
112
|
+
- `role`、`description` 必须是字符串。
|
|
113
|
+
- 标识符必须在当前词法作用域中可见。
|
|
114
|
+
- `use` 不能引用 `llm`、`tool`、`agent`、`memory` 资源绑定。
|
|
115
|
+
- 赋值目标只能是标识符或成员表达式。
|
|
116
|
+
- 函数调用参数数量必须匹配。
|
|
117
|
+
- `AgentName(input)` 要求目标 Agent 有 `main func`。
|
|
118
|
+
- `Worker.run(input)` 要求目标 Agent 有对应函数。
|
|
119
|
+
- `generate` 参数必须是对象字面量,包含 `input` 字段;`limit`、`attempts`、`debug` 可选,其中 `attempts` 必须是正整数,`debug` 必须是 boolean。
|
|
120
|
+
- shape 字段不能重复,类型只能是 `string`、`number`、`boolean`、`json`、`list` 或 `list[...]`。
|
|
121
|
+
- `< n` budget 在 `use` 中必须大于 0。
|
|
122
|
+
|
|
123
|
+
## 运行时语义
|
|
124
|
+
|
|
125
|
+
解释器行为:
|
|
126
|
+
|
|
127
|
+
- 入口选择:优先 `main agent` 和 `main func`;单 Agent 程序可省略 `main agent`。
|
|
128
|
+
- 函数调用创建新的运行时作用域。
|
|
129
|
+
- 子作用域可读父作用域变量。
|
|
130
|
+
- 赋值给已存在的父作用域变量会更新父作用域。
|
|
131
|
+
- 赋值给不存在的名字会在当前作用域创建局部变量。
|
|
132
|
+
- 局部变量可以遮蔽 import、agent、function 绑定。
|
|
133
|
+
- `if`、`loop`、每次 `repeat` attempt 都创建子作用域。
|
|
134
|
+
- `repeat` 外层变量可以跨 attempt 保留;attempt 内新建变量不会跨 attempt 保留。
|
|
135
|
+
- `use` 声明随作用域继承。
|
|
136
|
+
- 入口 shape 缺失字段由 `InputProvider` 补齐;非交互环境没有 provider 时抛错。
|
|
137
|
+
|
|
138
|
+
## Context Builder
|
|
139
|
+
|
|
140
|
+
`src/runtime/context.ts` 只在执行 `generate` 时工作。
|
|
141
|
+
|
|
142
|
+
输入:
|
|
143
|
+
|
|
144
|
+
- 当前 Agent 名称。
|
|
145
|
+
- 当前作用域 `model`、`role`、`description`。
|
|
146
|
+
- 当前可见 `use` 列表。
|
|
147
|
+
- `generate({ input, limit, attempts, debug })` 中的 `input` instruction。
|
|
148
|
+
- `generate` 返回 shape。
|
|
149
|
+
- 可选 `limit` 预算。
|
|
150
|
+
|
|
151
|
+
输出:
|
|
152
|
+
|
|
153
|
+
- system prompt。
|
|
154
|
+
- context 项列表。
|
|
155
|
+
- JSON schema。
|
|
156
|
+
- final user message。
|
|
157
|
+
|
|
158
|
+
V0 的预算裁剪按字符数实现:`2k` 约等于 2000 字符。这是当前实现行为,不代表 tokenizer-aware 预算。
|
|
159
|
+
|
|
160
|
+
裁剪是结构感知的:
|
|
161
|
+
|
|
162
|
+
- string 按字符截断。
|
|
163
|
+
- list 保留完整 item,从尾部移除。
|
|
164
|
+
- object 保留完整字段,从尾部移除。
|
|
165
|
+
- trace 中记录每个 context item 的 `originalSize` 和 `clippedSize`。
|
|
166
|
+
|
|
167
|
+
## LLM Provider
|
|
168
|
+
|
|
169
|
+
`ProtocolLlmProvider` 支持:
|
|
170
|
+
|
|
171
|
+
- OpenAI Chat Completions structured output。
|
|
172
|
+
- Anthropic Messages。
|
|
173
|
+
- Ollama `/api/chat`。
|
|
174
|
+
|
|
175
|
+
配置:
|
|
176
|
+
|
|
177
|
+
- `OPENAI_API_KEY`
|
|
178
|
+
- `OPENAI_BASE_URL`
|
|
179
|
+
- `ANTHROPIC_API_KEY`
|
|
180
|
+
- `ANTHROPIC_BASE_URL`
|
|
181
|
+
- `OLLAMA_BASE_URL`
|
|
182
|
+
- `AGENTSCRIPT_LLM_TIMEOUT_MS`
|
|
183
|
+
|
|
184
|
+
输出处理:
|
|
185
|
+
|
|
186
|
+
- provider HTTP 响应必须是 JSON。
|
|
187
|
+
- 模型内容必须能解析为 JSON,允许从 fenced JSON 或文本中的 `{...}` 提取。
|
|
188
|
+
- 解析后的值会先按 `generate` shape 做有限容错转换。
|
|
189
|
+
- `limit` 是可选 provider token limit。
|
|
190
|
+
- `attempts` 缺省值为 `1`。
|
|
191
|
+
- `debug` 缺省值为 `false`;为 `true` 时完整 prompt 打印到 stderr。
|
|
192
|
+
- JSON 解析失败或 shape 不匹配时,如果还有剩余 attempts,会把上一次错误和可用的上一次输出附加到下一次 `generate` 的 instruction。
|
|
193
|
+
- provider 网络、认证、超时、模型不存在等基础设施错误直接抛出,不做 repair 重试。
|
|
194
|
+
|
|
195
|
+
## Tool Provider
|
|
196
|
+
|
|
197
|
+
工具通过 `ToolProvider` 接口接入:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
interface ToolProvider {
|
|
201
|
+
call(request: ToolCallRequest): Promise<RuntimeValue>;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
mock tool provider 返回包含工具名、URI 和参数的 JSON,便于测试 trace 和上下文边界。
|
|
206
|
+
|
|
207
|
+
## Trace
|
|
208
|
+
|
|
209
|
+
V0 trace 事件:
|
|
210
|
+
|
|
211
|
+
- `input`
|
|
212
|
+
- `use`
|
|
213
|
+
- `generate`
|
|
214
|
+
- `tool`
|
|
215
|
+
- `agent`
|
|
216
|
+
|
|
217
|
+
跨 Agent 调用的内部事件嵌套在 `agent.data.trace` 下。顶层 trace 因此保留调用边界,不把子 Agent 的 `use`、`generate`、`tool` 事件平铺到父 Agent trace。
|
|
218
|
+
|
|
219
|
+
CLI 支持:
|
|
220
|
+
|
|
221
|
+
- 默认 JSON 输出携带 trace。
|
|
222
|
+
- `--trace trace.json` 写入 trace 文件。
|
|
223
|
+
- `--trace pretty` 追加可读 trace。
|
|
224
|
+
- `--verbose` 追加可读 trace。
|
|
225
|
+
- `--quiet` 只输出最终 value。
|
|
226
|
+
|
|
227
|
+
REPL 支持:
|
|
228
|
+
|
|
229
|
+
- `:trace`
|
|
230
|
+
- `:trace pretty`
|
|
231
|
+
|
|
232
|
+
## CLI 和 REPL
|
|
233
|
+
|
|
234
|
+
CLI:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
npm run agentscript -- tutorials/react.as --input '{"question":"What is AgentScript?"}'
|
|
238
|
+
npm run agentscript -- tutorials/react.as --check
|
|
239
|
+
npm run agentscript -- tutorials/react.as --parse
|
|
240
|
+
npm run agentscript -- tutorials/react.as --real-llm --input '{"question":"What is AgentScript?"}'
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
REPL:
|
|
244
|
+
|
|
245
|
+
- 无参数运行 `agentscript` 进入 REPL。
|
|
246
|
+
- `:import <import statement>` 添加 import。
|
|
247
|
+
- `:load <file.as>` 加载文件里的 imports 和 agents。
|
|
248
|
+
- 每次粘贴一个完整 `agent` 声明作为最小编辑单元。
|
|
249
|
+
- `:run [json]` 执行当前 session program。
|
|
250
|
+
|
|
251
|
+
## 测试范围
|
|
252
|
+
|
|
253
|
+
测试覆盖:
|
|
254
|
+
|
|
255
|
+
- tokenizer。
|
|
256
|
+
- parser。
|
|
257
|
+
- semantic analyzer。
|
|
258
|
+
- context builder。
|
|
259
|
+
- interpreter runtime。
|
|
260
|
+
- LLM provider URI 和请求构造。
|
|
261
|
+
- CLI 和 REPL。
|
|
262
|
+
- examples parse/check/execute 回归。
|
|
263
|
+
|
|
264
|
+
常用验证命令:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
npm run typecheck
|
|
268
|
+
npm test
|
|
269
|
+
npm run build
|
|
270
|
+
npm run check -- tutorials/react.as
|
|
271
|
+
npm run execute -- tutorials/helloworld.as --input '{}'
|
|
272
|
+
npm run execute -- tutorials/cli.as --input '{"name":"Rong","request":"Say hello from AgentScript"}'
|
|
273
|
+
node dist/bin/agentscript.js tutorials/react.as --input '{"question":"What is AgentScript?"}' --trace pretty
|
|
274
|
+
```
|