@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.
@@ -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
+ ```
@@ -27,7 +27,7 @@ main agent Assistant {
27
27
  question string
28
28
  }) {
29
29
  use input.question
30
- return generate({ input: "Answer the question" }) -> {
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
- return generate({ input: "Extract facts" }) -> {
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 plus a return shape.
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
- return generate({ input: "Answer from the referenced file." }) -> {
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
- return results.summary
437
+ results.summary
421
438
  }
422
439
  }
423
440
  ```
@@ -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
- return generate({ input: "Write a changelog from this git diff", limit: 1200 }) -> {
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]
@@ -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
- return generate({ input: "Extract normalized data from the API response", limit: 1200 }) -> {
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]
@@ -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
- return 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", limit: 1200 }) -> {
30
30
  summary string
31
31
  findings list[string]
32
32
  suggested_fixes list[string]
@@ -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
- return generate({ input: "Summarize the file for a busy teammate", limit: 1000 }) -> {
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]
@@ -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
- return generate({ input: "Create a practical markdown translation plan", limit: 1000 }) -> {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rong/agentscript",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
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
- return generate({ input: "Reply to the CLI user by name", limit: 300 }) -> {
15
+ generate({ input: "Reply to the CLI user by name", limit: 300 }) -> {
16
16
  ok boolean
17
17
  message string
18
18
  }
@@ -6,7 +6,7 @@ main agent {
6
6
  description "Return a simple hello world response."
7
7
 
8
8
  main func(input {}) {
9
- return {
9
+ {
10
10
  ok: true,
11
11
  message: "Hello, AgentScript!"
12
12
  }
@@ -10,7 +10,7 @@ main agent MemoryDemo {
10
10
  topic: input.topic
11
11
  })
12
12
 
13
- return Notes.query({
13
+ Notes.query({
14
14
  kind: "note"
15
15
  text: input.topic
16
16
  limit: 3
@@ -44,7 +44,7 @@ main agent PlanAndExecute {
44
44
  }
45
45
  }
46
46
 
47
- return finish(input.goal, results)
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
- return {
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
- return generate({ input: "Create the final answer from executed steps", limit: 800 }) -> {
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
- return generate({ input: "Create a three step plan", limit: 600 }) -> {
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
- return generate({ input: "Report the result of this step", limit: 500 }) -> {
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
- return generate({ input: "Verify this step result", limit: 300 }) -> {
142
+ generate({ input: "Verify this step result", limit: 300 }) -> {
143
143
  ok boolean
144
144
  reason string
145
145
  }
@@ -25,14 +25,14 @@ main agent ResearchAgent {
25
25
  done = enough(input.question, scratch)
26
26
  }
27
27
 
28
- return answer(input.question, scratch)
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
- return generate({ input: "Choose the next search focus", limit: 300 }) -> {
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
- return {
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
- return generate({ input: "Summarize the useful observation", limit: 400 }) -> {
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
- return verdict.done
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
- return generate({ input: "Answer using only the observations", limit: 800 }) -> {
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
@@ -22,7 +22,7 @@ main agent ReplGuide {
22
22
  }
23
23
  ]
24
24
 
25
- return {
25
+ {
26
26
  ok: true,
27
27
  title: "AgentScript REPL quick start",
28
28
  commands: commands
@@ -40,13 +40,13 @@ main agent SelfImprover {
40
40
  ok: result.ok
41
41
  })
42
42
 
43
- return result
43
+ result
44
44
  }
45
45
 
46
46
  func reflect(run) {
47
47
  use run
48
48
 
49
- return generate({
49
+ generate({
50
50
  input: "Extract one durable lesson that could improve a future run.",
51
51
  attempts: 3
52
52
  }) -> {