nexus-ai-pro 1.11.0 → 1.14.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 +42 -0
- package/CHANGELOG.md +106 -1
- package/README.md +260 -3
- package/dist/agent/create-agent.d.ts +119 -0
- package/dist/agent/create-agent.js +176 -0
- package/dist/agent/index.d.ts +5 -0
- package/dist/agent/index.js +4 -0
- package/dist/agent/middleware.d.ts +46 -0
- package/dist/agent/middleware.js +77 -0
- package/dist/graph/graph.d.ts +31 -1
- package/dist/graph/graph.js +292 -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/mcp/client.d.ts +106 -0
- package/dist/mcp/client.js +243 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.js +3 -0
- package/dist/mcp/protocol.d.ts +71 -0
- package/dist/mcp/protocol.js +68 -0
- package/dist/mcp/server.d.ts +46 -0
- package/dist/mcp/server.js +155 -0
- package/dist/store/index.d.ts +2 -0
- package/dist/store/index.js +1 -0
- package/dist/store/memory.d.ts +41 -0
- package/dist/store/memory.js +182 -0
- package/dist/store/redis.d.ts +49 -0
- package/dist/store/redis.js +128 -0
- package/dist/tracing/alerts.d.ts +60 -0
- package/dist/tracing/alerts.js +98 -0
- package/dist/tracing/compare.d.ts +31 -0
- package/dist/tracing/compare.js +69 -0
- package/dist/tracing/index.d.ts +6 -0
- package/dist/tracing/index.js +5 -0
- package/dist/tracing/instrument.d.ts +47 -0
- package/dist/tracing/instrument.js +138 -0
- package/dist/tracing/stores.d.ts +53 -0
- package/dist/tracing/stores.js +192 -0
- package/dist/tracing/tracer.d.ts +73 -0
- package/dist/tracing/tracer.js +182 -0
- package/dist/types/graph.d.ts +149 -4
- package/dist/types/graph.js +24 -0
- package/dist/types/store.d.ts +61 -0
- package/dist/types/store.js +9 -0
- package/dist/types/tracing.d.ts +102 -0
- package/dist/types/tracing.js +10 -0
- package/dist-cjs/agent/create-agent.d.ts +119 -0
- package/dist-cjs/agent/create-agent.js +181 -0
- package/dist-cjs/agent/index.d.ts +5 -0
- package/dist-cjs/agent/index.js +16 -0
- package/dist-cjs/agent/middleware.d.ts +46 -0
- package/dist-cjs/agent/middleware.js +82 -0
- package/dist-cjs/graph/graph.d.ts +31 -1
- package/dist-cjs/graph/graph.js +291 -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/mcp/client.d.ts +106 -0
- package/dist-cjs/mcp/client.js +282 -0
- package/dist-cjs/mcp/index.d.ts +3 -0
- package/dist-cjs/mcp/index.js +15 -0
- package/dist-cjs/mcp/protocol.d.ts +71 -0
- package/dist-cjs/mcp/protocol.js +77 -0
- package/dist-cjs/mcp/server.d.ts +46 -0
- package/dist-cjs/mcp/server.js +160 -0
- package/dist-cjs/store/index.d.ts +2 -0
- package/dist-cjs/store/index.js +6 -0
- package/dist-cjs/store/memory.d.ts +41 -0
- package/dist-cjs/store/memory.js +190 -0
- package/dist-cjs/store/redis.d.ts +49 -0
- package/dist-cjs/store/redis.js +132 -0
- package/dist-cjs/tracing/alerts.d.ts +60 -0
- package/dist-cjs/tracing/alerts.js +104 -0
- package/dist-cjs/tracing/compare.d.ts +31 -0
- package/dist-cjs/tracing/compare.js +73 -0
- package/dist-cjs/tracing/index.d.ts +6 -0
- package/dist-cjs/tracing/index.js +21 -0
- package/dist-cjs/tracing/instrument.d.ts +47 -0
- package/dist-cjs/tracing/instrument.js +142 -0
- package/dist-cjs/tracing/stores.d.ts +53 -0
- package/dist-cjs/tracing/stores.js +202 -0
- package/dist-cjs/tracing/tracer.d.ts +73 -0
- package/dist-cjs/tracing/tracer.js +187 -0
- package/dist-cjs/types/graph.d.ts +149 -4
- package/dist-cjs/types/graph.js +26 -1
- package/dist-cjs/types/store.d.ts +61 -0
- package/dist-cjs/types/store.js +10 -0
- package/dist-cjs/types/tracing.d.ts +102 -0
- package/dist-cjs/types/tracing.js +11 -0
- package/package.json +112 -11
package/API_STABILITY.md
CHANGED
|
@@ -313,6 +313,48 @@ 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
|
+
|
|
331
|
+
## Agent, store, MCP, and tracing stages (1.14.0)
|
|
332
|
+
|
|
333
|
+
The `nexus-ai-pro/agent`, `nexus-ai-pro/store`, `nexus-ai-pro/store/redis`, and `nexus-ai-pro/mcp`
|
|
334
|
+
subpaths are public and follow the 1.x rules. None is exported from the root import.
|
|
335
|
+
|
|
336
|
+
- `createAgent()` returns a compiled graph, so the graph guarantees above apply to an agent: a
|
|
337
|
+
superstep is atomic with respect to checkpointing, a finished task is never re-run by a resume, and
|
|
338
|
+
an approval survives a restart. The agent's state channels (`messages`, `iterations`, `answer`,
|
|
339
|
+
`stopReason`) are a normalized shape; what a model decides to put in them is not.
|
|
340
|
+
- `Store` is the contract; `MemoryStore` and `RedisStore` implement it. Ranking from a semantic search
|
|
341
|
+
depends on the embedding function a caller injects and is not a guarantee. `MemoryStore` is
|
|
342
|
+
process-local and bounded, and drops the least recently written item past `maxItems`.
|
|
343
|
+
- The MCP subpath implements a subset of the Model Context Protocol: initialize, tools, resources, and
|
|
344
|
+
prompts, over stdio and HTTP. Protocol versions and server behaviour are upstream contracts outside
|
|
345
|
+
this policy. Server-initiated streaming, sampling, and roots are not implemented; new methods may be
|
|
346
|
+
added in a minor release.
|
|
347
|
+
- `nexus-ai-pro/tracing` is public: `Tracer`, the `TraceStore` contract, `MemoryTraceStore`,
|
|
348
|
+
`JsonlTraceStore`, `traceGraph()`, `traceModelClient()`, `compareTraces()`, and `AlertEvaluator`.
|
|
349
|
+
The `Run`, `RunTree`, and `RunQuery` shapes are normalized; what a model puts in a run's inputs and
|
|
350
|
+
outputs is not. New `RunKind` values and query fields may be added in a minor release. Sampling is
|
|
351
|
+
probabilistic by definition, so which traces are kept is not a guarantee, but the tail rules are:
|
|
352
|
+
an error, a run past `keepSlowerThanMs`, or one past `keepCostlierThan` is always kept.
|
|
353
|
+
- `agentAsTool()` and the bundled middleware (`summarizeHistory`, `redactMessages`, `limitToolCalls`)
|
|
354
|
+
are public and additive.
|
|
355
|
+
- `AgentLoop`, `tool()`, and `ToolExecutor` keep their behaviour and are re-exported from
|
|
356
|
+
`nexus-ai-pro/agent` as well as the root.
|
|
357
|
+
|
|
316
358
|
## Deprecation process
|
|
317
359
|
|
|
318
360
|
Deprecated APIs are marked with `@deprecated` in declarations and described in the changelog. Removals
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,109 @@ Notable changes to this project are recorded here. The format follows [Keep a Ch
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.14.0] - 2026-09-20
|
|
8
|
+
|
|
9
|
+
The memory, agent, and MCP work planned for 1.13.0 ships here together with tracing, so no 1.13.0 was
|
|
10
|
+
published.
|
|
11
|
+
|
|
12
|
+
Memory, agents, MCP, and traces. An agent is now a graph rather than a loop, so it inherits
|
|
13
|
+
approvals, parallel tool calls, and durability. A store gives it memory that outlives a thread, MCP
|
|
14
|
+
connects it to tools this package does not have to ship, and every run can be recorded as a tree you
|
|
15
|
+
can search, compare, and alert on.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **`nexus-ai-pro/agent` and `createAgent()`.** Returns a compiled graph, so an agent gets
|
|
20
|
+
checkpoints, resume, forks, events, and a diagram from the graph runtime rather than from code
|
|
21
|
+
written twice.
|
|
22
|
+
- Tool calls run as parallel tasks, bounded by `toolConcurrency`.
|
|
23
|
+
- `interruptOn` makes a tool wait for a human. The approval is a checkpoint, so it can arrive days
|
|
24
|
+
later from another process, and it can approve, refuse with a reason the model sees, or approve
|
|
25
|
+
with corrected arguments.
|
|
26
|
+
- Middleware wraps the model call (`beforeModel`, `afterModel`) and each tool call
|
|
27
|
+
(`wrapToolCall`).
|
|
28
|
+
- `stopReason` distinguishes a finished answer from one that ran out of iterations, and malformed
|
|
29
|
+
tool arguments never reach a tool.
|
|
30
|
+
- `AgentLoop` is unchanged, for the case that wants none of this.
|
|
31
|
+
- **`nexus-ai-pro/store`, long-term memory.** Namespaced tuples, `put`/`get`/`delete`/`search`/
|
|
32
|
+
`listNamespaces`, TTLs, and field filters.
|
|
33
|
+
- Semantic search ranks by any embedding function you inject, so the store never imports the
|
|
34
|
+
embeddings runtime; without an index, a query matches text.
|
|
35
|
+
- `MemoryStore` is bounded, like the graph's memory checkpointer. `RedisStore`
|
|
36
|
+
(`nexus-ai-pro/store/redis`) shares memory across processes through a client-like interface.
|
|
37
|
+
- `compile({ store })` hands it to every node as `context.store`.
|
|
38
|
+
- **`nexus-ai-pro/tracing`, run trees you can query.** Metrics say how it is going; a trace says what
|
|
39
|
+
happened.
|
|
40
|
+
- Every family has a run kind: model, tool, graph, node, agent, retriever, embedding, image, voice,
|
|
41
|
+
realtime, operation. A run carries inputs, outputs, timing, tokens, cost, tags, and errors.
|
|
42
|
+
- `traceGraph()` turns the graph's own event stream into a run tree, so nothing inside the graph
|
|
43
|
+
knows about tracing and an untraced run pays nothing. `traceModelClient()` nests each model call
|
|
44
|
+
inside the node that made it, with its tokens and cost.
|
|
45
|
+
- Tail sampling keeps every error, slow run, and expensive run whatever the head rate is, because
|
|
46
|
+
the decision is made when a trace finishes.
|
|
47
|
+
- Redaction runs before storage: hidden fields are never written, and a `redact` hook gets the last
|
|
48
|
+
word.
|
|
49
|
+
- `MemoryTraceStore` is bounded; `JsonlTraceStore` appends to a file that survives a restart and can
|
|
50
|
+
be read back, pruned, and rotated.
|
|
51
|
+
- Queries filter by kind, status, name, model, tags, metadata, latency, cost, time, and feedback.
|
|
52
|
+
`tree()` assembles a trace, `formatTree()` prints it, and `compareTraces()` reports what changed
|
|
53
|
+
between two runs of the same shape.
|
|
54
|
+
- `recordFeedback()` attaches scores from people or from evaluators.
|
|
55
|
+
- `AlertEvaluator` runs rules over stored runs — error rate, latency percentiles, cost, count — and
|
|
56
|
+
every alert carries the runs that tripped it. `createWebhookNotifier()` posts them.
|
|
57
|
+
- **Bundled agent middleware.** `summarizeHistory` keeps a long transcript from growing without
|
|
58
|
+
bound, `redactMessages` keeps secrets out of provider requests and responses, and `limitToolCalls`
|
|
59
|
+
caps how often a tool may run.
|
|
60
|
+
- **`agentAsTool()`.** Gives one agent to another as a tool, so a supervisor can delegate while
|
|
61
|
+
keeping control. Each agent keeps its own memory, approvals, and thread.
|
|
62
|
+
|
|
63
|
+
- **`nexus-ai-pro/mcp`, both directions of the Model Context Protocol.** Implemented directly, with
|
|
64
|
+
no protocol SDK dependency.
|
|
65
|
+
- `McpClient` lists and calls tools, reads resources and prompts, and `toNexusTools()` turns a
|
|
66
|
+
server's tools into tools an agent can call, with optional name prefixes.
|
|
67
|
+
- `McpServer` exposes this application's tools and resources to other assistants.
|
|
68
|
+
- Stdio and HTTP transports are included, and the transport is an interface, so a client and a
|
|
69
|
+
server can be wired together in memory for a test.
|
|
70
|
+
|
|
71
|
+
## [1.12.0] - 2026-09-20
|
|
72
|
+
|
|
73
|
+
Graph control and introspection. A node can route itself, a run can pause at breakpoints and be
|
|
74
|
+
edited or forked, every task and custom event can be watched as it happens, and a graph can draw
|
|
75
|
+
itself.
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
|
|
79
|
+
- **`Command`.** A node returns `new Command({ update, goto })` to write state and choose its
|
|
80
|
+
successors in one step, instead of splitting the decision into a separate router. `goto` takes node
|
|
81
|
+
names or `Send`s. A route chosen by a task that finished before its step paused is kept on the
|
|
82
|
+
checkpoint, so it is still followed when the step resumes.
|
|
83
|
+
- **`Command.PARENT`.** A node inside a subgraph hands control back to the graph that contains it. The
|
|
84
|
+
subgraph's own writes and the update it addressed to the parent are reduced separately, in order,
|
|
85
|
+
so neither overwrites the other.
|
|
86
|
+
- **Breakpoints.** `interruptBefore` and `interruptAfter`, per compile or per run, pause a run at
|
|
87
|
+
chosen nodes with status `interrupted` and a `breakpoint` describing where. `continue()` carries on,
|
|
88
|
+
and does not pause again at the breakpoint it resumes from.
|
|
89
|
+
- **Deferred nodes.** `addNode(name, fn, { defer: true })` holds a node until every other pending task
|
|
90
|
+
has finished, so an aggregator after branches of different lengths runs once.
|
|
91
|
+
- **`updateState()`.** Merges a correction into a thread's latest checkpoint in place, keeping any
|
|
92
|
+
pending question; with `asNode`, applies it as that node's output and continues along its edges.
|
|
93
|
+
- **`fork()`.** Copies a thread's history up to a step into a new thread, leaving the original
|
|
94
|
+
untouched and runnable, and records `metadata.forkedFrom`.
|
|
95
|
+
- **`onEvent` and `context.emit()`.** A run can observe each task starting, retrying, and finishing
|
|
96
|
+
with its update, every checkpoint written, and custom events a node emits, such as model tokens. A
|
|
97
|
+
listener that throws never fails the run.
|
|
98
|
+
- **`describe()` and `nexus-ai-pro/graph/visualize`.** `describe()` returns a graph's nodes, edges, and
|
|
99
|
+
run-time routes as plain JSON, including subgraphs. `toMermaid()` draws it, with optional
|
|
100
|
+
highlighting of where a thread is; `toGraphJSON()` returns the data. The visualizer imports no
|
|
101
|
+
runtime code.
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
|
|
105
|
+
- **Parallel copies of a subgraph node no longer share a thread.** `asNode()` keyed the subgraph's
|
|
106
|
+
thread by node name, so two `Send` copies of one subgraph node in the same step wrote to the same
|
|
107
|
+
thread. It is now keyed by task; a plain node's task id is its name, so existing threads are
|
|
108
|
+
unaffected.
|
|
109
|
+
|
|
7
110
|
## [1.11.0] - 2026-09-18
|
|
8
111
|
|
|
9
112
|
Parallel graphs. A fan-out that looks parallel now runs in parallel, a graph can fan out over data it
|
|
@@ -614,7 +717,9 @@ shared policy vocabulary is in place for a future release that revisits this.
|
|
|
614
717
|
- URL fetching rejects unsafe private-network targets and limits response reads.
|
|
615
718
|
- CLI and audit findings no longer disclose detected secret values.
|
|
616
719
|
|
|
617
|
-
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.
|
|
720
|
+
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.14.0...HEAD
|
|
721
|
+
[1.14.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.12.0...v1.14.0
|
|
722
|
+
[1.12.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.11.0...v1.12.0
|
|
618
723
|
[1.11.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.10.0...v1.11.0
|
|
619
724
|
[1.10.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.9.0...v1.10.0
|
|
620
725
|
[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
|
|
@@ -559,6 +655,161 @@ private to the subgraph.
|
|
|
559
655
|
|
|
560
656
|
The graph is not in the root import. It costs nothing to a user who does not build graphs.
|
|
561
657
|
|
|
658
|
+
## Agents
|
|
659
|
+
|
|
660
|
+
An agent is a graph, so everything above applies to it: checkpoints, human approval, parallel work,
|
|
661
|
+
forks, events, and a diagram.
|
|
662
|
+
|
|
663
|
+
```ts
|
|
664
|
+
import { createAgent, agentInput, tool } from 'nexus-ai-pro/agent';
|
|
665
|
+
|
|
666
|
+
const agent = createAgent({
|
|
667
|
+
client: ai, // anything with complete(); NexusAI qualifies
|
|
668
|
+
systemPrompt: 'You are a support engineer.',
|
|
669
|
+
tools: [refundTool, emailTool],
|
|
670
|
+
interruptOn: { send_email: true }, // this one waits for a human
|
|
671
|
+
store, // long-term memory, below
|
|
672
|
+
checkpointer, // survives a restart
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
const run = await agent.invoke(agentInput('Refund order 1182 and tell the customer'), { threadId });
|
|
676
|
+
run.state.answer; // the final text
|
|
677
|
+
run.state.stopReason; // 'completed' | 'max_iterations'
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
**Tool calls run in parallel.** Each call the model requests becomes its own task, bounded by
|
|
681
|
+
`toolConcurrency`, so three lookups take as long as the slowest one.
|
|
682
|
+
|
|
683
|
+
**Approval is an interrupt, not a callback.** A tool listed in `interruptOn` pauses the run and
|
|
684
|
+
checkpoints it. The answer can approve, refuse with a reason the model sees, or approve with
|
|
685
|
+
corrected arguments:
|
|
686
|
+
|
|
687
|
+
```ts
|
|
688
|
+
if (run.status === 'awaiting_input') {
|
|
689
|
+
await agent.resumeWith(threadId, { approved: true, args: { to: 'billing@example.com' } });
|
|
690
|
+
}
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
Because it is a checkpoint, the approval can arrive days later, from another process.
|
|
694
|
+
|
|
695
|
+
**Middleware** wraps the parts worth controlling: `beforeModel` adjusts the request, `afterModel`
|
|
696
|
+
inspects or replaces the response, and `wrapToolCall` surrounds each tool call for logging, timing,
|
|
697
|
+
or policy. `AgentLoop` remains for the simple case that needs none of this.
|
|
698
|
+
|
|
699
|
+
## Long-term Memory
|
|
700
|
+
|
|
701
|
+
A checkpoint remembers one conversation. A store remembers across them:
|
|
702
|
+
|
|
703
|
+
```ts
|
|
704
|
+
import { MemoryStore } from 'nexus-ai-pro/store';
|
|
705
|
+
|
|
706
|
+
const store = new MemoryStore({ index: { embed, fields: ['text'] } }); // embed is yours
|
|
707
|
+
await store.put(['tenant-7', 'users', 'alice'], 'tone', { text: 'prefers brief answers' });
|
|
708
|
+
|
|
709
|
+
// In any node or tool, in any thread, later:
|
|
710
|
+
const memories = await context.store.search(['tenant-7', 'users', 'alice'], { query: 'how do they like answers?' });
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
Namespaces are tuples, so `['tenant-7', 'users', 'alice']` is both a place to put something and a
|
|
714
|
+
prefix to search. Items can expire with `ttlMs`, be filtered by field, and be ranked semantically by
|
|
715
|
+
any embedding function you inject — the store never imports the embeddings runtime, and without an
|
|
716
|
+
index a query falls back to matching text. `RedisStore` from `nexus-ai-pro/store/redis` carries the
|
|
717
|
+
same contract across processes through a client-like interface, so no Redis package is a dependency
|
|
718
|
+
here.
|
|
719
|
+
|
|
720
|
+
## MCP
|
|
721
|
+
|
|
722
|
+
The Model Context Protocol, both directions, implemented directly rather than through an SDK:
|
|
723
|
+
|
|
724
|
+
```ts
|
|
725
|
+
import { McpClient, createStdioTransport } from 'nexus-ai-pro/mcp';
|
|
726
|
+
import { Tracer, MemoryTraceStore } from 'nexus-ai-pro/tracing';
|
|
727
|
+
|
|
728
|
+
const client = new McpClient(createStdioTransport({ command: 'npx', args: ['-y', 'some-mcp-server'] }));
|
|
729
|
+
const agent = createAgent({ client: ai, tools: await client.toNexusTools({ prefix: 'files' }) });
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
That is how this package reaches a broad tool ecosystem without maintaining a catalogue of
|
|
733
|
+
integrations: anything exposed over MCP becomes tools an agent can call. The server direction lends
|
|
734
|
+
your tools out the same way, so a tool written once with `tool()` serves an agent here and an editor
|
|
735
|
+
elsewhere:
|
|
736
|
+
|
|
737
|
+
```ts
|
|
738
|
+
import { McpServer, createStdioServerTransport } from 'nexus-ai-pro/mcp';
|
|
739
|
+
|
|
740
|
+
await new McpServer({ name: 'my-app', tools: [refundTool] }).connect(createStdioServerTransport());
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
Stdio and HTTP transports are included, and the transport is an interface, so a test can wire a
|
|
744
|
+
client to a server in memory.
|
|
745
|
+
|
|
746
|
+
## Traces
|
|
747
|
+
|
|
748
|
+
Metrics say how it is going. A trace says what happened: the run tree of one request, with its
|
|
749
|
+
inputs, outputs, tokens, cost, and errors, stored where you can search it.
|
|
750
|
+
|
|
751
|
+
```ts
|
|
752
|
+
import { Tracer, MemoryTraceStore, traceGraph, traceModelClient } from 'nexus-ai-pro/tracing';
|
|
753
|
+
|
|
754
|
+
const tracer = new Tracer({
|
|
755
|
+
store: new MemoryTraceStore(), // or JsonlTraceStore({ file })
|
|
756
|
+
sampling: { rate: 0.05, keepErrors: true }, // 5% of traces, plus every failure
|
|
757
|
+
redaction: { hideFields: ['apiKey', 'user.email'] },
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
const tracing = traceGraph(tracer, { name: 'support-agent', kind: 'agent' });
|
|
761
|
+
const agent = createAgent({ client: traceModelClient(ai, tracer, { parent: () => tracing.runFor('model') }) });
|
|
762
|
+
|
|
763
|
+
const run = await agent.invoke(agentInput(question), { threadId, ...tracing.runOptions });
|
|
764
|
+
await tracing.finish(run);
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
**Nothing inside the graph knows about tracing.** The graph already reports every task starting,
|
|
768
|
+
retrying, and finishing; a trace is that stream written down as a tree. An application that does not
|
|
769
|
+
trace creates no context, allocates nothing, and does no per-call work.
|
|
770
|
+
|
|
771
|
+
**Tail sampling keeps what matters.** A 5% rate still records every error, every run slower than a
|
|
772
|
+
threshold, and every run more expensive than one, because the decision is made when the trace
|
|
773
|
+
finishes rather than when it starts.
|
|
774
|
+
|
|
775
|
+
**Redaction happens before storage**, so a field you hide is never written, and a `redact` hook gets
|
|
776
|
+
the last word on every run.
|
|
777
|
+
|
|
778
|
+
**Then ask questions of it:**
|
|
779
|
+
|
|
780
|
+
```ts
|
|
781
|
+
const failures = await store.query({ status: 'error', kind: 'model', since: yesterday, minLatencyMs: 2000 });
|
|
782
|
+
const tree = await store.tree(failures[0].traceId);
|
|
783
|
+
console.log(formatTree(tree));
|
|
784
|
+
|
|
785
|
+
await tracer.recordFeedback(runId, { key: 'thumbs', score: 0, source: 'user' });
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
`compareTraces(a, b)` lays two runs of the same shape side by side and reports what changed — the
|
|
789
|
+
step that got slower, the tool that stopped being called, the output that differs — which is how
|
|
790
|
+
"it worked yesterday" becomes an answerable question.
|
|
791
|
+
|
|
792
|
+
**Alerts** run the same queries on a timer, and carry the runs that tripped them:
|
|
793
|
+
|
|
794
|
+
```ts
|
|
795
|
+
import { AlertEvaluator, createWebhookNotifier } from 'nexus-ai-pro/tracing';
|
|
796
|
+
|
|
797
|
+
const alerts = new AlertEvaluator(
|
|
798
|
+
store,
|
|
799
|
+
[
|
|
800
|
+
{ name: 'error rate', metric: 'errorRate', threshold: 0.05, minRuns: 20 },
|
|
801
|
+
{ name: 'p95 latency', metric: 'latencyP95', threshold: 8000 },
|
|
802
|
+
{ name: 'hourly spend', metric: 'cost', threshold: 25, windowMs: 3_600_000 },
|
|
803
|
+
],
|
|
804
|
+
{ notifier: createWebhookNotifier({ url: process.env.ALERT_WEBHOOK! }) },
|
|
805
|
+
);
|
|
806
|
+
|
|
807
|
+
setInterval(() => void alerts.evaluate(), 60_000);
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
An alert names the rule, the measured value, and three runs that contributed, so the next step is
|
|
811
|
+
reading them rather than starting an investigation.
|
|
812
|
+
|
|
562
813
|
## Provider Batch Tiers
|
|
563
814
|
|
|
564
815
|
Both OpenAI and Anthropic sell an asynchronous tier at roughly half price, in exchange for a
|
|
@@ -1829,21 +2080,23 @@ only, so it never appears in an import graph.
|
|
|
1829
2080
|
| `nexus-ai-pro/providers/llamacpp` | 77 KB | 13% | none |
|
|
1830
2081
|
| `nexus-ai-pro/providers/lmstudio` | 77 KB | 13% | none |
|
|
1831
2082
|
| `nexus-ai-pro/providers/openai` | 77 KB | 13% | none |
|
|
2083
|
+
| `nexus-ai-pro/agent` | 76 KB | 12% | none |
|
|
1832
2084
|
| `nexus-ai-pro/providers/anthropic` | 70 KB | 11% | none |
|
|
1833
2085
|
| `nexus-ai-pro/providers/google` | 66 KB | 11% | none |
|
|
1834
2086
|
| `nexus-ai-pro/images` | 65 KB | 11% | none |
|
|
2087
|
+
| `nexus-ai-pro/graph` | 60 KB | 10% | none |
|
|
1835
2088
|
| `nexus-ai-pro/providers/ollama` | 58 KB | 9% | none |
|
|
1836
2089
|
| `nexus-ai-pro/batch/openai` | 52 KB | 8% | none |
|
|
1837
2090
|
| `nexus-ai-pro/batch/anthropic` | 52 KB | 8% | none |
|
|
1838
2091
|
| `nexus-ai-pro/operations` | 49 KB | 8% | none |
|
|
1839
2092
|
| `nexus-ai-pro/batch/mock` | 47 KB | 8% | none |
|
|
1840
2093
|
| `nexus-ai-pro/providers/cohere` | 46 KB | 8% | none |
|
|
1841
|
-
| `nexus-ai-pro/graph` | 46 KB | 8% | none |
|
|
1842
2094
|
| `nexus-ai-pro/realtime/openai-webrtc` | 46 KB | 8% | none |
|
|
1843
2095
|
| `nexus-ai-pro/security` | 40 KB | 7% | +3.4 MB |
|
|
1844
2096
|
| `nexus-ai-pro/models` | 35 KB | 6% | none |
|
|
1845
2097
|
| `nexus-ai-pro/images/inputs` | 31 KB | 5% | none |
|
|
1846
2098
|
| `nexus-ai-pro/realtime/openai-websocket` | 29 KB | 5% | none |
|
|
2099
|
+
| `nexus-ai-pro/tracing` | 26 KB | 4% | none |
|
|
1847
2100
|
| `nexus-ai-pro/evals` | 23 KB | 4% | none |
|
|
1848
2101
|
| `nexus-ai-pro/images/transform` | 22 KB | 4% | none |
|
|
1849
2102
|
| `nexus-ai-pro/images/stores` | 22 KB | 4% | none |
|
|
@@ -1852,6 +2105,7 @@ only, so it never appears in an import graph.
|
|
|
1852
2105
|
| `nexus-ai-pro/images/openai` | 19 KB | 3% | none |
|
|
1853
2106
|
| `nexus-ai-pro/realtime/mock` | 19 KB | 3% | none |
|
|
1854
2107
|
| `nexus-ai-pro/voice` | 18 KB | 3% | none |
|
|
2108
|
+
| `nexus-ai-pro/mcp` | 18 KB | 3% | none |
|
|
1855
2109
|
| `nexus-ai-pro/images/comfyui` | 17 KB | 3% | none |
|
|
1856
2110
|
| `nexus-ai-pro/embeddings/adapters` | 17 KB | 3% | none |
|
|
1857
2111
|
| `nexus-ai-pro/realtime/conversation` | 16 KB | 3% | none |
|
|
@@ -1865,6 +2119,7 @@ only, so it never appears in an import graph.
|
|
|
1865
2119
|
| `nexus-ai-pro/images/mock` | 12 KB | 2% | none |
|
|
1866
2120
|
| `nexus-ai-pro/optimizer` | 11 KB | 2% | none |
|
|
1867
2121
|
| `nexus-ai-pro/voice/session` | 11 KB | 2% | none |
|
|
2122
|
+
| `nexus-ai-pro/store/redis` | 11 KB | 2% | none |
|
|
1868
2123
|
| `nexus-ai-pro/providers` | 10 KB | 2% | none |
|
|
1869
2124
|
| `nexus-ai-pro/providers/base` | 10 KB | 2% | none |
|
|
1870
2125
|
| `nexus-ai-pro/embeddings/models` | 10 KB | 2% | none |
|
|
@@ -1874,6 +2129,8 @@ only, so it never appears in an import graph.
|
|
|
1874
2129
|
| `nexus-ai-pro/realtime/openai-server` | 8 KB | 1% | none |
|
|
1875
2130
|
| `nexus-ai-pro/capabilities` | 8 KB | 1% | none |
|
|
1876
2131
|
| `nexus-ai-pro/telephony/realtime-bridge` | 7 KB | 1% | none |
|
|
2132
|
+
| `nexus-ai-pro/graph/visualize` | 6 KB | 1.0% | none |
|
|
2133
|
+
| `nexus-ai-pro/store` | 6 KB | 1.0% | none |
|
|
1877
2134
|
| `nexus-ai-pro/providers/errors` | 5 KB | 0.8% | none |
|
|
1878
2135
|
| `nexus-ai-pro/embeddings/mock` | 5 KB | 0.8% | none |
|
|
1879
2136
|
| `nexus-ai-pro/cache/semantic-cache` | 5 KB | 0.8% | none |
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { type CompiledGraph } from '../graph/graph.js';
|
|
2
|
+
import type { GraphCheckpointer, NodeContext } from '../types/graph.js';
|
|
3
|
+
import type { CompletionRequest, Message, ToolDefinition } from '../types/messages.js';
|
|
4
|
+
import type { NexusResponse } from '../types/response.js';
|
|
5
|
+
import type { Store } from '../types/store.js';
|
|
6
|
+
/**
|
|
7
|
+
* An agent as a graph.
|
|
8
|
+
*
|
|
9
|
+
* `AgentLoop` is a `while` loop: it cannot be paused, resumed after a restart, inspected halfway, or
|
|
10
|
+
* made to run two tool calls at once, because a loop has nowhere to keep that state. The same agent
|
|
11
|
+
* expressed as a graph inherits all of it — checkpoints, human approval through `interrupt()`,
|
|
12
|
+
* parallel tool tasks through `Send`, forks, events, and a Mermaid diagram — without this module
|
|
13
|
+
* implementing any of them. `AgentLoop` stays for the simple case that wants none of that.
|
|
14
|
+
*/
|
|
15
|
+
/** The model call an agent makes. Injected, so this module needs no provider runtime. */
|
|
16
|
+
export interface AgentModelClient {
|
|
17
|
+
complete(request: CompletionRequest): Promise<NexusResponse>;
|
|
18
|
+
}
|
|
19
|
+
export interface AgentToolCall {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
args: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
/** What an approver may answer: allow, refuse with a reason, or allow with corrected arguments. */
|
|
25
|
+
export type AgentApproval = boolean | {
|
|
26
|
+
approved: true;
|
|
27
|
+
args?: Record<string, unknown>;
|
|
28
|
+
} | {
|
|
29
|
+
approved: false;
|
|
30
|
+
reason?: string;
|
|
31
|
+
};
|
|
32
|
+
export interface AgentApprovalPolicy {
|
|
33
|
+
/** The question an operator sees. Defaults to naming the tool and its arguments. */
|
|
34
|
+
reason?: (call: AgentToolCall) => string;
|
|
35
|
+
}
|
|
36
|
+
export interface AgentMiddleware {
|
|
37
|
+
name?: string;
|
|
38
|
+
/** Adjusts the request before it is sent: trim history, add context, swap the model. */
|
|
39
|
+
beforeModel?(context: {
|
|
40
|
+
request: CompletionRequest;
|
|
41
|
+
state: AgentState;
|
|
42
|
+
store?: Store;
|
|
43
|
+
}): CompletionRequest | void | Promise<CompletionRequest | void>;
|
|
44
|
+
/** Inspects or replaces the response: redact, validate, count. */
|
|
45
|
+
afterModel?(context: {
|
|
46
|
+
response: NexusResponse;
|
|
47
|
+
state: AgentState;
|
|
48
|
+
store?: Store;
|
|
49
|
+
}): NexusResponse | void | Promise<NexusResponse | void>;
|
|
50
|
+
/** Wraps a tool call, so a policy can log it, time it, or refuse it. */
|
|
51
|
+
wrapToolCall?(call: AgentToolCall, next: () => Promise<AgentToolResult>): Promise<AgentToolResult> | AgentToolResult;
|
|
52
|
+
}
|
|
53
|
+
export interface AgentToolResult {
|
|
54
|
+
ok: boolean;
|
|
55
|
+
result?: unknown;
|
|
56
|
+
error?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface CreateAgentOptions {
|
|
59
|
+
client: AgentModelClient;
|
|
60
|
+
model?: string;
|
|
61
|
+
tools?: ToolDefinition[];
|
|
62
|
+
systemPrompt?: string;
|
|
63
|
+
/** Model calls before the agent stops with `stopReason: 'max_iterations'`. Defaults to 8. */
|
|
64
|
+
maxIterations?: number;
|
|
65
|
+
/** Tool calls run at once. Defaults to 8; `1` runs them one at a time. */
|
|
66
|
+
toolConcurrency?: number;
|
|
67
|
+
/** Tools that need human approval before they run, keyed by tool name. */
|
|
68
|
+
interruptOn?: Record<string, AgentApprovalPolicy | true>;
|
|
69
|
+
middleware?: AgentMiddleware[];
|
|
70
|
+
/** Long-term memory, available to tools and middleware as `store`. */
|
|
71
|
+
store?: Store;
|
|
72
|
+
checkpointer?: GraphCheckpointer | false;
|
|
73
|
+
name?: string;
|
|
74
|
+
temperature?: number;
|
|
75
|
+
maxTokens?: number;
|
|
76
|
+
responseFormat?: CompletionRequest['responseFormat'];
|
|
77
|
+
metadata?: Record<string, unknown>;
|
|
78
|
+
}
|
|
79
|
+
declare const agentChannels: () => {
|
|
80
|
+
messages: import("../types/graph.js").Channel<Message[]>;
|
|
81
|
+
iterations: import("../types/graph.js").Channel<number>;
|
|
82
|
+
answer: import("../types/graph.js").Channel<string>;
|
|
83
|
+
stopReason: import("../types/graph.js").Channel<AgentStopReason | undefined>;
|
|
84
|
+
};
|
|
85
|
+
export type AgentChannels = ReturnType<typeof agentChannels>;
|
|
86
|
+
export type AgentState = {
|
|
87
|
+
messages: Message[];
|
|
88
|
+
iterations: number;
|
|
89
|
+
answer: string;
|
|
90
|
+
stopReason?: AgentStopReason;
|
|
91
|
+
};
|
|
92
|
+
export type AgentStopReason = 'completed' | 'max_iterations';
|
|
93
|
+
export type AgentGraph = CompiledGraph<AgentChannels>;
|
|
94
|
+
/** Wraps a question into the state an agent starts from. */
|
|
95
|
+
export declare function agentInput(goal: string): {
|
|
96
|
+
messages: Message[];
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Builds an agent and returns it as a compiled graph.
|
|
100
|
+
*
|
|
101
|
+
* Run it like any graph: `agent.invoke(agentInput('...'), { threadId })`. The result's `answer` is
|
|
102
|
+
* the final text, and `stopReason` says whether the agent finished or ran out of iterations.
|
|
103
|
+
*/
|
|
104
|
+
export declare function createAgent(options: CreateAgentOptions): AgentGraph;
|
|
105
|
+
/**
|
|
106
|
+
* Turns an agent into a tool another agent can call.
|
|
107
|
+
*
|
|
108
|
+
* The simplest multi-agent shape: a supervisor keeps control and delegates, rather than handing over
|
|
109
|
+
* the conversation. The specialist runs as its own graph, with its own memory and approvals, and
|
|
110
|
+
* returns its answer as the tool result.
|
|
111
|
+
*/
|
|
112
|
+
export declare function agentAsTool(options: {
|
|
113
|
+
agent: AgentGraph;
|
|
114
|
+
name: string;
|
|
115
|
+
description: string;
|
|
116
|
+
/** Threads the specialist's runs, so its work is resumable too. Defaults to a fresh thread. */
|
|
117
|
+
threadId?: (goal: string) => string;
|
|
118
|
+
}): ToolDefinition;
|
|
119
|
+
export type { NodeContext };
|