@rong/agentscript 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,146 +1,69 @@
1
1
  # AgentScript Context Engineering
2
2
 
3
- 本文档说明 AgentScript `use`、作用域和 `generate` 的核心设计含义。这个概念不属于某个特定版本,而是 AgentScript 区别于普通编程语言的基础语义。
3
+ 本文档是 AgentScript context engineering 的总纲。它说明 AgentScript 为什么存在、必须维护哪些边界,以及 `use ... as ...` 和 `generate` 两篇细化文档如何配合。
4
4
 
5
- AgentScript 表面上有变量、函数、循环和 Agent 调用,但它的主要目标不是成为通用编程语言,而是提供一种可审计、可组合、显式的 prompt context engineering DSL。
5
+ AgentScript 有变量、函数、循环、工具、memory Agent 调用,但它的目标不是成为通用编程语言,而是让 prompt context 显式、作用域化、类型化、可追踪、可审计。
6
6
 
7
- 后续开发涉及 `use`、scope、context builder、trace 或 prompt 结构时,应优先参考本文档。若实现细节与本文不一致,应先判断是实现尚未跟上设计,还是本文需要更新。
7
+ ## 文档结构
8
8
 
9
- ## 核心定位
9
+ Context engineering 设计拆成三篇:
10
10
 
11
- AgentScript 的控制流服务于 prompt context 构建。
12
-
13
- 普通语句负责组织数据、调用工具、调用 Agent 和更新中间状态。LLM 调用只能通过 `generate(...) -> { ... }` 发生,而 `generate` 能看到的上下文必须由 `use` 显式声明。
14
-
15
- AgentScript 的核心对象是:
16
-
17
- - `Data`:普通变量、JSON、list、file import、tool observation 和 Agent 返回值。
18
- - `Context Source`:由 `use expr < budget` 声明的 prompt context 来源。
19
- - `Generation Site`:由 `generate({ input, limit, attempts, debug }) -> shape` 声明的一次 LLM 调用。
20
- - `Boundary`:由 Agent、function 和 block scope 形成的 context 可见性边界。
21
-
22
- ## `use` 的语义
23
-
24
- `use` 不是普通编程语言中的变量读取,也不是把变量导入某个命名空间。`use` 的含义是:
25
-
26
- > 在当前作用域声明一个 prompt context source,使后续在该作用域内可见的 `generate` 可以把该 source 的值放入 prompt context。
27
-
28
- 例如:
29
-
30
- ```agentscript
31
- func answer(question, scratch) {
32
- use question
33
- use scratch.summary < 2k
34
-
35
- generate({
36
- input: "Answer the question using collected facts"
37
- limit: 800
38
- }) -> {
39
- ok boolean
40
- text string
41
- error string
42
- }
43
- }
44
- ```
45
-
46
- 这里 `question` 和 `scratch.summary` 是本次 `generate` 的显式 context source。没有被 `use` 的局部变量不应自动进入 prompt。
47
-
48
- ## `use` 应是延迟求值的 context source
49
-
50
- 目标语义是:
51
-
52
- > `use expr < budget` 声明的是 `expr` 这个 context source,而不是立即复制 `expr` 的当前值。真正构建 prompt 时,应在 `generate` 执行点解析该 source 的当前值。
53
-
54
- 因此,下面的程序应让 `generate` 看到更新后的 `scratch.summary`:
55
-
56
- ```agentscript
57
- main func(input) {
58
- scratch = []
59
- use scratch.summary < 2k
60
-
61
- scratch.add({ fact: "A" })
62
- scratch.add({ fact: "B" })
63
-
64
- generate({ input: "Answer from scratch" }) -> {
65
- text string
66
- }
67
- }
68
- ```
69
-
70
- 设计理由:
71
-
72
- - `use` 表达的是 context contract,而不是一次普通赋值。
73
- - Agent 常见模式会持续更新 scratch、plan、observations。
74
- - 如果 `use` 是快照,用户必须在每个 `generate` 前重复声明,容易造成陈旧 context。
75
- - 延迟求值更符合 context engineering 中“声明可见源,在调用点构建 prompt”的直觉。
11
+ - **Context Engineering**:本文,总览核心模型和不变量。
12
+ - **[`use ... as ...`](./use-as.md)**:说明如何选择数据作为 prompt context,label 如何工作,budget 如何应用,以及 scope 如何影响可见性。
13
+ - **[`generate`](./generate.md)**:说明 generation site、prompt 构造、agent identity、输出契约、预算、重试和 trace。
76
14
 
77
- 实现上可以把 `use` 存为 `expr + declaring scope + budget`,在 `generate` 构建 context 时再求值。
15
+ 语言参考仍然是紧凑语法说明;这些设计文档定义语义边界。
78
16
 
79
- ## `use` 与 prompt 暴露边界
17
+ ## 核心模型
80
18
 
81
- 默认情况下,LLM 不应看到当前函数内的全部变量。
82
-
83
- 以下内容只有被显式 `use` 后才可进入 prompt context:
84
-
85
- - 用户输入。
86
- - 中间结果。
87
- - scratch 或 memory-like 数据。
88
- - 工具 observation。
89
- - imported file 的内容。
90
- - 其他 Agent 的返回值。
19
+ AgentScript 的控制流服务于 prompt context 构建。
91
20
 
92
- 以下 runtime capability 不应作为 prompt context
21
+ 普通语句负责组织数据、调用工具、调用 Agent、查询 memory 和更新中间状态。LLM 调用只能通过 `generate(...) -> { ... }` 发生。一次 `generate` 只能看到由 `use` 显式声明、且在作用域中可见的 context source。
93
22
 
94
- - imported tool。
95
- - imported llm/model。
96
- - imported agent binding。
97
- - function binding。
98
- - provider URI、workspace path 等执行配置。
23
+ AgentScript 的核心对象是:
99
24
 
100
- 例如,下面应被语义分析禁止:
25
+ - **Data**:普通值,例如 input、JSON、list、文件内容、工具 observation、memory 查询结果和 Agent 返回值。
26
+ - **Context source**:通过 `use expr` 选择进入 prompt context 的数据,可带 budget 和 label。
27
+ - **Generation site**:一次由 `generate({ input, max_output, attempts, temperature, think, strict, debug }) -> shape` 表示的 LLM 调用。
28
+ - **Boundary**:由 Agent、function 或 block scope 形成的可见性边界。
29
+ - **Trace**:解释哪些 source 被选择、prompt context 如何构建、每次 generation 返回了什么的审计记录。
101
30
 
102
- ```agentscript
103
- use Search
104
- use Qwen
105
- use Worker
106
- use helper
107
- ```
31
+ ## 核心不变量
108
32
 
109
- 这条规则的目的不是类型洁癖,而是防止把执行能力或 runtime 配置误当作数据暴露给 LLM。
33
+ AgentScript 应维护这些不变量:
110
34
 
111
- ## Scope context boundary
35
+ - **不隐式捕获**:局部变量、工具输出、memory 记录和 trace 事件不会自动进入 prompt,除非被 `use` 选择。
36
+ - **作用域可见性**:context 可见性遵循 scope。子作用域可继承父作用域 context;function 和 Agent 调用创建独立 context boundary。
37
+ - **能力隔离**:imported tool、model、agent、memory handle、function、provider URI 和 runtime 配置是能力,不是 prompt data。
38
+ - **延迟解析 context**:`use expr` 声明 source,值在可见的 `generate` 构建 prompt 时解析。
39
+ - **prompt 分层**:prompt 区分 agent identity、selected context、instruction 和 output contract。
40
+ - **trace 可审计**:trace 必须解释 LLM 调用实际看到了什么,包括 source expression、label、budget、clipping 和结果。
112
41
 
113
- AgentScript 中的作用域不仅是变量可见性规则,也是 prompt context 可见性规则。
42
+ ## 边界模型
114
43
 
115
44
  ### Function boundary
116
45
 
117
- 函数调用应创建独立 context boundary。
46
+ 每次函数调用都有自己的 context boundary。callee 不会自动继承 caller 已选择的 context。数据必须作为参数传入,并在 callee 需要放进自己的 prompt 时再次 `use`。
118
47
 
119
48
  ```agentscript
120
49
  func caller(input) {
121
- use input.goal
50
+ use input.goal as goal
122
51
  helper(input)
123
52
  }
124
53
 
125
54
  func helper(input) {
126
- use input.detail
55
+ use input.detail as detail
127
56
  generate({ input: "Work on detail" }) -> {
128
57
  ok boolean
129
58
  }
130
59
  }
131
60
  ```
132
61
 
133
- `helper` 内部的 `generate` 不应自动继承 `caller` 的 `use input.goal`,除非该数据作为参数传入并在 `helper` 内显式 `use`。
134
-
135
- 推荐原则:
136
-
137
- - function 的 prompt context 由 function 自己声明。
138
- - function 返回值不携带 prompt context。
139
- - caller 的 `use` 不应隐式污染 callee。
62
+ `helper` 内的 `generate` 看到的是 `input.detail`,不是 `caller` 的 `input.goal`。
140
63
 
141
64
  ### Agent boundary
142
65
 
143
- Agent 调用是更强的 context boundary
66
+ Agent 调用形成更强的边界。被调用 Agent 不会看到 caller 的 prompt context,只会看到输入值和它自己的函数显式选择的 context
144
67
 
145
68
  ```agentscript
146
69
  result = Worker({
@@ -149,229 +72,33 @@ result = Worker({
149
72
  })
150
73
  ```
151
74
 
152
- `Worker` 不应自动看到 Controller context。Controller 必须通过参数显式传入必要数据,Worker 再用自己的 `use` 声明 prompt context
153
-
154
- 这保证:
155
-
156
- - 每个 Agent 的 prompt contract 独立可审计。
157
- - 多 Agent 组合不会发生隐式 context 泄露。
158
- - 子 Agent 只看到调用者明确传入的数据。
75
+ 这让 multi-agent 组合保持可审计:每个 Agent 都有自己的 prompt contract
159
76
 
160
77
  ### Block boundary
161
78
 
162
- `if`、`repeat`、`loop`、`for` 等 block 可以创建子作用域。子作用域内声明的 `use` 只应影响该子作用域内可见的 `generate`。
163
-
164
- ```agentscript
165
- if condition {
166
- temp = compute(input)
167
- use temp
168
- result = generate({ input: "Use temp" }) -> {
169
- ok boolean
170
- }
171
- }
172
- ```
173
-
174
- `temp` 和 `use temp` 不应泄漏到外层作用域。
175
-
176
- ### Parent context visibility
177
-
178
- 如果一个 block 内的 `generate` 处在某个父作用域之下,它可以看到父作用域声明的 context source。可见顺序应从外到内稳定排列,便于 trace 和 prompt 审计。
179
-
180
- ## Context 构建模型
181
-
182
- 一次 `generate` 的 prompt 应由四层组成。
183
-
184
- ### System
185
-
186
- System 层描述 Agent identity 和稳定行为约束,例如:
187
-
188
- - Agent name。
189
- - `role`。
190
- - `description`。
191
-
192
- System 层不应包含 provider URI、workspace path、tool implementation detail 或其它执行配置。
193
-
194
- ### Context
195
-
196
- Context 层来自当前 `generate` 可见的 `use` 声明。
197
-
198
- 每个 context item 应包含:
199
-
200
- - source expression,例如 `scratch.summary`。
201
- - resolved value。
202
- - rendered text。
203
- - budget。
204
- - clipping status。
205
-
206
- 推荐 prompt 形态:
207
-
208
- ```text
209
- Context:
210
- [0] question:
211
- What is AgentScript?
212
-
213
- [1] scratch.summary:
214
- [
215
- { "fact": "..." }
216
- ]
217
- ```
218
-
219
- source label 有助于模型理解 context,也有助于人类审计。
220
-
221
- ### Instruction
222
-
223
- Instruction 层来自 `generate(...)` 参数对象中的 `input` 字段。
224
-
225
- ```agentscript
226
- generate({ input: "Answer the question using only collected facts" }) -> {
227
- ok boolean
228
- text string
229
- }
230
- ```
231
-
232
- Instruction 是本次 LLM 调用的局部任务,不应混入长期 context。
233
-
234
- `limit`、`attempts` 和 `debug` 是 `generate` 的局部配置,不属于 prompt context。只有当上一次输出不是 JSON 或不满足 shape 时,runtime 才会在下一次尝试中把错误反馈附加到 instruction。
235
-
236
- ### Output contract
237
-
238
- Output contract 来自 `generate` 表达式上可选的 `-> { ... }` shape。
239
-
240
- ```agentscript
241
- generate({ input: "Answer" }) -> {
242
- ok boolean
243
- text string
244
- error string
245
- }
246
- ```
247
-
248
- LLM provider 和 runtime 应尽可能强制输出满足该 shape。
249
-
250
- ## Budget 语义
251
-
252
- `use expr < budget` 是 context item budget。
253
-
254
- ```agentscript
255
- use scratch.summary < 2k
256
- ```
257
-
258
- 它限制的是该 context source 渲染进 prompt 的大小,不是整个 LLM 调用的输出预算。
259
-
260
- `generate({ limit: budget }) { ... }` 是 generation budget。
261
-
262
- ```agentscript
263
- generate({
264
- input: "Summarize"
265
- limit: 500
266
- }) -> {
267
- text string
268
- }
269
- ```
270
-
271
- 它限制的是本次生成的输出规模或 provider token limit。
272
-
273
- 两者语义不同,不应混用。
274
-
275
- 可以先用字符数近似 context budget,但文档和 trace 必须明确实际裁剪策略。若未来切换到 token budget,不应改变 `use` 的抽象含义。
276
-
277
- ## Clipping 策略
278
-
279
- Context clipping 不应只做简单字符串截断,因为这会破坏 JSON/list 结构。
280
-
281
- 推荐策略:
282
-
283
- - string 可以按字符截断。
284
- - list 应优先保留完整 item。
285
- - object 应优先保留完整字段。
286
- - 超限时 trace 应记录原始大小、裁剪后大小和裁剪策略。
287
-
288
- 如果暂时使用简单字符串截断,必须在 trace 中标记 `clipped: true`,并在文档中说明这是早期实现策略。
289
-
290
- ## Trace 要求
291
-
292
- Trace 是 context engineering DSL 的核心调试接口。
293
-
294
- `use` trace 应记录声明信息:
295
-
296
- ```json
297
- {
298
- "kind": "use",
299
- "data": {
300
- "source": "scratch.summary",
301
- "budget": { "amount": 2, "unit": "k" }
302
- }
303
- }
304
- ```
305
-
306
- `generate` trace 应记录实际构建出的 context:
307
-
308
- ```json
309
- {
310
- "kind": "generate",
311
- "data": {
312
- "instruction": "Answer from scratch",
313
- "context": {
314
- "items": [
315
- {
316
- "source": "scratch.summary",
317
- "value": [{ "fact": "A" }],
318
- "text": "[...]",
319
- "budget": { "amount": 2, "unit": "k" },
320
- "clipped": false
321
- }
322
- ]
323
- }
324
- }
325
- }
326
- ```
327
-
328
- 这使开发者可以回答:
329
-
330
- - 本次 LLM 调用到底看到了什么?
331
- - 哪些 context source 被声明但没有进入当前 generate?
332
- - 哪些 context 被裁剪?
333
- - context 是从哪个表达式解析出来的?
334
- - caller 和 callee 的 context 是否发生了意外污染?
335
-
336
- ## `summary` view 的含义
337
-
338
- `scratch.summary` 是 AgentScript 中常见的 context engineering 写法。
339
-
340
- ```agentscript
341
- scratch = []
342
- scratch.add(observation)
343
- use scratch.summary < 2k
344
- ```
345
-
346
- 它表达的是“把 scratch 的 prompt-friendly view 放入 context”。如果实现中 `summary` 只是 JSON-safe list view,而不是真正的 LLM 摘要,应在文档和 trace 中明确。
347
-
348
- 推荐长期方向:
79
+ `if`、`repeat`、`loop`、`for` 等 block 创建子作用域。block 内声明的 context 影响 block 内的 `generate`,不会向外泄漏。
349
80
 
350
- - `summary` 表示适合 prompt 的紧凑视图。
351
- - `summary` 不应暴露 runtime resource binding。
352
- - `summary` 可以结合 clipping 策略保留最有用的完整 item。
81
+ ## Prompt 层次
353
82
 
354
- ## 实现约束
83
+ 一次 `generate` 的 prompt 由四个概念层组成:
355
84
 
356
- 为了避免把 AgentScript 误实现成普通编程语言,后续改动应遵守以下约束:
85
+ 1. **Agent identity**:当前 Agent 的 `role`、`description` 和稳定身份。
86
+ 2. **Selected context**:可见的 `use` 声明,渲染时带 source、label、value 和 budget 信息。
87
+ 3. **Instruction**:来自 `generate({ input: ... })` 的本次任务。
88
+ 4. **Output contract**:可选的 `-> { ... }` shape。
357
89
 
358
- - `generate` 不自动捕获局部变量。
359
- - `use` 是 context declaration,不是普通赋值。
360
- - `use` 的值应在 `generate` 构建 prompt 时解析。
361
- - function 和 Agent 调用应形成 context boundary。
362
- - runtime capability 不应进入 prompt context。
363
- - prompt 中应区分 system、context、instruction 和 output contract。
364
- - trace 必须能解释每次 `generate` 的实际 context。
90
+ 详细构造规则见 [`generate`](./generate.md)。
365
91
 
366
92
  ## 设计检查清单
367
93
 
368
- 修改 `use`、scope、context builder、trace 或 LLM provider 前,应检查:
94
+ 修改 `use`、scope、context builder、trace 或 LLM provider 行为前,应检查:
369
95
 
370
- - 这个改动是否让未 `use` 的数据进入了 prompt?
371
- - 这个改动是否让 caller context 隐式污染 callee?
372
- - 这个改动是否把 tool/model/agent/function binding 当作数据暴露给 LLM?
373
- - 这个改动是否保留了 context source 的可审计信息?
374
- - 这个改动是否让 `use` 退化成普通变量快照?
375
- - 这个改动是否混淆了 context budget 和 generation budget?
96
+ - 是否让未 `use` 的数据进入 prompt?
97
+ - 是否让 caller context 污染 callee?
98
+ - 是否把 tool/model/agent/function binding 当作 prompt data 暴露?
99
+ - 是否保留 source、label、budget 和 clipping 信息用于审计?
100
+ - 是否把 `use` 退化成快照赋值,而不是延迟 context source?
101
+ - 是否混淆 context budget 和 generation budget?
102
+ - 是否混淆 AgentScript context label 和 provider message role?
376
103
 
377
- AgentScript 的核心价值不是多一种控制流语法,而是让 prompt context 的来源、范围、预算和最终形态都变得显式、稳定、可审计。
104
+ AgentScript 的核心价值不是多一种控制流语法,而是让 prompt context 的来源、范围、预算、身份和最终 prompt 形态显式且稳定。
@@ -59,6 +59,24 @@ func run(input) {
59
59
  }
60
60
  ```
61
61
 
62
+ 这条规则适用于所有表达式形式,包括调用表达式。被调用者解析为本地函数还是 agent 调用,都不影响 final expression return。例如,直接用 agent 名称调用另一个 agent 时,会调用该 agent 的 `main func`,其结果会被隐式返回:
63
+
64
+ ```agentscript
65
+ agent Planner {
66
+ main func(input) {
67
+ generate({ input: "Create a plan" }) -> {
68
+ steps list[string]
69
+ }
70
+ }
71
+ }
72
+
73
+ agent Controller {
74
+ func run(input) {
75
+ Planner(input)
76
+ }
77
+ }
78
+ ```
79
+
62
80
  ```agentscript
63
81
  func get_result(result) {
64
82
  result.value
@@ -161,7 +179,7 @@ func summarize(content) {
161
179
 
162
180
  generate({
163
181
  input: "Summarize the content"
164
- limit: 1000
182
+ max_output: 1000
165
183
  }) -> {
166
184
  title string
167
185
  summary string