nexus-ai-pro 1.11.0 → 1.12.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/API_STABILITY.md +15 -0
- package/CHANGELOG.md +41 -1
- package/README.md +100 -3
- package/dist/graph/graph.d.ts +31 -1
- package/dist/graph/graph.js +291 -32
- package/dist/graph/index.d.ts +2 -2
- package/dist/graph/index.js +1 -1
- package/dist/graph/visualize.d.ts +30 -0
- package/dist/graph/visualize.js +74 -0
- package/dist/types/graph.d.ts +139 -4
- package/dist/types/graph.js +24 -0
- package/dist-cjs/graph/graph.d.ts +31 -1
- package/dist-cjs/graph/graph.js +290 -31
- package/dist-cjs/graph/index.d.ts +2 -2
- package/dist-cjs/graph/index.js +2 -1
- package/dist-cjs/graph/visualize.d.ts +30 -0
- package/dist-cjs/graph/visualize.js +78 -0
- package/dist-cjs/types/graph.d.ts +139 -4
- package/dist-cjs/types/graph.js +26 -1
- package/package.json +47 -11
package/API_STABILITY.md
CHANGED
|
@@ -313,6 +313,21 @@ Also since 1.11.0, all additive:
|
|
|
313
313
|
- `context.taskId` and `context.attempt` are new. Step events carry `tasks` and `attempts` when there
|
|
314
314
|
is something to report.
|
|
315
315
|
|
|
316
|
+
Also since 1.12.0, all additive:
|
|
317
|
+
|
|
318
|
+
- `Command` (with `Command.PARENT`) may be returned from a node; `NodeResult` names what a node may
|
|
319
|
+
return. `goto` routes are added to the node's outgoing edges, and a paused checkpoint records them in
|
|
320
|
+
the optional `gotos` field.
|
|
321
|
+
- `interruptBefore` and `interruptAfter` on compile and run options; a paused checkpoint and result
|
|
322
|
+
carry `breakpoint`, and step events may have type `breakpoint`.
|
|
323
|
+
- `NodeOptions.defer`, `GraphRunOptions.onEvent` with the `GraphEvent` union, and `context.emit()`.
|
|
324
|
+
New `GraphEvent` variants may be added in a minor release.
|
|
325
|
+
- `updateState()`, `fork()`, and `describe()` on a compiled graph, and the `nexus-ai-pro/graph/visualize`
|
|
326
|
+
subpath. The exact Mermaid text `toMermaid()` produces is not a guarantee — diagram layout may
|
|
327
|
+
improve in a minor release — but `GraphDescription` is a normalized shape.
|
|
328
|
+
- A subgraph node's thread id is `<parent thread>:<task id>`, which equals the previous
|
|
329
|
+
`<parent thread>:<node>` for any node not reached through `Send`.
|
|
330
|
+
|
|
316
331
|
## Deprecation process
|
|
317
332
|
|
|
318
333
|
Deprecated APIs are marked with `@deprecated` in declarations and described in the changelog. Removals
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,45 @@ Notable changes to this project are recorded here. The format follows [Keep a Ch
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.12.0] - 2026-09-20
|
|
8
|
+
|
|
9
|
+
Graph control and introspection. A node can route itself, a run can pause at breakpoints and be
|
|
10
|
+
edited or forked, every task and custom event can be watched as it happens, and a graph can draw
|
|
11
|
+
itself.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`Command`.** A node returns `new Command({ update, goto })` to write state and choose its
|
|
16
|
+
successors in one step, instead of splitting the decision into a separate router. `goto` takes node
|
|
17
|
+
names or `Send`s. A route chosen by a task that finished before its step paused is kept on the
|
|
18
|
+
checkpoint, so it is still followed when the step resumes.
|
|
19
|
+
- **`Command.PARENT`.** A node inside a subgraph hands control back to the graph that contains it. The
|
|
20
|
+
subgraph's own writes and the update it addressed to the parent are reduced separately, in order,
|
|
21
|
+
so neither overwrites the other.
|
|
22
|
+
- **Breakpoints.** `interruptBefore` and `interruptAfter`, per compile or per run, pause a run at
|
|
23
|
+
chosen nodes with status `interrupted` and a `breakpoint` describing where. `continue()` carries on,
|
|
24
|
+
and does not pause again at the breakpoint it resumes from.
|
|
25
|
+
- **Deferred nodes.** `addNode(name, fn, { defer: true })` holds a node until every other pending task
|
|
26
|
+
has finished, so an aggregator after branches of different lengths runs once.
|
|
27
|
+
- **`updateState()`.** Merges a correction into a thread's latest checkpoint in place, keeping any
|
|
28
|
+
pending question; with `asNode`, applies it as that node's output and continues along its edges.
|
|
29
|
+
- **`fork()`.** Copies a thread's history up to a step into a new thread, leaving the original
|
|
30
|
+
untouched and runnable, and records `metadata.forkedFrom`.
|
|
31
|
+
- **`onEvent` and `context.emit()`.** A run can observe each task starting, retrying, and finishing
|
|
32
|
+
with its update, every checkpoint written, and custom events a node emits, such as model tokens. A
|
|
33
|
+
listener that throws never fails the run.
|
|
34
|
+
- **`describe()` and `nexus-ai-pro/graph/visualize`.** `describe()` returns a graph's nodes, edges, and
|
|
35
|
+
run-time routes as plain JSON, including subgraphs. `toMermaid()` draws it, with optional
|
|
36
|
+
highlighting of where a thread is; `toGraphJSON()` returns the data. The visualizer imports no
|
|
37
|
+
runtime code.
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- **Parallel copies of a subgraph node no longer share a thread.** `asNode()` keyed the subgraph's
|
|
42
|
+
thread by node name, so two `Send` copies of one subgraph node in the same step wrote to the same
|
|
43
|
+
thread. It is now keyed by task; a plain node's task id is its name, so existing threads are
|
|
44
|
+
unaffected.
|
|
45
|
+
|
|
7
46
|
## [1.11.0] - 2026-09-18
|
|
8
47
|
|
|
9
48
|
Parallel graphs. A fan-out that looks parallel now runs in parallel, a graph can fan out over data it
|
|
@@ -614,7 +653,8 @@ shared policy vocabulary is in place for a future release that revisits this.
|
|
|
614
653
|
- URL fetching rejects unsafe private-network targets and limits response reads.
|
|
615
654
|
- CLI and audit findings no longer disclose detected secret values.
|
|
616
655
|
|
|
617
|
-
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.
|
|
656
|
+
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.12.0...HEAD
|
|
657
|
+
[1.12.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.11.0...v1.12.0
|
|
618
658
|
[1.11.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.10.0...v1.11.0
|
|
619
659
|
[1.10.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.9.0...v1.10.0
|
|
620
660
|
[1.9.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.8.0...v1.9.0
|
package/README.md
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# nexus-ai-pro
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The typed AI framework for TypeScript. One API for provider routing and failover, agent graphs that
|
|
4
|
+
run branches in parallel and survive a restart, durable background operations, guardrails, cost
|
|
5
|
+
control, images, voice, and evals.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Import the whole runtime, or one piece: every capability has its own entry point with a size budget
|
|
8
|
+
CI enforces, and the table below publishes what each one costs. A graph-only application loads 60 KB
|
|
9
|
+
and installs no third-party package at all.
|
|
6
10
|
|
|
7
11
|
- NPM: https://www.npmjs.com/package/nexus-ai-pro
|
|
8
12
|
- GitHub: https://github.com/mkhitar-abrahamyan/nexus-ai
|
|
@@ -533,6 +537,98 @@ await graph.history(threadId); // newest first
|
|
|
533
537
|
graph.resumeFrom(threadId, 3); // rewind and run forward
|
|
534
538
|
```
|
|
535
539
|
|
|
540
|
+
**Route from inside a node.** When a node already knows where to go — an agent that just picked a
|
|
541
|
+
tool, a triage step that classified a ticket — return a `Command` instead of splitting the decision
|
|
542
|
+
into a separate router:
|
|
543
|
+
|
|
544
|
+
```ts
|
|
545
|
+
import { Command } from 'nexus-ai-pro/graph';
|
|
546
|
+
|
|
547
|
+
.addNode('triage', (ctx) =>
|
|
548
|
+
new Command({ update: { label: classify(ctx.state) }, goto: isUrgent(ctx.state) ? 'page-oncall' : 'queue' }),
|
|
549
|
+
{ ends: ['page-oncall', 'queue'] },
|
|
550
|
+
)
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
`goto` takes node names or `Send`s, and `ends` keeps compile-time checks and diagrams exact. A node
|
|
554
|
+
inside a subgraph can return `new Command({ graph: Command.PARENT, goto: 'human' })` to hand control
|
|
555
|
+
back to the graph that contains it — how a nested agent escalates.
|
|
556
|
+
|
|
557
|
+
**Aggregate after branches of different lengths.** `{ defer: true }` holds a node until every other
|
|
558
|
+
pending task has finished, so an aggregator after a two-step branch and a one-step branch runs once,
|
|
559
|
+
after both, rather than once per arrival.
|
|
560
|
+
|
|
561
|
+
**Pause for inspection.** Breakpoints stop a run before or after chosen nodes, checkpointed, without
|
|
562
|
+
changing the nodes themselves:
|
|
563
|
+
|
|
564
|
+
```ts
|
|
565
|
+
const graph = builder.compile({ interruptBefore: ['publish'] });
|
|
566
|
+
const paused = await graph.invoke(input, { threadId }); // status: 'interrupted', breakpoint: { when: 'before', ... }
|
|
567
|
+
await graph.updateState(threadId, { draft: fixedDraft }); // correct something first, if needed
|
|
568
|
+
for await (const _ of graph.continue(threadId)) {} // then carry on
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
Set them per compile or per run; a run's list replaces the compiled one.
|
|
572
|
+
|
|
573
|
+
**Edit state, or fork a thread.** `updateState(threadId, update)` merges a correction into the latest
|
|
574
|
+
checkpoint through the channel reducers, leaving any pending question in place.
|
|
575
|
+
`updateState(threadId, update, { asNode: 'research' })` applies it as if that node had produced it,
|
|
576
|
+
so the next step follows that node's edges. `fork(threadId, { step })` copies the history up to a step
|
|
577
|
+
into a new thread and leaves the original untouched, so two answers to the same question can be run
|
|
578
|
+
side by side.
|
|
579
|
+
|
|
580
|
+
**Watch it run.** `onEvent` receives every task starting, retrying, and finishing with its update,
|
|
581
|
+
every checkpoint written, and whatever a node passes to `context.emit()` — model tokens as they
|
|
582
|
+
stream, a status line, an intermediate result:
|
|
583
|
+
|
|
584
|
+
```ts
|
|
585
|
+
.addNode('write', async (ctx) => {
|
|
586
|
+
for await (const token of streamAnswer(ctx.state)) ctx.emit({ token });
|
|
587
|
+
return { answer };
|
|
588
|
+
})
|
|
589
|
+
|
|
590
|
+
await graph.invoke(input, {
|
|
591
|
+
onEvent: (event) => event.type === 'custom' && process.stdout.write((event.data as { token: string }).token),
|
|
592
|
+
});
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
A listener that throws never fails the run it is watching.
|
|
596
|
+
|
|
597
|
+
**See the shape.** `graph.describe()` returns nodes, edges, and which routes are decided at run
|
|
598
|
+
time, as plain JSON. `toMermaid()` from `nexus-ai-pro/graph/visualize` draws it — solid arrows are
|
|
599
|
+
always taken, dotted ones are chosen at run time, and subgraphs are drawn inside the node that runs
|
|
600
|
+
them:
|
|
601
|
+
|
|
602
|
+
```ts
|
|
603
|
+
import { toMermaid } from 'nexus-ai-pro/graph/visualize';
|
|
604
|
+
|
|
605
|
+
console.log(toMermaid(graph, { highlight: checkpoint.next }));
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
This diagram is that function's actual output for a research-and-review graph:
|
|
609
|
+
|
|
610
|
+
```mermaid
|
|
611
|
+
flowchart TD
|
|
612
|
+
__start__([start])
|
|
613
|
+
__end__([end])
|
|
614
|
+
n_plan["plan"]
|
|
615
|
+
n_research["research<br/><small>retries</small>"]
|
|
616
|
+
n_summarize["summarize<br/><small>deferred</small>"]
|
|
617
|
+
n_review["review"]
|
|
618
|
+
n_publish["publish"]
|
|
619
|
+
__start__ --> n_plan
|
|
620
|
+
n_summarize --> n_review
|
|
621
|
+
n_publish --> __end__
|
|
622
|
+
n_plan -.-> n_research
|
|
623
|
+
n_research -.-> n_summarize
|
|
624
|
+
n_review -.-> n_publish
|
|
625
|
+
n_review -.-> n_plan
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
The visualizer is its own subpath and imports no runtime code, so drawing a graph costs nothing to an
|
|
629
|
+
application that only runs one. No image renderer is bundled; any Mermaid renderer turns the output
|
|
630
|
+
into PNG or SVG.
|
|
631
|
+
|
|
536
632
|
**Durable by construction.** The default checkpointer is in-process, holding up to 1,000 threads;
|
|
537
633
|
pass `checkpointer: false` to turn checkpointing off. Point it at the operation store
|
|
538
634
|
that already backs durable operations and a thread survives a restart — a different worker resumes
|
|
@@ -1832,13 +1928,13 @@ only, so it never appears in an import graph.
|
|
|
1832
1928
|
| `nexus-ai-pro/providers/anthropic` | 70 KB | 11% | none |
|
|
1833
1929
|
| `nexus-ai-pro/providers/google` | 66 KB | 11% | none |
|
|
1834
1930
|
| `nexus-ai-pro/images` | 65 KB | 11% | none |
|
|
1931
|
+
| `nexus-ai-pro/graph` | 60 KB | 10% | none |
|
|
1835
1932
|
| `nexus-ai-pro/providers/ollama` | 58 KB | 9% | none |
|
|
1836
1933
|
| `nexus-ai-pro/batch/openai` | 52 KB | 8% | none |
|
|
1837
1934
|
| `nexus-ai-pro/batch/anthropic` | 52 KB | 8% | none |
|
|
1838
1935
|
| `nexus-ai-pro/operations` | 49 KB | 8% | none |
|
|
1839
1936
|
| `nexus-ai-pro/batch/mock` | 47 KB | 8% | none |
|
|
1840
1937
|
| `nexus-ai-pro/providers/cohere` | 46 KB | 8% | none |
|
|
1841
|
-
| `nexus-ai-pro/graph` | 46 KB | 8% | none |
|
|
1842
1938
|
| `nexus-ai-pro/realtime/openai-webrtc` | 46 KB | 8% | none |
|
|
1843
1939
|
| `nexus-ai-pro/security` | 40 KB | 7% | +3.4 MB |
|
|
1844
1940
|
| `nexus-ai-pro/models` | 35 KB | 6% | none |
|
|
@@ -1874,6 +1970,7 @@ only, so it never appears in an import graph.
|
|
|
1874
1970
|
| `nexus-ai-pro/realtime/openai-server` | 8 KB | 1% | none |
|
|
1875
1971
|
| `nexus-ai-pro/capabilities` | 8 KB | 1% | none |
|
|
1876
1972
|
| `nexus-ai-pro/telephony/realtime-bridge` | 7 KB | 1% | none |
|
|
1973
|
+
| `nexus-ai-pro/graph/visualize` | 6 KB | 1.0% | none |
|
|
1877
1974
|
| `nexus-ai-pro/providers/errors` | 5 KB | 0.8% | none |
|
|
1878
1975
|
| `nexus-ai-pro/embeddings/mock` | 5 KB | 0.8% | none |
|
|
1879
1976
|
| `nexus-ai-pro/cache/semantic-cache` | 5 KB | 0.8% | none |
|
package/dist/graph/graph.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChannelSchema, CompileOptions, EdgeRouter, GraphCheckpoint, GraphProgress, GraphResult, GraphRunOptions, GraphStatus, GraphStepEvent, NodeFn, NodeOptions, StateUpdate } from '../types/graph.js';
|
|
1
|
+
import type { ChannelSchema, CompileOptions, EdgeRouter, GraphCheckpoint, GraphDescription, GraphProgress, GraphResult, GraphRunOptions, GraphStatus, GraphStepEvent, NodeFn, NodeOptions, StateUpdate } from '../types/graph.js';
|
|
2
2
|
interface GraphNodeDefinition<S extends ChannelSchema> {
|
|
3
3
|
fn: NodeFn<S>;
|
|
4
4
|
options: NodeOptions;
|
|
@@ -91,6 +91,36 @@ export declare class CompiledGraph<S extends ChannelSchema> {
|
|
|
91
91
|
* passes the answer into the subgraph, which continues where it stopped rather than starting over.
|
|
92
92
|
*/
|
|
93
93
|
asNode<P extends ChannelSchema>(): NodeFn<P>;
|
|
94
|
+
/**
|
|
95
|
+
* The graph's shape as plain data: nodes, edges, and which routes are chosen at run time.
|
|
96
|
+
*
|
|
97
|
+
* What `nexus-ai-pro/graph/visualize` draws, and what a UI or a test can inspect without running
|
|
98
|
+
* anything. Subgraphs added through `asNode()` are described inside the node that runs them.
|
|
99
|
+
*/
|
|
100
|
+
describe(): GraphDescription;
|
|
101
|
+
/**
|
|
102
|
+
* Edits a thread's state.
|
|
103
|
+
*
|
|
104
|
+
* Without `asNode`, the update is merged into the latest checkpoint in place, through the channel
|
|
105
|
+
* reducers, and the run continues exactly where it was — including a thread paused for input.
|
|
106
|
+
* With `asNode`, the update is applied as if that node had just produced it: a new checkpoint is
|
|
107
|
+
* written and the next step follows that node's edges. That is how an operator corrects a wrong
|
|
108
|
+
* intermediate result and lets the rest of the graph run on the fix.
|
|
109
|
+
*/
|
|
110
|
+
updateState(threadId: string, update: StateUpdate<S>, options?: {
|
|
111
|
+
asNode?: string;
|
|
112
|
+
}): Promise<GraphCheckpoint<S>>;
|
|
113
|
+
/**
|
|
114
|
+
* Copies a thread's history up to `step` into a new thread, and returns the new thread's id.
|
|
115
|
+
*
|
|
116
|
+
* Rewinding with `resumeFrom()` replaces the original timeline. A fork keeps it: both threads stay
|
|
117
|
+
* readable and runnable, so two answers to the same question can be compared side by side. Every
|
|
118
|
+
* copied checkpoint records `metadata.forkedFrom`.
|
|
119
|
+
*/
|
|
120
|
+
fork(threadId: string, options?: {
|
|
121
|
+
step?: number;
|
|
122
|
+
threadId?: string;
|
|
123
|
+
}): Promise<string>;
|
|
94
124
|
private run;
|
|
95
125
|
/** Runs one task to a verdict, applying its retry policy and timeout. */
|
|
96
126
|
private runTask;
|