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.
- package/dist/lib/agents/agency-agent/agent.agency +169 -28
- package/dist/lib/agents/agency-agent/agent.js +579 -152
- package/dist/lib/agents/agency-agent/lib/attachments.js +2 -2
- package/dist/lib/agents/agency-agent/lib/config.agency +5 -0
- package/dist/lib/agents/agency-agent/lib/config.js +11 -0
- package/dist/lib/agents/agency-agent/lib/defaultPolicy.agency +106 -0
- package/dist/lib/agents/agency-agent/lib/defaultPolicy.js +764 -3
- package/dist/lib/agents/agency-agent/lib/modelFilters.js +1 -1
- package/dist/lib/agents/agency-agent/lib/resolution.js +4 -4
- package/dist/lib/agents/agency-agent/lib/search.js +3 -3
- package/dist/lib/agents/agency-agent/lib/settings.js +1 -1
- package/dist/lib/agents/agency-agent/lib/utils.js +1 -1
- package/dist/lib/agents/agency-agent/shared.agency +22 -0
- package/dist/lib/agents/agency-agent/shared.js +160 -3
- package/dist/lib/agents/agency-agent/subagents/code.js +1 -1
- package/dist/lib/agents/agency-agent/subagents/explorer.js +1 -1
- package/dist/lib/agents/agency-agent/subagents/oracle.js +1 -1
- package/dist/lib/agents/agency-agent/subagents/research.js +1 -1
- package/dist/lib/agents/agency-agent/subagents/review.js +4 -4
- package/dist/lib/agents/agency-agent/tests/agentTurn.js +1 -1
- package/dist/lib/agents/agency-agent/tests/attachments.js +1 -1
- package/dist/lib/agents/agency-agent/tests/attachmentsTurn.js +2 -2
- package/dist/lib/agents/agency-agent/tests/gitPolicy.js +3 -3
- package/dist/lib/agents/agency-agent/tests/oneShotRounds.agency +20 -0
- package/dist/lib/agents/agency-agent/tests/oneShotRounds.js +555 -0
- package/dist/lib/agents/agency-agent/tests/oneShotRounds.test.json +9 -0
- package/dist/lib/agents/review/agent.js +3 -3
- package/dist/lib/cli/doctor.d.ts +8 -0
- package/dist/lib/cli/doctor.js +21 -13
- package/dist/lib/cli/doctor.test.js +34 -0
- package/dist/lib/cli/help.js +1 -5
- package/dist/lib/cli/runBundledAgent.d.ts +17 -1
- package/dist/lib/cli/runBundledAgent.js +73 -2
- package/dist/lib/cli/runBundledAgent.test.d.ts +1 -0
- package/dist/lib/cli/runBundledAgent.test.js +96 -0
- package/dist/lib/config.d.ts +42 -33
- package/dist/lib/config.js +108 -6
- package/dist/lib/config.test.js +121 -2
- package/dist/lib/ir/prettyPrint.js +25 -4
- package/dist/lib/parseCache.js +8 -13
- package/dist/lib/parseCache.test.js +5 -8
- package/dist/lib/parser.js +5 -12
- package/dist/lib/preprocessors/typescriptPreprocessor.d.ts +0 -28
- package/dist/lib/preprocessors/typescriptPreprocessor.js +0 -245
- package/dist/lib/runtime/configOverrides.d.ts +17 -16
- package/dist/lib/runtime/configOverrides.js +27 -16
- package/dist/lib/runtime/configOverrides.test.js +116 -2
- package/dist/lib/runtime/prompt.js +7 -3
- package/dist/lib/runtime/runner.d.ts +2 -2
- package/dist/lib/runtime/runner.js +26 -7
- package/dist/lib/runtime/state/context.js +9 -2
- package/dist/lib/stdlib/llm.d.ts +1 -0
- package/dist/lib/stdlib/version.d.ts +1 -1
- package/dist/lib/stdlib/version.js +1 -1
- package/dist/scripts/agency.d.ts +2 -0
- package/dist/scripts/agency.js +55 -12
- package/dist/scripts/agency.test.js +73 -1
- package/package.json +1 -1
- package/stdlib/agency/eval.js +1 -1
- package/stdlib/agency.js +1 -1
- package/stdlib/agent.agency +9 -9
- package/stdlib/agent.js +5 -5
- package/stdlib/data/tech/hackernews.js +1 -1
- package/stdlib/index.js +15 -15
- package/stdlib/llm.agency +2 -1
- package/stdlib/llm.js +3 -3
- package/stdlib/markdown.js +1 -1
- package/stdlib/memory.js +2 -2
- package/stdlib/object.js +5 -5
- package/stdlib/policy.agency +21 -7
- package/stdlib/policy.js +45 -16
- package/stdlib/skills.js +1 -1
- package/stdlib/strategy.js +3 -3
- package/stdlib/thread.js +3 -3
- package/stdlib/ui/chart.js +2 -2
- package/stdlib/ui/cli.agency +1 -1
- package/stdlib/ui/cli.js +1 -1
- package/stdlib/ui/layout.js +3 -3
- package/stdlib/ui/table.js +2 -2
- package/stdlib/ui.js +3 -3
- package/dist/lib/agents/docs/cli/cli/agent.md +0 -16
- package/dist/lib/agents/docs/cli/cli/compile.md +0 -21
- package/dist/lib/agents/docs/cli/cli/coverage.md +0 -112
- package/dist/lib/agents/docs/cli/cli/debug.md +0 -41
- package/dist/lib/agents/docs/cli/cli/doc.md +0 -98
- package/dist/lib/agents/docs/cli/cli/editor-integration.md +0 -44
- package/dist/lib/agents/docs/cli/cli/eval-judge.md +0 -72
- package/dist/lib/agents/docs/cli/cli/eval.md +0 -194
- package/dist/lib/agents/docs/cli/cli/format.md +0 -23
- package/dist/lib/agents/docs/cli/cli/index.md +0 -7
- package/dist/lib/agents/docs/cli/cli/local.md +0 -92
- package/dist/lib/agents/docs/cli/cli/models.md +0 -63
- package/dist/lib/agents/docs/cli/cli/optimize.md +0 -338
- package/dist/lib/agents/docs/cli/cli/pack.md +0 -56
- package/dist/lib/agents/docs/cli/cli/policy.md +0 -23
- package/dist/lib/agents/docs/cli/cli/preprocess-and-ast.md +0 -21
- package/dist/lib/agents/docs/cli/cli/review.md +0 -16
- package/dist/lib/agents/docs/cli/cli/run.md +0 -79
- package/dist/lib/agents/docs/cli/cli/schedule.md +0 -89
- package/dist/lib/agents/docs/cli/cli/serve.md +0 -52
- package/dist/lib/agents/docs/cli/cli/test.md +0 -44
- package/dist/lib/agents/docs/cli/cli/trace-and-bundle.md +0 -75
- package/dist/lib/agents/docs/cli/cli/typecheck.md +0 -19
- package/dist/lib/agents/docs/guide/guide/advanced-types.md +0 -26
- package/dist/lib/agents/docs/guide/guide/agency-config-file.md +0 -212
- package/dist/lib/agents/docs/guide/guide/agency-packages.md +0 -54
- package/dist/lib/agents/docs/guide/guide/agency-stdlib.md +0 -14
- package/dist/lib/agents/docs/guide/guide/agency-vs-typescript.md +0 -33
- package/dist/lib/agents/docs/guide/guide/attachments.md +0 -56
- package/dist/lib/agents/docs/guide/guide/basic-syntax.md +0 -350
- package/dist/lib/agents/docs/guide/guide/blocks.md +0 -134
- package/dist/lib/agents/docs/guide/guide/build-integration.md +0 -99
- package/dist/lib/agents/docs/guide/guide/builtins.md +0 -84
- package/dist/lib/agents/docs/guide/guide/callbacks.md +0 -169
- package/dist/lib/agents/docs/guide/guide/checkpointing.md +0 -101
- package/dist/lib/agents/docs/guide/guide/cli-args.md +0 -190
- package/dist/lib/agents/docs/guide/guide/common-functions.md +0 -36
- package/dist/lib/agents/docs/guide/guide/compiling-and-running.md +0 -62
- package/dist/lib/agents/docs/guide/guide/concurrency.md +0 -108
- package/dist/lib/agents/docs/guide/guide/cross-thread-context.md +0 -226
- package/dist/lib/agents/docs/guide/guide/custom-providers.md +0 -195
- package/dist/lib/agents/docs/guide/guide/debugging.md +0 -67
- package/dist/lib/agents/docs/guide/guide/developer-tools.md +0 -90
- package/dist/lib/agents/docs/guide/guide/effects-and-raises.md +0 -137
- package/dist/lib/agents/docs/guide/guide/effects.md +0 -100
- package/dist/lib/agents/docs/guide/guide/error-handling.md +0 -161
- package/dist/lib/agents/docs/guide/guide/exercise-1.md +0 -32
- package/dist/lib/agents/docs/guide/guide/functions.md +0 -94
- package/dist/lib/agents/docs/guide/guide/getting-started.md +0 -35
- package/dist/lib/agents/docs/guide/guide/global-var-initialization.md +0 -70
- package/dist/lib/agents/docs/guide/guide/global-vs-static.md +0 -76
- package/dist/lib/agents/docs/guide/guide/guards.md +0 -134
- package/dist/lib/agents/docs/guide/guide/handlers.md +0 -196
- package/dist/lib/agents/docs/guide/guide/image-generation.md +0 -113
- package/dist/lib/agents/docs/guide/guide/imports-and-packages.md +0 -100
- package/dist/lib/agents/docs/guide/guide/interrupts-from-typescript.md +0 -84
- package/dist/lib/agents/docs/guide/guide/interrupts-part-2.md +0 -54
- package/dist/lib/agents/docs/guide/guide/interrupts.md +0 -139
- package/dist/lib/agents/docs/guide/guide/llm-part-2.md +0 -111
- package/dist/lib/agents/docs/guide/guide/llm.md +0 -109
- package/dist/lib/agents/docs/guide/guide/mcp.md +0 -295
- package/dist/lib/agents/docs/guide/guide/memory.md +0 -401
- package/dist/lib/agents/docs/guide/guide/message-threads.md +0 -111
- package/dist/lib/agents/docs/guide/guide/nodes.md +0 -50
- package/dist/lib/agents/docs/guide/guide/observability.md +0 -99
- package/dist/lib/agents/docs/guide/guide/partial-application.md +0 -96
- package/dist/lib/agents/docs/guide/guide/pattern-matching.md +0 -366
- package/dist/lib/agents/docs/guide/guide/policies.md +0 -67
- package/dist/lib/agents/docs/guide/guide/schema-parameter-injection.md +0 -101
- package/dist/lib/agents/docs/guide/guide/schemas.md +0 -99
- package/dist/lib/agents/docs/guide/guide/serving.md +0 -165
- package/dist/lib/agents/docs/guide/guide/state-isolation.md +0 -139
- package/dist/lib/agents/docs/guide/guide/streaming.md +0 -28
- package/dist/lib/agents/docs/guide/guide/tags.md +0 -72
- package/dist/lib/agents/docs/guide/guide/testing.md +0 -187
- package/dist/lib/agents/docs/guide/guide/troubleshooting.md +0 -86
- package/dist/lib/agents/docs/guide/guide/ts-helpers.md +0 -559
- package/dist/lib/agents/docs/guide/guide/ts-interop.md +0 -72
- package/dist/lib/agents/docs/guide/guide/type-validation.md +0 -187
- package/dist/lib/agents/docs/guide/guide/types.md +0 -181
- package/dist/lib/agents/docs/guide/guide/unused.md +0 -178
- package/dist/lib/agents/docs/guide/guide/unused2.md +0 -258
- package/dist/lib/agents/docs/guide/guide/value-parameterized-types.md +0 -186
- package/dist/lib/agents/docs/guide/guide/vscode-extension.md +0 -33
- package/dist/lib/agents/docs/guide/guide/why-agency.md +0 -323
- package/dist/lib/preprocessors/typescriptPreprocessor.config.test.js +0 -327
- package/stdlib/browser.js +0 -421
- package/stdlib/chart.js +0 -983
- package/stdlib/cli.js +0 -1116
- package/stdlib/email.js +0 -1104
- package/stdlib/imessage.js +0 -377
- package/stdlib/keyring.js +0 -803
- package/stdlib/layout.js +0 -3657
- package/stdlib/oauth.js +0 -862
- package/stdlib/schemas.js +0 -223
- package/stdlib/search.js +0 -629
- package/stdlib/sms.js +0 -419
- package/stdlib/table.js +0 -1419
- package/stdlib/threads.js +0 -1041
- package/stdlib/types.js +0 -222
- package/stdlib/validators.js +0 -1606
- /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)
|