@falai/agent 2.0.0 → 2.1.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/dist/cjs/core/Agent.d.ts +1 -1
- package/dist/cjs/core/Agent.js +3 -3
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/AutoChainExecutor.d.ts +2 -2
- package/dist/cjs/core/AutoChainExecutor.js +2 -2
- package/dist/cjs/core/AutoChainExecutor.js.map +1 -1
- package/dist/cjs/core/PromptComposer.d.ts +1 -1
- package/dist/cjs/core/PromptComposer.js +2 -2
- package/dist/cjs/core/PromptComposer.js.map +1 -1
- package/dist/cjs/core/ResponseEngine.d.ts +1 -1
- package/dist/cjs/core/ResponseModal.js +6 -6
- package/dist/cjs/core/ResponseModal.js.map +1 -1
- package/dist/cjs/core/ResponsePipeline.d.ts +2 -2
- package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/cjs/core/ResponsePipeline.js.map +1 -1
- package/dist/cjs/core/SignalProcessor.d.ts +3 -3
- package/dist/cjs/core/SignalProcessor.d.ts.map +1 -1
- package/dist/cjs/core/SignalProcessor.js +1 -1
- package/dist/cjs/core/SignalProcessor.js.map +1 -1
- package/dist/cjs/core/Step.d.ts +1 -1
- package/dist/cjs/core/Step.js +1 -1
- package/dist/cjs/core/ToolManager.d.ts +1 -1
- package/dist/cjs/core/ToolManager.js +1 -1
- package/dist/cjs/core/flow-namespace.d.ts +4 -4
- package/dist/cjs/core/flow-namespace.d.ts.map +1 -1
- package/dist/cjs/core/flow-namespace.js +14 -25
- package/dist/cjs/core/flow-namespace.js.map +1 -1
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.d.ts +1 -1
- package/dist/cjs/providers/AnthropicProvider.js +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +1 -1
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts +1 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.js +1 -1
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +1 -1
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/ai.d.ts +1 -1
- package/dist/cjs/types/ai.js +1 -1
- package/dist/cjs/types/flow.d.ts +33 -25
- package/dist/cjs/types/flow.d.ts.map +1 -1
- package/dist/cjs/types/index.d.ts +1 -1
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/signals.d.ts +4 -5
- package/dist/cjs/types/signals.d.ts.map +1 -1
- package/dist/cjs/utils/session.d.ts +1 -1
- package/dist/cjs/utils/session.js +4 -4
- package/dist/cjs/utils/session.js.map +1 -1
- package/dist/core/Agent.d.ts +1 -1
- package/dist/core/Agent.js +3 -3
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/AutoChainExecutor.d.ts +2 -2
- package/dist/core/AutoChainExecutor.js +2 -2
- package/dist/core/AutoChainExecutor.js.map +1 -1
- package/dist/core/PromptComposer.d.ts +1 -1
- package/dist/core/PromptComposer.js +2 -2
- package/dist/core/PromptComposer.js.map +1 -1
- package/dist/core/ResponseEngine.d.ts +1 -1
- package/dist/core/ResponseModal.js +6 -6
- package/dist/core/ResponseModal.js.map +1 -1
- package/dist/core/ResponsePipeline.d.ts +2 -2
- package/dist/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/core/ResponsePipeline.js.map +1 -1
- package/dist/core/SignalProcessor.d.ts +3 -3
- package/dist/core/SignalProcessor.d.ts.map +1 -1
- package/dist/core/SignalProcessor.js +1 -1
- package/dist/core/SignalProcessor.js.map +1 -1
- package/dist/core/Step.d.ts +1 -1
- package/dist/core/Step.js +1 -1
- package/dist/core/ToolManager.d.ts +1 -1
- package/dist/core/ToolManager.js +1 -1
- package/dist/core/flow-namespace.d.ts +4 -4
- package/dist/core/flow-namespace.d.ts.map +1 -1
- package/dist/core/flow-namespace.js +14 -25
- package/dist/core/flow-namespace.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/providers/AnthropicProvider.d.ts +1 -1
- package/dist/providers/AnthropicProvider.js +1 -1
- package/dist/providers/GeminiProvider.d.ts +1 -1
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +1 -1
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAIProvider.d.ts +1 -1
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +1 -1
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/dist/types/agent.d.ts +1 -1
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/ai.d.ts +1 -1
- package/dist/types/ai.js +1 -1
- package/dist/types/flow.d.ts +33 -25
- package/dist/types/flow.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/signals.d.ts +4 -5
- package/dist/types/signals.d.ts.map +1 -1
- package/dist/utils/session.d.ts +1 -1
- package/dist/utils/session.js +4 -4
- package/dist/utils/session.js.map +1 -1
- package/docs/README.md +12 -3
- package/docs/concepts/architecture.md +19 -26
- package/docs/concepts/directives.md +53 -84
- package/docs/concepts/pipeline.md +4 -4
- package/docs/guides/flow-control.md +12 -13
- package/docs/guides/streaming.md +1 -1
- package/docs/migration/README.md +9 -10
- package/docs/migration/v1-to-v2.md +508 -6
- package/docs/reference/adapters.md +1 -1
- package/docs/reference/directive.md +9 -10
- package/docs/reference/flow.md +3 -3
- package/docs/reference/instruction.md +1 -1
- package/docs/reference/providers.md +14 -14
- package/docs/reference/signals.md +3 -4
- package/docs/reference/step.md +9 -10
- package/docs/reference/tool.md +1 -1
- package/docs/start/01-install.md +1 -1
- package/docs/start/02-first-agent.md +2 -3
- package/examples/01-quickstart.ts +1 -1
- package/examples/02-data-extraction.ts +1 -1
- package/examples/03-tools.ts +1 -1
- package/examples/04-instructions.ts +1 -1
- package/examples/05-branching.ts +1 -1
- package/examples/06-flow-control.ts +1 -1
- package/examples/07-streaming.ts +1 -1
- package/examples/08-persistence.ts +1 -1
- package/examples/09-signals.ts +1 -1
- package/examples/tsconfig.json +1 -3
- package/package.json +9 -5
- package/src/core/Agent.ts +4 -4
- package/src/core/AutoChainExecutor.ts +3 -3
- package/src/core/PromptComposer.ts +2 -2
- package/src/core/ResponseEngine.ts +1 -1
- package/src/core/ResponseModal.ts +18 -18
- package/src/core/ResponsePipeline.ts +1 -2
- package/src/core/SignalProcessor.ts +7 -7
- package/src/core/Step.ts +1 -1
- package/src/core/ToolManager.ts +1 -1
- package/src/core/flow-namespace.ts +32 -53
- package/src/index.ts +2 -3
- package/src/providers/AnthropicProvider.ts +2 -2
- package/src/providers/GeminiProvider.ts +2 -2
- package/src/providers/OpenAIProvider.ts +2 -2
- package/src/types/agent.ts +1 -1
- package/src/types/ai.ts +1 -1
- package/src/types/flow.ts +41 -26
- package/src/types/index.ts +0 -1
- package/src/types/signals.ts +4 -5
- package/src/utils/session.ts +5 -5
- package/docs/migration/route-to-flow.md +0 -560
- package/docs/reference/pre-directive.md +0 -131
package/docs/README.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Documentation"
|
|
3
|
+
description: "Typed conversations where code stays in charge. Docs for @falai/agent."
|
|
4
|
+
type: overview
|
|
5
|
+
order: 0
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# Documentation
|
|
2
9
|
|
|
3
|
-
|
|
10
|
+
**Typed conversations where code stays in charge.**
|
|
11
|
+
|
|
12
|
+
Define flows, steps, and tools in TypeScript; the framework calls the LLM only for the parts that need language — routing, extraction, and generation.
|
|
4
13
|
|
|
5
14
|
## New here?
|
|
6
15
|
|
|
@@ -12,7 +21,7 @@ Walk through a five-step tutorial that builds a working agent end to end, from i
|
|
|
12
21
|
|
|
13
22
|
Eight task-shaped recipes covering conditions, branching, flow control, instructions, persistence, streaming, errors, and compaction.
|
|
14
23
|
|
|
15
|
-
[Browse the guides](./guides/)
|
|
24
|
+
[Browse the guides](./guides/conditions.md)
|
|
16
25
|
|
|
17
26
|
## Want the why?
|
|
18
27
|
|
|
@@ -24,7 +33,7 @@ Three concept pages that build the mental model: the seven primitives, the per-t
|
|
|
24
33
|
|
|
25
34
|
One page per public type. Signatures, field tables, errors, and short runnable examples for `createAgent`, `Flow`, `Step`, `Tool`, `Instruction`, `Directive`, signals, providers, adapters, and more.
|
|
26
35
|
|
|
27
|
-
[Open the reference](./reference/)
|
|
36
|
+
[Open the reference](./reference/create-agent.md)
|
|
28
37
|
|
|
29
38
|
---
|
|
30
39
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Architecture"
|
|
3
|
-
description: "The
|
|
3
|
+
description: "The six primitives of @falai/agent and how they fit together to keep language on the AI's side and decisions on the code's side."
|
|
4
4
|
type: concept
|
|
5
5
|
order: 1
|
|
6
6
|
---
|
|
@@ -9,11 +9,11 @@ order: 1
|
|
|
9
9
|
|
|
10
10
|
> the AI understands, the code is in control
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Six types do all the work. Five are about declaration — what the agent looks like in source. One is about control — what tools and hooks return at runtime to redirect a turn. This page maps the ownership and reference relationships between them, explains the schema-first principle that makes pre-extraction work, and draws the line between what the AI does and what the code does.
|
|
13
13
|
|
|
14
14
|
LLMs are good at language and unreliable at control flow. They paraphrase well; they do not maintain invariants. They infer intent well; they do not enforce completion gates. The framework's job is to keep the AI on the side of language — understanding intent, extracting structured data, generating prose — while keeping the code on the side of decisions: which flow runs, when a flow completes, what a tool actually does, what state survives a turn.
|
|
15
15
|
|
|
16
|
-
This page explains the shape of that seam. It names the
|
|
16
|
+
This page explains the shape of that seam. It names the six primitives, says what each one is for, and shows how they reference each other. It does not teach syntax. Once the mental model is in place, the [reference](../reference/create-agent.md) pages document the contracts and the [tutorial](../start/01-install.md) walks through the code line by line.
|
|
17
17
|
|
|
18
18
|
## Core vocabulary
|
|
19
19
|
|
|
@@ -32,9 +32,9 @@ Eight terms cover everything below. Every other term in the docs defines itself
|
|
|
32
32
|
|
|
33
33
|
These are the words the rest of the docs use without footnotes. They are also the words the type system uses — every name in the table maps directly to an exported symbol or a generic parameter.
|
|
34
34
|
|
|
35
|
-
## The
|
|
35
|
+
## The six primitives
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
Six types do all the work. The first five are about declaration — what the agent looks like in source. The last one is about control — what tools and hooks return at runtime to act on a turn. None of them is novel on its own. The shape of the framework is in how few there are and how cleanly they compose.
|
|
38
38
|
|
|
39
39
|
A small illustrative sketch first, just to show the silhouette:
|
|
40
40
|
|
|
@@ -62,7 +62,7 @@ const agent = createAgent({
|
|
|
62
62
|
});
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
Five of the
|
|
65
|
+
Five of the six primitives appear by name in that block. The remaining one — `Directive` — surfaces only when control flow is on the line, returned from a tool or hook to redirect the conversation.
|
|
66
66
|
|
|
67
67
|
### Agent
|
|
68
68
|
|
|
@@ -96,19 +96,15 @@ An instruction owns its rendered position in the prompt. The composer renders ea
|
|
|
96
96
|
|
|
97
97
|
### Directive
|
|
98
98
|
|
|
99
|
-
A `Directive<TContext, TData>` is a flat object literal — not a class, not a builder, not a discriminated union — that any tool, hook, or branch returns to act on the turn. Every field is optional. A directive carries up to four orthogonal payloads: at most **one position field** (`goTo`, `goToStep`, `complete`, `abort`, or `reset`), zero or one **verbatim reply**, optional **state writes** (`dataUpdate` / `contextUpdate`), and optional `reason` strings inside object forms for traceability. The flatness is intentional — earlier drafts modeled directives as a discriminated union, but a flat object composes more naturally when a single decision point needs to write state, change position, and speak verbatim in one return value.
|
|
99
|
+
A `Directive<TContext, TData>` is a flat object literal — not a class, not a builder, not a discriminated union — that any tool, hook, or branch returns to act on the turn. Every field is optional. A directive carries up to four orthogonal payloads: at most **one position field** (`goTo`, `goToStep`, `complete`, `abort`, or `reset`), zero or one **verbatim reply**, optional **state writes** (`dataUpdate` / `contextUpdate`), and optional **pre-LLM augmentation** (`appendPrompt`, `injectTools`, `halt`) plus optional `reason` strings inside object forms for traceability. The flatness is intentional — earlier drafts modeled directives as a discriminated union, but a flat object composes more naturally when a single decision point needs to write state, change position, and speak verbatim in one return value.
|
|
100
100
|
|
|
101
|
-
The directive is the single language the framework speaks for control flow. A tool that decides "this user is ineligible" returns `{ goTo: "denial", reply: "Sorry — you don't qualify." }`. A finalize hook that finishes a booking returns `{ complete: true, dataUpdate: { bookingId } }`. A
|
|
101
|
+
The directive is the single language the framework speaks for control flow. A tool that decides "this user is ineligible" returns `{ goTo: "denial", reply: "Sorry — you don't qualify." }`. A finalize hook that finishes a booking returns `{ complete: true, dataUpdate: { bookingId } }`. A prepare hook that detects a VIP returns `{ appendPrompt: ["This caller is VIP — confirm preferences first."] }`. All of these merge through one algorithm — position fields by precedence, state writes shallow-merged, `reply` last-wins — implemented as `flow.merge(a, b)` and applied uniformly across the turn pipeline.
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
A `PreDirective<TContext, TData>` extends `Directive` with three fields that only make sense before the turn's LLM call: `appendPrompt` (sentences added to this turn's system prompt), `injectTools` (tools added to this turn's available list), and `halt` (skip the LLM call entirely). It is the return type of `onEnter` and `prepare` hooks. Lifetime is one turn; PreDirective fields never persist into `session.pendingDirective`.
|
|
106
|
-
|
|
107
|
-
A pre-directive owns the per-turn shaping slots in the prompt composer and the tool manager. `appendPrompt` flows into a transient appendage slot — never cached, never persisted, recomputed every turn. `injectTools` flows into a transient tool layer that stacks on top of step → flow → agent scopes. `halt` is the kill switch: when set, the engine skips the model, and if `reply` is also set the verbatim string becomes the assistant message. PreDirective is also the parent of the v2.x `SignalDirective` — the signals primitive adds two further fields on top of this exact shape, so signal handlers participate in the same merge algorithm as everything else.
|
|
103
|
+
The three pre-LLM fields (`appendPrompt`, `injectTools`, `halt`) have a one-turn lifetime: they only take effect in pre-LLM hooks (`onEnter`, `prepare`). When emitted from post-LLM hooks or persisted to `session.pendingDirective`, they are ignored with a WARN log. This keeps one type for all emitters while the engine enforces the phase boundary at runtime.
|
|
108
104
|
|
|
109
105
|
## Supporting concepts
|
|
110
106
|
|
|
111
|
-
The
|
|
107
|
+
The six primitives carry the weight. Four supporting pieces make them ergonomic.
|
|
112
108
|
|
|
113
109
|
### `flow` namespace
|
|
114
110
|
|
|
@@ -164,7 +160,7 @@ Branches are also the place where the AI/code split is most visible at the call
|
|
|
164
160
|
|
|
165
161
|
## How the primitives reference each other
|
|
166
162
|
|
|
167
|
-
The diagram below maps the ownership and reference relationships between the
|
|
163
|
+
The diagram below maps the ownership and reference relationships between the six primitives and the two state surfaces. Solid arrows are ownership. Dashed lines are scoping or extension. The two state nodes (`Schema` and `Context`) are not primitives — they are the typed surfaces the primitives operate on, drawn at the bottom because everything else references them.
|
|
168
164
|
|
|
169
165
|
```mermaid
|
|
170
166
|
graph TB
|
|
@@ -186,26 +182,23 @@ graph TB
|
|
|
186
182
|
Step -.scoped.- Tool
|
|
187
183
|
Step -.scoped.- Instruction
|
|
188
184
|
Step -->|branches| Step
|
|
189
|
-
Step -->|onEnter / prepare|
|
|
185
|
+
Step -->|onEnter / prepare| Directive
|
|
190
186
|
Step -->|finalize| Directive
|
|
191
187
|
|
|
192
188
|
Tool -->|ctx.dispatch| Directive
|
|
193
189
|
Tool -->|ToolResult.directive| Directive
|
|
194
190
|
|
|
195
|
-
PreDirective -.extends.-> Directive
|
|
196
|
-
|
|
197
191
|
Directive -.merged via.-> FlowNS[flow.merge]
|
|
198
|
-
PreDirective -.validated via.-> FlowNS
|
|
199
192
|
|
|
200
193
|
classDef primitive fill:#1e293b,stroke:#0ea5e9,color:#fff;
|
|
201
194
|
classDef state fill:#0f172a,stroke:#64748b,color:#cbd5e1;
|
|
202
|
-
class Agent,Flow,Step,Tool,Instruction,Directive
|
|
195
|
+
class Agent,Flow,Step,Tool,Instruction,Directive primitive;
|
|
203
196
|
class Schema,Context state;
|
|
204
197
|
```
|
|
205
198
|
|
|
206
|
-
Read it top-down. The agent owns flows, tools, and instructions, and binds them to a single schema and a single context type. A flow owns steps and may scope its own instructions and tools. A step references the schema through `collect` and `requires`, may carry its own scoped instructions and tools, and may fork via `branches` into another step. Hooks and tools emit directives — pre-LLM hooks
|
|
199
|
+
Read it top-down. The agent owns flows, tools, and instructions, and binds them to a single schema and a single context type. A flow owns steps and may scope its own instructions and tools. A step references the schema through `collect` and `requires`, may carry its own scoped instructions and tools, and may fork via `branches` into another step. Hooks and tools emit directives — pre-LLM hooks use the pre-LLM fields (`appendPrompt`, `injectTools`, `halt`), post-LLM hooks use position/state/reply fields. The `flow` namespace validates and merges them.
|
|
207
200
|
|
|
208
|
-
The two state types — `Schema` for `TData`, `Context` for `TContext` — sit at the bottom because everything else points at them. They are not primitives in the same sense as the
|
|
201
|
+
The two state types — `Schema` for `TData`, `Context` for `TContext` — sit at the bottom because everything else points at them. They are not primitives in the same sense as the six types; they are the typed surfaces those primitives operate on, and they are owned by the agent.
|
|
209
202
|
|
|
210
203
|
Two things are deliberately absent from this diagram. There is no separate "router" primitive — flow selection is an internal pipeline phase, not a user-facing type. There is no separate "session" primitive in the declaration model — sessions are runtime state, indexed by `sessionId`, persisted by adapters, but not something application code constructs as a building block. Both of those concerns live in the [turn pipeline](./pipeline.md), where they are explained as steps in the per-turn sequence rather than parts of the static structure.
|
|
211
204
|
|
|
@@ -241,9 +234,9 @@ There is no implicit messaging. The framework never emits a message of its own.
|
|
|
241
234
|
|
|
242
235
|
There is no glossary. Eight terms are defined in the callout at the top of this page, and every other term in the docs defines itself at first use on the page that introduces it. The framework's surface is small enough that a glossary would duplicate prose without adding clarity.
|
|
243
236
|
|
|
244
|
-
## Why
|
|
237
|
+
## Why six primitives
|
|
245
238
|
|
|
246
|
-
The set of
|
|
239
|
+
The set of six is the result of a few specific cuts. Each one collapsed a category of duplication into a single shape, and each one is worth naming for its own sake — not for migration purposes (the [migration guide](../migration/v1-to-v2.md) covers that), but because the surface visible today is the result of those choices.
|
|
247
240
|
|
|
248
241
|
**One word per concept.** The verb form `route()` is still the act of selecting a flow, and "routing" is still the gerund — but the noun for "a single conversational goal" is **Flow**. The system that selects one is the **FlowRouter**. There is no overlap between the noun and the verb, which keeps the surface readable when the two appear in the same sentence.
|
|
249
242
|
|
|
@@ -251,7 +244,7 @@ The set of seven is the result of a few specific cuts. Each one collapsed a cate
|
|
|
251
244
|
|
|
252
245
|
**One Tool with optional metadata.** A `Tool` is a single interface. The simple case is `{ id, handler }`. The production case adds `validateInput`, `checkPermissions`, `isReadOnly`, `isConcurrencySafe`, `isDestructive`, and `maxResultSizeChars` — every one optional. There is no upgrade boundary mid-codebase: a tool that starts as a plain function adds metadata fields when it needs them, without changing type or import. The executor reads each field defensively (undefined falls back to safe defaults), so the same tool runs identically with two metadata fields or zero.
|
|
253
246
|
|
|
254
|
-
The remaining four primitives — Agent, Step,
|
|
247
|
+
The remaining four primitives — Agent, Step, Flow, Directive — were always single-shape concepts. The six-primitive count is what survives those three consolidations plus the three that stood on their own.
|
|
255
248
|
|
|
256
249
|
## Construction shape
|
|
257
250
|
|
|
@@ -274,7 +267,7 @@ The construction shape encodes the ownership tree: an agent owns flows, tools, a
|
|
|
274
267
|
|
|
275
268
|
## What's next
|
|
276
269
|
|
|
277
|
-
The next page walks through what happens when `agent.respond(message)` is called: the per-turn pipeline, resolution precedence (`pendingDirective` first, then signals + routing in parallel, then auto-step chains, then branches, then linear succession), the directive bus, and how `flow.merge` collapses simultaneous emissions into a single applied directive. After that, the [Directives](./directives.md) page goes deeper into the directive shape itself — why it is flat, how
|
|
270
|
+
The next page walks through what happens when `agent.respond(message)` is called: the per-turn pipeline, resolution precedence (`pendingDirective` first, then signals + routing in parallel, then auto-step chains, then branches, then linear succession), the directive bus, and how `flow.merge` collapses simultaneous emissions into a single applied directive. After that, the [Directives](./directives.md) page goes deeper into the directive shape itself — why it is flat, how `SignalDirective` extends it for signals, and what each field does.
|
|
278
271
|
|
|
279
272
|
If the goal right now is to write code, the [tutorial](../start/01-install.md) starts from a one-line install and arrives at a working agent in five short pages. If the goal is to look up an exact contract, every primitive on this page has a [reference](../reference/create-agent.md) page with the full TypeScript declaration, a fields table, two short examples, and the typed errors it can throw.
|
|
280
273
|
|
|
@@ -20,10 +20,8 @@ emitters, one shape.
|
|
|
20
20
|
|
|
21
21
|
This page explains why the shape is flat, what each field does, how
|
|
22
22
|
they merge when more than one handler emits during the same turn, and
|
|
23
|
-
how `Directive
|
|
24
|
-
|
|
25
|
-
without adding a parallel type system. The page is conceptual — the
|
|
26
|
-
[directive reference](../reference/directive.md) carries the
|
|
23
|
+
how `Directive` and `SignalDirective` relate. The page is conceptual —
|
|
24
|
+
the [directive reference](../reference/directive.md) carries the
|
|
27
25
|
field-by-field contract.
|
|
28
26
|
|
|
29
27
|
## Why a flat shape
|
|
@@ -70,9 +68,9 @@ algorithm answers once.
|
|
|
70
68
|
**Composable.** A directive carries up to four orthogonal payloads
|
|
71
69
|
without forcing them into a hierarchy: at most one position field,
|
|
72
70
|
optional state writes (`dataUpdate` / `contextUpdate`), an optional
|
|
73
|
-
verbatim `reply`, and
|
|
74
|
-
|
|
75
|
-
alongside `complete`. A booking tool's success result writes the
|
|
71
|
+
verbatim `reply`, and optional pre-LLM augmentations (`appendPrompt`,
|
|
72
|
+
`injectTools`, `halt`). `dataUpdate` works alongside `goTo`. `reply`
|
|
73
|
+
works alongside `complete`. A booking tool's success result writes the
|
|
76
74
|
booking id and finishes the flow in one return value:
|
|
77
75
|
`{ complete: true, dataUpdate: { bookingId } }`. A bridge utterance
|
|
78
76
|
at a flow boundary writes nothing and only speaks: `{ reply: "Let me
|
|
@@ -186,26 +184,24 @@ LLM for the conversation.
|
|
|
186
184
|
|
|
187
185
|
`reply` co-validates with two other fields. With **`abort`**, it is
|
|
188
186
|
rejected at validation — an aborted conversation cannot deliver a
|
|
189
|
-
reply. With **`halt: true
|
|
190
|
-
|
|
191
|
-
`
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
`reply` — and adds three more that only make sense before this turn's
|
|
208
|
-
LLM call: `appendPrompt`, `injectTools`, and `halt`.
|
|
187
|
+
reply. With **`halt: true`**, it is the assistant message and the
|
|
188
|
+
turn ends with `stoppedReason: 'reply'`; if `halt` is set without
|
|
189
|
+
`reply`, the turn ends with `stoppedReason: 'halt'` and an empty
|
|
190
|
+
body. Across multiple emitters in the same turn, `reply` is
|
|
191
|
+
**last-wins** — the most recent emission overrides earlier ones,
|
|
192
|
+
with a debug log so the override is visible in the trace.
|
|
193
|
+
|
|
194
|
+
`reply` works the same regardless of which phase emits it. The phase
|
|
195
|
+
determines whether the reply replaces a message that would have been
|
|
196
|
+
generated (pre-LLM) or replaces one that just was (post-LLM).
|
|
197
|
+
|
|
198
|
+
## Pre-LLM-only fields
|
|
199
|
+
|
|
200
|
+
Three fields on `Directive` only take effect in pre-LLM hooks
|
|
201
|
+
(`onEnter`, `prepare`). When emitted from post-LLM hooks (`finalize`,
|
|
202
|
+
`onComplete`) or persisted to `session.pendingDirective`, they are
|
|
203
|
+
**ignored with a WARN log** — a visible signal in your logs that
|
|
204
|
+
says "hey, this did nothing here."
|
|
209
205
|
|
|
210
206
|
**`appendPrompt: string[]`** is the prompt nudge slot. Each string is
|
|
211
207
|
a sentence the prompt composer appends to the system prompt for this
|
|
@@ -236,15 +232,13 @@ halt the turn. The field is the framework's circuit breaker: a hook
|
|
|
236
232
|
that detects an unresolvable state can stop the turn outright
|
|
237
233
|
without competing with other emitters.
|
|
238
234
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
`
|
|
245
|
-
|
|
246
|
-
`halt` after the fact has no LLM call to halt. The remaining base
|
|
247
|
-
`Directive` portion is honored.
|
|
235
|
+
These fields are stripped from `session.pendingDirective` before
|
|
236
|
+
persistence — they cannot survive across turns by design. If a
|
|
237
|
+
post-LLM hook returns a directive with these fields set, they are
|
|
238
|
+
dropped with a WARN log: an `appendPrompt` after the fact has no
|
|
239
|
+
prompt to append to, an `injectTools` after the fact has no LLM call
|
|
240
|
+
to inject into, and a `halt` after the fact has no LLM call to halt.
|
|
241
|
+
The remaining fields are honored normally.
|
|
248
242
|
|
|
249
243
|
`appendPrompt` is concatenated across emitters in emission order
|
|
250
244
|
without deduplication — duplicate sentences from different sources
|
|
@@ -252,22 +246,18 @@ are preserved (a flow-level "be polite" plus a step-level "be polite"
|
|
|
252
246
|
is acceptable redundancy). `injectTools` is concatenated and then
|
|
253
247
|
deduped by `Tool.id`, with the later definition winning — typically a
|
|
254
248
|
step-level injection overriding a flow-level default. `halt` is
|
|
255
|
-
logical-OR. The merge rules for the
|
|
256
|
-
|
|
257
|
-
|
|
249
|
+
logical-OR. The merge rules for the base fields stay identical:
|
|
250
|
+
position fields by precedence, `reply` last-wins, state writes
|
|
251
|
+
shallow-merged.
|
|
258
252
|
|
|
259
|
-
##
|
|
253
|
+
## SignalDirective
|
|
260
254
|
|
|
261
|
-
`
|
|
262
|
-
|
|
263
|
-
with two signal-specific fields. The chain is one direction —
|
|
264
|
-
capabilities accumulate as you go down — and each level is the return
|
|
265
|
-
type of a specific class of emitter:
|
|
255
|
+
`SignalDirective` extends `Directive` with two signal-pipeline-specific
|
|
256
|
+
fields: `stopOtherSignals` and `replyWith`.
|
|
266
257
|
|
|
267
258
|
```mermaid
|
|
268
259
|
classDiagram
|
|
269
|
-
Directive <|--
|
|
270
|
-
PreDirective <|-- SignalDirective
|
|
260
|
+
Directive <|-- SignalDirective
|
|
271
261
|
|
|
272
262
|
class Directive {
|
|
273
263
|
+goTo? string | object
|
|
@@ -278,9 +268,6 @@ classDiagram
|
|
|
278
268
|
+reply? string
|
|
279
269
|
+dataUpdate? Partial~TData~
|
|
280
270
|
+contextUpdate? Partial~TContext~
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
class PreDirective {
|
|
284
271
|
+appendPrompt? string[]
|
|
285
272
|
+injectTools? Tool[]
|
|
286
273
|
+halt? boolean
|
|
@@ -291,41 +278,25 @@ classDiagram
|
|
|
291
278
|
+replyWith? string | function
|
|
292
279
|
}
|
|
293
280
|
|
|
294
|
-
note for Directive "
|
|
295
|
-
note for
|
|
296
|
-
note for SignalDirective "Returned by signals (pre / post / both phases)."
|
|
281
|
+
note for Directive "One type for all hooks, tools, and branches.\nPre-LLM fields ignored with WARN log outside pre-LLM hooks."
|
|
282
|
+
note for SignalDirective "Returned by signal handlers (pre / post / both phases)."
|
|
297
283
|
```
|
|
298
284
|
|
|
299
|
-
`Directive` is what tools (return value or `ctx.dispatch`), `finalize`
|
|
300
|
-
hooks, `flow.hooks.onComplete`, and branch `then` targets return. It
|
|
301
|
-
is plain JSON-serializable data — the same shape that sits on the
|
|
302
|
-
session as `pendingDirective` and crosses the persistence boundary.
|
|
303
|
-
|
|
304
|
-
`PreDirective` is what `flow.hooks.onEnter`, `step.hooks.onEnter`,
|
|
305
|
-
and `step.hooks.prepare` return. The three augmentation fields and a
|
|
306
|
-
live `Tool[]` reference make it non-serializable; the type system
|
|
307
|
-
encodes the one-turn lifetime by being a structurally separate type
|
|
308
|
-
that the engine strips before persistence.
|
|
309
|
-
|
|
310
285
|
`SignalDirective` is what signal handlers return — pre-phase
|
|
311
286
|
handlers, post-phase handlers, and `both`-phase handlers all use the
|
|
312
|
-
same type.
|
|
313
|
-
|
|
314
|
-
consumed inside the signal pipeline, not the directive bus), and
|
|
287
|
+
same type. `stopOtherSignals` skips remaining handlers in the same
|
|
288
|
+
phase (consumed inside the signal pipeline, not the directive bus).
|
|
315
289
|
`replyWith` is a late-binding `reply` that accepts a function form
|
|
316
290
|
evaluated at emit time. Phase semantics still apply: when a
|
|
317
|
-
`SignalDirective` runs in the post-phase,
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
same `flow.merge` that handles tool directives — the inheritance
|
|
327
|
-
chain exists to widen the type at the call site without splitting the
|
|
328
|
-
runtime.
|
|
291
|
+
`SignalDirective` runs in the post-phase, `appendPrompt` /
|
|
292
|
+
`injectTools` / `halt` are dropped (they have no meaning after the
|
|
293
|
+
LLM call) and position fields set `pendingDirective` for the *next*
|
|
294
|
+
turn rather than redirecting this one.
|
|
295
|
+
|
|
296
|
+
Both types share one merge algorithm and one validation pass. A
|
|
297
|
+
pre-phase signal can dispatch a `SignalDirective`, a `prepare` hook
|
|
298
|
+
can return a `Directive`, and the engine merges them through the same
|
|
299
|
+
`flow.merge`.
|
|
329
300
|
|
|
330
301
|
## The `flow` namespace
|
|
331
302
|
|
|
@@ -358,9 +329,8 @@ within the same tier), `reply` is last-wins, `dataUpdate` and
|
|
|
358
329
|
`contextUpdate` shallow-merge in emission order, `appendPrompt`
|
|
359
330
|
concatenates without deduplication, `injectTools` concatenates and
|
|
360
331
|
then dedupes by `Tool.id` (later definition wins), and `halt` is
|
|
361
|
-
logical-OR. The function is generic
|
|
362
|
-
|
|
363
|
-
`Directive`s yields a `Directive`.
|
|
332
|
+
logical-OR. The function is generic: merging two `Directive`s yields
|
|
333
|
+
a `Directive`.
|
|
364
334
|
|
|
365
335
|
`flow.validate(d)` enforces three structural invariants and throws
|
|
366
336
|
`FlowConfigurationError` when any fails: at most one position field
|
|
@@ -384,8 +354,7 @@ small.
|
|
|
384
354
|
The directive's mental model is in this page; the field-by-field
|
|
385
355
|
contract — every position field's shorthand and object form, every
|
|
386
356
|
state-write rule, every typed error the validator can throw — is in
|
|
387
|
-
the [Directive reference](../reference/directive.md).
|
|
388
|
-
extras have their own [PreDirective reference](../reference/pre-directive.md).
|
|
357
|
+
the [Directive reference](../reference/directive.md).
|
|
389
358
|
The signal-specific additions live in [Signals](../reference/signals.md).
|
|
390
359
|
|
|
391
360
|
When the goal is to *use* directives in handlers, the
|
|
@@ -174,7 +174,7 @@ Sources, in fixed order:
|
|
|
174
174
|
4. `step.hooks.prepare`
|
|
175
175
|
5. Any `ctx.dispatch` calls made inside the above hooks
|
|
176
176
|
|
|
177
|
-
These return `
|
|
177
|
+
These return `Directive` — with the pre-LLM fields
|
|
178
178
|
three pre-LLM-only fields (`appendPrompt`, `injectTools`, `halt`). The
|
|
179
179
|
merged result feeds the prompt composer and tool manager before the
|
|
180
180
|
LLM call:
|
|
@@ -199,7 +199,7 @@ Sources, in fixed order:
|
|
|
199
199
|
5. The `then` branch of any matched `step.branches` entry whose `then`
|
|
200
200
|
was a full `Directive` (not just a step id)
|
|
201
201
|
|
|
202
|
-
These return
|
|
202
|
+
These return `Directive`. Pre-LLM-only fields here are
|
|
203
203
|
dropped with a debug warning — `halt` after the fact has no meaning,
|
|
204
204
|
and `appendPrompt` / `injectTools` could not influence a call that
|
|
205
205
|
has already happened.
|
|
@@ -222,7 +222,7 @@ the persistence boundary.
|
|
|
222
222
|
## Algorithm 4 — merge rules
|
|
223
223
|
|
|
224
224
|
When the bus has more than one directive in a phase, the pipeline
|
|
225
|
-
folds them into a single `Directive` (
|
|
225
|
+
folds them into a single `Directive` (with pre-LLM fields honored in the pre-LLM
|
|
226
226
|
phase) using the following rules. Same rules in both phases; the
|
|
227
227
|
pre-LLM phase additionally folds the three augmentation fields.
|
|
228
228
|
|
|
@@ -392,7 +392,7 @@ elides:
|
|
|
392
392
|
The pipeline is the *what happens*. The directive is the *how
|
|
393
393
|
handlers ask for things to happen*. The next concept page covers the
|
|
394
394
|
flat shape, the position field rules, the inheritance chain
|
|
395
|
-
`Directive →
|
|
395
|
+
`Directive → SignalDirective`, and the `flow`
|
|
396
396
|
namespace helpers (`flow.isDirective`, `flow.merge`, `flow.validate`)
|
|
397
397
|
that make the bus introspectable from user code.
|
|
398
398
|
|
|
@@ -237,18 +237,19 @@ payloads — `reply`, `dataUpdate`, and the position field don't
|
|
|
237
237
|
compete for the same slot.
|
|
238
238
|
|
|
239
239
|
To skip the LLM **before** it runs (rather than from a finalize hook
|
|
240
|
-
*after*),
|
|
241
|
-
|
|
240
|
+
*after*), return a `Directive` from a prepare hook with `halt: true`
|
|
241
|
+
— see below.
|
|
242
242
|
|
|
243
|
-
##
|
|
243
|
+
## Pre-LLM fields (pre-LLM hooks only)
|
|
244
244
|
|
|
245
245
|
Pre-LLM hooks (`flow.hooks.onEnter`, `step.hooks.onEnter`,
|
|
246
|
-
`step.hooks.prepare`) return a
|
|
247
|
-
|
|
248
|
-
|
|
246
|
+
`step.hooks.prepare`) return a `Directive` — the same type as
|
|
247
|
+
post-LLM hooks, but with three fields that only take effect before
|
|
248
|
+
this turn's LLM call.
|
|
249
249
|
|
|
250
250
|
```typescript
|
|
251
|
-
interface
|
|
251
|
+
interface Directive {
|
|
252
|
+
// ...all position/state/reply fields...
|
|
252
253
|
appendPrompt?: string[];
|
|
253
254
|
injectTools?: Tool[];
|
|
254
255
|
halt?: boolean;
|
|
@@ -257,8 +258,8 @@ interface PreDirective extends Directive {
|
|
|
257
258
|
|
|
258
259
|
Lifetime is one turn. None of the three fields persist on
|
|
259
260
|
`session.pendingDirective` — they're stripped before the write.
|
|
260
|
-
Returning a
|
|
261
|
-
a
|
|
261
|
+
Returning a Directive with these fields from a post-LLM hook ignores
|
|
262
|
+
them with a WARN log.
|
|
262
263
|
|
|
263
264
|
### `appendPrompt` — nudge the system prompt
|
|
264
265
|
|
|
@@ -349,7 +350,7 @@ await agent.dispatch({ goTo: "Billing", reply: "Transferring you now." }, sessio
|
|
|
349
350
|
|
|
350
351
|
The call validates the directive (`flow.validate`), confirms any
|
|
351
352
|
`goTo`-named flow exists (throws `FlowConfigurationError` if not),
|
|
352
|
-
strips
|
|
353
|
+
strips pre-LLM-only fields, writes `pendingDirective` onto the
|
|
353
354
|
session, and persists if an adapter is configured.
|
|
354
355
|
|
|
355
356
|
`pendingDirective` is **single-shot** — consumed exactly once and
|
|
@@ -375,7 +376,7 @@ Where to emit:
|
|
|
375
376
|
|----------------|------|-----|
|
|
376
377
|
| Tool handler, mid-flight | `Directive` | `ctx.dispatch(d)` |
|
|
377
378
|
| Tool handler, on return | `Directive` | `return { data, directive: d }` |
|
|
378
|
-
| `prepare` / `onEnter` hook | `
|
|
379
|
+
| `prepare` / `onEnter` hook | `Directive` | `return d` (pre-LLM fields honored) |
|
|
379
380
|
| `finalize` / `onComplete` hook | `Directive` | `return d` |
|
|
380
381
|
| Branch `then` target | `Directive` | `then: d` (see [Branching](./branching.md)) |
|
|
381
382
|
| Outside a turn (webhook, job) | `Directive` | `await agent.dispatch(d, session)` |
|
|
@@ -397,8 +398,6 @@ Code or model speaking:
|
|
|
397
398
|
|
|
398
399
|
- [Directive reference](../reference/directive.md) — every field,
|
|
399
400
|
every shorthand, every validation rule.
|
|
400
|
-
- [PreDirective reference](../reference/pre-directive.md) —
|
|
401
|
-
pre-LLM-only fields and merge rules.
|
|
402
401
|
- [Directives concept](../concepts/directives.md) — the mental model
|
|
403
402
|
and the inheritance chain.
|
|
404
403
|
- [Branching](./branching.md) — when the redirect is source-local
|
package/docs/guides/streaming.md
CHANGED
|
@@ -85,7 +85,7 @@ for await (const chunk of agent.respondStream({ history })) {
|
|
|
85
85
|
|
|
86
86
|
If you need finer-grained tool telemetry — which tool fired, with what arguments — read `chunk.toolCalls` on the terminal chunk. It mirrors the same field on the non-streaming `AgentResponse`. For per-tool progress UI, attach observability to the [tool's `handler`](../reference/tool.md) directly; the streaming chunk shape stays clean.
|
|
87
87
|
|
|
88
|
-
When a step uses [verbatim `reply`](../reference/step.md) or a
|
|
88
|
+
When a step uses [verbatim `reply`](../reference/step.md) or a `halt` directive, the engine skips the LLM entirely and yields a single chunk with `done: true` and the full text in `accumulated`. The renderer above handles that case without a special branch — there is just no spinner gap.
|
|
89
89
|
|
|
90
90
|
## The terminal chunk
|
|
91
91
|
|
package/docs/migration/README.md
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Migration guides for upgrading
|
|
1
|
+
---
|
|
2
|
+
title: "Migration"
|
|
3
|
+
description: "Migration guides for upgrading @falai/agent from v1 to v2."
|
|
4
|
+
type: overview
|
|
5
|
+
order: 99
|
|
6
|
+
---
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
# Migration
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
Upgrading from `1.x`? The consolidated migration guide covers every breaking change in v2 — including the Route → Flow rename, the Instruction unification, the Tool merge, and the Directive collapse — with rename tables, per-adapter schema migrations, and before/after code for each section.
|
|
8
11
|
|
|
9
12
|
[Read the v1 → v2 migration guide](./v1-to-v2.md)
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Use this guide if you are landing the minor release that ships just before `2.0`, which renames the `Route` domain noun to `Flow` across symbols, config, and persistence.
|
|
14
|
-
|
|
15
|
-
[Read the Route → Flow guide](./route-to-flow.md)
|
|
14
|
+
Section 3 covers the Route → Flow rename in full, including per-adapter SQL/Mongo/Redis/OpenSearch migration snippets and ID-prefix guidance.
|