@rong/agentscript 0.1.1 → 0.1.3
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 +13 -0
- package/README.md +23 -22
- package/dist/parser/parser.js +26 -2
- package/dist/providers/llm/anthropic.js +2 -1
- package/dist/providers/llm/ollama.js +5 -2
- package/dist/providers/llm/openai.js +7 -4
- package/dist/providers/mock/index.js +1 -1
- package/dist/runtime/context.js +18 -6
- package/dist/runtime/evaluator.js +1 -0
- package/dist/runtime/generate.js +4 -2
- package/dist/runtime/interpreter.js +12 -9
- package/dist/runtime/scope.js +2 -2
- package/dist/semantic/analyzer.js +7 -1
- package/docs/cn/context-engineering.md +7 -7
- package/docs/cn/final-expression-return.md +215 -0
- package/docs/cn/language.md +23 -6
- package/docs/cn/role-label.md +492 -0
- package/docs/design-history/v0-design.md +5 -5
- package/docs/design-history/v1-design.md +2 -2
- package/docs/design-history/v2-design.md +3 -3
- package/docs/en/context-engineering.md +6 -6
- package/docs/en/final-expression-return.md +215 -0
- package/docs/en/language.md +23 -6
- package/examples/changelog.as +3 -3
- package/examples/extract.as +3 -3
- package/examples/review.as +4 -4
- package/examples/summarize.as +3 -3
- package/examples/translate.as +4 -4
- package/package.json +1 -1
- package/tutorials/cli.as +1 -1
- package/tutorials/helloworld.as +1 -1
- package/tutorials/memory.as +1 -1
- package/tutorials/plan-execute.as +6 -6
- package/tutorials/react.as +6 -6
- package/tutorials/repl.as +1 -1
- package/tutorials/self-improve.as +2 -2
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# AgentScript Final Expression Return
|
|
2
|
+
|
|
3
|
+
This document describes the implicit return rule for AgentScript functions.
|
|
4
|
+
|
|
5
|
+
## 1. Basic rule
|
|
6
|
+
|
|
7
|
+
The final top-level expression in a function body can be used as the function return value.
|
|
8
|
+
|
|
9
|
+
```agentscript
|
|
10
|
+
func answer(input) {
|
|
11
|
+
use input.question
|
|
12
|
+
|
|
13
|
+
generate({ input: "Answer the question" }) -> {
|
|
14
|
+
ok boolean
|
|
15
|
+
answer string
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This is equivalent to:
|
|
21
|
+
|
|
22
|
+
```agentscript
|
|
23
|
+
func answer(input) {
|
|
24
|
+
use input.question
|
|
25
|
+
|
|
26
|
+
return generate({ input: "Answer the question" }) -> {
|
|
27
|
+
ok boolean
|
|
28
|
+
answer string
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This rule is called:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
final expression return
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 2. Expressions that can be implicitly returned
|
|
40
|
+
|
|
41
|
+
The final line can implicitly return these expression forms:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
generate(...) -> shape
|
|
45
|
+
regular function call
|
|
46
|
+
agent call
|
|
47
|
+
variable reference
|
|
48
|
+
field access
|
|
49
|
+
index access
|
|
50
|
+
object literal
|
|
51
|
+
list literal
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Examples:
|
|
55
|
+
|
|
56
|
+
```agentscript
|
|
57
|
+
func run(input) {
|
|
58
|
+
Worker(input)
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This rule applies to all expression forms, including calls. It does not matter whether the callee resolves to a local function or an agent call. For example, calling another agent by name invokes that agent's `main func`, and the result is returned implicitly:
|
|
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
|
+
|
|
80
|
+
```agentscript
|
|
81
|
+
func get_result(result) {
|
|
82
|
+
result.value
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```agentscript
|
|
87
|
+
func observe(action) {
|
|
88
|
+
{
|
|
89
|
+
facts: [action.summary],
|
|
90
|
+
source: action.source
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 3. Statements that cannot be implicitly returned
|
|
96
|
+
|
|
97
|
+
The following constructs are not expressions and do not participate in final expression return:
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
use declaration
|
|
101
|
+
assignment statement
|
|
102
|
+
import
|
|
103
|
+
loop
|
|
104
|
+
repeat
|
|
105
|
+
for
|
|
106
|
+
if/else, which can remain non-expression syntax in early versions
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Example:
|
|
110
|
+
|
|
111
|
+
```agentscript
|
|
112
|
+
func bad(input) {
|
|
113
|
+
use input.question
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This function has no return expression. It returns `none`, or the semantic analyzer may report a warning.
|
|
118
|
+
|
|
119
|
+
Assignment also does not return a value:
|
|
120
|
+
|
|
121
|
+
```agentscript
|
|
122
|
+
func f() {
|
|
123
|
+
x = answer()
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
To return the assigned value, write:
|
|
128
|
+
|
|
129
|
+
```agentscript
|
|
130
|
+
func f() {
|
|
131
|
+
x = answer()
|
|
132
|
+
x
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## 4. Explicit `return` takes priority
|
|
137
|
+
|
|
138
|
+
Explicit `return` remains valid and is recommended for complex control flow.
|
|
139
|
+
|
|
140
|
+
```agentscript
|
|
141
|
+
func answer(input) {
|
|
142
|
+
if input.dry_run {
|
|
143
|
+
return {
|
|
144
|
+
ok: false,
|
|
145
|
+
answer: "dry run"
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
generate({ input: "Answer" }) -> {
|
|
150
|
+
ok boolean
|
|
151
|
+
answer string
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 5. No return value
|
|
157
|
+
|
|
158
|
+
If a function has no explicit `return` and its final line is not a returnable expression, it returns:
|
|
159
|
+
|
|
160
|
+
```agentscript
|
|
161
|
+
none
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
This can also be written explicitly:
|
|
165
|
+
|
|
166
|
+
```agentscript
|
|
167
|
+
return none
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Use this form to express that a function only produces side effects.
|
|
171
|
+
|
|
172
|
+
## 6. Recommended style
|
|
173
|
+
|
|
174
|
+
For typical LLM calls, omit `return`:
|
|
175
|
+
|
|
176
|
+
```agentscript
|
|
177
|
+
func summarize(content) {
|
|
178
|
+
use content < 8k
|
|
179
|
+
|
|
180
|
+
generate({
|
|
181
|
+
input: "Summarize the content"
|
|
182
|
+
limit: 1000
|
|
183
|
+
}) -> {
|
|
184
|
+
title string
|
|
185
|
+
summary string
|
|
186
|
+
key_points list[string]
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
For branches, early exits, and error handling, use explicit `return`:
|
|
192
|
+
|
|
193
|
+
```agentscript
|
|
194
|
+
func answer(input) {
|
|
195
|
+
if not input.question {
|
|
196
|
+
return {
|
|
197
|
+
ok: false,
|
|
198
|
+
answer: ""
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
use input.question
|
|
203
|
+
|
|
204
|
+
generate({ input: "Answer the question" }) -> {
|
|
205
|
+
ok boolean
|
|
206
|
+
answer string
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## One-sentence definition
|
|
212
|
+
|
|
213
|
+
```text
|
|
214
|
+
A function returns the value of its final top-level expression when no explicit return is reached.
|
|
215
|
+
```
|
package/docs/en/language.md
CHANGED
|
@@ -27,7 +27,7 @@ main agent Assistant {
|
|
|
27
27
|
question string
|
|
28
28
|
}) {
|
|
29
29
|
use input.question
|
|
30
|
-
|
|
30
|
+
generate({ input: "Answer the question" }) -> {
|
|
31
31
|
ok boolean
|
|
32
32
|
answer string
|
|
33
33
|
}
|
|
@@ -138,7 +138,7 @@ Runtime values are JSON-oriented:
|
|
|
138
138
|
Shapes are used for input validation and `generate` output validation:
|
|
139
139
|
|
|
140
140
|
```agentscript
|
|
141
|
-
|
|
141
|
+
generate({ input: "Extract facts" }) -> {
|
|
142
142
|
ok boolean
|
|
143
143
|
title string
|
|
144
144
|
items list[json]
|
|
@@ -158,6 +158,8 @@ Shapes are not a full static type system.
|
|
|
158
158
|
use input.question
|
|
159
159
|
use Requirements < 4k
|
|
160
160
|
use past_lessons < 2k
|
|
161
|
+
use input.question as user
|
|
162
|
+
use docs.summary < 4k as evidence
|
|
161
163
|
```
|
|
162
164
|
|
|
163
165
|
### Rules
|
|
@@ -167,17 +169,31 @@ use past_lessons < 2k
|
|
|
167
169
|
- Memory query results do not automatically enter prompts.
|
|
168
170
|
- Trace events do not automatically enter prompts.
|
|
169
171
|
- `use value < n` applies a context budget.
|
|
172
|
+
- `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.
|
|
170
174
|
- `llm`, `tool`, `agent`, `memory` bindings cannot be used.
|
|
171
175
|
- Function bindings cannot be used.
|
|
172
176
|
- `use` declarations are inherited by child scopes.
|
|
173
177
|
|
|
178
|
+
### Context labels
|
|
179
|
+
|
|
180
|
+
The label after `as` is literal label text. It is not an expression, is not evaluated, and does not read variables from scope.
|
|
181
|
+
|
|
182
|
+
```agentscript
|
|
183
|
+
use docs as evidence
|
|
184
|
+
use docs.summary < 4k as retrieved evidence
|
|
185
|
+
use input.question as user
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`as evidence` labels the context section as `evidence` even if a variable named `evidence` exists. Labels organize prompt sections and trace output; they do not change provider message roles such as `system`, `user`, or `assistant`.
|
|
189
|
+
|
|
174
190
|
### Deferred evaluation
|
|
175
191
|
|
|
176
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.
|
|
177
193
|
|
|
178
194
|
## Generate
|
|
179
195
|
|
|
180
|
-
`generate` calls the current model and requires an `input` instruction
|
|
196
|
+
`generate` calls the current model and requires an `input` instruction. A return shape is optional.
|
|
181
197
|
|
|
182
198
|
```agentscript
|
|
183
199
|
answer = generate({
|
|
@@ -198,7 +214,8 @@ answer = generate({
|
|
|
198
214
|
- `limit` is the generation budget (number or `2k` style). Optional.
|
|
199
215
|
- `attempts` controls retry for JSON parse errors or shape mismatch. Optional, defaults to 1.
|
|
200
216
|
- `debug` prints the full prompt to stderr. Optional, defaults to false.
|
|
201
|
-
- The `-> { ... }` block declares the expected output shape.
|
|
217
|
+
- 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.
|
|
202
219
|
- Provider errors (auth, network, timeout, missing model) fail directly without retry.
|
|
203
220
|
- Shape validation includes coercion (e.g. `"true"` -> `true`, `"42"` -> `42`).
|
|
204
221
|
|
|
@@ -365,7 +382,7 @@ import file Config from "./config.json"
|
|
|
365
382
|
func answer(input) {
|
|
366
383
|
use Requirements < 4k
|
|
367
384
|
use Config
|
|
368
|
-
|
|
385
|
+
generate({ input: "Answer from the referenced file." }) -> {
|
|
369
386
|
ok boolean
|
|
370
387
|
answer string
|
|
371
388
|
}
|
|
@@ -417,7 +434,7 @@ main agent Controller {
|
|
|
417
434
|
result = Executor({ goal: input.goal, step: step })
|
|
418
435
|
results.add(result)
|
|
419
436
|
}
|
|
420
|
-
|
|
437
|
+
results.summary
|
|
421
438
|
}
|
|
422
439
|
}
|
|
423
440
|
```
|
package/examples/changelog.as
CHANGED
|
@@ -13,10 +13,10 @@ main agent ChangelogWriter {
|
|
|
13
13
|
path: input.diff_path
|
|
14
14
|
})
|
|
15
15
|
|
|
16
|
-
use input.diff_path
|
|
17
|
-
use diff < 10k
|
|
16
|
+
use input.diff_path as diff path
|
|
17
|
+
use diff < 10k as git diff
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
generate({ input: "Write a changelog from this git diff", limit: 1200 }) -> {
|
|
20
20
|
title string
|
|
21
21
|
highlights list[string]
|
|
22
22
|
breaking_changes list[string]
|
package/examples/extract.as
CHANGED
|
@@ -14,10 +14,10 @@ main agent ApiExtractor {
|
|
|
14
14
|
timeout: 10000
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
-
use input.url
|
|
18
|
-
use response < 8k
|
|
17
|
+
use input.url as endpoint
|
|
18
|
+
use response < 8k as api response
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
generate({ input: "Extract normalized data from the API response", limit: 1200 }) -> {
|
|
21
21
|
records list[json]
|
|
22
22
|
fields list[string]
|
|
23
23
|
warnings list[string]
|
package/examples/review.as
CHANGED
|
@@ -22,11 +22,11 @@ main agent CodeReviewAssistant {
|
|
|
22
22
|
max: 100
|
|
23
23
|
})
|
|
24
24
|
|
|
25
|
-
use input.path
|
|
26
|
-
use todos < 4k
|
|
27
|
-
use fixmes < 4k
|
|
25
|
+
use input.path as source path
|
|
26
|
+
use todos < 4k as todo findings
|
|
27
|
+
use fixmes < 4k as fixme findings
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
generate({ input: "Turn TODO and FIXME scan results into prioritized repair suggestions", limit: 1200 }) -> {
|
|
30
30
|
summary string
|
|
31
31
|
findings list[string]
|
|
32
32
|
suggested_fixes list[string]
|
package/examples/summarize.as
CHANGED
|
@@ -13,10 +13,10 @@ main agent FileSummarizer {
|
|
|
13
13
|
path: input.path
|
|
14
14
|
})
|
|
15
15
|
|
|
16
|
-
use input.path
|
|
17
|
-
use content < 8k
|
|
16
|
+
use input.path as source path
|
|
17
|
+
use content < 8k as file content
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
generate({ input: "Summarize the file for a busy teammate", limit: 1000 }) -> {
|
|
20
20
|
title string
|
|
21
21
|
summary string
|
|
22
22
|
key_points list[string]
|
package/examples/translate.as
CHANGED
|
@@ -17,11 +17,11 @@ main agent MarkdownTranslator {
|
|
|
17
17
|
max: 50
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
use input.path
|
|
21
|
-
use input.target_language
|
|
22
|
-
use files < 4k
|
|
20
|
+
use input.path as source path
|
|
21
|
+
use input.target_language as target language
|
|
22
|
+
use files < 4k as markdown files
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
generate({ input: "Create a practical markdown translation plan", limit: 1000 }) -> {
|
|
25
25
|
target_language string
|
|
26
26
|
files list[string]
|
|
27
27
|
glossary_notes list[string]
|
package/package.json
CHANGED
package/tutorials/cli.as
CHANGED
package/tutorials/helloworld.as
CHANGED
package/tutorials/memory.as
CHANGED
|
@@ -44,7 +44,7 @@ main agent PlanAndExecute {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
finish(input.goal, results)
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
func run_step(goal, step, previous) {
|
|
@@ -60,7 +60,7 @@ main agent PlanAndExecute {
|
|
|
60
60
|
result: result
|
|
61
61
|
})
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
{
|
|
64
64
|
ok: verdict.ok,
|
|
65
65
|
reason: verdict.reason,
|
|
66
66
|
result: {
|
|
@@ -75,7 +75,7 @@ main agent PlanAndExecute {
|
|
|
75
75
|
use goal
|
|
76
76
|
use results.summary < 2k
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
generate({ input: "Create the final answer from executed steps", limit: 800 }) -> {
|
|
79
79
|
ok boolean
|
|
80
80
|
text string
|
|
81
81
|
error string
|
|
@@ -93,7 +93,7 @@ agent Planner {
|
|
|
93
93
|
use input.problem
|
|
94
94
|
use input.previous < 1k
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
generate({ input: "Create a three step plan", limit: 600 }) -> {
|
|
97
97
|
step1 string
|
|
98
98
|
step2 string
|
|
99
99
|
step3 string
|
|
@@ -121,7 +121,7 @@ agent Executor {
|
|
|
121
121
|
|
|
122
122
|
use observation
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
generate({ input: "Report the result of this step", limit: 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
|
-
|
|
142
|
+
generate({ input: "Verify this step result", limit: 300 }) -> {
|
|
143
143
|
ok boolean
|
|
144
144
|
reason string
|
|
145
145
|
}
|
package/tutorials/react.as
CHANGED
|
@@ -25,14 +25,14 @@ main agent ResearchAgent {
|
|
|
25
25
|
done = enough(input.question, scratch)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
answer(input.question, scratch)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
func reason(question, scratch) {
|
|
32
32
|
use question
|
|
33
33
|
use scratch.summary < 1k
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
generate({ input: "Choose the next search focus", limit: 300 }) -> {
|
|
36
36
|
focus string
|
|
37
37
|
why string
|
|
38
38
|
}
|
|
@@ -42,7 +42,7 @@ main agent ResearchAgent {
|
|
|
42
42
|
raw_query = Search.query(question, thought)
|
|
43
43
|
raw_result = Search.search(raw_query)
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
{
|
|
46
46
|
query: raw_query.summary,
|
|
47
47
|
result: {
|
|
48
48
|
summary: raw_result.summary,
|
|
@@ -60,7 +60,7 @@ main agent ResearchAgent {
|
|
|
60
60
|
|
|
61
61
|
use raw
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
generate({ input: "Summarize the useful observation", limit: 400 }) -> {
|
|
64
64
|
facts list[string]
|
|
65
65
|
source string
|
|
66
66
|
}
|
|
@@ -74,14 +74,14 @@ main agent ResearchAgent {
|
|
|
74
74
|
done boolean
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
verdict.done
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
func answer(question, scratch) {
|
|
81
81
|
use question
|
|
82
82
|
use scratch.summary < 2k
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
generate({ input: "Answer using only the observations", limit: 800 }) -> {
|
|
85
85
|
ok boolean
|
|
86
86
|
text string
|
|
87
87
|
error string
|
package/tutorials/repl.as
CHANGED
|
@@ -40,13 +40,13 @@ main agent SelfImprover {
|
|
|
40
40
|
ok: result.ok
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
result
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
func reflect(run) {
|
|
47
47
|
use run
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
generate({
|
|
50
50
|
input: "Extract one durable lesson that could improve a future run.",
|
|
51
51
|
attempts: 3
|
|
52
52
|
}) -> {
|