@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.
@@ -1,322 +1,104 @@
1
1
  # AgentScript Context Engineering
2
2
 
3
- This document explains the core design semantics of `use`, scopes, and `generate` in AgentScript. These concepts are not specific to any version they are the fundamental semantics that distinguish AgentScript from general-purpose programming languages.
3
+ This document is the top-level design map for AgentScript context engineering. It explains why AgentScript exists, what boundaries it enforces, and how the detailed `use ... as ...` and `generate` documents fit together.
4
4
 
5
- AgentScript has variables, functions, loops, and agent calls, but its primary purpose is not to be a general-purpose language. It is an auditable, composable, explicit prompt context engineering DSL.
5
+ AgentScript has variables, functions, loops, tools, memory, and agent calls, but its purpose is not to be a general-purpose programming language. Its purpose is to make prompt context explicit, scoped, typed, traceable, and auditable.
6
6
 
7
- ## Core positioning
7
+ ## Document structure
8
8
 
9
- AgentScript's control flow serves prompt context construction.
9
+ The context engineering design is split into three documents:
10
10
 
11
- Ordinary statements organize data, call tools, call agents, and update intermediate state. LLM calls happen only through `generate(...) -> { ... }`, and the context visible to `generate` must be declared explicitly with `use`.
11
+ - **Context Engineering**: this overview; explains the mental model and invariants.
12
+ - **[`use ... as ...`](./use-as.md)**: explains how data is selected as prompt context, how labels work, how budgets are applied, and how scope affects visibility.
13
+ - **[`generate`](./generate.md)**: explains generation sites, prompt construction, agent identity, output contracts, budgets, retries, and trace output.
12
14
 
13
- The core objects are:
14
-
15
- - **Data**: ordinary variables, JSON values, lists, file imports, tool observations, agent return values.
16
- - **Context Source**: a prompt context origin declared by `use expr < budget`.
17
- - **Generation Site**: an LLM call declared by `generate({ input, limit, attempts, debug }) -> shape`.
18
- - **Boundary**: context visibility boundaries formed by agent, function, and block scopes.
19
-
20
- ## Semantics of `use`
21
-
22
- `use` is not a variable read or a namespace import. Its meaning is:
23
-
24
- > Declare a prompt context source in the current scope, so that `generate` calls visible in that scope may include the source's current value in the prompt context.
25
-
26
- Example:
27
-
28
- ```agentscript
29
- func answer(question, scratch) {
30
- use question
31
- use scratch.summary < 2k
32
-
33
- generate({
34
- input: "Answer the question using collected facts"
35
- limit: 800
36
- }) -> {
37
- ok boolean
38
- text string
39
- error string
40
- }
41
- }
42
- ```
15
+ The language reference remains the compact syntax reference. These design documents define the intended semantics.
43
16
 
44
- Here `question` and `scratch.summary` are explicit context sources for the `generate` call. Local variables not selected by `use` must not enter the prompt.
17
+ ## Core model
45
18
 
46
- ### Deferred evaluation
19
+ AgentScript control flow serves prompt context construction.
47
20
 
48
- `use expr < budget` declares a context source, not a snapshot of the current value. The source is resolved at the `generate` execution point.
21
+ Ordinary statements organize data, call tools, call agents, query memory, and update intermediate state. LLM calls happen only through `generate(...) -> { ... }`. A `generate` call sees only context sources explicitly declared with `use` and visible through scope.
49
22
 
50
- ```agentscript
51
- main func(input) {
52
- scratch = []
53
- use scratch.summary < 2k
54
-
55
- scratch.add({ fact: "A" })
56
- scratch.add({ fact: "B" })
57
-
58
- generate({ input: "Answer from scratch" }) -> {
59
- text string
60
- }
61
- }
62
- ```
63
-
64
- The `generate` call sees both facts.
65
-
66
- Rationale:
67
-
68
- - `use` expresses a context contract, not an assignment.
69
- - Agent patterns continuously update scratch, plans, and observations.
70
- - A snapshot-based `use` would require re-declaration before every `generate`, risking stale context.
23
+ The core objects are:
71
24
 
72
- ### What cannot be used
25
+ - **Data**: ordinary values such as input, JSON, lists, file contents, tool observations, memory query results, and agent return values.
26
+ - **Context source**: data selected for prompt context by `use expr`, optionally with a budget and label.
27
+ - **Generation site**: one LLM call expressed by `generate({ input, max_output, attempts, temperature, think, strict, debug }) -> shape`.
28
+ - **Boundary**: a visibility boundary formed by an agent, function, or block scope.
29
+ - **Trace**: the audit record explaining which sources were selected, how prompt context was built, and what each generation returned.
73
30
 
74
- The following runtime capabilities must never enter prompt context:
31
+ ## Key invariants
75
32
 
76
- - Imported tools
77
- - Imported LLMs / models
78
- - Imported agent bindings
79
- - Function bindings
80
- - Provider URIs, workspace paths, and other execution configuration
33
+ AgentScript should preserve these invariants:
81
34
 
82
- These should be rejected by the semantic analyzer:
35
+ - **No implicit capture**: local variables, tool outputs, memory records, and trace events do not enter prompts unless selected with `use`.
36
+ - **Scoped visibility**: context visibility follows scope. Child scopes can inherit parent context; function and agent calls create independent context boundaries.
37
+ - **Capability isolation**: imported tools, models, agents, memory handles, functions, provider URIs, and runtime configuration are capabilities, not prompt data.
38
+ - **Deferred context resolution**: `use expr` declares a source. The value is resolved when a visible `generate` builds its prompt.
39
+ - **Layered prompts**: prompts distinguish agent identity, selected context, instruction, and output contract.
40
+ - **Auditable traces**: trace output must explain what the LLM call actually saw, including source expressions, labels, budgets, clipping, and generated results.
83
41
 
84
- ```agentscript
85
- use Search -- invalid (tool binding)
86
- use Qwen -- invalid (LLM binding)
87
- use Worker -- invalid (agent binding)
88
- use helper -- invalid (function binding)
89
- ```
90
-
91
- ## Scope as context boundary
92
-
93
- Scopes in AgentScript control both variable visibility and prompt context visibility.
42
+ ## Boundary model
94
43
 
95
44
  ### Function boundary
96
45
 
97
- Each function call creates an independent context boundary.
46
+ Each function call has its own context boundary. A callee does not automatically inherit the caller's selected context. Data must be passed as an argument and selected again when the callee wants it in its own prompt.
98
47
 
99
48
  ```agentscript
100
49
  func caller(input) {
101
- use input.goal
50
+ use input.goal as goal
102
51
  helper(input)
103
52
  }
104
53
 
105
54
  func helper(input) {
106
- use input.detail
55
+ use input.detail as detail
107
56
  generate({ input: "Work on detail" }) -> {
108
57
  ok boolean
109
58
  }
110
59
  }
111
60
  ```
112
61
 
113
- The `generate` inside `helper` must not inherit `caller`'s `use input.goal`. Data must be passed as arguments and explicitly `use`d.
62
+ The `generate` inside `helper` sees `input.detail`, not `caller`'s `input.goal`.
114
63
 
115
64
  ### Agent boundary
116
65
 
117
- Agent calls create a stronger context boundary.
66
+ Agent calls create a stronger boundary. A called agent does not see the caller's prompt context. It sees only its input value and the context selected by its own functions.
118
67
 
119
68
  ```agentscript
120
69
  result = Worker({
121
- goal: input.goal
70
+ goal: input.goal,
122
71
  previous: results.summary
123
72
  })
124
73
  ```
125
74
 
126
- `Worker` must not see the caller's context. The caller passes data explicitly through arguments.
127
-
128
- This guarantees:
129
-
130
- - Each agent's prompt contract is independently auditable.
131
- - Multi-agent composition does not cause implicit context leakage.
132
- - Sub-agents see only explicitly passed data.
75
+ This keeps multi-agent composition auditable: each agent has its own prompt contract.
133
76
 
134
77
  ### Block boundary
135
78
 
136
- Blocks (`if`, `repeat`, `loop`, `for`) create child scopes. `use` declarations inside a block affect only `generate` calls within that block.
137
-
138
- ```agentscript
139
- if condition {
140
- temp = compute(input)
141
- use temp
142
- result = generate({ input: "Use temp" }) -> {
143
- ok boolean
144
- }
145
- }
146
- ```
147
-
148
- `temp` and `use temp` must not leak to the outer scope.
149
-
150
- ### Parent context visibility
79
+ Blocks such as `if`, `repeat`, `loop`, and `for` create child scopes. Context declared inside the block affects `generate` calls inside that block and does not leak upward.
151
80
 
152
- A `generate` call in a nested scope can see context sources declared in parent scopes. The visible order must be stable from outer to inner for trace and prompt audit.
81
+ ## Prompt layers
153
82
 
154
- ## Context construction model
83
+ A `generate` call is built from four conceptual layers:
155
84
 
156
- A `generate` call's prompt consists of four layers.
85
+ 1. **Agent identity**: current agent `role`, `description`, and stable behavioral identity.
86
+ 2. **Selected context**: visible `use` declarations, rendered with source, label, value, and budget information.
87
+ 3. **Instruction**: the per-call task from `generate({ input: ... })`.
88
+ 4. **Output contract**: the optional `-> { ... }` shape.
157
89
 
158
- ### System
159
-
160
- Describes agent identity and stable behavioral constraints:
161
-
162
- - Agent name
163
- - `role`
164
- - `description`
165
-
166
- Must not contain execution configuration (provider URIs, workspace paths, tool internals).
167
-
168
- ### Context
169
-
170
- Comes from `use` declarations visible to the current `generate`.
171
-
172
- Each context item records:
173
-
174
- - source expression (e.g. `scratch.summary`)
175
- - resolved value
176
- - rendered text
177
- - budget
178
- - clipping status
179
-
180
- Recommended prompt format:
181
-
182
- ```text
183
- Context:
184
- [0] question:
185
- What is AgentScript?
186
-
187
- [1] scratch.summary:
188
- [
189
- { "fact": "..." }
190
- ]
191
- ```
192
-
193
- Source labels help models understand context and help humans audit prompts.
194
-
195
- ### Instruction
196
-
197
- Comes from the `input` field of `generate(...)` options.
198
-
199
- ```agentscript
200
- generate({ input: "Answer the question using only collected facts" }) -> {
201
- ok boolean
202
- text string
203
- }
204
- ```
205
-
206
- The instruction is the per-call task. `limit`, `attempts`, and `debug` are local configuration, not prompt context. Error feedback from previous failed attempts is appended to the instruction.
207
-
208
- ### Output contract
209
-
210
- Comes from the optional `-> { ... }` shape on a `generate` expression.
211
-
212
- ```agentscript
213
- generate({ input: "Answer" }) -> {
214
- ok boolean
215
- text string
216
- error string
217
- }
218
- ```
219
-
220
- The LLM provider and runtime enforce shape compliance as strictly as possible.
221
-
222
- ## Budget semantics
223
-
224
- `use expr < budget` is a **context item budget**. It limits how much of that source may be rendered into the prompt.
225
-
226
- `generate({ limit: budget })` is a **generation budget**. It limits output size or the provider's token limit.
227
-
228
- They have different meanings and must not be confused.
229
-
230
- Character count is used as an approximation. Future implementations may switch to token-aware budgets without changing the abstraction.
231
-
232
- ## Clipping strategy
233
-
234
- Context clipping must not simply truncate strings, as that would break JSON and list structure.
235
-
236
- Strategy:
237
-
238
- - Strings: may be truncated by character count.
239
- - Lists: prefer keeping complete items, dropping from the tail.
240
- - Objects: prefer keeping complete fields, dropping from the tail.
241
- - Trace: record original size, clipped size, and strategy for each item.
242
-
243
- ## Trace requirements
244
-
245
- Trace is the primary debugging interface for a context engineering DSL.
246
-
247
- `use` trace:
248
-
249
- ```json
250
- {
251
- "kind": "use",
252
- "data": {
253
- "source": "scratch.summary",
254
- "budget": { "amount": 2, "unit": "k" }
255
- }
256
- }
257
- ```
258
-
259
- `generate` trace:
260
-
261
- ```json
262
- {
263
- "kind": "generate",
264
- "data": {
265
- "instruction": "Answer from scratch",
266
- "context": {
267
- "items": [
268
- {
269
- "source": "scratch.summary",
270
- "value": [{ "fact": "A" }],
271
- "text": "[...]",
272
- "budget": { "amount": 2, "unit": "k" },
273
- "clipped": false
274
- }
275
- ]
276
- }
277
- }
278
- }
279
- ```
280
-
281
- This answers:
282
-
283
- - What did the LLM call actually see?
284
- - Which context sources were declared but not included?
285
- - What was clipped?
286
- - Which expression was the source resolved from?
287
- - Did caller and callee contexts leak?
288
-
289
- ## The `summary` view
290
-
291
- `scratch.summary` is a common pattern:
292
-
293
- ```agentscript
294
- scratch = []
295
- scratch.add(observation)
296
- use scratch.summary < 2k
297
- ```
298
-
299
- It expresses "put the prompt-friendly view of scratch into context." If the implementation provides only a JSON-safe list view rather than a true LLM summary, this should be documented and visible in the trace.
300
-
301
- ## Implementation constraints
302
-
303
- Future changes must respect:
304
-
305
- - `generate` does not automatically capture local variables.
306
- - `use` is a context declaration, not an assignment.
307
- - `use` values are resolved when `generate` builds the prompt.
308
- - Function and agent calls form context boundaries.
309
- - Runtime capabilities must never enter prompt context.
310
- - Prompts must distinguish system, context, instruction, and output contract layers.
311
- - Trace must explain every `generate` call's actual context.
90
+ See [`generate`](./generate.md) for the detailed construction rules.
312
91
 
313
92
  ## Design checklist
314
93
 
315
- Before modifying `use`, scope, context builder, trace, or the LLM provider, verify:
94
+ Before changing `use`, scope, context builder, trace, or LLM provider behavior, verify:
95
+
96
+ - Does this let unused data enter a prompt?
97
+ - Does this let caller context pollute a callee?
98
+ - Does this expose tool/model/agent/function bindings as prompt data?
99
+ - Does this preserve source, label, budget, and clipping information for audit?
100
+ - Does this reduce `use` to a snapshot assignment instead of a deferred context source?
101
+ - Does this confuse context budget with generation budget?
102
+ - Does this confuse AgentScript context labels with provider message roles?
316
103
 
317
- - Does this change let unused data enter the prompt?
318
- - Does this change let caller context implicitly pollute callee?
319
- - Does this change expose tool/model/agent/function bindings as prompt data?
320
- - Does this change preserve audit information for context sources?
321
- - Does this change reduce `use` to an ordinary variable snapshot?
322
- - Does this change confuse context budget with generation budget?
104
+ AgentScript's core value is not another control-flow syntax. Its value is making prompt context source, scope, budget, identity, and final prompt shape explicit and stable.
@@ -175,11 +175,11 @@ For typical LLM calls, omit `return`:
175
175
 
176
176
  ```agentscript
177
177
  func summarize(content) {
178
- use content < 8k
178
+ use content max 8k
179
179
 
180
180
  generate({
181
- input: "Summarize the content"
182
- limit: 1000
181
+ input: "Summarize the content",
182
+ max_output: 1000
183
183
  }) -> {
184
184
  title string
185
185
  summary string