@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 @@ Supported shape types: `string`, `number`, `boolean`, `json`, `list`, `list[T]`
150
150
 
151
151
  Shapes are not a full static type system.
152
152
 
153
+ Object literals use JSON-like syntax: fields are written as `key: value`, and multiple fields must be separated with commas.
154
+
153
155
  ## Explicit context with `use`
154
156
 
155
157
  `use` selects values that may be included in later `generate` prompts within the current scope and child scopes.
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
  ### Rules
@@ -168,9 +170,9 @@ use docs.summary < 4k as evidence
168
170
  - Tool outputs do not automatically enter prompts.
169
171
  - Memory query results do not automatically enter prompts.
170
172
  - Trace events do not automatically enter prompts.
171
- - `use value < n` applies a context budget.
173
+ - `use value max n` applies a context budget.
172
174
  - `use value as label` attaches a literal context label to the selected source.
173
- - `use value < n as label` applies the budget first, then attaches the label.
175
+ - `use value max n as label` applies the budget first, then attaches the label.
174
176
  - `llm`, `tool`, `agent`, `memory` bindings cannot be used.
175
177
  - Function bindings cannot be used.
176
178
  - `use` declarations are inherited by child scopes.
@@ -181,7 +183,7 @@ The label after `as` is literal label text. It is not an expression, is not eval
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
  ### Deferred evaluation
191
193
 
192
- `use expr < budget` declares a context source, not a snapshot. The expression is re-evaluated when `generate` builds the prompt. This means updates to a variable made after `use` but before `generate` are visible at generation time.
194
+ `use expr max budget` declares a context source, not a snapshot. The expression is re-evaluated when `generate` builds the prompt. This means updates to a variable made after `use` but before `generate` are visible at generation time.
195
+
196
+ For the full design semantics, see [`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
  ### Semantics
212
216
 
213
217
  - `input` is the per-generation instruction. Required.
214
- - `limit` is the generation budget (number or `2k` style). Optional.
215
- - `attempts` controls retry for JSON parse errors or shape mismatch. Optional, defaults to 1.
218
+ - `max_output` is the output generation budget (number or `2k` style). Optional.
219
+ - `attempts` controls retry for JSON parse errors or shape mismatch. It is the maximum total number of attempts, including the first one. Optional, defaults to 1.
220
+ - `temperature` is a provider sampling hint. Optional. Unsupported provider hints default to warn in debug mode and ignore otherwise.
221
+ - `think` is a provider/model reasoning hint. Optional. Unsupported provider hints default to warn in debug mode and ignore otherwise.
222
+ - `strict` controls shape validation strictness. Optional, defaults to false.
216
223
  - `debug` prints the full prompt to stderr. Optional, defaults to false.
217
224
  - The optional `-> { ... }` block declares the expected output shape.
218
- - Without `-> { ... }`, the generate output is unconstrained: AgentScript does not add a return schema to the prompt, does not request provider structured output, and does not coerce or validate the returned value.
225
+ - Without `-> { ... }`, the generate output is unconstrained: AgentScript does not add a return schema to the prompt, does not request provider structured output, and does not coerce or validate the returned value. Free-form generate is allowed but not recommended for agent workflows.
219
226
  - Provider errors (auth, network, timeout, missing model) fail directly without retry.
220
227
  - Shape validation includes coercion (e.g. `"true"` -> `true`, `"42"` -> `42`).
221
228
 
229
+ For prompt construction, identity, retry, and trace semantics, see [`generate`](./generate.md).
230
+
222
231
  ## Control flow
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
- Supported operators: `==`, `!=`, `and`, `or`, `not`. `<` is not a general comparison operator it is used for budgets and loop limits.
243
+ Supported operators: `==`, `!=`, `<`, `and`, `or`, `not`. Context budgets and loop limits use `max`, so `<` remains an ordinary comparison operator like `==`.
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 @@ Each iteration creates a child scope. Outer variables updated inside the loop pe
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]` is read-only. Index must be a non-negative integer.
283
292
  - `list.add(value)` mutates the list. Takes exactly one argument.
284
293
  - `.length` returns the list length.
285
- - `.summary` returns a JSON-safe runtime view of the list. It is not an LLM-generated summary or semantic compression; any prompt-size reduction comes from explicit context budgets such as `use scratch.summary < 2k`.
294
+ - `.summary` returns a JSON-safe runtime view of the list. It is not an LLM-generated summary or semantic compression; any prompt-size reduction comes from explicit context budgets such as `use scratch.summary max 2k`.
286
295
 
287
296
  ## Tools
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 @@ Write and patch operations return undoable effect records. `File.undo` accepts a
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 requests are restricted to the origin of the import URI.
@@ -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 @@ Text files are loaded as strings. JSON files are parsed as JSON values. File con
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
  ### Rules
@@ -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
+ This document defines how `use` selects prompt context in AgentScript, including context labels, budgets, scope visibility, deferred evaluation, and trace requirements.
4
+
5
+ For the larger mental model, see [Context Engineering](./context-engineering.md). For prompt construction and output contracts, see [`generate`](./generate.md).
6
+
7
+ ## Purpose
8
+
9
+ `use` is not a variable read, assignment, or namespace import. It declares a prompt context source.
10
+
11
+ ```agentscript
12
+ use input.question as user question
13
+ use scratch.summary max 2k as observations
14
+ ```
15
+
16
+ The meaning is:
17
+
18
+ ```text
19
+ make this source visible to later generate calls in the current scope and child scopes
20
+ ```
21
+
22
+ Local variables not selected with `use` do not enter the prompt.
23
+
24
+ ## Syntax
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
+ The fixed order is:
34
+
35
+ ```text
36
+ what to select -> how much to include -> what role it plays as context
37
+ ```
38
+
39
+ Examples:
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 labels
48
+
49
+ The label after `as` is literal label text. It is not an expression, is not evaluated, and does not read variables from scope.
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
+ `as evidence` labels the context section as `evidence` even if a variable named `evidence` exists.
58
+
59
+ Labels affect:
60
+
61
+ - prompt section labels
62
+ - trace display
63
+ - context organization
64
+ - debug and audit readability
65
+
66
+ Labels do not affect:
67
+
68
+ - agent identity
69
+ - provider message roles
70
+ - tool permissions
71
+ - system/user/assistant authority
72
+
73
+ ## Provider roles are not context labels
74
+
75
+ Provider roles such as `system`, `user`, `assistant`, and `tool` are LLM API transport details. AgentScript context labels are prompt-internal organization labels.
76
+
77
+ The following labels are reserved to avoid confusion with provider roles:
78
+
79
+ ```text
80
+ system
81
+ assistant
82
+ tool
83
+ developer
84
+ ```
85
+
86
+ `user` is allowed as a context label because it often means "this context item is user input". It still does not create a separate provider `user` message.
87
+
88
+ ## Deferred evaluation
89
+
90
+ `use expr` declares a source, not a snapshot. The expression is evaluated when a visible `generate` builds its 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
+ The `generate` call sees both facts.
107
+
108
+ This keeps `use` as a context contract instead of a value copy.
109
+
110
+ ## Scope visibility
111
+
112
+ A `use` declaration is visible to later `generate` calls in the same scope and child scopes.
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
+ The inner `generate` can see both `user question` and `detail`. The `detail` context does not leak outside the block.
126
+
127
+ Function and agent calls form independent context boundaries. A callee does not automatically inherit the caller's selected context.
128
+
129
+ ## What cannot be used
130
+
131
+ Runtime capabilities must not enter prompt context:
132
+
133
+ - imported tools
134
+ - imported LLM/model bindings
135
+ - imported agent bindings
136
+ - memory handles
137
+ - function bindings
138
+ - provider URIs and workspace/runtime configuration
139
+
140
+ Invalid examples:
141
+
142
+ ```agentscript
143
+ use Search
144
+ use Qwen
145
+ use Worker
146
+ use helper
147
+ ```
148
+
149
+ Use the data returned by these capabilities instead:
150
+
151
+ ```agentscript
152
+ results = Search.search(input.question)
153
+ use results max 4k as search results
154
+ ```
155
+
156
+ ## Budget semantics
157
+
158
+ `use expr max budget` is a context item budget. It limits how much of that source may be rendered into the prompt.
159
+
160
+ ```agentscript
161
+ use docs.summary max 4k as evidence
162
+ ```
163
+
164
+ This is different from `generate({ max_output: ... })`, which is an output generation budget. See [`generate`](./generate.md).
165
+
166
+ ## Prompt rendering
167
+
168
+ A labeled context item is rendered as a 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
+ If no label is provided, the renderer may use the numeric context index and include the source expression separately.
184
+
185
+ ## Trace requirements
186
+
187
+ A `use` trace event records the declaration:
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
+ A generated built context item records the resolved value and rendering metadata:
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 must make the selected source, label, budget, clipping status, and resolved value auditable.
215
+
216
+ ## Design checklist
217
+
218
+ Before changing `use`, verify:
219
+
220
+ - Does unused data stay out of prompts?
221
+ - Is the source evaluated at `generate` time?
222
+ - Does the label remain literal text rather than an expression?
223
+ - Are provider roles still separate from context labels?
224
+ - Are budgets attached to context items, not the whole generation?
225
+ - Do function and agent boundaries prevent context leakage?
@@ -14,9 +14,9 @@ main agent ChangelogWriter {
14
14
  })
15
15
 
16
16
  use input.diff_path as diff path
17
- use diff < 10k as git diff
17
+ use diff max 10k as git diff
18
18
 
19
- generate({ input: "Write a changelog from this git diff", limit: 1200 }) -> {
19
+ generate({ input: "Write a changelog from this git diff", max_output: 1200 }) -> {
20
20
  title string
21
21
  highlights list[string]
22
22
  breaking_changes list[string]
@@ -15,9 +15,9 @@ main agent ApiExtractor {
15
15
  })
16
16
 
17
17
  use input.url as endpoint
18
- use response < 8k as api response
18
+ use response max 8k as api response
19
19
 
20
- generate({ input: "Extract normalized data from the API response", limit: 1200 }) -> {
20
+ generate({ input: "Extract normalized data from the API response", max_output: 1200 }) -> {
21
21
  records list[json]
22
22
  fields list[string]
23
23
  warnings list[string]
@@ -23,10 +23,10 @@ main agent CodeReviewAssistant {
23
23
  })
24
24
 
25
25
  use input.path as source path
26
- use todos < 4k as todo findings
27
- use fixmes < 4k as fixme findings
26
+ use todos max 4k as todo findings
27
+ use fixmes max 4k as fixme findings
28
28
 
29
- generate({ input: "Turn TODO and FIXME scan results into prioritized repair suggestions", limit: 1200 }) -> {
29
+ generate({ input: "Turn TODO and FIXME scan results into prioritized repair suggestions", max_output: 1200 }) -> {
30
30
  summary string
31
31
  findings list[string]
32
32
  suggested_fixes list[string]
@@ -14,9 +14,9 @@ main agent FileSummarizer {
14
14
  })
15
15
 
16
16
  use input.path as source path
17
- use content < 8k as file content
17
+ use content max 8k as file content
18
18
 
19
- generate({ input: "Summarize the file for a busy teammate", limit: 1000 }) -> {
19
+ generate({ input: "Summarize the file for a busy teammate", max_output: 1000 }) -> {
20
20
  title string
21
21
  summary string
22
22
  key_points list[string]
@@ -19,9 +19,9 @@ main agent MarkdownTranslator {
19
19
 
20
20
  use input.path as source path
21
21
  use input.target_language as target language
22
- use files < 4k as markdown files
22
+ use files max 4k as markdown files
23
23
 
24
- generate({ input: "Create a practical markdown translation plan", limit: 1000 }) -> {
24
+ generate({ input: "Create a practical markdown translation plan", max_output: 1000 }) -> {
25
25
  target_language string
26
26
  files list[string]
27
27
  glossary_notes list[string]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rong/agentscript",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "AgentScript context engineering language runtime",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/tutorials/cli.as CHANGED
@@ -12,7 +12,7 @@ main agent {
12
12
  use input.name
13
13
  use input.request
14
14
 
15
- generate({ input: "Reply to the CLI user by name", limit: 300 }) -> {
15
+ generate({ input: "Reply to the CLI user by name", max_output: 300 }) -> {
16
16
  ok boolean
17
17
  message string
18
18
  }
@@ -5,14 +5,14 @@ main agent MemoryDemo {
5
5
  topic string
6
6
  }) {
7
7
  Notes.add({
8
- kind: "note"
9
- text: input.topic
8
+ kind: "note",
9
+ text: input.topic,
10
10
  topic: input.topic
11
11
  })
12
12
 
13
13
  Notes.query({
14
- kind: "note"
15
- text: input.topic
14
+ kind: "note",
15
+ text: input.topic,
16
16
  limit: 3
17
17
  })
18
18
  }
@@ -31,7 +31,7 @@ main agent PlanAndExecute {
31
31
  }
32
32
  ]
33
33
 
34
- for step in steps < 6 {
34
+ for step in steps max 6 {
35
35
  outcome = run_step(input.goal, step, results)
36
36
  results.add(outcome.result)
37
37
 
@@ -73,9 +73,9 @@ main agent PlanAndExecute {
73
73
 
74
74
  func finish(goal, results) {
75
75
  use goal
76
- use results.summary < 2k
76
+ use results.summary max 2k
77
77
 
78
- generate({ input: "Create the final answer from executed steps", limit: 800 }) -> {
78
+ generate({ input: "Create the final answer from executed steps", max_output: 800 }) -> {
79
79
  ok boolean
80
80
  text string
81
81
  error string
@@ -91,9 +91,9 @@ agent Planner {
91
91
  main func(input) {
92
92
  use input.goal
93
93
  use input.problem
94
- use input.previous < 1k
94
+ use input.previous max 1k
95
95
 
96
- generate({ input: "Create a three step plan", limit: 600 }) -> {
96
+ generate({ input: "Create a three step plan", max_output: 600 }) -> {
97
97
  step1 string
98
98
  step2 string
99
99
  step3 string
@@ -109,7 +109,7 @@ agent Executor {
109
109
  main func(input) {
110
110
  use input.goal
111
111
  use input.step
112
- use input.previous < 1k
112
+ use input.previous max 1k
113
113
 
114
114
  query = Search.query(input.goal, input.step, input.previous)
115
115
  raw = Search.search(query)
@@ -121,7 +121,7 @@ agent Executor {
121
121
 
122
122
  use observation
123
123
 
124
- generate({ input: "Report the result of this step", limit: 500 }) -> {
124
+ generate({ input: "Report the result of this step", max_output: 500 }) -> {
125
125
  ok boolean
126
126
  output json
127
127
  error string
@@ -139,7 +139,7 @@ agent Verifier {
139
139
  use input.step
140
140
  use input.result
141
141
 
142
- generate({ input: "Verify this step result", limit: 300 }) -> {
142
+ generate({ input: "Verify this step result", max_output: 300 }) -> {
143
143
  ok boolean
144
144
  reason string
145
145
  }