@rong/agentscript 0.1.3 → 0.1.5

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.
@@ -150,16 +150,18 @@ generate({ input: "Extract facts" }) -> {
150
150
 
151
151
  Shape 不是完整的静态类型系统。
152
152
 
153
+ 对象字面量使用 JSON-like 语法:字段写作 `key: value`,多字段之间必须用逗号分隔。
154
+
153
155
  ## 显式上下文(`use`)
154
156
 
155
157
  `use` 选择在当前作用域及其子作用域中,后续 `generate` 可以包含哪些变量的值。
156
158
 
157
159
  ```agentscript
158
160
  use input.question
159
- use Requirements < 4k
160
- use past_lessons < 2k
161
+ use Requirements max 4k
162
+ use past_lessons max 2k
161
163
  use input.question as user
162
- use docs.summary < 4k as evidence
164
+ use docs.summary max 4k as evidence
163
165
  ```
164
166
 
165
167
  ### 规则
@@ -168,9 +170,9 @@ use docs.summary < 4k as evidence
168
170
  - 工具输出不会自动进入 prompt。
169
171
  - Memory 查询结果不会自动进入 prompt。
170
172
  - Trace 事件不会自动进入 prompt。
171
- - `use value < n` 应用上下文预算。
173
+ - `use value max n` 应用上下文预算。
172
174
  - `use value as label` 为选中的 context source 附加字面标签。
173
- - `use value < n as label` 先应用预算,再附加标签。
175
+ - `use value max n as label` 先应用预算,再附加标签。
174
176
  - `llm`、`tool`、`agent`、`memory` 绑定不能被 `use`。
175
177
  - 函数绑定不能被 `use`。
176
178
  - `use` 声明被子作用域继承。
@@ -181,7 +183,7 @@ use docs.summary < 4k as evidence
181
183
 
182
184
  ```agentscript
183
185
  use docs as evidence
184
- use docs.summary < 4k as retrieved evidence
186
+ use docs.summary max 4k as retrieved evidence
185
187
  use input.question as user
186
188
  ```
187
189
 
@@ -189,7 +191,9 @@ use input.question as user
189
191
 
190
192
  ### 延迟求值
191
193
 
192
- `use expr < budget` 声明的是 context source,而不是当前值的快照。当 `generate` 构建 prompt 时,表达式会被重新求值。这意味着在 `use` 之后、`generate` 之前对变量的修改在生成时刻是可见的。
194
+ `use expr max budget` 声明的是 context source,而不是当前值的快照。当 `generate` 构建 prompt 时,表达式会被重新求值。这意味着在 `use` 之后、`generate` 之前对变量的修改在生成时刻是可见的。
195
+
196
+ 完整设计语义见 [`use ... as ...`](./use-as.md)。
193
197
 
194
198
  ## Generate
195
199
 
@@ -197,9 +201,9 @@ use input.question as user
197
201
 
198
202
  ```agentscript
199
203
  answer = generate({
200
- input: "Answer using the selected context."
201
- limit: 800
202
- attempts: 3
204
+ input: "Answer using the selected context.",
205
+ max_output: 800,
206
+ attempts: 3,
203
207
  debug: true
204
208
  }) -> {
205
209
  ok boolean
@@ -211,14 +215,19 @@ answer = generate({
211
215
  ### 语义
212
216
 
213
217
  - `input`:每次生成的指令。必填。
214
- - `limit`:生成预算(数字或 `2k` 格式)。可选。
215
- - `attempts`:JSON 解析失败或 shape 不匹配时的重试次数。可选,默认 1。
218
+ - `max_output`:输出生成预算(数字或 `2k` 格式)。可选。
219
+ - `attempts`:JSON 解析失败或 shape 不匹配时的尝试次数。它是包含第一次调用在内的最大总尝试次数。可选,默认 1。
220
+ - `temperature`:provider sampling hint。可选。不支持的 provider hint 默认在 debug mode 下 warn,否则 ignore。
221
+ - `think`:provider/model reasoning hint。可选。不支持的 provider hint 默认在 debug mode 下 warn,否则 ignore。
222
+ - `strict`:控制 shape validation 是否严格。可选,默认 false。
216
223
  - `debug`:将完整 prompt 打印到 stderr。可选,默认 false。
217
224
  - 可选的 `-> { ... }` 块声明期望的输出 shape。
218
- - 不写 `-> { ... }` 时,`generate` 输出无约束:AgentScript 不会在 prompt 中加入返回 schema,不会要求 provider 使用结构化输出,也不会对返回值做类型强制转换或 shape 校验。
225
+ - 不写 `-> { ... }` 时,`generate` 输出无约束:AgentScript 不会在 prompt 中加入返回 schema,不会要求 provider 使用结构化输出,也不会对返回值做类型强制转换或 shape 校验。自由形式的 `generate` 是允许的,但不推荐用于 agent workflow。
219
226
  - Provider 错误(认证、网络、超时、模型不存在)直接失败,不做重试。
220
227
  - Shape 校验包含类型强制转换(如 `"true"` -> `true`,`"42"` -> `42`)。
221
228
 
229
+ Prompt 构造、identity、retry 和 trace 语义见 [`generate`](./generate.md)。
230
+
222
231
  ## 控制流
223
232
 
224
233
  ### If / else
@@ -231,14 +240,14 @@ if answer.ok and not input.dry_run {
231
240
  }
232
241
  ```
233
242
 
234
- 支持的运算符:`==`、`!=`、`and`、`or`、`not`。`<` 不是通用比较运算符——它只能用于预算和循环上限。
243
+ 支持的运算符:`==`、`!=`、`<`、`and`、`or`、`not`。Context budget 和循环上限使用 `max`,因此 `<` 恢复为类似 `==` 的普通比较运算符。
235
244
 
236
245
  ### Loop until
237
246
 
238
247
  ```agentscript
239
248
  done = false
240
249
 
241
- loop until done < 6 {
250
+ loop until done max 6 {
242
251
  observation = observe(input)
243
252
  done = observation.ok
244
253
  }
@@ -262,7 +271,7 @@ repeat * 3 {
262
271
  ### For in
263
272
 
264
273
  ```agentscript
265
- for step in plan.steps < 12 {
274
+ for step in plan.steps max 12 {
266
275
  result = Executor(step)
267
276
  results.add(result)
268
277
  }
@@ -282,7 +291,7 @@ summary = items.summary
282
291
  - `list[index]` 只读。index 必须是非负整数。
283
292
  - `list.add(value)` 修改原列表。恰好接受一个参数。
284
293
  - `.length` 返回列表长度。
285
- - `.summary` 返回列表的 JSON-safe 运行时视图。它不是 LLM 生成的摘要,也不是语义压缩;如果需要控制 prompt 大小,应通过 `use scratch.summary < 2k` 这类显式 context budget 裁剪。
294
+ - `.summary` 返回列表的 JSON-safe 运行时视图。它不是 LLM 生成的摘要,也不是语义压缩;如果需要控制 prompt 大小,应通过 `use scratch.summary max 2k` 这类显式 context budget 裁剪。
286
295
 
287
296
  ## 工具
288
297
 
@@ -300,9 +309,9 @@ import tool Http from "https://api.example.com"
300
309
 
301
310
  ```agentscript
302
311
  files = Find.run({
303
- path: "."
304
- name: "*.ts"
305
- type: "file"
312
+ path: ".",
313
+ name: "*.ts",
314
+ type: "file",
306
315
  max: 50
307
316
  })
308
317
  ```
@@ -311,9 +320,9 @@ files = Find.run({
311
320
 
312
321
  ```agentscript
313
322
  matches = Grep.run({
314
- path: "src"
315
- pattern: "TODO"
316
- include: "*.ts"
323
+ path: "src",
324
+ pattern: "TODO",
325
+ include: "*.ts",
317
326
  max: 100
318
327
  })
319
328
  ```
@@ -322,8 +331,8 @@ matches = Grep.run({
322
331
 
323
332
  ```agentscript
324
333
  lines = Sed.run({
325
- path: "src/main.as"
326
- start: 1
334
+ path: "src/main.as",
335
+ start: 1,
327
336
  max: 20
328
337
  })
329
338
  ```
@@ -331,10 +340,21 @@ lines = Sed.run({
331
340
  ### File
332
341
 
333
342
  ```agentscript
334
- content = File.read({ path: "README.md" })
335
- entries = File.list({ path: "src" })
336
- result = File.write({ path: "output.md", content: "# Result" })
337
- result = File.patch({ path: "file.as", search: "old", replace: "new" })
343
+ content = File.read({
344
+ path: "README.md"
345
+ })
346
+ entries = File.list({
347
+ path: "src"
348
+ })
349
+ result = File.write({
350
+ path: "output.md",
351
+ content: "# Result"
352
+ })
353
+ result = File.patch({
354
+ path: "file.as",
355
+ search: "old",
356
+ replace: "new"
357
+ })
338
358
  result = File.undo(effects)
339
359
  ```
340
360
 
@@ -343,14 +363,24 @@ result = File.undo(effects)
343
363
  ### Env
344
364
 
345
365
  ```agentscript
346
- home = Env.get({ name: "HOME" })
366
+ home = Env.get({
367
+ name: "HOME"
368
+ })
347
369
  ```
348
370
 
349
371
  ### Http
350
372
 
351
373
  ```agentscript
352
- response = Http.get({ url: "/api/data", headers: { Authorization: "Bearer ..." }, timeout: 10000 })
353
- response = Http.post({ url: "/api/submit", body: { key: "value" }, timeout: 10000 })
374
+ response = Http.get({
375
+ url: "/api/data",
376
+ headers: { Authorization: "Bearer ..." },
377
+ timeout: 10000
378
+ })
379
+ response = Http.post({
380
+ url: "/api/submit",
381
+ body: { key: "value" },
382
+ timeout: 10000
383
+ })
354
384
  ```
355
385
 
356
386
  HTTP 请求限制在 import URI 的 origin 内。
@@ -380,7 +410,7 @@ import file Requirements from "./requirements.md"
380
410
  import file Config from "./config.json"
381
411
 
382
412
  func answer(input) {
383
- use Requirements < 4k
413
+ use Requirements max 4k
384
414
  use Config
385
415
  generate({ input: "Answer from the referenced file." }) -> {
386
416
  ok boolean
@@ -395,18 +425,18 @@ func answer(input) {
395
425
 
396
426
  ```agentscript
397
427
  Lessons.add({
398
- kind: "lesson"
399
- text: reflection.insight
428
+ kind: "lesson",
429
+ text: reflection.insight,
400
430
  goal: input.goal
401
431
  })
402
432
 
403
433
  past = Lessons.query({
404
- kind: "lesson"
405
- text: input.goal
434
+ kind: "lesson",
435
+ text: input.goal,
406
436
  limit: 5
407
437
  })
408
438
 
409
- use past < 2k
439
+ use past max 2k
410
440
  ```
411
441
 
412
442
  ### 规则
@@ -430,8 +460,11 @@ main agent Controller {
430
460
  main func(input) {
431
461
  plan = Planner(input)
432
462
  results = []
433
- for step in plan.steps < 10 {
434
- result = Executor({ goal: input.goal, step: step })
463
+ for step in plan.steps max 10 {
464
+ result = Executor({
465
+ goal: input.goal,
466
+ step: step
467
+ })
435
468
  results.add(result)
436
469
  }
437
470
  results.summary
@@ -0,0 +1,225 @@
1
+ # `use ... as ...`
2
+
3
+ 本文档定义 AgentScript 中 `use` 如何选择 prompt context,包括 context label、budget、scope 可见性、延迟求值和 trace 要求。
4
+
5
+ 整体模型见 [Context Engineering](./context-engineering.md)。Prompt 构造和输出契约见 [`generate`](./generate.md)。
6
+
7
+ ## 目的
8
+
9
+ `use` 不是变量读取、赋值或命名空间导入。它声明一个 prompt context source。
10
+
11
+ ```agentscript
12
+ use input.question as user question
13
+ use scratch.summary max 2k as observations
14
+ ```
15
+
16
+ 含义是:
17
+
18
+ ```text
19
+ 让这个 source 对当前作用域及子作用域中后续的 generate 可见
20
+ ```
21
+
22
+ 没有被 `use` 选择的局部变量不会进入 prompt。
23
+
24
+ ## 语法
25
+
26
+ ```agentscript
27
+ use expr
28
+ use expr max budget
29
+ use expr as label
30
+ use expr max budget as label
31
+ ```
32
+
33
+ 固定顺序是:
34
+
35
+ ```text
36
+ 选择什么 -> 限制多少 -> 作为何种上下文
37
+ ```
38
+
39
+ 示例:
40
+
41
+ ```agentscript
42
+ use input.question as user question
43
+ use docs.summary max 4k as retrieved evidence
44
+ use scratch.summary max 2k as observations
45
+ ```
46
+
47
+ ## Context label
48
+
49
+ `as` 后面的 label 是字面标签文本,不是表达式,不会求值,也不会读取作用域中的变量。
50
+
51
+ ```agentscript
52
+ use docs as evidence
53
+ use docs.summary max 4k as retrieved evidence
54
+ use input.question as user
55
+ ```
56
+
57
+ 即使当前作用域中存在名为 `evidence` 的变量,`as evidence` 也只是把 context section 标记为 `evidence`。
58
+
59
+ Label 影响:
60
+
61
+ - prompt section label
62
+ - trace display
63
+ - context organization
64
+ - debug 和 audit 可读性
65
+
66
+ Label 不影响:
67
+
68
+ - agent identity
69
+ - provider message role
70
+ - tool 权限
71
+ - system/user/assistant 权限
72
+
73
+ ## Provider role 不是 context label
74
+
75
+ `system`、`user`、`assistant`、`tool` 等 provider role 是 LLM API 的传输协议细节。AgentScript context label 是 prompt 内部组织标签。
76
+
77
+ 为避免和 provider role 混淆,以下 label 保留:
78
+
79
+ ```text
80
+ system
81
+ assistant
82
+ tool
83
+ developer
84
+ ```
85
+
86
+ `user` 允许作为 context label,因为它常用于表达“这段 context 是用户输入”。它仍然不会创建单独的 provider `user` message。
87
+
88
+ ## 延迟求值
89
+
90
+ `use expr` 声明的是 source,不是快照。表达式会在可见的 `generate` 构建 prompt 时求值。
91
+
92
+ ```agentscript
93
+ main func(input) {
94
+ scratch = []
95
+ use scratch.summary max 2k as observations
96
+
97
+ scratch.add({ fact: "A" })
98
+ scratch.add({ fact: "B" })
99
+
100
+ generate({ input: "Answer from observations" }) -> {
101
+ text string
102
+ }
103
+ }
104
+ ```
105
+
106
+ 该 `generate` 能看到两个 fact。
107
+
108
+ 这让 `use` 保持为 context contract,而不是一次值复制。
109
+
110
+ ## Scope 可见性
111
+
112
+ `use` 声明对同一作用域和子作用域中后续的 `generate` 可见。
113
+
114
+ ```agentscript
115
+ use input.question as user question
116
+
117
+ if input.needs_detail {
118
+ use input.detail as detail
119
+ generate({ input: "Answer with detail" }) -> {
120
+ text string
121
+ }
122
+ }
123
+ ```
124
+
125
+ 内部 `generate` 可以看到 `user question` 和 `detail`。`detail` context 不会泄漏到 block 外部。
126
+
127
+ Function 和 Agent 调用形成独立 context boundary。Callee 不会自动继承 caller 选择的 context。
128
+
129
+ ## 不能 use 什么
130
+
131
+ Runtime capability 不能进入 prompt context:
132
+
133
+ - imported tool
134
+ - imported LLM/model binding
135
+ - imported agent binding
136
+ - memory handle
137
+ - function binding
138
+ - provider URI 和 workspace/runtime 配置
139
+
140
+ 非法示例:
141
+
142
+ ```agentscript
143
+ use Search
144
+ use Qwen
145
+ use Worker
146
+ use helper
147
+ ```
148
+
149
+ 应改为使用这些 capability 返回的数据:
150
+
151
+ ```agentscript
152
+ results = Search.search(input.question)
153
+ use results max 4k as search results
154
+ ```
155
+
156
+ ## Budget 语义
157
+
158
+ `use expr max budget` 是 context item budget,限制该 source 渲染进 prompt 的大小。
159
+
160
+ ```agentscript
161
+ use docs.summary max 4k as evidence
162
+ ```
163
+
164
+ 这不同于 `generate({ max_output: ... })` 的 output generation budget。详见 [`generate`](./generate.md)。
165
+
166
+ ## Prompt 渲染
167
+
168
+ 带 label 的 context item 渲染为 context section:
169
+
170
+ ```text
171
+ Context:
172
+ [user question]
173
+ source: input.question
174
+ What is AgentScript?
175
+
176
+ [observations]
177
+ source: scratch.summary
178
+ [
179
+ { "fact": "..." }
180
+ ]
181
+ ```
182
+
183
+ 如果没有 label,renderer 可以使用数字 context index,并单独显示 source expression。
184
+
185
+ ## Trace 要求
186
+
187
+ `use` trace event 记录声明信息:
188
+
189
+ ```json
190
+ {
191
+ "kind": "use",
192
+ "data": {
193
+ "source": "scratch.summary",
194
+ "label": "observations",
195
+ "budget": { "amount": 2, "unit": "k" }
196
+ }
197
+ }
198
+ ```
199
+
200
+ `generate` 的 built context item 记录解析后的值和渲染元数据:
201
+
202
+ ```json
203
+ {
204
+ "index": 0,
205
+ "source": "scratch.summary",
206
+ "label": "observations",
207
+ "value": [{ "fact": "A" }],
208
+ "text": "[...]",
209
+ "budget": { "amount": 2, "unit": "k" },
210
+ "clipped": false
211
+ }
212
+ ```
213
+
214
+ Trace 必须让 source、label、budget、clipping 状态和 resolved value 可审计。
215
+
216
+ ## 设计检查清单
217
+
218
+ 修改 `use` 前,应检查:
219
+
220
+ - 未使用的数据是否仍然不会进入 prompt?
221
+ - source 是否仍在 `generate` 时求值?
222
+ - label 是否仍是字面文本,而不是表达式?
223
+ - provider role 是否仍与 context label 分离?
224
+ - budget 是否仍附着在 context item 上,而不是整个 generation 上?
225
+ - function 和 Agent boundary 是否仍能阻止 context 泄漏?