@falai/agent 2.2.2 → 2.2.4
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/ResponseModal.d.ts +6 -0
- package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
- package/dist/cjs/core/ResponseModal.js +21 -4
- package/dist/cjs/core/ResponseModal.js.map +1 -1
- package/dist/cjs/core/SignalEvaluator.d.ts +1 -1
- package/dist/cjs/core/SignalEvaluator.d.ts.map +1 -1
- package/dist/cjs/core/SignalEvaluator.js +3 -2
- package/dist/cjs/core/SignalEvaluator.js.map +1 -1
- package/dist/cjs/core/SignalProcessor.d.ts.map +1 -1
- package/dist/cjs/core/SignalProcessor.js +1 -3
- package/dist/cjs/core/SignalProcessor.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/signals.d.ts +9 -9
- package/dist/cjs/types/signals.d.ts.map +1 -1
- package/dist/core/ResponseModal.d.ts +6 -0
- package/dist/core/ResponseModal.d.ts.map +1 -1
- package/dist/core/ResponseModal.js +21 -4
- package/dist/core/ResponseModal.js.map +1 -1
- package/dist/core/SignalEvaluator.d.ts +1 -1
- package/dist/core/SignalEvaluator.d.ts.map +1 -1
- package/dist/core/SignalEvaluator.js +3 -2
- package/dist/core/SignalEvaluator.js.map +1 -1
- package/dist/core/SignalProcessor.d.ts.map +1 -1
- package/dist/core/SignalProcessor.js +1 -3
- package/dist/core/SignalProcessor.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/signals.d.ts +9 -9
- package/dist/types/signals.d.ts.map +1 -1
- package/docs/guides/streaming.md +1 -1
- package/docs/reference/signals.md +8 -6
- package/package.json +1 -1
- package/src/core/ResponseModal.ts +30 -5
- package/src/core/SignalEvaluator.ts +3 -2
- package/src/core/SignalProcessor.ts +1 -4
- package/src/index.ts +1 -1
- package/src/types/signals.ts +9 -9
package/dist/types/signals.d.ts
CHANGED
|
@@ -14,15 +14,15 @@ import type { Event } from "./history";
|
|
|
14
14
|
* Shape is locked to enable forward-compatible persistence in v2.0.
|
|
15
15
|
*/
|
|
16
16
|
export interface SignalTriggerState {
|
|
17
|
-
/** When this signal first
|
|
17
|
+
/** When this signal first completed its handler successfully. */
|
|
18
18
|
firstTriggeredAt: Date;
|
|
19
|
-
/** When this signal last
|
|
19
|
+
/** When this signal last completed its handler successfully. */
|
|
20
20
|
lastTriggeredAt: Date;
|
|
21
|
-
/** Total number of
|
|
21
|
+
/** Total number of successful handler completions for this signal. */
|
|
22
22
|
count: number;
|
|
23
|
-
/** Free-text reason from the last trigger (if
|
|
23
|
+
/** Free-text reason from the last successful trigger (if supplied). */
|
|
24
24
|
lastReason?: string;
|
|
25
|
-
/** Which phase the signal last
|
|
25
|
+
/** Which phase the signal last completed in. */
|
|
26
26
|
lastPhase?: 'pre' | 'post';
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
@@ -146,9 +146,9 @@ export interface SignalContext<TContext = unknown, TData = unknown, TExtract = v
|
|
|
146
146
|
* Conditions use the v2 `when` / `if` split:
|
|
147
147
|
* - `when`: AI-evaluated string(s). Entries prefixed with `!` are exclusion
|
|
148
148
|
* conditions rendered under "DO NOT TRIGGER WHEN" in the classifier prompt.
|
|
149
|
-
* Non-prefixed entries render under "TRIGGER WHEN". Positive entries use
|
|
150
|
-
* semantics (
|
|
151
|
-
* inhibits firing).
|
|
149
|
+
* Non-prefixed entries render under "TRIGGER WHEN". Positive entries use OR
|
|
150
|
+
* semantics (any match can trigger). Negative entries also use OR semantics
|
|
151
|
+
* for exclusion (any match inhibits firing).
|
|
152
152
|
* - `if`: Code-evaluated function(s). Free. AND semantics.
|
|
153
153
|
*
|
|
154
154
|
* When both `if` and `when` are set, `if` evaluates first. If `if` returns
|
|
@@ -167,7 +167,7 @@ export interface Signal<TContext = unknown, TData = unknown, TExtract = void> {
|
|
|
167
167
|
description?: string;
|
|
168
168
|
/**
|
|
169
169
|
* AI-evaluated trigger condition(s). String or array of strings.
|
|
170
|
-
* - Non-prefixed entries:
|
|
170
|
+
* - Non-prefixed entries: OR semantics. Any match can trigger.
|
|
171
171
|
* - `!`-prefixed entries: OR exclusion. Any match inhibits firing.
|
|
172
172
|
*
|
|
173
173
|
* At prompt-render time, the framework splits entries by prefix:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/types/signals.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAMvC;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAC/B,
|
|
1
|
+
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/types/signals.ts"],"names":[],"mappings":"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"}
|
package/docs/guides/streaming.md
CHANGED
|
@@ -36,7 +36,7 @@ interface AgentResponseStreamChunk<TData> {
|
|
|
36
36
|
}
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
`delta` is the new token(s); concatenating every `delta` reproduces the final reply. `accumulated` is the running total — useful when your renderer needs the full string each tick (e.g., a Markdown view that re-parses on every update). `done` flips to `true` exactly once, on the terminal chunk.
|
|
39
|
+
`delta` is the new token(s); concatenating every `delta` reproduces the final reply unless a post-phase signal replaces the message on the terminal chunk. `accumulated` is the authoritative running total — useful when your renderer needs the full string each tick (e.g., a Markdown view that re-parses on every update). `done` flips to `true` exactly once, on the terminal chunk.
|
|
40
40
|
|
|
41
41
|
## Render incrementally
|
|
42
42
|
|
|
@@ -130,7 +130,7 @@ interface AgentOptions<TContext, TData> {
|
|
|
130
130
|
| `id` | `string` | no | auto-generated | Stable identifier within a session. Used for `SignalsState.triggers` keying and on `SignalFiring`. Must be unique across the agent's signals. |
|
|
131
131
|
| `title` | `string` | no | — | Display title shown in logs and traces. |
|
|
132
132
|
| `description` | `string` | no | — | Free-text description; rendered into the classifier prompt. |
|
|
133
|
-
| `when` | `string \| string[]` | no | — | AI-evaluated condition(s).
|
|
133
|
+
| `when` | `string \| string[]` | no | — | AI-evaluated condition(s). Non-prefixed entries render under "TRIGGER WHEN" (OR semantics — any match can trigger). Entries prefixed with `!` are exclusion conditions rendered under "DO NOT TRIGGER WHEN" (OR semantics — any match inhibits firing). |
|
|
134
134
|
| `if` | `SignalPredicate \| SignalPredicate[]` | no | — | Code predicate(s). AND semantics. Free to evaluate. Runs before `when`; if any returns `false`, `when` is skipped (no token cost). |
|
|
135
135
|
| `extract` | `SignalSchema<TExtract>` | no | — | When set, the signal operates in extraction mode. JSON Schema object describing the per-signal `extracted` field merged into the classifier response. The `TExtract` generic carries the resulting type onto `ctx.extracted`. |
|
|
136
136
|
| `phase` | `'pre' \| 'post' \| 'both'` | yes | — | When the signal evaluates. `'pre'` runs in parallel with routing. `'post'` runs after the LLM call, before persistence. `'both'` evaluates in both phases. |
|
|
@@ -207,11 +207,13 @@ Persisted on `session.signals`. Adapters preserve this shape bit-identical.
|
|
|
207
207
|
|
|
208
208
|
| `SignalTriggerState` field | Type | Notes |
|
|
209
209
|
|----------------------------|------|-------|
|
|
210
|
-
| `firstTriggeredAt` | `Date` | When this signal first
|
|
211
|
-
| `lastTriggeredAt` | `Date` | When this signal last
|
|
212
|
-
| `count` | `number` | Total
|
|
213
|
-
| `lastReason` | `string \| undefined` | The `reason` from the most recent
|
|
214
|
-
| `lastPhase` | `'pre' \| 'post' \| undefined` | The phase of the most recent
|
|
210
|
+
| `firstTriggeredAt` | `Date` | When this signal first completed its handler successfully in the session. Never updated on subsequent successful triggers. |
|
|
211
|
+
| `lastTriggeredAt` | `Date` | When this signal last completed its handler successfully. Drives `cooldown` arithmetic. |
|
|
212
|
+
| `count` | `number` | Total successful handler completions for this signal in this session. Monotonically increasing. |
|
|
213
|
+
| `lastReason` | `string \| undefined` | The `reason` from the most recent successful trigger. |
|
|
214
|
+
| `lastPhase` | `'pre' \| 'post' \| undefined` | The phase of the most recent successful trigger. |
|
|
215
|
+
|
|
216
|
+
Handler errors are still surfaced on `SignalFiring.handlerError`, but they do not update `SignalsState.triggers`. A `behavior: 'once'` or cooldown signal can therefore retry after an app-side handler failure.
|
|
215
217
|
|
|
216
218
|
### `signalBatchSize`
|
|
217
219
|
|
package/package.json
CHANGED
|
@@ -370,6 +370,18 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
370
370
|
return this.agent.tool;
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Post-phase signal replies replace the user-visible message after the
|
|
375
|
+
* response has otherwise completed. Undefined means "leave it unchanged";
|
|
376
|
+
* an empty string is an explicit replacement.
|
|
377
|
+
*/
|
|
378
|
+
private applyPostSignalReply(
|
|
379
|
+
message: string,
|
|
380
|
+
directive: Directive<TContext, TData> | undefined,
|
|
381
|
+
): string {
|
|
382
|
+
return directive?.reply !== undefined ? directive.reply : message;
|
|
383
|
+
}
|
|
384
|
+
|
|
373
385
|
/**
|
|
374
386
|
* Collect scoped instructions from agent, flow, and step into a ScopedInstructions value.
|
|
375
387
|
* @private
|
|
@@ -1112,14 +1124,16 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1112
1124
|
session = { ...session, pendingDirective: postResult.mergedDirective };
|
|
1113
1125
|
}
|
|
1114
1126
|
|
|
1127
|
+
const message = this.applyPostSignalReply(haltMessage, postResult.mergedDirective);
|
|
1128
|
+
|
|
1115
1129
|
await this.finalizeSession(session, effectiveContext);
|
|
1116
1130
|
return {
|
|
1117
|
-
message
|
|
1131
|
+
message,
|
|
1118
1132
|
session,
|
|
1119
1133
|
toolCalls: undefined,
|
|
1120
1134
|
isFlowComplete: false,
|
|
1121
1135
|
executedSteps: [],
|
|
1122
|
-
stoppedReason:
|
|
1136
|
+
stoppedReason: haltMessage ? 'reply' : 'halt',
|
|
1123
1137
|
triggeredSignals: signalFirings.length > 0 ? signalFirings as unknown as SignalFiring<unknown, TData>[] : undefined,
|
|
1124
1138
|
};
|
|
1125
1139
|
}
|
|
@@ -1287,6 +1301,8 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1287
1301
|
session = { ...session, pendingDirective: postResult.mergedDirective };
|
|
1288
1302
|
}
|
|
1289
1303
|
|
|
1304
|
+
message = this.applyPostSignalReply(message, postResult.mergedDirective);
|
|
1305
|
+
|
|
1290
1306
|
// Ensure response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
1291
1307
|
// - executedSteps: array of steps executed (empty array if none)
|
|
1292
1308
|
// - stoppedReason: why execution stopped (undefined for fallback)
|
|
@@ -1634,10 +1650,12 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1634
1650
|
session = { ...session, pendingDirective: postResult.mergedDirective };
|
|
1635
1651
|
}
|
|
1636
1652
|
|
|
1653
|
+
const message = this.applyPostSignalReply(haltMessage, postResult.mergedDirective);
|
|
1654
|
+
|
|
1637
1655
|
await this.finalizeSession(session, effectiveContext);
|
|
1638
1656
|
yield {
|
|
1639
|
-
delta:
|
|
1640
|
-
accumulated:
|
|
1657
|
+
delta: message,
|
|
1658
|
+
accumulated: message,
|
|
1641
1659
|
done: true,
|
|
1642
1660
|
session,
|
|
1643
1661
|
stoppedReason: haltMessage ? 'reply' : 'halt',
|
|
@@ -1767,8 +1785,15 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1767
1785
|
finalSession = { ...finalSession, pendingDirective: postResult.mergedDirective };
|
|
1768
1786
|
}
|
|
1769
1787
|
|
|
1788
|
+
const accumulated = this.applyPostSignalReply(chunk.accumulated, postResult.mergedDirective);
|
|
1789
|
+
const delta = postResult.mergedDirective?.reply !== undefined
|
|
1790
|
+
? accumulated
|
|
1791
|
+
: chunk.delta;
|
|
1792
|
+
|
|
1770
1793
|
yield {
|
|
1771
1794
|
...chunk,
|
|
1795
|
+
delta,
|
|
1796
|
+
accumulated,
|
|
1772
1797
|
session: finalSession,
|
|
1773
1798
|
triggeredSignals: signalFirings.length > 0 ? signalFirings as unknown as SignalFiring<unknown, TData>[] : undefined,
|
|
1774
1799
|
} as AgentResponseStreamChunk<TData>;
|
|
@@ -2880,4 +2905,4 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
2880
2905
|
}
|
|
2881
2906
|
}
|
|
2882
2907
|
|
|
2883
|
-
}
|
|
2908
|
+
}
|
|
@@ -45,7 +45,7 @@ export interface EvaluateSignalsParams<TContext = unknown, TData = unknown> {
|
|
|
45
45
|
* Builds the classifier prompt for a batch of signals.
|
|
46
46
|
*
|
|
47
47
|
* Splits `when` entries by `!` prefix at render time:
|
|
48
|
-
* - Non-`!` → "TRIGGER WHEN (
|
|
48
|
+
* - Non-`!` → "TRIGGER WHEN (ANY matches)"
|
|
49
49
|
* - `!` entries → prefix stripped, "DO NOT TRIGGER WHEN (ANY inhibits)"
|
|
50
50
|
*
|
|
51
51
|
* Extraction schemas render under "WHEN MATCHED, EXTRACT".
|
|
@@ -61,6 +61,7 @@ export function buildSignalClassifierPrompt<TContext = unknown, TData = unknown>
|
|
|
61
61
|
"You are evaluating signals for this conversation.",
|
|
62
62
|
"",
|
|
63
63
|
"For each signal, decide whether it matched based on the most recent user message AND the conversation context. Be conservative: only mark a signal matched when there is CLEAR, EXPLICIT evidence.",
|
|
64
|
+
"Positive TRIGGER WHEN entries are alternatives: ANY one positive entry can trigger the signal. DO NOT TRIGGER WHEN entries are exclusions: ANY one exclusion inhibits the signal.",
|
|
64
65
|
].join("\n");
|
|
65
66
|
|
|
66
67
|
const signalBlocks: string[] = [];
|
|
@@ -89,7 +90,7 @@ export function buildSignalClassifierPrompt<TContext = unknown, TData = unknown>
|
|
|
89
90
|
// Unconditional + extract → ALWAYS EXTRACT
|
|
90
91
|
lines.push(` ALWAYS EXTRACT`);
|
|
91
92
|
} else if (positiveEntries.length > 0) {
|
|
92
|
-
lines.push(` TRIGGER WHEN (
|
|
93
|
+
lines.push(` TRIGGER WHEN (ANY matches):`);
|
|
93
94
|
for (const entry of positiveEntries) {
|
|
94
95
|
lines.push(` • ${entry}`);
|
|
95
96
|
}
|
|
@@ -533,7 +533,7 @@ export class SignalProcessor<TContext = unknown, TData = unknown> {
|
|
|
533
533
|
bus.push(resolvedDirective);
|
|
534
534
|
}
|
|
535
535
|
|
|
536
|
-
//
|
|
536
|
+
// Record trigger only after the handler has completed successfully.
|
|
537
537
|
updatedSession = recordTrigger(updatedSession, m.signal, m.reason, phase);
|
|
538
538
|
|
|
539
539
|
const handlerDurationMs = performance.now() - start;
|
|
@@ -568,9 +568,6 @@ export class SignalProcessor<TContext = unknown, TData = unknown> {
|
|
|
568
568
|
// Handler errors logged at ERROR regardless of debug flag (Requirement 13.2)
|
|
569
569
|
logger.error(`[Signals] Handler threw for signal "${m.signal.id ?? 'unknown'}": ${errorMessage}`);
|
|
570
570
|
|
|
571
|
-
// Still record trigger even on error (the signal matched)
|
|
572
|
-
updatedSession = recordTrigger(updatedSession, m.signal, m.reason, phase);
|
|
573
|
-
|
|
574
571
|
firings.push({
|
|
575
572
|
id: m.signal.id ?? 'unknown',
|
|
576
573
|
phase,
|
package/src/index.ts
CHANGED
|
@@ -183,4 +183,4 @@ export type {
|
|
|
183
183
|
ConditionWhen,
|
|
184
184
|
} from "./types";
|
|
185
185
|
export { EventKind, MessageRole } from "./types";
|
|
186
|
-
export { createSession, createSessionId, enterFlow, enterStep, completeCurrentFlow, isFlowCompletedThisSession, mergeCollected } from "./utils";
|
|
186
|
+
export { createSession, createSessionId, createPersistedState, enterFlow, enterStep, completeCurrentFlow, isFlowCompletedThisSession, mergeCollected } from "./utils";
|
package/src/types/signals.ts
CHANGED
|
@@ -20,15 +20,15 @@ import type { Event } from "./history";
|
|
|
20
20
|
* Shape is locked to enable forward-compatible persistence in v2.0.
|
|
21
21
|
*/
|
|
22
22
|
export interface SignalTriggerState {
|
|
23
|
-
/** When this signal first
|
|
23
|
+
/** When this signal first completed its handler successfully. */
|
|
24
24
|
firstTriggeredAt: Date;
|
|
25
|
-
/** When this signal last
|
|
25
|
+
/** When this signal last completed its handler successfully. */
|
|
26
26
|
lastTriggeredAt: Date;
|
|
27
|
-
/** Total number of
|
|
27
|
+
/** Total number of successful handler completions for this signal. */
|
|
28
28
|
count: number;
|
|
29
|
-
/** Free-text reason from the last trigger (if
|
|
29
|
+
/** Free-text reason from the last successful trigger (if supplied). */
|
|
30
30
|
lastReason?: string;
|
|
31
|
-
/** Which phase the signal last
|
|
31
|
+
/** Which phase the signal last completed in. */
|
|
32
32
|
lastPhase?: 'pre' | 'post';
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -197,9 +197,9 @@ export interface SignalContext<
|
|
|
197
197
|
* Conditions use the v2 `when` / `if` split:
|
|
198
198
|
* - `when`: AI-evaluated string(s). Entries prefixed with `!` are exclusion
|
|
199
199
|
* conditions rendered under "DO NOT TRIGGER WHEN" in the classifier prompt.
|
|
200
|
-
* Non-prefixed entries render under "TRIGGER WHEN". Positive entries use
|
|
201
|
-
* semantics (
|
|
202
|
-
* inhibits firing).
|
|
200
|
+
* Non-prefixed entries render under "TRIGGER WHEN". Positive entries use OR
|
|
201
|
+
* semantics (any match can trigger). Negative entries also use OR semantics
|
|
202
|
+
* for exclusion (any match inhibits firing).
|
|
203
203
|
* - `if`: Code-evaluated function(s). Free. AND semantics.
|
|
204
204
|
*
|
|
205
205
|
* When both `if` and `when` are set, `if` evaluates first. If `if` returns
|
|
@@ -225,7 +225,7 @@ export interface Signal<
|
|
|
225
225
|
|
|
226
226
|
/**
|
|
227
227
|
* AI-evaluated trigger condition(s). String or array of strings.
|
|
228
|
-
* - Non-prefixed entries:
|
|
228
|
+
* - Non-prefixed entries: OR semantics. Any match can trigger.
|
|
229
229
|
* - `!`-prefixed entries: OR exclusion. Any match inhibits firing.
|
|
230
230
|
*
|
|
231
231
|
* At prompt-render time, the framework splits entries by prefix:
|