@pattern-js/mod-agents 0.2.0
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/LICENSE +21 -0
- package/README.md +41 -0
- package/dist/boundaries.d.ts +21 -0
- package/dist/boundaries.d.ts.map +1 -0
- package/dist/boundaries.js +71 -0
- package/dist/boundaries.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/mod.d.ts +10 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +37 -0
- package/dist/mod.js.map +1 -0
- package/dist/ops.d.ts +10 -0
- package/dist/ops.d.ts.map +1 -0
- package/dist/ops.js +110 -0
- package/dist/ops.js.map +1 -0
- package/dist/service.d.ts +28 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +81 -0
- package/dist/service.js.map +1 -0
- package/dist/types.d.ts +175 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +126 -0
- package/dist/types.js.map +1 -0
- package/dist/well-known.d.ts +52 -0
- package/dist/well-known.d.ts.map +1 -0
- package/dist/well-known.js +27 -0
- package/dist/well-known.js.map +1 -0
- package/docs/guides/authoring-tools.md +99 -0
- package/docs/index.md +122 -0
- package/docs/ops/agents.guardrail.md +5 -0
- package/docs/ops/agents.tools.merge.md +5 -0
- package/docs/ops/agents.tools.ops.md +4 -0
- package/docs/ops/agents.tools.workflows.md +3 -0
- package/docs/ops/boundary.tool.md +5 -0
- package/docs/ops/boundary.tool.return.md +1 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pattern contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @pattern-js/mod-agents
|
|
2
|
+
|
|
3
|
+
The **neutral** agents contracts layer for [Pattern](../../README.md) — plain-JSON
|
|
4
|
+
agent/tool/guardrail descriptors and the modality-agnostic turn event protocol,
|
|
5
|
+
with **no SDK dependency**. Provider mods reify the descriptors; apps consume the
|
|
6
|
+
events. Neither has to know about the other.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @pattern-js/mod-agents
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## When to use
|
|
13
|
+
|
|
14
|
+
Install it whenever you want agents in your app — but never *alone*. It
|
|
15
|
+
contributes the `boundary.tool` pair, the toolset/guardrail ops, and the live
|
|
16
|
+
tool registry (`AGENTS_SERVICE`); it does **not** run an agent. Pair it with a
|
|
17
|
+
provider (`@pattern-js/mod-agents-openai`) that reifies the descriptors and emits
|
|
18
|
+
the turn events.
|
|
19
|
+
|
|
20
|
+
**When not:** a single model call with no tools, no agent loop, and no streaming
|
|
21
|
+
turn events — a provider op straight from the canvas is lighter than the agents
|
|
22
|
+
stack.
|
|
23
|
+
|
|
24
|
+
## Prerequisites
|
|
25
|
+
|
|
26
|
+
Always ship it with a provider. Usually also `@pattern-js/mod-store` (history +
|
|
27
|
+
blobs) and `@pattern-js/mod-vault` (the API key).
|
|
28
|
+
|
|
29
|
+
## Config
|
|
30
|
+
|
|
31
|
+
The contracts always ship paired with a provider — add both as strings in
|
|
32
|
+
`pattern.config.json`:
|
|
33
|
+
|
|
34
|
+
```jsonc
|
|
35
|
+
{ "mods": ["@pattern-js/mod-agents", "@pattern-js/mod-agents-openai"] }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For options, export a local wrapper mod that calls the `agentsMod({...})` factory.
|
|
39
|
+
|
|
40
|
+
Full documentation: the **Agents (contracts)** chapter at `/docs` (served by
|
|
41
|
+
`@pattern-js/mod-docs`), or [the source](docs/index.md).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — the boundary.tool pair.
|
|
3
|
+
*
|
|
4
|
+
* A tool is a WORKFLOW that starts with `boundary.tool` (name, description,
|
|
5
|
+
* params as JSON Schema — the SchemaBuilder UI in the editor) and ends with
|
|
6
|
+
* `boundary.tool.return`. That one shape buys, for free:
|
|
7
|
+
*
|
|
8
|
+
* - engine-side argument validation (`validate: true` → TriggerInputError
|
|
9
|
+
* before the body runs — an LLM's malformed args never reach your graph),
|
|
10
|
+
* - discovery (the registry scans for these triggers, like hook listeners),
|
|
11
|
+
* - run linkage (each call is a ctx.invoke sub-run: ↳ links + sampled I/O —
|
|
12
|
+
* the Runs page is the agent debugger).
|
|
13
|
+
*
|
|
14
|
+
* Guardrails reuse the SAME pair by convention: a guardrail is a tool
|
|
15
|
+
* workflow whose result is `{ tripwire: boolean, info?: unknown }`.
|
|
16
|
+
*/
|
|
17
|
+
import { type OpDefinition } from "@pattern-js/core";
|
|
18
|
+
export declare const toolTrigger: OpDefinition;
|
|
19
|
+
export declare const toolReturn: OpDefinition;
|
|
20
|
+
export declare const agentBoundaryOps: OpDefinition[];
|
|
21
|
+
//# sourceMappingURL=boundaries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundaries.d.ts","sourceRoot":"","sources":["../src/boundaries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAML,KAAK,YAAY,EAElB,MAAM,kBAAkB,CAAC;AAI1B,eAAO,MAAM,WAAW,EAAE,YAwCzB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,YAUxB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,YAAY,EAA8B,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — the boundary.tool pair.
|
|
3
|
+
*
|
|
4
|
+
* A tool is a WORKFLOW that starts with `boundary.tool` (name, description,
|
|
5
|
+
* params as JSON Schema — the SchemaBuilder UI in the editor) and ends with
|
|
6
|
+
* `boundary.tool.return`. That one shape buys, for free:
|
|
7
|
+
*
|
|
8
|
+
* - engine-side argument validation (`validate: true` → TriggerInputError
|
|
9
|
+
* before the body runs — an LLM's malformed args never reach your graph),
|
|
10
|
+
* - discovery (the registry scans for these triggers, like hook listeners),
|
|
11
|
+
* - run linkage (each call is a ctx.invoke sub-run: ↳ links + sampled I/O —
|
|
12
|
+
* the Runs page is the agent debugger).
|
|
13
|
+
*
|
|
14
|
+
* Guardrails reuse the SAME pair by convention: a guardrail is a tool
|
|
15
|
+
* workflow whose result is `{ tripwire: boolean, info?: unknown }`.
|
|
16
|
+
*/
|
|
17
|
+
import { jsonSchemaToZod, required, userInputSchema, value, z, } from "@pattern-js/core";
|
|
18
|
+
const jsonSchema = z.record(z.string(), z.unknown());
|
|
19
|
+
export const toolTrigger = {
|
|
20
|
+
type: "boundary.tool",
|
|
21
|
+
title: "boundary.tool",
|
|
22
|
+
description: "Declares this workflow as an agent-callable tool. config: { name, description, params (JSON Schema) }. " +
|
|
23
|
+
"Outputs { args (validated), user }.",
|
|
24
|
+
boundary: "trigger",
|
|
25
|
+
pair: "boundary.tool.return",
|
|
26
|
+
inputs: {},
|
|
27
|
+
// Wire a core.schema.define node into `params` and the resolve phase
|
|
28
|
+
// freezes it — same trick as http.request's body/query/params.
|
|
29
|
+
configInputs: {
|
|
30
|
+
name: value(z.string()),
|
|
31
|
+
description: value(z.string()),
|
|
32
|
+
params: value(jsonSchema),
|
|
33
|
+
},
|
|
34
|
+
outputs: (config) => ({
|
|
35
|
+
args: config.params
|
|
36
|
+
? value(jsonSchemaToZod(config.params), { validate: true })
|
|
37
|
+
: value(z.record(z.string(), z.unknown())),
|
|
38
|
+
user: value(userInputSchema),
|
|
39
|
+
}),
|
|
40
|
+
config: z.object({
|
|
41
|
+
/** Tool name the model sees (unique per app; snake_case reads best). */
|
|
42
|
+
name: z.string().min(1),
|
|
43
|
+
/** What the model reads to decide when to call this tool. */
|
|
44
|
+
description: z.string().optional(),
|
|
45
|
+
/** JSON Schema for the arguments (engine-validated on every call). */
|
|
46
|
+
params: jsonSchema.optional(),
|
|
47
|
+
/** Pause for human approval before each call (HITL). */
|
|
48
|
+
needsApproval: z.boolean().optional(),
|
|
49
|
+
/**
|
|
50
|
+
* Reserve this tool for use as a GUARDRAIL (or other by-name invocation)
|
|
51
|
+
* only — it's still resolvable via `agents.guardrail`, but the default
|
|
52
|
+
* `agents.tools.workflows` toolset leaves it out, so the model is never
|
|
53
|
+
* offered it as a callable tool. Name it explicitly to include it anyway.
|
|
54
|
+
*/
|
|
55
|
+
guardrail: z.boolean().optional(),
|
|
56
|
+
}),
|
|
57
|
+
execute: () => ({}),
|
|
58
|
+
};
|
|
59
|
+
export const toolReturn = {
|
|
60
|
+
type: "boundary.tool.return",
|
|
61
|
+
title: "boundary.tool.return",
|
|
62
|
+
description: "Tool out-gate: { result } goes back to the calling agent as the tool's output.",
|
|
63
|
+
boundary: "outgate",
|
|
64
|
+
pair: "boundary.tool",
|
|
65
|
+
reusable: false,
|
|
66
|
+
inputs: { result: required() },
|
|
67
|
+
outputs: {},
|
|
68
|
+
execute: async (ctx) => ({ result: await ctx.input.value("result") }),
|
|
69
|
+
};
|
|
70
|
+
export const agentBoundaryOps = [toolTrigger, toolReturn];
|
|
71
|
+
//# sourceMappingURL=boundaries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundaries.js","sourceRoot":"","sources":["../src/boundaries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,eAAe,EACf,QAAQ,EACR,eAAe,EACf,KAAK,EACL,CAAC,GAGF,MAAM,kBAAkB,CAAC;AAE1B,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAErD,MAAM,CAAC,MAAM,WAAW,GAAiB;IACvC,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,eAAe;IACtB,WAAW,EACT,yGAAyG;QACzG,qCAAqC;IACvC,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,sBAAsB;IAC5B,MAAM,EAAE,EAAE;IACV,qEAAqE;IACrE,+DAA+D;IAC/D,YAAY,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACvB,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC9B,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC;KAC1B;IACD,OAAO,EAAE,CAAC,MAA4B,EAAS,EAAE,CAAC,CAAC;QACjD,IAAI,EAAE,MAAM,CAAC,MAAM;YACjB,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,MAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACpE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5C,IAAI,EAAE,KAAK,CAAC,eAAe,CAAC;KAC7B,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,wEAAwE;QACxE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACvB,6DAA6D;QAC7D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAClC,sEAAsE;QACtE,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE;QAC7B,wDAAwD;QACxD,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QACrC;;;;;WAKG;QACH,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KAClC,CAAC;IACF,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAiB;IACtC,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,sBAAsB;IAC7B,WAAW,EAAE,gFAAgF;IAC7F,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,eAAe;IACrB,QAAQ,EAAE,KAAK;IACf,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;IAC9B,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;CACtE,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAmB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** @pattern-js/mod-agents — public surface (the neutral agent contracts). */
|
|
2
|
+
export { agentsMod } from "./mod.js";
|
|
3
|
+
export { default } from "./mod.js";
|
|
4
|
+
export { AGENTS_SERVICE, agentsService, workflowToolRef, type AgentsService, type OpToolRegistration, type WorkflowToolRegistration, } from "./well-known.js";
|
|
5
|
+
export { AgentsRegistry } from "./service.js";
|
|
6
|
+
export { agentBoundaryOps, toolTrigger, toolReturn } from "./boundaries.js";
|
|
7
|
+
export { agentsOps } from "./ops.js";
|
|
8
|
+
export { agentSchema, guardrailSchema, historySchema, messagePartSchema, toolRefSchema, toolsetSchema, turnEventSchema, type AgentDescriptor, type GuardrailDescriptor, type History, type MessagePart, type ToolRef, type ToolsetDescriptor, type TurnEvent, type TurnStopReason, } from "./types.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EACL,cAAc,EACd,aAAa,EACb,eAAe,EACf,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EACL,WAAW,EACX,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACd,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** @pattern-js/mod-agents — public surface (the neutral agent contracts). */
|
|
2
|
+
export { agentsMod } from "./mod.js";
|
|
3
|
+
export { default } from "./mod.js";
|
|
4
|
+
export { AGENTS_SERVICE, agentsService, workflowToolRef, } from "./well-known.js";
|
|
5
|
+
export { AgentsRegistry } from "./service.js";
|
|
6
|
+
export { agentBoundaryOps, toolTrigger, toolReturn } from "./boundaries.js";
|
|
7
|
+
export { agentsOps } from "./ops.js";
|
|
8
|
+
export { agentSchema, guardrailSchema, historySchema, messagePartSchema, toolRefSchema, toolsetSchema, turnEventSchema, } from "./types.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EACL,cAAc,EACd,aAAa,EACb,eAAe,GAIhB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EACL,WAAW,EACX,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,GAShB,MAAM,YAAY,CAAC"}
|
package/dist/mod.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — the mod. Registers the boundary.tool pair, the
|
|
3
|
+
* neutral toolset/guardrail ops, and the live tool registry (AGENTS_SERVICE).
|
|
4
|
+
*/
|
|
5
|
+
import { type PatternMod } from "@pattern-js/core";
|
|
6
|
+
export declare function agentsMod(): PatternMod;
|
|
7
|
+
/** A ready-to-use agents-contracts mod (for `loadMods`/`engine.use`). */
|
|
8
|
+
declare const _default: PatternMod;
|
|
9
|
+
export default _default;
|
|
10
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAA0B,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAiB3E,wBAAgB,SAAS,IAAI,UAAU,CAUtC;AAED,yEAAyE;;AACzE,wBAA2B"}
|
package/dist/mod.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — the mod. Registers the boundary.tool pair, the
|
|
3
|
+
* neutral toolset/guardrail ops, and the live tool registry (AGENTS_SERVICE).
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { localFs, provideFilesystem } from "@pattern-js/runtime-node";
|
|
8
|
+
import { defineMod } from "@pattern-js/core";
|
|
9
|
+
import { agentBoundaryOps } from "./boundaries.js";
|
|
10
|
+
import { agentsOps } from "./ops.js";
|
|
11
|
+
import { AgentsRegistry } from "./service.js";
|
|
12
|
+
import { AGENTS_SERVICE } from "./well-known.js";
|
|
13
|
+
/** The packaged docs/ chapter (the `docs` contribution points at "agents-docs"). */
|
|
14
|
+
function packagedDocs(engine) {
|
|
15
|
+
try {
|
|
16
|
+
const dir = fileURLToPath(new URL("../docs", import.meta.url));
|
|
17
|
+
if (existsSync(dir))
|
|
18
|
+
provideFilesystem(engine, "agents-docs", localFs(dir));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
/* packaged without docs — the contribution is simply skipped */
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function agentsMod() {
|
|
25
|
+
return defineMod({
|
|
26
|
+
name: "@pattern-js/mod-agents",
|
|
27
|
+
docs: { filesystem: "agents-docs", title: "Agents", order: 50 },
|
|
28
|
+
ops: [...agentBoundaryOps, ...agentsOps],
|
|
29
|
+
setup: (engine) => {
|
|
30
|
+
packagedDocs(engine);
|
|
31
|
+
engine.provideService(AGENTS_SERVICE, new AgentsRegistry(engine));
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/** A ready-to-use agents-contracts mod (for `loadMods`/`engine.use`). */
|
|
36
|
+
export default agentsMod();
|
|
37
|
+
//# sourceMappingURL=mod.js.map
|
package/dist/mod.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,SAAS,EAAgC,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,oFAAoF;AACpF,SAAS,YAAY,CAAC,MAAc;IAClC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,IAAI,UAAU,CAAC,GAAG,CAAC;YAAE,iBAAiB,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9E,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;IAClE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,SAAS,CAAC;QACf,IAAI,EAAE,wBAAwB;QAC9B,IAAI,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;QAC/D,GAAG,EAAE,CAAC,GAAG,gBAAgB,EAAE,GAAG,SAAS,CAAC;QACxC,KAAK,EAAE,CAAC,MAAc,EAAE,EAAE;YACxB,YAAY,CAAC,MAAM,CAAC,CAAC;YACrB,MAAM,CAAC,cAAc,CAAC,cAAc,EAAE,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;QACpE,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,yEAAyE;AACzE,eAAe,SAAS,EAAE,CAAC"}
|
package/dist/ops.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — neutral ops (toolset plumbing + guardrail refs).
|
|
3
|
+
*
|
|
4
|
+
* Provider-independent nodes: pick workflow tools into a toolset, merge
|
|
5
|
+
* toolsets from several sources, wrap a tool workflow as a guardrail
|
|
6
|
+
* descriptor. The agent/run ops live in provider mods.
|
|
7
|
+
*/
|
|
8
|
+
import { type OpDefinition } from "@pattern-js/core";
|
|
9
|
+
export declare const agentsOps: OpDefinition[];
|
|
10
|
+
//# sourceMappingURL=ops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAmH/D,eAAO,MAAM,SAAS,EAAE,YAAY,EAAsD,CAAC"}
|
package/dist/ops.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — neutral ops (toolset plumbing + guardrail refs).
|
|
3
|
+
*
|
|
4
|
+
* Provider-independent nodes: pick workflow tools into a toolset, merge
|
|
5
|
+
* toolsets from several sources, wrap a tool workflow as a guardrail
|
|
6
|
+
* descriptor. The agent/run ops live in provider mods.
|
|
7
|
+
*/
|
|
8
|
+
import { value, z } from "@pattern-js/core";
|
|
9
|
+
import { agentsService, workflowToolRef } from "./well-known.js";
|
|
10
|
+
import { toolsetSchema } from "./types.js";
|
|
11
|
+
const toolsWorkflows = {
|
|
12
|
+
type: "agents.tools.workflows",
|
|
13
|
+
title: "agents.tools.workflows",
|
|
14
|
+
description: 'Collect boundary.tool workflows into a toolset. config.tools: tool names to include, or empty/["*"] for all.',
|
|
15
|
+
config: z.object({
|
|
16
|
+
/** Tool names to include; empty (or ["*"]) = every discovered tool. */
|
|
17
|
+
tools: z.array(z.string()).default([]),
|
|
18
|
+
}),
|
|
19
|
+
inputs: {},
|
|
20
|
+
outputs: { toolset: value(toolsetSchema) },
|
|
21
|
+
execute: (ctx) => {
|
|
22
|
+
const svc = agentsService(ctx);
|
|
23
|
+
const wanted = ctx.config.tools.filter((t) => t !== "*");
|
|
24
|
+
const all = svc.listWorkflowTools();
|
|
25
|
+
const picked = wanted.length === 0
|
|
26
|
+
? // Auto-pickup offers every tool to the model EXCEPT guardrail-only
|
|
27
|
+
// ones (a moderation classifier must not become a callable tool).
|
|
28
|
+
// Name one explicitly below to include it anyway.
|
|
29
|
+
all.filter((t) => !t.guardrail)
|
|
30
|
+
: wanted.map((name) => {
|
|
31
|
+
const reg = svc.getWorkflowTool(name);
|
|
32
|
+
if (!reg) {
|
|
33
|
+
const known = all.map((t) => t.name).join(", ") || "(none)";
|
|
34
|
+
throw new Error(`agents: no tool workflow named "${name}" — known tools: ${known}`);
|
|
35
|
+
}
|
|
36
|
+
return reg;
|
|
37
|
+
});
|
|
38
|
+
const toolset = { kind: "toolset", tools: picked.map(workflowToolRef) };
|
|
39
|
+
return { toolset };
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
const toolsOps = {
|
|
43
|
+
type: "agents.tools.ops",
|
|
44
|
+
title: "agents.tools.ops",
|
|
45
|
+
description: "Collect mod-contributed code tools into a toolset. config.tools: names to include, empty = all registered.",
|
|
46
|
+
config: z.object({ tools: z.array(z.string()).default([]) }),
|
|
47
|
+
inputs: {},
|
|
48
|
+
outputs: { toolset: value(toolsetSchema) },
|
|
49
|
+
execute: (ctx) => {
|
|
50
|
+
const svc = agentsService(ctx);
|
|
51
|
+
const wanted = ctx.config.tools;
|
|
52
|
+
const all = svc.listOpTools();
|
|
53
|
+
const picked = wanted.length === 0 ? all : all.filter((t) => wanted.includes(t.name));
|
|
54
|
+
const toolset = {
|
|
55
|
+
kind: "toolset",
|
|
56
|
+
tools: picked.map((t) => ({ origin: "op", name: t.name, needsApproval: t.needsApproval })),
|
|
57
|
+
};
|
|
58
|
+
return { toolset };
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
const toolsMerge = {
|
|
62
|
+
type: "agents.tools.merge",
|
|
63
|
+
title: "agents.tools.merge",
|
|
64
|
+
description: "Merge toolsets (workflow tools + MCP servers + op tools) into one. config.count sets the inputs.",
|
|
65
|
+
config: z.object({ count: z.number().int().min(2).max(8).default(2) }),
|
|
66
|
+
inputs: (config) => Object.fromEntries(Array.from({ length: config.count ?? 2 }, (_v, i) => [`tools${i}`, value(toolsetSchema)])),
|
|
67
|
+
outputs: { toolset: value(toolsetSchema) },
|
|
68
|
+
execute: async (ctx) => {
|
|
69
|
+
const count = ctx.config.count;
|
|
70
|
+
const sets = await Promise.all(Array.from({ length: count }, (_v, i) => ctx.input.has(`tools${i}`) ? ctx.input.value(`tools${i}`) : undefined));
|
|
71
|
+
const tools = sets.filter(Boolean).flatMap((s) => s.tools);
|
|
72
|
+
// De-dup by identity (a tool picked twice via different routes is once).
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
const deduped = tools.filter((t) => {
|
|
75
|
+
const key = JSON.stringify(t);
|
|
76
|
+
if (seen.has(key))
|
|
77
|
+
return false;
|
|
78
|
+
seen.add(key);
|
|
79
|
+
return true;
|
|
80
|
+
});
|
|
81
|
+
return { toolset: { kind: "toolset", tools: deduped } };
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
const guardrail = {
|
|
85
|
+
type: "agents.guardrail",
|
|
86
|
+
title: "agents.guardrail",
|
|
87
|
+
description: "Wrap a boundary.tool workflow (returning { tripwire, info? }) as an input or output guardrail.",
|
|
88
|
+
config: z.object({
|
|
89
|
+
/** The tool workflow's declared name. */
|
|
90
|
+
tool: z.string().min(1),
|
|
91
|
+
direction: z.enum(["input", "output"]).default("input"),
|
|
92
|
+
}),
|
|
93
|
+
inputs: {},
|
|
94
|
+
outputs: { guardrail: value() },
|
|
95
|
+
execute: (ctx) => {
|
|
96
|
+
const cfg = ctx.config;
|
|
97
|
+
const reg = agentsService(ctx).getWorkflowTool(cfg.tool);
|
|
98
|
+
if (!reg)
|
|
99
|
+
throw new Error(`agents: no tool workflow named "${cfg.tool}" to use as a guardrail`);
|
|
100
|
+
const descriptor = {
|
|
101
|
+
kind: "guardrail",
|
|
102
|
+
direction: cfg.direction,
|
|
103
|
+
workflowId: reg.workflowId,
|
|
104
|
+
name: reg.name,
|
|
105
|
+
};
|
|
106
|
+
return { guardrail: descriptor };
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
export const agentsOps = [toolsWorkflows, toolsOps, toolsMerge, guardrail];
|
|
110
|
+
//# sourceMappingURL=ops.js.map
|
package/dist/ops.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops.js","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — the registry implementation.
|
|
3
|
+
*
|
|
4
|
+
* Workflow tools are DISCOVERED, never registered by hand: the service scans
|
|
5
|
+
* the engine's workflow registry for `boundary.tool` triggers and keeps the
|
|
6
|
+
* index live via `onWorkflowsChanged` (the same pattern hook listeners use) —
|
|
7
|
+
* deploy a tool workflow from the admin and the next agent run sees it.
|
|
8
|
+
*/
|
|
9
|
+
import type { Engine } from "@pattern-js/core";
|
|
10
|
+
import type { AgentsService, OpToolRegistration, WorkflowToolRegistration } from "./well-known.js";
|
|
11
|
+
export declare class AgentsRegistry implements AgentsService {
|
|
12
|
+
private readonly engine;
|
|
13
|
+
private workflowTools;
|
|
14
|
+
private opTools;
|
|
15
|
+
private turns;
|
|
16
|
+
constructor(engine: Engine);
|
|
17
|
+
private rescan;
|
|
18
|
+
private index;
|
|
19
|
+
listWorkflowTools(): WorkflowToolRegistration[];
|
|
20
|
+
getWorkflowTool(name: string): WorkflowToolRegistration | undefined;
|
|
21
|
+
registerOpTool(reg: OpToolRegistration): void;
|
|
22
|
+
listOpTools(): OpToolRegistration[];
|
|
23
|
+
getOpTool(name: string): OpToolRegistration | undefined;
|
|
24
|
+
registerTurn(turnId: string, controller: AbortController): void;
|
|
25
|
+
releaseTurn(turnId: string): void;
|
|
26
|
+
abortTurn(turnId: string, reason?: unknown): boolean;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAY,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,wBAAwB,EACzB,MAAM,iBAAiB,CAAC;AAEzB,qBAAa,cAAe,YAAW,aAAa;IAKtC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,aAAa,CAA+C;IACpE,OAAO,CAAC,OAAO,CAAyC;IACxD,OAAO,CAAC,KAAK,CAAsC;gBAEtB,MAAM,EAAE,MAAM;IAK3C,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,KAAK;IA8Bb,iBAAiB,IAAI,wBAAwB,EAAE;IAI/C,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,wBAAwB,GAAG,SAAS;IAInE,cAAc,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI;IAO7C,WAAW,IAAI,kBAAkB,EAAE;IAInC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIvD,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI;IAI/D,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIjC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO;CAOrD"}
|
package/dist/service.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — the registry implementation.
|
|
3
|
+
*
|
|
4
|
+
* Workflow tools are DISCOVERED, never registered by hand: the service scans
|
|
5
|
+
* the engine's workflow registry for `boundary.tool` triggers and keeps the
|
|
6
|
+
* index live via `onWorkflowsChanged` (the same pattern hook listeners use) —
|
|
7
|
+
* deploy a tool workflow from the admin and the next agent run sees it.
|
|
8
|
+
*/
|
|
9
|
+
export class AgentsRegistry {
|
|
10
|
+
engine;
|
|
11
|
+
workflowTools = new Map();
|
|
12
|
+
opTools = new Map();
|
|
13
|
+
turns = new Map();
|
|
14
|
+
constructor(engine) {
|
|
15
|
+
this.engine = engine;
|
|
16
|
+
for (const wf of engine.workflows.list())
|
|
17
|
+
this.index(wf);
|
|
18
|
+
engine.onWorkflowsChanged(() => this.rescan());
|
|
19
|
+
}
|
|
20
|
+
rescan() {
|
|
21
|
+
this.workflowTools.clear();
|
|
22
|
+
for (const wf of this.engine.workflows.list())
|
|
23
|
+
this.index(wf);
|
|
24
|
+
}
|
|
25
|
+
index(workflow) {
|
|
26
|
+
for (const node of workflow.nodes) {
|
|
27
|
+
if (node.op !== "boundary.tool")
|
|
28
|
+
continue;
|
|
29
|
+
const cfg = (node.config ?? {});
|
|
30
|
+
if (!cfg.name)
|
|
31
|
+
continue;
|
|
32
|
+
const existing = this.workflowTools.get(cfg.name);
|
|
33
|
+
if (existing && existing.workflowId !== workflow.id) {
|
|
34
|
+
console.warn(`[pattern/mod-agents] tool name "${cfg.name}" is declared by both "${existing.workflowId}" and "${workflow.id}" — keeping the first`);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
this.workflowTools.set(cfg.name, {
|
|
38
|
+
workflowId: workflow.id,
|
|
39
|
+
nodeId: node.id,
|
|
40
|
+
name: cfg.name,
|
|
41
|
+
description: cfg.description,
|
|
42
|
+
params: cfg.params,
|
|
43
|
+
needsApproval: cfg.needsApproval,
|
|
44
|
+
guardrail: cfg.guardrail,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
listWorkflowTools() {
|
|
49
|
+
return [...this.workflowTools.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
50
|
+
}
|
|
51
|
+
getWorkflowTool(name) {
|
|
52
|
+
return this.workflowTools.get(name);
|
|
53
|
+
}
|
|
54
|
+
registerOpTool(reg) {
|
|
55
|
+
if (this.opTools.has(reg.name)) {
|
|
56
|
+
throw new Error(`[pattern/mod-agents] op tool "${reg.name}" is already registered`);
|
|
57
|
+
}
|
|
58
|
+
this.opTools.set(reg.name, reg);
|
|
59
|
+
}
|
|
60
|
+
listOpTools() {
|
|
61
|
+
return [...this.opTools.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
62
|
+
}
|
|
63
|
+
getOpTool(name) {
|
|
64
|
+
return this.opTools.get(name);
|
|
65
|
+
}
|
|
66
|
+
registerTurn(turnId, controller) {
|
|
67
|
+
this.turns.set(turnId, controller);
|
|
68
|
+
}
|
|
69
|
+
releaseTurn(turnId) {
|
|
70
|
+
this.turns.delete(turnId);
|
|
71
|
+
}
|
|
72
|
+
abortTurn(turnId, reason) {
|
|
73
|
+
const ctrl = this.turns.get(turnId);
|
|
74
|
+
if (!ctrl)
|
|
75
|
+
return false;
|
|
76
|
+
this.turns.delete(turnId);
|
|
77
|
+
ctrl.abort(reason ?? new Error("turn aborted"));
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — the neutral contracts.
|
|
3
|
+
*
|
|
4
|
+
* Two families of shapes, both PLAIN JSON (structured-cloneable: they flow on
|
|
5
|
+
* edges and may cross worker boundaries — provider SDK objects never do; a
|
|
6
|
+
* provider mod reifies descriptors into SDK instances at execute time):
|
|
7
|
+
*
|
|
8
|
+
* - **Descriptors** — what an agent/toolset/guardrail value IS on the canvas.
|
|
9
|
+
* - **Turn events** — the modality-agnostic stream a running agent emits
|
|
10
|
+
* (text deltas, tool activity, approval requests, a guaranteed terminal
|
|
11
|
+
* event). Chat UIs, stores and SSE responses all speak this one protocol;
|
|
12
|
+
* voice surfaces later consume the same stream (`audio.ref` is reserved).
|
|
13
|
+
*
|
|
14
|
+
* Message content is PARTS-based from day one (text | image_ref) — retrofitting
|
|
15
|
+
* parts into string messages is the painful version.
|
|
16
|
+
*/
|
|
17
|
+
import { z } from "@pattern-js/core";
|
|
18
|
+
export declare const messagePartSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
19
|
+
type: z.ZodLiteral<"text">;
|
|
20
|
+
text: z.ZodString;
|
|
21
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
22
|
+
type: z.ZodLiteral<"image_ref">;
|
|
23
|
+
blobId: z.ZodString;
|
|
24
|
+
mime: z.ZodOptional<z.ZodString>;
|
|
25
|
+
}, z.core.$strip>]>;
|
|
26
|
+
export type MessagePart = z.infer<typeof messagePartSchema>;
|
|
27
|
+
/**
|
|
28
|
+
* Conversation history: provider-shaped items, treated as OPAQUE by everything
|
|
29
|
+
* except the provider mod that produced them (pull from the store → agent run
|
|
30
|
+
* → push back). Keeping them opaque lets each provider use its native item
|
|
31
|
+
* format losslessly.
|
|
32
|
+
*/
|
|
33
|
+
export declare const historySchema: z.ZodArray<z.ZodUnknown>;
|
|
34
|
+
export type History = unknown[];
|
|
35
|
+
export declare const toolRefSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
36
|
+
origin: z.ZodLiteral<"workflow">;
|
|
37
|
+
workflowId: z.ZodString;
|
|
38
|
+
name: z.ZodString;
|
|
39
|
+
description: z.ZodOptional<z.ZodString>;
|
|
40
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
41
|
+
needsApproval: z.ZodOptional<z.ZodBoolean>;
|
|
42
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
43
|
+
origin: z.ZodLiteral<"mcp">;
|
|
44
|
+
transport: z.ZodEnum<{
|
|
45
|
+
http: "http";
|
|
46
|
+
stdio: "stdio";
|
|
47
|
+
}>;
|
|
48
|
+
url: z.ZodOptional<z.ZodString>;
|
|
49
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
50
|
+
command: z.ZodOptional<z.ZodString>;
|
|
51
|
+
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
52
|
+
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
53
|
+
serverLabel: z.ZodOptional<z.ZodString>;
|
|
54
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
55
|
+
origin: z.ZodLiteral<"op">;
|
|
56
|
+
name: z.ZodString;
|
|
57
|
+
needsApproval: z.ZodOptional<z.ZodBoolean>;
|
|
58
|
+
}, z.core.$strip>], "origin">;
|
|
59
|
+
export type ToolRef = z.infer<typeof toolRefSchema>;
|
|
60
|
+
export declare const toolsetSchema: z.ZodObject<{
|
|
61
|
+
kind: z.ZodLiteral<"toolset">;
|
|
62
|
+
tools: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
63
|
+
origin: z.ZodLiteral<"workflow">;
|
|
64
|
+
workflowId: z.ZodString;
|
|
65
|
+
name: z.ZodString;
|
|
66
|
+
description: z.ZodOptional<z.ZodString>;
|
|
67
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
68
|
+
needsApproval: z.ZodOptional<z.ZodBoolean>;
|
|
69
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
70
|
+
origin: z.ZodLiteral<"mcp">;
|
|
71
|
+
transport: z.ZodEnum<{
|
|
72
|
+
http: "http";
|
|
73
|
+
stdio: "stdio";
|
|
74
|
+
}>;
|
|
75
|
+
url: z.ZodOptional<z.ZodString>;
|
|
76
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
77
|
+
command: z.ZodOptional<z.ZodString>;
|
|
78
|
+
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
79
|
+
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
80
|
+
serverLabel: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
82
|
+
origin: z.ZodLiteral<"op">;
|
|
83
|
+
name: z.ZodString;
|
|
84
|
+
needsApproval: z.ZodOptional<z.ZodBoolean>;
|
|
85
|
+
}, z.core.$strip>], "origin">>;
|
|
86
|
+
}, z.core.$strip>;
|
|
87
|
+
export type ToolsetDescriptor = z.infer<typeof toolsetSchema>;
|
|
88
|
+
export declare const guardrailSchema: z.ZodObject<{
|
|
89
|
+
kind: z.ZodLiteral<"guardrail">;
|
|
90
|
+
direction: z.ZodEnum<{
|
|
91
|
+
input: "input";
|
|
92
|
+
output: "output";
|
|
93
|
+
}>;
|
|
94
|
+
workflowId: z.ZodString;
|
|
95
|
+
name: z.ZodString;
|
|
96
|
+
}, z.core.$strip>;
|
|
97
|
+
export type GuardrailDescriptor = z.infer<typeof guardrailSchema>;
|
|
98
|
+
export interface AgentDescriptor {
|
|
99
|
+
kind: "agent";
|
|
100
|
+
name: string;
|
|
101
|
+
instructions: string;
|
|
102
|
+
model?: string;
|
|
103
|
+
modelSettings?: Record<string, unknown>;
|
|
104
|
+
tools?: ToolsetDescriptor;
|
|
105
|
+
guardrails?: GuardrailDescriptor[];
|
|
106
|
+
/** Other agents this one may hand off to. */
|
|
107
|
+
handoffs?: AgentDescriptor[];
|
|
108
|
+
handoffDescription?: string;
|
|
109
|
+
/** JSON Schema for structured final output (provider-enforced). */
|
|
110
|
+
outputSchema?: Record<string, unknown>;
|
|
111
|
+
}
|
|
112
|
+
export declare const agentSchema: z.ZodType<AgentDescriptor>;
|
|
113
|
+
export declare const turnEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
114
|
+
type: z.ZodLiteral<"text.delta">;
|
|
115
|
+
delta: z.ZodString;
|
|
116
|
+
turnId: z.ZodString;
|
|
117
|
+
runId: z.ZodString;
|
|
118
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
119
|
+
type: z.ZodLiteral<"text.done">;
|
|
120
|
+
text: z.ZodString;
|
|
121
|
+
turnId: z.ZodString;
|
|
122
|
+
runId: z.ZodString;
|
|
123
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
124
|
+
type: z.ZodLiteral<"tool.activity">;
|
|
125
|
+
toolName: z.ZodString;
|
|
126
|
+
callId: z.ZodOptional<z.ZodString>;
|
|
127
|
+
phase: z.ZodEnum<{
|
|
128
|
+
error: "error";
|
|
129
|
+
start: "start";
|
|
130
|
+
done: "done";
|
|
131
|
+
}>;
|
|
132
|
+
args: z.ZodOptional<z.ZodUnknown>;
|
|
133
|
+
result: z.ZodOptional<z.ZodUnknown>;
|
|
134
|
+
error: z.ZodOptional<z.ZodString>;
|
|
135
|
+
subRunId: z.ZodOptional<z.ZodString>;
|
|
136
|
+
turnId: z.ZodString;
|
|
137
|
+
runId: z.ZodString;
|
|
138
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
139
|
+
type: z.ZodLiteral<"audio.ref">;
|
|
140
|
+
blobId: z.ZodString;
|
|
141
|
+
mime: z.ZodString;
|
|
142
|
+
turnId: z.ZodString;
|
|
143
|
+
runId: z.ZodString;
|
|
144
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
145
|
+
type: z.ZodLiteral<"approval.request">;
|
|
146
|
+
interruption: z.ZodObject<{
|
|
147
|
+
id: z.ZodString;
|
|
148
|
+
toolName: z.ZodString;
|
|
149
|
+
args: z.ZodUnknown;
|
|
150
|
+
}, z.core.$strip>;
|
|
151
|
+
stateToken: z.ZodString;
|
|
152
|
+
turnId: z.ZodString;
|
|
153
|
+
runId: z.ZodString;
|
|
154
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
155
|
+
type: z.ZodLiteral<"error">;
|
|
156
|
+
message: z.ZodString;
|
|
157
|
+
code: z.ZodOptional<z.ZodString>;
|
|
158
|
+
turnId: z.ZodString;
|
|
159
|
+
runId: z.ZodString;
|
|
160
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
161
|
+
type: z.ZodLiteral<"done">;
|
|
162
|
+
stopReason: z.ZodEnum<{
|
|
163
|
+
error: "error";
|
|
164
|
+
complete: "complete";
|
|
165
|
+
interrupted: "interrupted";
|
|
166
|
+
cancelled: "cancelled";
|
|
167
|
+
}>;
|
|
168
|
+
turnId: z.ZodString;
|
|
169
|
+
runId: z.ZodString;
|
|
170
|
+
}, z.core.$strip>], "type">;
|
|
171
|
+
export type TurnEvent = z.infer<typeof turnEventSchema>;
|
|
172
|
+
export type TurnStopReason = Extract<TurnEvent, {
|
|
173
|
+
type: "done";
|
|
174
|
+
}>["stopReason"];
|
|
175
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,kBAAkB,CAAC;AAIrC,eAAO,MAAM,iBAAiB;;;;;;;mBAQ5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D;;;;;GAKG;AACH,eAAO,MAAM,aAAa,0BAAuB,CAAC;AAClD,MAAM,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC;AAIhC,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;6BA2BxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGxB,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE9D,eAAO,MAAM,eAAe;;;;;;;;iBAM1B,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAElE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,UAAU,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACnC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,eAAO,MAAM,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe,CAapB,CAAC;AAMhC,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAoC1B,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,SAAS,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,YAAY,CAAC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — the neutral contracts.
|
|
3
|
+
*
|
|
4
|
+
* Two families of shapes, both PLAIN JSON (structured-cloneable: they flow on
|
|
5
|
+
* edges and may cross worker boundaries — provider SDK objects never do; a
|
|
6
|
+
* provider mod reifies descriptors into SDK instances at execute time):
|
|
7
|
+
*
|
|
8
|
+
* - **Descriptors** — what an agent/toolset/guardrail value IS on the canvas.
|
|
9
|
+
* - **Turn events** — the modality-agnostic stream a running agent emits
|
|
10
|
+
* (text deltas, tool activity, approval requests, a guaranteed terminal
|
|
11
|
+
* event). Chat UIs, stores and SSE responses all speak this one protocol;
|
|
12
|
+
* voice surfaces later consume the same stream (`audio.ref` is reserved).
|
|
13
|
+
*
|
|
14
|
+
* Message content is PARTS-based from day one (text | image_ref) — retrofitting
|
|
15
|
+
* parts into string messages is the painful version.
|
|
16
|
+
*/
|
|
17
|
+
import { z } from "@pattern-js/core";
|
|
18
|
+
/* ── message parts ─────────────────────────────────────────────────────── */
|
|
19
|
+
export const messagePartSchema = z.union([
|
|
20
|
+
z.object({ type: z.literal("text"), text: z.string() }),
|
|
21
|
+
z.object({
|
|
22
|
+
type: z.literal("image_ref"),
|
|
23
|
+
/** A blob id (mod-store) — providers inline it (e.g. base64 data URL). */
|
|
24
|
+
blobId: z.string(),
|
|
25
|
+
mime: z.string().optional(),
|
|
26
|
+
}),
|
|
27
|
+
]);
|
|
28
|
+
/**
|
|
29
|
+
* Conversation history: provider-shaped items, treated as OPAQUE by everything
|
|
30
|
+
* except the provider mod that produced them (pull from the store → agent run
|
|
31
|
+
* → push back). Keeping them opaque lets each provider use its native item
|
|
32
|
+
* format losslessly.
|
|
33
|
+
*/
|
|
34
|
+
export const historySchema = z.array(z.unknown());
|
|
35
|
+
/* ── descriptors ───────────────────────────────────────────────────────── */
|
|
36
|
+
export const toolRefSchema = z.discriminatedUnion("origin", [
|
|
37
|
+
z.object({
|
|
38
|
+
origin: z.literal("workflow"),
|
|
39
|
+
workflowId: z.string(),
|
|
40
|
+
name: z.string(),
|
|
41
|
+
description: z.string().optional(),
|
|
42
|
+
/** JSON Schema for the tool arguments (engine-enforced via boundary.tool). */
|
|
43
|
+
params: z.record(z.string(), z.unknown()).optional(),
|
|
44
|
+
/** Pause for human approval before each call (HITL). */
|
|
45
|
+
needsApproval: z.boolean().optional(),
|
|
46
|
+
}),
|
|
47
|
+
z.object({
|
|
48
|
+
origin: z.literal("mcp"),
|
|
49
|
+
transport: z.enum(["http", "stdio"]),
|
|
50
|
+
url: z.string().optional(),
|
|
51
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
52
|
+
command: z.string().optional(),
|
|
53
|
+
args: z.array(z.string()).optional(),
|
|
54
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
55
|
+
serverLabel: z.string().optional(),
|
|
56
|
+
}),
|
|
57
|
+
z.object({
|
|
58
|
+
origin: z.literal("op"),
|
|
59
|
+
/** Name in the AGENTS_SERVICE op-tool registry (mods register in setup). */
|
|
60
|
+
name: z.string(),
|
|
61
|
+
needsApproval: z.boolean().optional(),
|
|
62
|
+
}),
|
|
63
|
+
]);
|
|
64
|
+
export const toolsetSchema = z.object({
|
|
65
|
+
kind: z.literal("toolset"),
|
|
66
|
+
tools: z.array(toolRefSchema),
|
|
67
|
+
});
|
|
68
|
+
export const guardrailSchema = z.object({
|
|
69
|
+
kind: z.literal("guardrail"),
|
|
70
|
+
direction: z.enum(["input", "output"]),
|
|
71
|
+
/** A boundary.tool workflow returning { tripwire: boolean, info?: unknown }. */
|
|
72
|
+
workflowId: z.string(),
|
|
73
|
+
name: z.string(),
|
|
74
|
+
});
|
|
75
|
+
export const agentSchema = z.lazy(() => z.object({
|
|
76
|
+
kind: z.literal("agent"),
|
|
77
|
+
name: z.string(),
|
|
78
|
+
instructions: z.string(),
|
|
79
|
+
model: z.string().optional(),
|
|
80
|
+
modelSettings: z.record(z.string(), z.unknown()).optional(),
|
|
81
|
+
tools: toolsetSchema.optional(),
|
|
82
|
+
guardrails: z.array(guardrailSchema).optional(),
|
|
83
|
+
handoffs: z.array(agentSchema).optional(),
|
|
84
|
+
handoffDescription: z.string().optional(),
|
|
85
|
+
outputSchema: z.record(z.string(), z.unknown()).optional(),
|
|
86
|
+
}));
|
|
87
|
+
/* ── the turn event protocol ───────────────────────────────────────────── */
|
|
88
|
+
const base = { turnId: z.string(), runId: z.string() };
|
|
89
|
+
export const turnEventSchema = z.discriminatedUnion("type", [
|
|
90
|
+
/** Streaming text. */
|
|
91
|
+
z.object({ ...base, type: z.literal("text.delta"), delta: z.string() }),
|
|
92
|
+
/** A complete assistant message (also emitted after deltas). */
|
|
93
|
+
z.object({ ...base, type: z.literal("text.done"), text: z.string() }),
|
|
94
|
+
/** Tool lifecycle: start → done | error. Args/results may be elided/truncated. */
|
|
95
|
+
z.object({
|
|
96
|
+
...base,
|
|
97
|
+
type: z.literal("tool.activity"),
|
|
98
|
+
toolName: z.string(),
|
|
99
|
+
callId: z.string().optional(),
|
|
100
|
+
phase: z.enum(["start", "done", "error"]),
|
|
101
|
+
args: z.unknown().optional(),
|
|
102
|
+
result: z.unknown().optional(),
|
|
103
|
+
error: z.string().optional(),
|
|
104
|
+
/** Set when the tool ran as a linked sub-run (deep-link into the admin). */
|
|
105
|
+
subRunId: z.string().optional(),
|
|
106
|
+
}),
|
|
107
|
+
/** Reserved for the voice round: a chunk of audio parked as a blob. */
|
|
108
|
+
z.object({ ...base, type: z.literal("audio.ref"), blobId: z.string(), mime: z.string() }),
|
|
109
|
+
/** HITL: the turn paused awaiting approval; resume via the provider mod. */
|
|
110
|
+
z.object({
|
|
111
|
+
...base,
|
|
112
|
+
type: z.literal("approval.request"),
|
|
113
|
+
interruption: z.object({ id: z.string(), toolName: z.string(), args: z.unknown() }),
|
|
114
|
+
/** Opaque serialized run state — only the provider mod reads it. */
|
|
115
|
+
stateToken: z.string(),
|
|
116
|
+
}),
|
|
117
|
+
/** An error, as turn CONTENT (chat UIs render an inline card, not a toast). */
|
|
118
|
+
z.object({ ...base, type: z.literal("error"), message: z.string(), code: z.string().optional() }),
|
|
119
|
+
/** GUARANTEED terminal event — a consumer can always settle on `done`. */
|
|
120
|
+
z.object({
|
|
121
|
+
...base,
|
|
122
|
+
type: z.literal("done"),
|
|
123
|
+
stopReason: z.enum(["complete", "interrupted", "error", "cancelled"]),
|
|
124
|
+
}),
|
|
125
|
+
]);
|
|
126
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,kBAAkB,CAAC;AAErC,8EAA8E;AAE9E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC;IACvC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACvD,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;QAC5B,0EAA0E;QAC1E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC5B,CAAC;CACH,CAAC,CAAC;AAGH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAGlD,8EAA8E;AAE9E,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE;IAC1D,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QAC7B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;QACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAClC,8EAA8E;QAC9E,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;QACpD,wDAAwD;QACxD,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KACtC,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;QACxB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC1B,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;QACpD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC9B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;QACpC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;QAChD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KACnC,CAAC;IACF,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;QACvB,4EAA4E;QAC5E,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KACtC,CAAC;CACH,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;CAC9B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;IAC5B,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtC,gFAAgF;IAChF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;CACjB,CAAC,CAAC;AAkBH,MAAM,CAAC,MAAM,WAAW,GAA+B,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CACjE,CAAC,CAAC,MAAM,CAAC;IACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACxB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC3D,KAAK,EAAE,aAAa,CAAC,QAAQ,EAAE;IAC/B,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IAC/C,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE;IACzC,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACzC,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC3D,CAAC,CAC2B,CAAC;AAEhC,8EAA8E;AAE9E,MAAM,IAAI,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;AAEvD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAC1D,sBAAsB;IACtB,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACvE,gEAAgE;IAChE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACrE,kFAAkF;IAClF,CAAC,CAAC,MAAM,CAAC;QACP,GAAG,IAAI;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC;QAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;QACpB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC7B,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QACzC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC5B,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,4EAA4E;QAC5E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAChC,CAAC;IACF,uEAAuE;IACvE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACzF,4EAA4E;IAC5E,CAAC,CAAC,MAAM,CAAC;QACP,GAAG,IAAI;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC;QACnC,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QACnF,oEAAoE;QACpE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;KACvB,CAAC;IACF,+EAA+E;IAC/E,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;IACjG,0EAA0E;IAC1E,CAAC,CAAC,MAAM,CAAC;QACP,GAAG,IAAI;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;QACvB,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;KACtE,CAAC;CACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — the well-known service seam.
|
|
3
|
+
*
|
|
4
|
+
* Provider mods (mod-agents-openai…) and consumers (mod-chat) meet here:
|
|
5
|
+
* the tool registry lives on AGENTS_SERVICE; nobody imports a provider mod
|
|
6
|
+
* to find tools.
|
|
7
|
+
*/
|
|
8
|
+
import type { OpContext } from "@pattern-js/core";
|
|
9
|
+
import type { ToolRef } from "./types.js";
|
|
10
|
+
export declare const AGENTS_SERVICE = "agentsService";
|
|
11
|
+
/** A boundary.tool workflow discovered in the registry. */
|
|
12
|
+
export interface WorkflowToolRegistration {
|
|
13
|
+
workflowId: string;
|
|
14
|
+
nodeId: string;
|
|
15
|
+
name: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
params?: Record<string, unknown>;
|
|
18
|
+
needsApproval?: boolean;
|
|
19
|
+
/** Guardrail-only: resolvable by name, but excluded from the default toolset. */
|
|
20
|
+
guardrail?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** A code tool a mod contributes directly (registered in its `setup`). */
|
|
23
|
+
export interface OpToolRegistration {
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
/** JSON Schema for the arguments. */
|
|
27
|
+
params: Record<string, unknown>;
|
|
28
|
+
execute(args: Record<string, unknown>, ctx: OpContext): unknown | Promise<unknown>;
|
|
29
|
+
needsApproval?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface AgentsService {
|
|
32
|
+
/** Live view of every boundary.tool workflow (registered ⇄ discovered). */
|
|
33
|
+
listWorkflowTools(): WorkflowToolRegistration[];
|
|
34
|
+
getWorkflowTool(name: string): WorkflowToolRegistration | undefined;
|
|
35
|
+
/** Mods contribute ready-made tools here from their setup. */
|
|
36
|
+
registerOpTool(reg: OpToolRegistration): void;
|
|
37
|
+
listOpTools(): OpToolRegistration[];
|
|
38
|
+
getOpTool(name: string): OpToolRegistration | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Turn-scoped cancellation. A STREAMING run settles for the engine as soon
|
|
41
|
+
* as its out-gates capture (the SSE tail flows after), so engine.cancelRun
|
|
42
|
+
* can't reach an in-flight agent turn — providers register an
|
|
43
|
+
* AbortController per turnId instead, and a Stop button calls `abortTurn`.
|
|
44
|
+
*/
|
|
45
|
+
registerTurn(turnId: string, controller: AbortController): void;
|
|
46
|
+
releaseTurn(turnId: string): void;
|
|
47
|
+
abortTurn(turnId: string, reason?: unknown): boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare function agentsService(ctx: OpContext): AgentsService;
|
|
50
|
+
/** ToolRef for a workflow tool registration (what flows on toolset edges). */
|
|
51
|
+
export declare function workflowToolRef(reg: WorkflowToolRegistration): ToolRef;
|
|
52
|
+
//# sourceMappingURL=well-known.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"well-known.d.ts","sourceRoot":"","sources":["../src/well-known.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAE9C,2DAA2D;AAC3D,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,0EAA0E;AAC1E,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnF,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,iBAAiB,IAAI,wBAAwB,EAAE,CAAC;IAChD,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,wBAAwB,GAAG,SAAS,CAAC;IACpE,8DAA8D;IAC9D,cAAc,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC9C,WAAW,IAAI,kBAAkB,EAAE,CAAC;IACpC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAAC;IACxD;;;;;OAKG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IAChE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CACtD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,GAAG,aAAa,CAQ3D;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,GAAG,EAAE,wBAAwB,GAAG,OAAO,CAStE"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-agents — the well-known service seam.
|
|
3
|
+
*
|
|
4
|
+
* Provider mods (mod-agents-openai…) and consumers (mod-chat) meet here:
|
|
5
|
+
* the tool registry lives on AGENTS_SERVICE; nobody imports a provider mod
|
|
6
|
+
* to find tools.
|
|
7
|
+
*/
|
|
8
|
+
export const AGENTS_SERVICE = "agentsService";
|
|
9
|
+
export function agentsService(ctx) {
|
|
10
|
+
const svc = ctx.services[AGENTS_SERVICE];
|
|
11
|
+
if (!svc) {
|
|
12
|
+
throw new Error('agent ops need @pattern-js/mod-agents installed — add "@pattern-js/mod-agents" to your pattern.config.json mods');
|
|
13
|
+
}
|
|
14
|
+
return svc;
|
|
15
|
+
}
|
|
16
|
+
/** ToolRef for a workflow tool registration (what flows on toolset edges). */
|
|
17
|
+
export function workflowToolRef(reg) {
|
|
18
|
+
return {
|
|
19
|
+
origin: "workflow",
|
|
20
|
+
workflowId: reg.workflowId,
|
|
21
|
+
name: reg.name,
|
|
22
|
+
description: reg.description,
|
|
23
|
+
params: reg.params,
|
|
24
|
+
needsApproval: reg.needsApproval,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=well-known.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"well-known.js","sourceRoot":"","sources":["../src/well-known.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,CAAC;AA2C9C,MAAM,UAAU,aAAa,CAAC,GAAc;IAC1C,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,cAAc,CAA8B,CAAC;IACtE,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,iHAAiH,CAClH,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,eAAe,CAAC,GAA6B;IAC3D,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,aAAa,EAAE,GAAG,CAAC,aAAa;KACjC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Authoring tools
|
|
3
|
+
order: 10
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Authoring agent tools
|
|
7
|
+
|
|
8
|
+
A tool is just a workflow with a `boundary.tool` trigger and a
|
|
9
|
+
`boundary.tool.return` out-gate. Reach for one whenever the model needs to
|
|
10
|
+
*do* something — look data up, call an API, change state — rather than only
|
|
11
|
+
talk. Three things make it a good tool.
|
|
12
|
+
|
|
13
|
+
## 1. A tight schema
|
|
14
|
+
|
|
15
|
+
The trigger's `params` is a JSON Schema the **engine validates** before your
|
|
16
|
+
graph runs — the model's arguments are checked at the door, so a hallucinated
|
|
17
|
+
shape becomes a clean `TriggerInputError`, never a malformed value deep in
|
|
18
|
+
your logic. Be specific: required fields, enums, and descriptions (the model
|
|
19
|
+
reads them to decide *when* and *how* to call).
|
|
20
|
+
|
|
21
|
+
```jsonc
|
|
22
|
+
// workflows/tool-weather.json
|
|
23
|
+
{ "id": "tool-weather",
|
|
24
|
+
"nodes": [
|
|
25
|
+
{ "id": "in", "op": "boundary.tool",
|
|
26
|
+
"config": {
|
|
27
|
+
"name": "get_weather",
|
|
28
|
+
"description": "Current weather for a city.",
|
|
29
|
+
"params": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"properties": { "city": { "type": "string", "description": "City name, e.g. \"Lyon\"" } },
|
|
32
|
+
"required": ["city"] } } },
|
|
33
|
+
{ "id": "fetch", "op": "…your graph…", "comment": "call the weather API" },
|
|
34
|
+
{ "id": "out", "op": "boundary.tool.return" } ],
|
|
35
|
+
"edges": [
|
|
36
|
+
{ "from": { "node": "in", "port": "args" }, "to": { "node": "fetch", "port": "in" } },
|
|
37
|
+
{ "from": { "node": "fetch", "port": "result" }, "to": { "node": "out", "port": "result" } } ] }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The trigger outputs `args` (validated against your schema) and `user` (the
|
|
41
|
+
calling principal). In the editor, `params` is a visual SchemaBuilder.
|
|
42
|
+
|
|
43
|
+
## 2. A real return
|
|
44
|
+
|
|
45
|
+
Wire your result into `boundary.tool.return`'s `result` — that's exactly what
|
|
46
|
+
the model sees. Keep it small and structured; the model pays attention tokens
|
|
47
|
+
for every field. A weather tool returns `{ tempC, summary }`, not the raw API
|
|
48
|
+
envelope. `boundary.tool.return` is the only legal terminal for a tool
|
|
49
|
+
workflow, so every branch must converge on it.
|
|
50
|
+
|
|
51
|
+
## 3. It's debuggable for free
|
|
52
|
+
|
|
53
|
+
Every tool call runs as a **linked sub-run** (`ctx.invoke`). Open the agent's
|
|
54
|
+
run in the admin and each invocation is a child run (↳) with its own node
|
|
55
|
+
waterfall and sampled I/O — you see exactly what the model passed and what
|
|
56
|
+
came back. No print-debugging an opaque function.
|
|
57
|
+
|
|
58
|
+
## Three origins — and when to choose each
|
|
59
|
+
|
|
60
|
+
- **Workflow tools** — what we just built; `agents.tools.workflows` collects
|
|
61
|
+
every `boundary.tool` in the app (or a named subset). The default: visible,
|
|
62
|
+
debuggable, yours. With no names it auto-includes everything *except*
|
|
63
|
+
guardrail-only tools.
|
|
64
|
+
- **MCP servers** — `agents.mcp.server` exposes an existing MCP server's tools
|
|
65
|
+
(HTTP or stdio, pooled per process). Choose this to borrow tools you don't
|
|
66
|
+
want to re-implement.
|
|
67
|
+
- **Op tools** — a mod registers plain-function tools in its setup
|
|
68
|
+
(`AGENTS_SERVICE.registerOpTool`), picked by `agents.tools.ops`. Choose this
|
|
69
|
+
for tools a mod ships as code rather than a visible workflow.
|
|
70
|
+
|
|
71
|
+
Merge any combination with `agents.tools.merge` (config `count` = how many
|
|
72
|
+
toolset inputs) and wire the result into `agents.agent`'s `tools` input.
|
|
73
|
+
|
|
74
|
+
## Gating a tool behind approval (HITL)
|
|
75
|
+
|
|
76
|
+
Set `needsApproval: true` on the `boundary.tool` config and the agent pauses
|
|
77
|
+
before the call, emitting an `approval.request` (with an opaque resume
|
|
78
|
+
`stateToken`). The chat app turns that into Approve/Deny buttons;
|
|
79
|
+
`agents.run.resume` continues the **same** turn with the decision. Use it for
|
|
80
|
+
tools with side effects — sending mail, spending money, deleting rows.
|
|
81
|
+
|
|
82
|
+
## Authoring a guardrail
|
|
83
|
+
|
|
84
|
+
A guardrail reuses the **same** `boundary.tool` pair: a tool workflow whose
|
|
85
|
+
`result` is `{ tripwire: boolean, info? }`. The provider calls it as an input
|
|
86
|
+
or output guardrail (a linked sub-run, like any tool), and a `tripwire: true`
|
|
87
|
+
ends the turn cleanly with an inline card.
|
|
88
|
+
|
|
89
|
+
1. Author the classifier as a `boundary.tool` workflow. Mark it
|
|
90
|
+
`guardrail: true` so `agents.tools.workflows` leaves it **out** of the
|
|
91
|
+
model's callable toolbox — a moderation classifier must not become a tool
|
|
92
|
+
the model can invoke.
|
|
93
|
+
2. Wrap it with `agents.guardrail` (config: `tool` = the workflow's name,
|
|
94
|
+
`direction` = `input` | `output`).
|
|
95
|
+
3. Wire the descriptor into `agents.agent`'s `guardrails` input (one or an
|
|
96
|
+
array).
|
|
97
|
+
|
|
98
|
+
Input guardrails vet the user's message before the model sees it; output
|
|
99
|
+
guardrails vet the model's answer before it reaches the user.
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Agents (contracts)
|
|
2
|
+
|
|
3
|
+
`@pattern-js/mod-agents` is the **neutral** agents layer — plain-JSON
|
|
4
|
+
descriptors and the turn event protocol, with no SDK dependency. Provider
|
|
5
|
+
mods (like `@pattern-js/mod-agents-openai`) reify the descriptors into running
|
|
6
|
+
agents; apps (like `@pattern-js/mod-chat`) consume the events. Neither has to
|
|
7
|
+
know about the other.
|
|
8
|
+
|
|
9
|
+
## When to use
|
|
10
|
+
|
|
11
|
+
Install this whenever you want agents in your app — but you never install it
|
|
12
|
+
*alone*. It contributes the `boundary.tool` pair, the toolset/guardrail ops,
|
|
13
|
+
and the live tool registry (`AGENTS_SERVICE`); it does **not** run an agent.
|
|
14
|
+
Pair it with a provider (`@pattern-js/mod-agents-openai`) for `agents.agent` /
|
|
15
|
+
`agents.run`, and usually with `@pattern-js/mod-store` (history + blobs) and
|
|
16
|
+
`@pattern-js/mod-vault` (the API key).
|
|
17
|
+
|
|
18
|
+
**When not:** if all you need is a single model call with no tools, no agent
|
|
19
|
+
loop, and no streaming turn events, a provider op straight from the canvas is
|
|
20
|
+
lighter than the agents stack. The agents layer earns its keep the moment
|
|
21
|
+
there are tools, handoffs, guardrails, or a live transcript.
|
|
22
|
+
|
|
23
|
+
```jsonc
|
|
24
|
+
// pattern.config.json — the contracts always ship with a provider
|
|
25
|
+
{ "mods": ["@pattern-js/mod-agents", "@pattern-js/mod-agents-openai"] }
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Tools are workflows
|
|
29
|
+
|
|
30
|
+
A tool is a **workflow** that starts with a `boundary.tool` trigger and ends
|
|
31
|
+
with `boundary.tool.return`. The trigger's config carries the `name` and
|
|
32
|
+
`description` the model reads, plus a JSON-Schema `params` the **engine**
|
|
33
|
+
validates before your graph runs — a model's hallucinated args become a clean
|
|
34
|
+
`TriggerInputError` at the door, never a malformed value deep in your logic.
|
|
35
|
+
That one shape also buys discovery (the registry scans for these triggers,
|
|
36
|
+
live) and debugging: every call is a **linked sub-run** (↳ in the Runs page,
|
|
37
|
+
with sampled I/O), so the admin's run view is your agent debugger.
|
|
38
|
+
|
|
39
|
+
### Three tool origins — and when to choose each
|
|
40
|
+
|
|
41
|
+
| origin | op | reach for it when |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| **workflow** | `agents.tools.workflows` | the tool is your own logic, and you want it visible/debuggable on the canvas (the default — drop a `boundary.tool` workflow in the app and every agent picks it up). |
|
|
44
|
+
| **MCP server** | `agents.mcp.server` (provider mod) | you want to expose an existing MCP server's tools (HTTP or stdio) without re-implementing them. |
|
|
45
|
+
| **op (code)** | `agents.tools.ops` | a mod ships a ready-made tool as a plain function (registered via `AGENTS_SERVICE.registerOpTool` in setup) rather than a visible workflow. |
|
|
46
|
+
|
|
47
|
+
`agents.tools.workflows` with no names auto-collects every `boundary.tool` in
|
|
48
|
+
the app **except** guardrail-only ones (`guardrail: true` on the trigger keeps
|
|
49
|
+
a moderation classifier from becoming a callable tool — name it explicitly to
|
|
50
|
+
include it anyway). Combine any origins with `agents.tools.merge` (config
|
|
51
|
+
`count` sets the input ports) and wire the result into `agents.agent`'s
|
|
52
|
+
`tools` input.
|
|
53
|
+
|
|
54
|
+
## Guardrails reuse the tool shape
|
|
55
|
+
|
|
56
|
+
A guardrail is the same `boundary.tool` pair by convention — a tool workflow
|
|
57
|
+
whose `result` is `{ tripwire: boolean, info? }`. `agents.guardrail` wraps a
|
|
58
|
+
named tool workflow as an `input` or `output` guardrail descriptor; input
|
|
59
|
+
guardrails vet the user's message before the model sees it, output guardrails
|
|
60
|
+
vet the answer. A trip surfaces as an inline error card in the chat and the
|
|
61
|
+
turn ends cleanly with the reason — never a crash. Mark the underlying tool
|
|
62
|
+
`guardrail: true` so it stays out of the model's callable toolbox.
|
|
63
|
+
|
|
64
|
+
## The turn event protocol
|
|
65
|
+
|
|
66
|
+
A running agent emits one **modality-agnostic** stream that every surface
|
|
67
|
+
speaks — SSE responses, the chat's persisted log, future voice surfaces:
|
|
68
|
+
|
|
69
|
+
- `text.delta` / `text.done` — streaming text, then the settled message.
|
|
70
|
+
- `tool.activity` — a tool's lifecycle (`start` → `done` | `error`), with an
|
|
71
|
+
optional `subRunId` deep-linking into the admin.
|
|
72
|
+
- `approval.request` — the turn paused for human approval (HITL), carrying an
|
|
73
|
+
opaque `stateToken` only the provider mod reads.
|
|
74
|
+
- `error` — errors are turn **content** (chats render an inline card, not a
|
|
75
|
+
toast).
|
|
76
|
+
- `audio.ref` — reserved for the voice round.
|
|
77
|
+
- `done { stopReason }` — a **guaranteed** terminal event
|
|
78
|
+
(`complete | interrupted | error | cancelled`), so a consumer can always
|
|
79
|
+
settle.
|
|
80
|
+
|
|
81
|
+
These are event-name constants on the wire, not ops. Descriptors and events
|
|
82
|
+
are both plain JSON (structured-cloneable) so they flow on edges and cross
|
|
83
|
+
worker boundaries; provider SDK objects never do — a provider mod reifies
|
|
84
|
+
descriptors into SDK instances only at execute time.
|
|
85
|
+
|
|
86
|
+
## Integration
|
|
87
|
+
|
|
88
|
+
- **Provider** (`@pattern-js/mod-agents-openai`) — meets this mod at the
|
|
89
|
+
`AGENTS_SERVICE` service seam: it asks the registry for tools, nobody
|
|
90
|
+
imports a provider to find them. Reifies descriptors → SDK; emits the turn
|
|
91
|
+
events.
|
|
92
|
+
- **`@pattern-js/mod-store`** — history is opaque provider items pulled from a
|
|
93
|
+
store and pushed back; image-part tools resolve blob ids through it.
|
|
94
|
+
- **`@pattern-js/mod-chat`** — the product surface; its `chat.turn.pipeline`
|
|
95
|
+
wires `agents.tools.workflows` → `agents.agent` → `agents.run` and persists
|
|
96
|
+
the event stream.
|
|
97
|
+
|
|
98
|
+
## The agentic shape
|
|
99
|
+
|
|
100
|
+
Request → extract the user's message → collect tools + define the agent →
|
|
101
|
+
run → stream the response. The canvas version, end to end:
|
|
102
|
+
|
|
103
|
+
```workflow
|
|
104
|
+
{ "id": "agent.turn",
|
|
105
|
+
"name": "Agent · one turn",
|
|
106
|
+
"nodes": [
|
|
107
|
+
{ "id": "in", "op": "boundary.http.request", "config": { "method": "POST", "path": "/api/agent" } },
|
|
108
|
+
{ "id": "msg", "op": "core.object.get", "config": { "path": "message" }, "comment": "the user's text out of the body" },
|
|
109
|
+
{ "id": "tools", "op": "agents.tools.workflows", "comment": "every boundary.tool in the app; name a subset to narrow" },
|
|
110
|
+
{ "id": "agent", "op": "agents.agent", "config": { "name": "assistant", "instructions": "You are a helpful assistant." } },
|
|
111
|
+
{ "id": "run", "op": "agents.run", "comment": "streams turn events; needs an API key" },
|
|
112
|
+
{ "id": "out", "op": "boundary.http.response" } ],
|
|
113
|
+
"edges": [
|
|
114
|
+
{ "from": { "node": "in", "port": "body" }, "to": { "node": "msg", "port": "object" } },
|
|
115
|
+
{ "from": { "node": "tools", "port": "toolset" }, "to": { "node": "agent", "port": "tools" } },
|
|
116
|
+
{ "from": { "node": "agent", "port": "agent" }, "to": { "node": "run", "port": "agent" } },
|
|
117
|
+
{ "from": { "node": "msg", "port": "out" }, "to": { "node": "run", "port": "input" } },
|
|
118
|
+
{ "from": { "node": "run", "port": "events" }, "to": { "node": "out", "port": "stream" } } ] }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
For the full agentic app (history, persistence, approvals, Stop), use
|
|
122
|
+
`@pattern-js/mod-chat` — its turn pipeline is this shape, hardened.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Wrap a `boundary.tool` workflow (one that returns `{ tripwire, info? }`) as an
|
|
2
|
+
input or output guardrail and feed it into `agents.agent`'s guardrails input.
|
|
3
|
+
A tripped guardrail surfaces as an inline card in the chat — the run ends
|
|
4
|
+
cleanly with the reason, never a crash. Input guardrails vet the user's
|
|
5
|
+
message before the model sees it; output guardrails vet the model's answer.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Combine several toolsets into one — workflow tools (`agents.tools.workflows`),
|
|
2
|
+
MCP servers (`agents.mcp.server`), and op tools (`agents.tools.ops`) all
|
|
3
|
+
produce toolset values, and this merges them (config `count` sets how many
|
|
4
|
+
inputs). Wire the result into `agents.agent`'s tools. The three tool origins,
|
|
5
|
+
one toolbox.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
Collect mod-contributed CODE tools (registered via
|
|
2
|
+
`AGENTS_SERVICE.registerOpTool`) into a toolset — config `tools` names which
|
|
3
|
+
to include, empty = all. The third tool origin alongside workflow tools and
|
|
4
|
+
MCP: for tools a mod ships as plain functions rather than visible workflows.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
The trigger that makes a workflow callable by agents. Config: `name`,
|
|
2
|
+
`description`, `params` (JSON Schema — engine-validated, so your graph never
|
|
3
|
+
sees malformed args), optional `needsApproval` for human-in-the-loop. Outputs
|
|
4
|
+
`args` (validated) + `user` (the principal). Pair with `boundary.tool.return`
|
|
5
|
+
whose `result` becomes the tool's return value to the model.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
The out-gate that closes a `boundary.tool` workflow: whatever you wire into `result` is exactly what the calling agent reads back as the tool's output. Keep it small and structured — the model spends attention tokens on every field, so return `{ tempC, summary }`, not a raw API envelope. For a guardrail tool, this is where `{ tripwire, info? }` goes. Pairs with `boundary.tool`; it's the only legal terminal for a tool workflow, so every branch must converge here.
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pattern-js/mod-agents",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Neutral agent contracts for Pattern: agent/tool/guardrail descriptors that flow on edges, the boundary.tool workflow pair (engine-validated params), the modality-agnostic turn event protocol, and the tool registry — no model-provider dependency. Pair with @pattern-js/mod-agents-openai (or a future provider mod).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"docs",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"zod": "^4.0.0",
|
|
22
|
+
"@pattern-js/core": "0.2.0",
|
|
23
|
+
"@pattern-js/runtime-node": "0.2.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^22.0.0",
|
|
27
|
+
"typescript": "^5.6.0"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22.5"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/makkr-studio/pattern.git",
|
|
35
|
+
"directory": "packages/mod-agents"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/makkr-studio/pattern#readme",
|
|
38
|
+
"bugs": "https://github.com/makkr-studio/pattern/issues",
|
|
39
|
+
"author": "Makkr Studio (https://github.com/makkr-studio)",
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsc -p tsconfig.json",
|
|
42
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
43
|
+
}
|
|
44
|
+
}
|