agency-lang 0.7.0 → 0.7.2

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.
Files changed (182) hide show
  1. package/dist/lib/agents/agency-agent/agent.agency +169 -28
  2. package/dist/lib/agents/agency-agent/agent.js +579 -152
  3. package/dist/lib/agents/agency-agent/lib/attachments.js +2 -2
  4. package/dist/lib/agents/agency-agent/lib/config.agency +5 -0
  5. package/dist/lib/agents/agency-agent/lib/config.js +11 -0
  6. package/dist/lib/agents/agency-agent/lib/defaultPolicy.agency +106 -0
  7. package/dist/lib/agents/agency-agent/lib/defaultPolicy.js +764 -3
  8. package/dist/lib/agents/agency-agent/lib/modelFilters.js +1 -1
  9. package/dist/lib/agents/agency-agent/lib/resolution.js +4 -4
  10. package/dist/lib/agents/agency-agent/lib/search.js +3 -3
  11. package/dist/lib/agents/agency-agent/lib/settings.js +1 -1
  12. package/dist/lib/agents/agency-agent/lib/utils.js +1 -1
  13. package/dist/lib/agents/agency-agent/shared.agency +22 -0
  14. package/dist/lib/agents/agency-agent/shared.js +160 -3
  15. package/dist/lib/agents/agency-agent/subagents/code.js +1 -1
  16. package/dist/lib/agents/agency-agent/subagents/explorer.js +1 -1
  17. package/dist/lib/agents/agency-agent/subagents/oracle.js +1 -1
  18. package/dist/lib/agents/agency-agent/subagents/research.js +1 -1
  19. package/dist/lib/agents/agency-agent/subagents/review.js +4 -4
  20. package/dist/lib/agents/agency-agent/tests/agentTurn.js +1 -1
  21. package/dist/lib/agents/agency-agent/tests/attachments.js +1 -1
  22. package/dist/lib/agents/agency-agent/tests/attachmentsTurn.js +2 -2
  23. package/dist/lib/agents/agency-agent/tests/gitPolicy.js +3 -3
  24. package/dist/lib/agents/agency-agent/tests/oneShotRounds.agency +20 -0
  25. package/dist/lib/agents/agency-agent/tests/oneShotRounds.js +555 -0
  26. package/dist/lib/agents/agency-agent/tests/oneShotRounds.test.json +9 -0
  27. package/dist/lib/agents/review/agent.js +3 -3
  28. package/dist/lib/cli/doctor.d.ts +8 -0
  29. package/dist/lib/cli/doctor.js +21 -13
  30. package/dist/lib/cli/doctor.test.js +34 -0
  31. package/dist/lib/cli/help.js +1 -5
  32. package/dist/lib/cli/runBundledAgent.d.ts +17 -1
  33. package/dist/lib/cli/runBundledAgent.js +73 -2
  34. package/dist/lib/cli/runBundledAgent.test.d.ts +1 -0
  35. package/dist/lib/cli/runBundledAgent.test.js +96 -0
  36. package/dist/lib/config.d.ts +42 -33
  37. package/dist/lib/config.js +108 -6
  38. package/dist/lib/config.test.js +121 -2
  39. package/dist/lib/ir/prettyPrint.js +25 -4
  40. package/dist/lib/parseCache.js +8 -13
  41. package/dist/lib/parseCache.test.js +5 -8
  42. package/dist/lib/parser.js +5 -12
  43. package/dist/lib/preprocessors/typescriptPreprocessor.d.ts +0 -28
  44. package/dist/lib/preprocessors/typescriptPreprocessor.js +0 -245
  45. package/dist/lib/runtime/configOverrides.d.ts +17 -16
  46. package/dist/lib/runtime/configOverrides.js +27 -16
  47. package/dist/lib/runtime/configOverrides.test.js +116 -2
  48. package/dist/lib/runtime/prompt.js +7 -3
  49. package/dist/lib/runtime/runner.d.ts +2 -2
  50. package/dist/lib/runtime/runner.js +26 -7
  51. package/dist/lib/runtime/state/context.js +9 -2
  52. package/dist/lib/stdlib/llm.d.ts +1 -0
  53. package/dist/lib/stdlib/version.d.ts +1 -1
  54. package/dist/lib/stdlib/version.js +1 -1
  55. package/dist/scripts/agency.d.ts +2 -0
  56. package/dist/scripts/agency.js +55 -12
  57. package/dist/scripts/agency.test.js +73 -1
  58. package/package.json +1 -1
  59. package/stdlib/agency/eval.js +1 -1
  60. package/stdlib/agency.js +1 -1
  61. package/stdlib/agent.agency +9 -9
  62. package/stdlib/agent.js +5 -5
  63. package/stdlib/data/tech/hackernews.js +1 -1
  64. package/stdlib/index.js +15 -15
  65. package/stdlib/llm.agency +2 -1
  66. package/stdlib/llm.js +3 -3
  67. package/stdlib/markdown.js +1 -1
  68. package/stdlib/memory.js +2 -2
  69. package/stdlib/object.js +5 -5
  70. package/stdlib/policy.agency +21 -7
  71. package/stdlib/policy.js +45 -16
  72. package/stdlib/skills.js +1 -1
  73. package/stdlib/strategy.js +3 -3
  74. package/stdlib/thread.js +3 -3
  75. package/stdlib/ui/chart.js +2 -2
  76. package/stdlib/ui/cli.agency +1 -1
  77. package/stdlib/ui/cli.js +1 -1
  78. package/stdlib/ui/layout.js +3 -3
  79. package/stdlib/ui/table.js +2 -2
  80. package/stdlib/ui.js +3 -3
  81. package/dist/lib/agents/docs/cli/cli/agent.md +0 -16
  82. package/dist/lib/agents/docs/cli/cli/compile.md +0 -21
  83. package/dist/lib/agents/docs/cli/cli/coverage.md +0 -112
  84. package/dist/lib/agents/docs/cli/cli/debug.md +0 -41
  85. package/dist/lib/agents/docs/cli/cli/doc.md +0 -98
  86. package/dist/lib/agents/docs/cli/cli/editor-integration.md +0 -44
  87. package/dist/lib/agents/docs/cli/cli/eval-judge.md +0 -72
  88. package/dist/lib/agents/docs/cli/cli/eval.md +0 -194
  89. package/dist/lib/agents/docs/cli/cli/format.md +0 -23
  90. package/dist/lib/agents/docs/cli/cli/index.md +0 -7
  91. package/dist/lib/agents/docs/cli/cli/local.md +0 -92
  92. package/dist/lib/agents/docs/cli/cli/models.md +0 -63
  93. package/dist/lib/agents/docs/cli/cli/optimize.md +0 -338
  94. package/dist/lib/agents/docs/cli/cli/pack.md +0 -56
  95. package/dist/lib/agents/docs/cli/cli/policy.md +0 -23
  96. package/dist/lib/agents/docs/cli/cli/preprocess-and-ast.md +0 -21
  97. package/dist/lib/agents/docs/cli/cli/review.md +0 -16
  98. package/dist/lib/agents/docs/cli/cli/run.md +0 -79
  99. package/dist/lib/agents/docs/cli/cli/schedule.md +0 -89
  100. package/dist/lib/agents/docs/cli/cli/serve.md +0 -52
  101. package/dist/lib/agents/docs/cli/cli/test.md +0 -44
  102. package/dist/lib/agents/docs/cli/cli/trace-and-bundle.md +0 -75
  103. package/dist/lib/agents/docs/cli/cli/typecheck.md +0 -19
  104. package/dist/lib/agents/docs/guide/guide/advanced-types.md +0 -26
  105. package/dist/lib/agents/docs/guide/guide/agency-config-file.md +0 -212
  106. package/dist/lib/agents/docs/guide/guide/agency-packages.md +0 -54
  107. package/dist/lib/agents/docs/guide/guide/agency-stdlib.md +0 -14
  108. package/dist/lib/agents/docs/guide/guide/agency-vs-typescript.md +0 -33
  109. package/dist/lib/agents/docs/guide/guide/attachments.md +0 -56
  110. package/dist/lib/agents/docs/guide/guide/basic-syntax.md +0 -350
  111. package/dist/lib/agents/docs/guide/guide/blocks.md +0 -134
  112. package/dist/lib/agents/docs/guide/guide/build-integration.md +0 -99
  113. package/dist/lib/agents/docs/guide/guide/builtins.md +0 -84
  114. package/dist/lib/agents/docs/guide/guide/callbacks.md +0 -169
  115. package/dist/lib/agents/docs/guide/guide/checkpointing.md +0 -101
  116. package/dist/lib/agents/docs/guide/guide/cli-args.md +0 -190
  117. package/dist/lib/agents/docs/guide/guide/common-functions.md +0 -36
  118. package/dist/lib/agents/docs/guide/guide/compiling-and-running.md +0 -62
  119. package/dist/lib/agents/docs/guide/guide/concurrency.md +0 -108
  120. package/dist/lib/agents/docs/guide/guide/cross-thread-context.md +0 -226
  121. package/dist/lib/agents/docs/guide/guide/custom-providers.md +0 -195
  122. package/dist/lib/agents/docs/guide/guide/debugging.md +0 -67
  123. package/dist/lib/agents/docs/guide/guide/developer-tools.md +0 -90
  124. package/dist/lib/agents/docs/guide/guide/effects-and-raises.md +0 -137
  125. package/dist/lib/agents/docs/guide/guide/effects.md +0 -100
  126. package/dist/lib/agents/docs/guide/guide/error-handling.md +0 -161
  127. package/dist/lib/agents/docs/guide/guide/exercise-1.md +0 -32
  128. package/dist/lib/agents/docs/guide/guide/functions.md +0 -94
  129. package/dist/lib/agents/docs/guide/guide/getting-started.md +0 -35
  130. package/dist/lib/agents/docs/guide/guide/global-var-initialization.md +0 -70
  131. package/dist/lib/agents/docs/guide/guide/global-vs-static.md +0 -76
  132. package/dist/lib/agents/docs/guide/guide/guards.md +0 -134
  133. package/dist/lib/agents/docs/guide/guide/handlers.md +0 -196
  134. package/dist/lib/agents/docs/guide/guide/image-generation.md +0 -113
  135. package/dist/lib/agents/docs/guide/guide/imports-and-packages.md +0 -100
  136. package/dist/lib/agents/docs/guide/guide/interrupts-from-typescript.md +0 -84
  137. package/dist/lib/agents/docs/guide/guide/interrupts-part-2.md +0 -54
  138. package/dist/lib/agents/docs/guide/guide/interrupts.md +0 -139
  139. package/dist/lib/agents/docs/guide/guide/llm-part-2.md +0 -111
  140. package/dist/lib/agents/docs/guide/guide/llm.md +0 -109
  141. package/dist/lib/agents/docs/guide/guide/mcp.md +0 -295
  142. package/dist/lib/agents/docs/guide/guide/memory.md +0 -401
  143. package/dist/lib/agents/docs/guide/guide/message-threads.md +0 -111
  144. package/dist/lib/agents/docs/guide/guide/nodes.md +0 -50
  145. package/dist/lib/agents/docs/guide/guide/observability.md +0 -99
  146. package/dist/lib/agents/docs/guide/guide/partial-application.md +0 -96
  147. package/dist/lib/agents/docs/guide/guide/pattern-matching.md +0 -366
  148. package/dist/lib/agents/docs/guide/guide/policies.md +0 -67
  149. package/dist/lib/agents/docs/guide/guide/schema-parameter-injection.md +0 -101
  150. package/dist/lib/agents/docs/guide/guide/schemas.md +0 -99
  151. package/dist/lib/agents/docs/guide/guide/serving.md +0 -165
  152. package/dist/lib/agents/docs/guide/guide/state-isolation.md +0 -139
  153. package/dist/lib/agents/docs/guide/guide/streaming.md +0 -28
  154. package/dist/lib/agents/docs/guide/guide/tags.md +0 -72
  155. package/dist/lib/agents/docs/guide/guide/testing.md +0 -187
  156. package/dist/lib/agents/docs/guide/guide/troubleshooting.md +0 -86
  157. package/dist/lib/agents/docs/guide/guide/ts-helpers.md +0 -559
  158. package/dist/lib/agents/docs/guide/guide/ts-interop.md +0 -72
  159. package/dist/lib/agents/docs/guide/guide/type-validation.md +0 -187
  160. package/dist/lib/agents/docs/guide/guide/types.md +0 -181
  161. package/dist/lib/agents/docs/guide/guide/unused.md +0 -178
  162. package/dist/lib/agents/docs/guide/guide/unused2.md +0 -258
  163. package/dist/lib/agents/docs/guide/guide/value-parameterized-types.md +0 -186
  164. package/dist/lib/agents/docs/guide/guide/vscode-extension.md +0 -33
  165. package/dist/lib/agents/docs/guide/guide/why-agency.md +0 -323
  166. package/dist/lib/preprocessors/typescriptPreprocessor.config.test.js +0 -327
  167. package/stdlib/browser.js +0 -421
  168. package/stdlib/chart.js +0 -983
  169. package/stdlib/cli.js +0 -1116
  170. package/stdlib/email.js +0 -1104
  171. package/stdlib/imessage.js +0 -377
  172. package/stdlib/keyring.js +0 -803
  173. package/stdlib/layout.js +0 -3657
  174. package/stdlib/oauth.js +0 -862
  175. package/stdlib/schemas.js +0 -223
  176. package/stdlib/search.js +0 -629
  177. package/stdlib/sms.js +0 -419
  178. package/stdlib/table.js +0 -1419
  179. package/stdlib/threads.js +0 -1041
  180. package/stdlib/types.js +0 -222
  181. package/stdlib/validators.js +0 -1606
  182. /package/dist/lib/{preprocessors/typescriptPreprocessor.config.test.d.ts → cli/doctor.test.d.ts} +0 -0
@@ -1,99 +0,0 @@
1
- ---
2
- name: Schemas
3
- description: Shows how Agency converts types into runtime Zod schemas via the `schema()` function and the bang (`!`) shorthand for validating values and function parameters.
4
- ---
5
-
6
- # Schemas
7
-
8
- Have you ever wished you could create Zod Schemas from your TypeScript types, or use your TypeScript types to parse and validate data at runtime? You can do this in Agency!
9
-
10
- ## `schema()` function
11
- You can get the schema from a type using the `schema` function, and use it to validate an object:
12
-
13
- ```ts
14
- type Person = {
15
- name: string;
16
- age: number;
17
- }
18
- const personSchema = schema(Person)
19
-
20
- // validated will be a Result type
21
- const validated = personSchema.parse(someObject)
22
- ```
23
-
24
- If you have a string containing JSON data, use `parseJSON`.
25
-
26
- ```ts
27
- const validated = personSchema.parseJSON(someJSONString)
28
- ```
29
-
30
- ## The bang(!) syntax
31
-
32
- Agency also has a shorthand for validation: the bang syntax. Here’s what it looks like.
33
-
34
- ```ts
35
- const foo: Person! = someObject
36
- ```
37
-
38
- Now, `foo` will be a `Result` type. If the validation fails, it will be a `failure`, otherwise it will be a `success`.
39
-
40
- You can use this with llm calls too:
41
-
42
- ```ts
43
- const result: Person! = await llm("Describe a person.")
44
- ```
45
-
46
- Remember to unwrap the `Result` type to get the value out of it.
47
-
48
- You can also use the bang shorthand syntax to validate parameters passed into functions:
49
-
50
- ```ts
51
- function greet(name: string!, age: number!) {
52
- // ...
53
- }
54
- ```
55
-
56
- If any of these parameters fails to validate, the function returns immediately with a `failure`.
57
-
58
- You can use the bang syntax to validate the return value from a function as well.
59
-
60
- ```ts
61
- function getPerson(): Person! {
62
- // ...
63
- }
64
- ```
65
-
66
- If the value fails to validate, the function will return a `failure`.
67
-
68
- ## Schemas and Result Types
69
-
70
- When you use schema validation with `Result` types, there are some nuances to be aware of:
71
-
72
- 1. `failure`s are never validated. For instance, suppose you have validation on the parameters of a function. If you pass in a `failure`, Agency won't validate it. Similarly, if a function returns a `failure`, Agency doesn't validate that `failure`.
73
- 2. We never rewrap a `Result` type. This only applies to successes, because as I said, Agency doesn't even try to validate a `failure`. But we don't double-wrap `success`es. If a function returns a `success` but fails validation, we will return a `failure`. If a function returns a `success` and passes validation, we don't wrap it in another `success`. We simply propagate the existing `success` value.
74
-
75
- ## Validating Result types
76
-
77
- You can also add validation for the Result type itself.
78
-
79
- ```ts
80
- const foo: Result! = someObject
81
- ```
82
-
83
- This will validate that `foo` is a `Result` type, which could be either `success` or `failure`.
84
-
85
- Here's another example:
86
-
87
- ```ts
88
- const foo: Result<Person>! = someObject
89
- ```
90
-
91
- This will validate that `foo` is a `Result` type, and if it's a `success`, it will validate that the wrapped value is a `Person`.
92
-
93
- With `Result` types, you can also define types for both the `success` and `failure`. However, `failures` aren't touched, so what happens if you try to validate it?
94
-
95
- ```ts
96
- const foo: Result<Person, Error>! = someObject
97
- ```
98
-
99
- Agency still only validates if `foo` is a `success`. If it's a `failure`, we do not validate that the `failure` has the given type. This is because if we did, and the validation failed, we would have to replace this `failure` with a new `failure`, and then we would lose the original `failure` information.
@@ -1,165 +0,0 @@
1
- ---
2
- name: Serving Agency Code
3
- description: How to expose exported Agency functions and nodes over MCP (stdio) or HTTP REST so external tools and services can invoke your agents.
4
- ---
5
-
6
- # Serving Agency Code
7
-
8
- Agency can serve your functions and nodes over MCP (stdio) or HTTP REST, letting external tools and services call into your agents.
9
-
10
- ## Exporting Functions and Nodes
11
-
12
- Only items marked with `export` are exposed by the serve system:
13
-
14
- ```agency
15
- export safe def add(a: number, b: number): number {
16
- """
17
- Adds two numbers together.
18
- @param a - First number
19
- @param b - Second number
20
- """
21
- return a + b
22
- }
23
-
24
- export node main(message: string) {
25
- // This node will be callable via the serve system
26
- return process(message)
27
- }
28
-
29
- def internal(): string {
30
- // This function is NOT exported — it won't appear in the serve API
31
- return "only used internally"
32
- }
33
- ```
34
-
35
- The `safe` modifier tells the serve system that a function is read-only (no side effects). MCP clients see this as a `readOnlyHint` annotation.
36
-
37
- ## MCP Server
38
-
39
- Start an MCP server over stdio:
40
-
41
- ```bash
42
- agency serve mcp myagent.agency
43
- agency serve mcp myagent.agency --name "My Agent"
44
- ```
45
-
46
- Options:
47
- - `--name <name>` — Server name reported to MCP clients (defaults to filename)
48
-
49
- The server implements the MCP protocol (JSON-RPC 2.0 over stdio) with `tools/list` and `tools/call`. Each exported function becomes an MCP tool with its description and Zod-derived JSON Schema.
50
-
51
- ## HTTP Server
52
-
53
- Start an HTTP REST server:
54
-
55
- ```bash
56
- agency serve http myagent.agency
57
- agency serve http myagent.agency --port 8080
58
- agency serve http myagent.agency --api-key my-secret-key
59
- ```
60
-
61
- Options:
62
- - `--port <port>` — Port to listen on (default: 3545)
63
- - `--api-key <key>` — Require Bearer token authentication
64
- - `--standalone` — Generate a bundled `server.js` file instead of starting a server
65
-
66
- ### Routes
67
-
68
- **`GET /list`** — Returns a manifest of available functions and nodes:
69
-
70
- ```json
71
- {
72
- "functions": [
73
- { "name": "add", "description": "Adds two numbers together.", "safe": true }
74
- ],
75
- "nodes": [
76
- { "name": "main", "parameters": ["message"] }
77
- ]
78
- }
79
- ```
80
-
81
- **`POST /functions/:name`** — Call an exported function:
82
-
83
- ```bash
84
- curl -X POST http://localhost:3545/functions/add \
85
- -H 'Content-Type: application/json' \
86
- -d '{"a": 3, "b": 4}'
87
- ```
88
-
89
- Response:
90
- ```json
91
- { "success": true, "value": 7 }
92
- ```
93
-
94
- **`POST /nodes/:name`** — Run an exported node:
95
-
96
- ```bash
97
- curl -X POST http://localhost:3545/nodes/main \
98
- -H 'Content-Type: application/json' \
99
- -d '{"message": "hello"}'
100
- ```
101
-
102
- Response:
103
- ```json
104
- { "success": true, "value": { "result": "processed hello" } }
105
- ```
106
-
107
- ### Interrupts
108
-
109
- If a node triggers an interrupt during execution, the response includes the interrupt data:
110
-
111
- ```json
112
- {
113
- "success": true,
114
- "value": {
115
- "interrupts": [
116
- { "type": "interrupt", "effect": "std::read", "message": "Do you approve?" }
117
- ],
118
- "state": "..."
119
- }
120
- }
121
- ```
122
-
123
- To resume after an interrupt, use **`POST /resume`** with the interrupts and your responses:
124
-
125
- ```bash
126
- curl -X POST http://localhost:3545/resume \
127
- -H 'Content-Type: application/json' \
128
- -d '{
129
- "interrupts": [... the interrupts array from above ...],
130
- "responses": [{"type": "approve"}]
131
- }'
132
- ```
133
-
134
- The `responses` array corresponds positionally to the `interrupts` array.
135
-
136
- ### Authentication
137
-
138
- When `--api-key` is set, all requests must include a Bearer token:
139
-
140
- ```bash
141
- curl -H 'Authorization: Bearer my-secret-key' http://localhost:3545/list
142
- ```
143
-
144
- Requests without a valid token receive a `401 Unauthorized` response.
145
-
146
- ### Standalone Mode
147
-
148
- Generate a self-contained server file that can be deployed without the Agency CLI:
149
-
150
- ```bash
151
- agency serve http myagent.agency --standalone
152
- ```
153
-
154
- This produces a bundled `.server.js` file via esbuild.
155
-
156
- ## What Gets Exported
157
-
158
- | Syntax | Served as |
159
- |---|---|
160
- | `export def foo()` | MCP tool / HTTP function |
161
- | `export safe def foo()` | MCP tool (with readOnlyHint) / HTTP function |
162
- | `export node main()` | HTTP node |
163
- | `export static const x = ...` | Available in module but not directly callable |
164
- | `def foo()` (no export) | Not served |
165
- | `node main()` (no export) | Not served |
@@ -1,139 +0,0 @@
1
- ---
2
- name: State Isolation
3
- description: Explains how every Agency node call gets isolated state when invoked from TypeScript, and how `static` variables let you share expensive one-time initialization across runs.
4
- ---
5
-
6
- # State Isolation
7
-
8
- Every run of an agent gets full isolated state. Suppose you define an agent like this.
9
-
10
- ```ts
11
- const log = []
12
- node main(name:string) {
13
- const result = "Hello, ${name}!"
14
- log.push(result)
15
- return log
16
- }
17
- ```
18
-
19
- This agent has a global variable, `log`. Now, suppose you're using this agent in a web server context. As you know, any node defined in Agency can be imported and run as a regular function in TypeScript:
20
-
21
- ```ts
22
- // note you have to import from the compiled .js file, not the .agency file
23
- import { main } from "./main.js";
24
-
25
- async function run() {
26
- const result = await main("Adit");
27
- console.log(result);
28
- }
29
-
30
- run();
31
- ```
32
-
33
- In a web server, you may have multiple requests concurrently calling this agent. Let's say you have *five* requests concurrently calling this agent, with these names:
34
-
35
- ```
36
- Colin
37
- Ed
38
- Jonny
39
- Phil
40
- Thom
41
- ```
42
-
43
- Five requests that call the `main` node, push an entry to `log`, and then return `log` as the return value. What return value is each request going to get? You may think each request is mutating the same array, so at least one request will get an array with all five values.
44
-
45
- ```ts
46
- [
47
- "Hello, Colin!",
48
- "Hello, Ed!",
49
- "Hello, Jonny!",
50
- "Hello, Phil!",
51
- "Hello, Thom!"
52
- ]
53
- ```
54
-
55
- But that's not correct! Each request will get an array with a single value:
56
-
57
- ```ts
58
- // 1
59
- ["Hello, Colin!"]
60
-
61
- // 2
62
- ["Hello, Ed!"]
63
-
64
- // 3
65
- ["Hello, Jonny!"]
66
-
67
- // 4
68
- ["Hello, Phil!"]
69
-
70
- // 5
71
- ["Hello, Thom!"]
72
- ```
73
-
74
- Every call to an Agency agent gets state isolation, so each run has its own copy of the global variables. This makes it much easier to reason about your agent, as you don't have to think about concurrency.
75
-
76
- ## Todos example
77
-
78
- It's a common pattern to have agents keep track of their work by creating todos. Let's create an agent that keeps track of its todos:
79
-
80
- ```ts
81
- const todos = []
82
-
83
- def addTodo(todo: string) {
84
- todos.push(todo)
85
- }
86
-
87
- def getTodos() {
88
- return todos
89
- }
90
-
91
- def markDone(todo: string) {
92
- const index = todos.indexOf(todo)
93
- if (index !== -1) {
94
- todos.splice(index, 1)
95
- }
96
- }
97
-
98
- node main() {
99
- const result = llm("Do some stuff", tools: [addTodo, getTodos, markDone])
100
- }
101
- ```
102
-
103
- We can just create a global variable, `todos`, and then add todos to it. Each run of the agent will have its own copy of the `todos` array, so you don't have to worry about concurrency issues.
104
-
105
- ## Isolation across concurrent branches
106
-
107
- Suppose you want to run three research agents in parallel to explore a topic in different ways. You want all three agents to keep track of their todos. *The same isolation property also extends to branches.*
108
-
109
- You can still use the same todos code without worrying about concurrency, because each agent will get their own copy of the `todos` variable.
110
-
111
- ```ts
112
- parallel {
113
- // both have their own copy of the todos array
114
- researchAgentA()
115
- researchAgentB()
116
- }
117
- ```
118
-
119
- If you *want* branches to have shared state, you can get that too; pass `shared: true`. See the [concurrency guide](/guide/concurrency) for details.
120
-
121
- ## State in TypeScript
122
- This isolated state model only applies to state defined in agency. Any state that you define in TypeScript will not get this kind of state isolation, unless you explicitly code it to. In the agent code above, if the `log` array lived in TypeScript code, then the requests wouldn't have state isolation:
123
-
124
- foo.ts:
125
- ```ts
126
- export const log = []
127
- ```
128
-
129
- main.agency:
130
- ```ts
131
- import { log } from "./foo.js"
132
- node main(name:string) {
133
- const result = llm(`Hello, ${name}!`)
134
- log.push(result)
135
- return log
136
- }
137
- ```
138
-
139
- If you want to create global variables in TypeScript that get the same kind of state isolation, [Agency exports some helpers you can use](/guide/ts-helpers).
@@ -1,28 +0,0 @@
1
- ---
2
- name: Streaming
3
- description: Explains how to stream responses from the model in an LLM call, using the `stream` option and `onStream` callback.
4
- ---
5
-
6
- # Streaming
7
-
8
- To stream your response back, you need to do two things:
9
- 1. Set `stream: true` in your LLM call.
10
-
11
- ```ts
12
- const response = llm("What is the capital of France?", { stream: true })
13
- ```
14
-
15
- 2. Provide an `onStream` callback function to handle the streamed data.
16
-
17
- You can provide callbacks in Agency code or TypeScript code. Here is an example in Agency code.
18
-
19
- ```ts
20
- node main() {
21
- callback("onStream") as data {
22
- printJSON(data)
23
- }
24
- const response = llm("What is the capital of India?", stream: true)
25
- }
26
- ```
27
-
28
- Read more about callbacks [here](/guide/callbacks).
@@ -1,72 +0,0 @@
1
- ---
2
- name: Tags and Redaction
3
- description: Attach arbitrary tags to values with std::tag, and use the built-in redact tag to keep secrets like API keys out of state logs.
4
- ---
5
-
6
- # Tags and Redaction
7
-
8
- The `std::tag` module lets you attach arbitrary tags to values and read them
9
- back anywhere in your program.
10
-
11
- ```ts
12
- import { tag, setTags, getTags, removeTag, removeAllTags } from "std::tag"
13
-
14
- tag(x, "source", "user-upload") // attach a key/value tag
15
- tag(x, "reviewed") // value defaults to true
16
- setTags(x, { team: "growth", tier: 2 }) // attach several at once
17
- const tags = getTags(x) // { source: "user-upload", reviewed: true, team: "growth", tier: 2 }
18
- removeTag(x, "reviewed") // drop one tag
19
- removeAllTags(x) // drop them all
20
- ```
21
-
22
- Every function returns the value's current tags (an empty object once cleared),
23
- which doubles as a confirmation when one of these is used as an LLM tool.
24
-
25
- ## Value vs. reference semantics
26
-
27
- How a tag is stored depends on the kind of value:
28
-
29
- - **Primitives** (string, number, boolean) are keyed by **value**. Tagging one
30
- copy of `"secret"` tags every equal `"secret"`. This is what makes redacting
31
- an API key work no matter how the string was copied.
32
- - **Objects and arrays** are keyed by **reference**. Tagging one object does
33
- *not* tag a structurally-equal but distinct object.
34
-
35
- > Tags on **plain objects and arrays** survive `fork`, `race`, `parallel`,
36
- > and interrupt/resume, the same as primitive (value) tags. A **spread or
37
- > structural copy** (`{...obj}`) produces an *untagged* new object — durability
38
- > follows the *same* object, not its copies. Tags on **frozen/sealed objects**
39
- > and **native-typed objects** (`Date`, `Map`, `Set`, …) are branch-local
40
- > (best-effort) — they can't carry the durable marker.
41
-
42
- ## Redaction
43
-
44
- The built-in `redact` tag marks a value so it is replaced with `"[REDACTED]"`
45
- in [state logs](/guide/observability). Use it for API keys and other secrets:
46
-
47
- ```ts
48
- import { redact } from "std::tag"
49
-
50
- def callApi(apiKey: string) {
51
- redact(apiKey)
52
- return fetch("https://api.example.com", { headers: { key: apiKey } })
53
- }
54
- ```
55
-
56
- `redact(x)` is shorthand for `tag(x, "redact", true)`.
57
-
58
- Four limits to know:
59
-
60
- - **Whole-value only.** A secret is redacted where it appears as a logged value
61
- on its own. A secret concatenated into a larger logged string (for example a
62
- URL query parameter) is *not* scrubbed — tag the exact string that gets
63
- logged.
64
- - **Values, never keys.** Redaction rewrites values, not object keys. A secret
65
- used as a key (e.g. `{ "sk-...": {...} }`) still appears in the log verbatim —
66
- tag the value, not the thing that becomes a key.
67
- - **State logs only.** Redaction governs what `std::statelog` records. It does
68
- not affect `print()` or other direct output.
69
- - **Not a secrecy guarantee.** Redaction is best-effort scrubbing of state-log
70
- events emitted while your program runs. It is not an information-flow or
71
- security control — treat it as a way to keep secrets out of routine telemetry,
72
- not as a guarantee a secret can never be observed.
@@ -1,187 +0,0 @@
1
- ---
2
- name: Testing
3
- description: Introduces Agency's built-in testing framework, covering fixture generation, exact-match versus LLM-as-judge fixtures, and running tests with the `test` command.
4
- ---
5
-
6
- # Testing
7
-
8
- Agency comes with a built-in testing framework that makes it easy to test your agents.
9
-
10
- ## Generating fixtures
11
-
12
- Generate fixtures for your agent by running
13
-
14
- ```
15
- agency test fixtures foo.agency
16
- ```
17
-
18
- Agency will execute your node. If there are multiple nodes, it will ask you which node to execute. The return value of the node will be saved as the fixture value.
19
-
20
- ## Test types
21
-
22
- There are two test types:
23
- - exact match
24
- - LLM as a judge.
25
-
26
- After you have generated the fixture, you can choose what test type you want. If you choose LLM as a judge, you'll need to provide a judge prompt that the LLM can use to judge the result.
27
-
28
- ## Test file
29
-
30
- The fixtures command will create a test file with the same name as your agency file, but with the .test.json extension instead
31
-
32
- ```
33
- foo.agency → foo.test.json
34
- ```
35
-
36
- ## Running tests
37
-
38
- Use the `agency test` command to run the test. You can give it either the path to the agency file or the path to the test.json file.
39
-
40
- ## Test file options
41
-
42
- ### File-level options
43
-
44
- A few options live at the top of the file, and apply to the whole file:
45
-
46
- - **`skip`** — skip every test in the file.
47
- - **`skipOnCI`** — skip every test in the file when running in CI.
48
- - **`skipReason`** — a note printed when the file is skipped.
49
- - **`defaultTimeoutMs`** — default timeout for every test, unless a test sets its own `timeoutMs`.
50
-
51
- ```json
52
- {
53
- "skipOnCI": true,
54
- "skipReason": "Needs a local Ollama server",
55
- "defaultTimeoutMs": 30000,
56
- "tests": [ ... ]
57
- }
58
- ```
59
-
60
- ### Test-level options
61
-
62
- A `.test.json` file has a top-level `tests` array, where each entry is one test case. The fixtures command will generate these entries for you.
63
-
64
- ```json
65
- {
66
- "tests": [
67
- {
68
- "nodeName": "main",
69
- "input": "",
70
- "expectedOutput": "\"hello world\"",
71
- "evaluationCriteria": [{ "type": "exact" }]
72
- }
73
- ]
74
- }
75
- ```
76
-
77
- Required:
78
-
79
- - **`nodeName`** — the node to run.
80
- - **`input`** — the input passed to the node.
81
- - **`expectedOutput`** — the expected return value, JSON-encoded as a string.
82
- - **`evaluationCriteria`** — how to compare the result to `expectedOutput` (see below).
83
-
84
- Optional:
85
-
86
- - **`description`** — a human-readable description.
87
- - **`skip`** — set to `true` to skip this test.
88
- - **`skipOnCI`** — skip only when running in CI (i.e. when the `CI` env var is set). Handy for tests that depend on a developer machine, like macOS-only builtins or interactive prompts.
89
- - **`retry`** — number of times to retry before failing. Useful for flaky tests.
90
- - **`timeoutMs`** — per-test timeout in milliseconds. Defaults to 2 minutes and is capped at 5.
91
- - **`argv`** — extra command-line arguments to hand the node. These show up as `process.argv.slice(2)`, so you can test `std::args` and other argv-reading code. A JSON array of strings.
92
-
93
- ### Evaluation criteria
94
-
95
- There are two ways to judge a result:
96
-
97
- #### Exact match
98
-
99
- ```json
100
- "evaluationCriteria": [{ "type": "exact" }]
101
- ```
102
-
103
- Actual output matches the `expectedOutput` exactly.
104
-
105
- #### LLM Judge
106
-
107
- ```json
108
- "evaluationCriteria": [
109
- {
110
- "type": "llmJudge",
111
- "judgePrompt": "The greeting can be any hello to Alice; exact wording doesn't matter.",
112
- "desiredAccuracy": 75
113
- }
114
- ]
115
- ```
116
-
117
- Ask an LLM to judge the result. `judgePrompt` is a string that describes what a correct result looks like. An LLM judge will see how close the actual output is to the expected output and give a score between 1 and 100. The desired accuracy is the minimum score required.
118
-
119
- ### Interrupt handlers
120
-
121
- If your node raises [interrupts](/guide/interrupts), list the responses in order under `interruptHandlers`:
122
-
123
- ```json
124
- "interruptHandlers": [
125
- { "action": "approve", "expectedMessage": "confirm" }
126
- ]
127
- ```
128
-
129
- - **`action`** — one of `"approve"`, `"reject"`, `"modify"`, or `"resolve"`.
130
- - **`resolvedValue`** — the value to return when the action is `"resolve"`.
131
- - **`expectedMessage`** — asserts the interrupt's message matches before responding.
132
-
133
- ### Mocking LLM calls
134
-
135
- To keep a test deterministic, you can mock out `llm()` calls. Set `useTestLLMProvider: true` and give an ordered list of mocks, one per `llm()` call:
136
-
137
- ```json
138
- "useTestLLMProvider": true,
139
- "llmMocks": [
140
- { "return": "hello there" },
141
- { "toolCall": { "name": "search", "args": { "q": "cats" } } }
142
- ]
143
- ```
144
-
145
- Each mock is
146
- - a `return` (the value the call produces), or
147
- - a `toolCall` (a tool the model "decides" to call).
148
-
149
- If your test runs several agents, you can make `llmMocks` an object keyed by agent name (the agent's file basename), giving each agent its own queue of mocks. You can also use a `"*"` key to catch calls from any agent not listed.
150
-
151
- ```json
152
- "llmMocks": {
153
- "main": [{ "return": "main-summary" }],
154
- "mutatePrompt": [{ "return": { "operations": [] } }]
155
- }
156
- ```
157
-
158
- ## Coverage
159
-
160
- Want to know which lines of your `.agency` code your tests actually exercise? Add `--coverage`:
161
-
162
- ```
163
- agency test --coverage tests/
164
- ```
165
-
166
- Agency tracks every step the runtime executes, and prints a summary when the run finishes:
167
-
168
- ```
169
- Agency Coverage Report
170
- ======================
171
- stdlib/array.agency 100.0% (76/76 steps)
172
- stdlib/math.agency 33.3% (2/6 steps)
173
- ────────────────────────────────────────────────────────────
174
- Total 53.8% (162/301 steps)
175
- ```
176
-
177
- Other things you can do:
178
- - generate a detailed report with `agency coverage report`
179
- - generate an HTML report with `agency coverage report --html`
180
- - enforce minimum coverage in CI with `--threshold` / `--per-file-threshold`
181
-
182
- See the [coverage CLI reference](/cli/coverage) for the full set of options.
183
-
184
- ## References
185
-
186
- - [`test` CLI reference](/cli/test)
187
- - [`coverage` CLI reference](/cli/coverage)