nodal-agents 0.4.0 → 0.4.3
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/README.md +34 -14
- package/cli.js +16 -1
- package/migrations/0030_agent_fallback_llm_keys.sql +6 -0
- package/migrations/0031_llm_key_capabilities.sql +7 -0
- package/migrations/0032_drop_llm_key_model_caps.sql +9 -0
- package/migrations/0033_agent_fallback_chain.sql +21 -0
- package/migrations/meta/_journal.json +28 -0
- package/package.json +2 -1
- package/runner.js +602 -94
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/app-path-routes-manifest.json +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page.js +3 -3
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/page.js +2 -2
- package/web/.next/server/app/(dashboard)/agents/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/agents/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/approvals/page.js +2 -2
- package/web/.next/server/app/(dashboard)/approvals/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/approvals/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/automations/page.js +2 -2
- package/web/.next/server/app/(dashboard)/automations/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/automations/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/billing/page.js +1 -1
- package/web/.next/server/app/(dashboard)/billing/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/billing/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page.js +2 -2
- package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/connectors/page.js +1 -1
- package/web/.next/server/app/(dashboard)/connectors/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/connectors/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/credentials/page.js +1 -1
- package/web/.next/server/app/(dashboard)/credentials/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/credentials/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/[id]/page.js +2 -2
- package/web/.next/server/app/(dashboard)/jobs/[id]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/jobs/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/page.js +2 -2
- package/web/.next/server/app/(dashboard)/jobs/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/jobs/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/llm-providers/page.js +2 -2
- package/web/.next/server/app/(dashboard)/llm-providers/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/llm-providers/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/logs/page.js +1 -1
- package/web/.next/server/app/(dashboard)/logs/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/logs/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/mcp/page.js +2 -2
- package/web/.next/server/app/(dashboard)/mcp/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/mcp/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/memories/page.js +2 -2
- package/web/.next/server/app/(dashboard)/memories/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/memories/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page.js +2 -2
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/page.js +2 -2
- package/web/.next/server/app/(dashboard)/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/new/page.js +2 -2
- package/web/.next/server/app/(dashboard)/skills/new/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/skills/new/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/page.js +2 -2
- package/web/.next/server/app/(dashboard)/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +1 -1
- package/web/.next/server/app/_global-error.rsc +2 -2
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
- package/web/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +2 -2
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/server/app/_not-found.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/server/app/api/oauth/[provider]/callback/route.js +1 -1
- package/web/.next/server/app/api/oauth/[provider]/start/route.js +1 -1
- package/web/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/onboarding.html +1 -1
- package/web/.next/server/app/onboarding.rsc +3 -3
- package/web/.next/server/app/onboarding.segments/_full.segment.rsc +3 -3
- package/web/.next/server/app/onboarding.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/onboarding.segments/_index.segment.rsc +3 -3
- package/web/.next/server/app/onboarding.segments/_tree.segment.rsc +2 -2
- package/web/.next/server/app/onboarding.segments/onboarding/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/onboarding.segments/onboarding.segment.rsc +1 -1
- package/web/.next/server/app-paths-manifest.json +1 -1
- package/web/.next/server/chunks/3233.js +1 -0
- package/web/.next/server/chunks/4574.js +1 -1
- package/web/.next/server/chunks/4808.js +1 -0
- package/web/.next/server/chunks/{3057.js → 7466.js} +1 -1
- package/web/.next/server/chunks/7741.js +3 -3
- package/web/.next/server/chunks/8052.js +1 -0
- package/web/.next/server/chunks/8766.js +1 -0
- package/web/.next/server/chunks/8782.js +1 -0
- package/web/.next/server/chunks/9084.js +1 -0
- package/web/.next/server/chunks/{7557.js → 9606.js} +2 -2
- package/web/.next/server/middleware-build-manifest.js +1 -1
- package/web/.next/server/pages/404.html +1 -1
- package/web/.next/server/pages/500.html +1 -1
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/static/chunks/{9060-df7c0c4c6fa27737.js → 2575-e660568bd1a9bcb6.js} +2 -2
- package/web/.next/static/chunks/3233-e6efb7fb1fa24591.js +1 -0
- package/web/.next/static/chunks/5436-c1006a40e59853ed.js +1 -0
- package/web/.next/static/chunks/7025-7afa82fda10bddc4.js +62 -0
- package/web/.next/static/chunks/{5801-e411029984b17b8b.js → 8396-f3502b9af3172006.js} +1 -1
- package/web/.next/static/chunks/{8503-ced632da5c3fce79.js → 9098-2bfef80a73c706b3.js} +1 -1
- package/web/.next/static/chunks/9123-5c5ad180c831baa4.js +1 -0
- package/web/.next/static/chunks/{6679-7c76034b83edeb06.js → 9582-fbf7c8d9b2a39101.js} +1 -1
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/page-de6c8fc7cb73a3de.js +2 -0
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/telegram/page-6d4161f1e0b19885.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/agents/page-50005050a3304bee.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/approvals/page-7f4314908d1024f6.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/automations/page-7693601b49363371.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/chat/page-839128f211f63728.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/connectors/page-a6a1d8f0a33d2faf.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/jobs/[id]/page-4fc570c6c1e39edb.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/jobs/page-cf861b235dc54ced.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/layout-769de8a52528194a.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/llm-providers/page-99eab754716f9071.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/mcp/page-082442b4f9ac0f91.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/memories/page-e201633b4bbbdf73.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/page-a42d880f7036e866.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/settings/page-d85cac3728506241.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/[id]/edit/page-ecaf3520da303237.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/new/page-cdbc2aada2be0bfc.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/page-234553540bef945b.js +1 -0
- package/web/.next/static/css/78ead23854ab041e.css +3 -0
- package/web/.next/server/chunks/1511.js +0 -1
- package/web/.next/server/chunks/2103.js +0 -1
- package/web/.next/server/chunks/211.js +0 -1
- package/web/.next/server/chunks/8178.js +0 -1
- package/web/.next/server/chunks/9201.js +0 -1
- package/web/.next/server/chunks/9824.js +0 -1
- package/web/.next/static/chunks/1165-ec573be2aa63710b.js +0 -1
- package/web/.next/static/chunks/2569-6b5e0af9c1f584a4.js +0 -1
- package/web/.next/static/chunks/6522-3f865de55adb618d.js +0 -1
- package/web/.next/static/chunks/921-f437093debcddbb3.js +0 -1
- package/web/.next/static/chunks/9421-d522a48618c4fe37.js +0 -62
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/page-d3724fbf38b71806.js +0 -2
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/telegram/page-e6b35d5f361044a9.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/agents/page-b58294bf588f4581.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/approvals/page-b9e504918d043b6d.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/automations/page-4807e81e2af3030e.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/chat/page-2c8f9571a443f250.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/connectors/page-72ccb0e3a5ed6f2d.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/jobs/[id]/page-40172a14d0b1368f.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/jobs/page-d4a3a16745e02fd1.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/layout-4d5634ba460464d7.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/llm-providers/page-90fb785e2ab32759.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/mcp/page-426478332dfe8313.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/memories/page-aa46f5f7efbfa262.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/page-fc49d7ed8e472118.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/settings/page-1cc10beb46234c7d.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/[id]/edit/page-0b61f21847f4c7a0.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/new/page-9de96e643c361732.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/page-4566512d74e54bfe.js +0 -1
- package/web/.next/static/css/0a81480f93d3ab37.css +0 -3
- /package/web/.next/static/{9FXcaPSw8KYgjKzjKLpT2 → n6jP_zB4kqJScKY_T2ciu}/_buildManifest.js +0 -0
- /package/web/.next/static/{9FXcaPSw8KYgjKzjKLpT2 → n6jP_zB4kqJScKY_T2ciu}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -7,9 +7,14 @@
|
|
|
7
7
|
[](https://nodejs.org)
|
|
8
8
|
[](https://www.typescriptlang.org)
|
|
9
9
|
|
|
10
|
-
Build and orchestrate AI agents on your own hardware
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Build and orchestrate a **team of AI agents** on your own hardware —
|
|
11
|
+
each with its own personality, tools, memory, and model. Talk to them in
|
|
12
|
+
the dashboard or on Telegram; they research, write files, call your
|
|
13
|
+
connectors, and delegate to each other to get the job done.
|
|
14
|
+
|
|
15
|
+
**No SaaS lock-in. No per-token markup. No cloud roundtrip.** Two commands
|
|
16
|
+
to install, runs on any machine with Node 22+ (Mac, PC, Linux), and works
|
|
17
|
+
with **any LLM** — frontier or local, paid or free.
|
|
13
18
|
|
|
14
19
|
---
|
|
15
20
|
|
|
@@ -18,9 +23,11 @@ no cloud roundtrip.** Runs on any machine with Node 22+ — Mac, PC, Linux.
|
|
|
18
23
|
| | |
|
|
19
24
|
| --- | --- |
|
|
20
25
|
| 🏠 **Local-first** | Single binary, embedded Postgres, zero cloud dependency. Your conversations, memory, and credentials stay on your machine. |
|
|
21
|
-
| 🔌 **
|
|
26
|
+
| 🔌 **Any model, per agent** | Anthropic, OpenAI, Google, Groq, Mistral, OpenRouter, or any local model (LM Studio, Ollama). Setup is just an API key per provider — **each agent picks its own model**, so you can run Claude for the orchestrator and **DeepSeek V4** for the workers. The quirks of OSS frontier models (DeepSeek's non-spec tool args, Kimi/Qwen/GLM XML tool formats, and round-tripping a reasoning model's chain-of-thought across tool calls so MiniMax M3 / DeepSeek / Gemini 3 don't degrade mid-task) are handled automatically. |
|
|
27
|
+
| 🛟 **Provider failover** | Give an agent a backup key chain — if its provider 5xx's, times out, or hits quota mid-job, the runner fails over to the next one and keeps going (and fails loud only when the whole chain is down). |
|
|
22
28
|
| 🧠 **Memory that compounds** | Persistent facts (entity-scoped, auto-injected into every job) and chat-thread continuity (your agent remembers what it said 30 seconds ago — and what it said yesterday). |
|
|
23
|
-
| 🤝 **Orchestrators that finish** | Router and planner orchestrators delegate to specialist sub-agents
|
|
29
|
+
| 🤝 **Orchestrators that finish** | Router and planner orchestrators delegate to specialist sub-agents, then resume on completion to wrap up the answer. |
|
|
30
|
+
| 🛡️ **Agents that don't lie, loop, or die** | Generic runtime guards: a per-job token budget and a no-progress detector kill runaway loops; a no-false-success guard refuses to report "done" when an action actually failed (fail loud, never fake it); turn/chain/delegation caps bound everything. |
|
|
24
31
|
| 🔧 **Multi-instance connectors** | Gmail perso *and* Gmail boulot on the same install. OAuth *and* API-key supported. Active list + Marketplace UI in the dashboard. |
|
|
25
32
|
| 🗂️ **Workspaces** | Multiple isolated workspaces on one install (personal vs work) — each with its own agents, skills, connectors, jobs and memory. Switch from the sidebar. |
|
|
26
33
|
| 🤖 **Self-extending (ROOT agent)** | Designate an orchestrator as ROOT and let it create skills/agents and assign them on your behalf — gated by per-grant toggles and an autonomy level (propose-confirm → fully-autonomous). |
|
|
@@ -48,8 +55,8 @@ nodal-agents up
|
|
|
48
55
|
|
|
49
56
|
Open <http://localhost:3000>. The CLI spawns an embedded Postgres on a
|
|
50
57
|
free port, applies migrations, seeds the system skills, and starts the
|
|
51
|
-
runner (`:3001`) and dashboard (`:3000`).
|
|
52
|
-
|
|
58
|
+
runner (`:3001`) and dashboard (`:3000`). Connect an LLM provider from
|
|
59
|
+
**LLM Providers** in the dashboard — paste an API key and you're running.
|
|
53
60
|
|
|
54
61
|
> Requires Node 22+. No external Postgres, no Redis, no cloud config.
|
|
55
62
|
> Data lives at `~/.nodalai/` — wipe with `rm -rf ~/.nodalai`.
|
|
@@ -77,7 +84,7 @@ When a newer version is available, `nodal-agents up` also prints a one-line
|
|
|
77
84
|
notice:
|
|
78
85
|
|
|
79
86
|
```
|
|
80
|
-
ℹ v0.4.
|
|
87
|
+
ℹ v0.4.3 available — run `nodal-agents update`
|
|
81
88
|
```
|
|
82
89
|
|
|
83
90
|
### Build from source
|
|
@@ -131,7 +138,8 @@ Delegations create child jobs that resume the parent on completion.
|
|
|
131
138
|
|
|
132
139
|
| Route | Purpose |
|
|
133
140
|
| --- | --- |
|
|
134
|
-
| `/agents` | Create, edit, assign skills + connectors + MCP servers to agents. |
|
|
141
|
+
| `/agents` | Create, edit, assign skills + connectors + MCP servers to agents — and pick each agent's provider + model (with an optional failover chain). |
|
|
142
|
+
| `/llm-providers` | Connect each LLM provider with a single API key — enable/disable inline. Models are chosen per-agent, not here. |
|
|
135
143
|
| `/jobs` | Live job stream — task, agent, status, full transcript, tool I/O. |
|
|
136
144
|
| `/connectors` | Active connector instances + Marketplace (multi-instance, OAuth or API-key). |
|
|
137
145
|
| `/mcp` | Active MCP servers + Marketplace — HTTP & stdio, a growing catalogue, plus add/edit your own custom servers. |
|
|
@@ -140,7 +148,7 @@ Delegations create child jobs that resume the parent on completion.
|
|
|
140
148
|
| `/logs` | Tool-call audit — input/output JSON per call, filterable by tool name. |
|
|
141
149
|
| `/approvals` | Human-in-the-loop gates for risky tools (and the ROOT agent's meta-tools under propose-confirm). |
|
|
142
150
|
| `/automations` | Cron-scheduled agent triggers. |
|
|
143
|
-
| `/settings` |
|
|
151
|
+
| `/settings` | Auth mode, network (loopback / LAN), bot tokens, workspace management, ROOT-agent grants + autonomy. |
|
|
144
152
|
|
|
145
153
|
---
|
|
146
154
|
|
|
@@ -204,18 +212,30 @@ pnpm deps:check # runs locally and in CI before every release
|
|
|
204
212
|
|
|
205
213
|
## Status
|
|
206
214
|
|
|
207
|
-
**Current release:** `0.3
|
|
215
|
+
**Current release:** `0.4.3` on npm `latest`. Used daily by the
|
|
208
216
|
maintainer, stable enough for personal production. Pre-1.0 — breaking
|
|
209
217
|
changes are still possible between minors.
|
|
210
218
|
|
|
211
219
|
### Shipped and working
|
|
212
220
|
|
|
213
|
-
- Multi-LLM provider
|
|
221
|
+
- Multi-LLM, **per-agent model selection** — provider setup is just an API key
|
|
222
|
+
(one per provider); each agent chooses its own model on top. Frontier and
|
|
223
|
+
local providers, including **DeepSeek V4** (non-spec tool-call args normalized
|
|
224
|
+
automatically) and **reasoning models like MiniMax M3** (their hidden
|
|
225
|
+
chain-of-thought is round-tripped across tool calls so they keep reasoning on
|
|
226
|
+
multi-turn tasks), plus native tool-call parsing for Kimi K2 / Qwen3-Coder / GLM
|
|
227
|
+
- **Provider failover** — an opt-in ordered key chain per agent; on a 5xx /
|
|
228
|
+
timeout / quota mid-job the runner fails over to the next key, and fails loud
|
|
229
|
+
(`all_providers_failed`) only when the whole chain is exhausted
|
|
230
|
+
- **Reliability guards (generic, model-agnostic)** — per-job token budget +
|
|
231
|
+
no-progress detector (kill runaway loops), and a no-false-success guard that
|
|
232
|
+
refuses to complete a job as "success" when a tool action failed and was never
|
|
233
|
+
resolved (fail loud, never fake it)
|
|
214
234
|
- Persistent memory (sanitation, dedup, importance ranking, auto-injection,
|
|
215
235
|
feedback loop)
|
|
216
236
|
- Session-thread continuity on chat channels (Telegram today)
|
|
217
|
-
- Orchestrator (router + planner) with delegation chains
|
|
218
|
-
|
|
237
|
+
- Orchestrator (router + planner) with delegation chains that resume the
|
|
238
|
+
parent on completion
|
|
219
239
|
- Multi-instance connectors with OAuth (Gmail, Drive, Sheets, Docs, Notion,
|
|
220
240
|
Airtable) and API-key (Notion, Airtable, Apify, Firecrawl, Tavily)
|
|
221
241
|
- MCP catalog — Streamable HTTP *and* stdio (local subprocess) servers, API-key auth; a growing catalogue (Stripe, n8n, Supabase, Airtable, Notion…) with a "test pending" badge on entries not yet verified live, plus add *and edit* your own custom HTTP/stdio servers from the dashboard
|
package/cli.js
CHANGED
|
@@ -12185,6 +12185,13 @@ var init_connector_catalog = __esm({
|
|
|
12185
12185
|
}
|
|
12186
12186
|
});
|
|
12187
12187
|
|
|
12188
|
+
// ../../packages/shared/src/model-catalog.ts
|
|
12189
|
+
var init_model_catalog = __esm({
|
|
12190
|
+
"../../packages/shared/src/model-catalog.ts"() {
|
|
12191
|
+
"use strict";
|
|
12192
|
+
}
|
|
12193
|
+
});
|
|
12194
|
+
|
|
12188
12195
|
// ../../packages/shared/src/index.ts
|
|
12189
12196
|
var init_src2 = __esm({
|
|
12190
12197
|
"../../packages/shared/src/index.ts"() {
|
|
@@ -12210,6 +12217,7 @@ var init_src2 = __esm({
|
|
|
12210
12217
|
init_providers();
|
|
12211
12218
|
init_root_agent();
|
|
12212
12219
|
init_connector_catalog();
|
|
12220
|
+
init_model_catalog();
|
|
12213
12221
|
}
|
|
12214
12222
|
});
|
|
12215
12223
|
|
|
@@ -12364,7 +12372,6 @@ var init_llm_keys = __esm({
|
|
|
12364
12372
|
apiKeyLast4: text("api_key_last4").notNull().default(""),
|
|
12365
12373
|
baseUrl: text("base_url"),
|
|
12366
12374
|
nickname: text("nickname"),
|
|
12367
|
-
defaultModel: text("default_model"),
|
|
12368
12375
|
isActive: boolean("is_active").notNull().default(true),
|
|
12369
12376
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
12370
12377
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
@@ -12393,6 +12400,14 @@ var init_agents = __esm({
|
|
|
12393
12400
|
personality: text("personality").notNull(),
|
|
12394
12401
|
model: text("model").default("claude-sonnet-4-6-20260217"),
|
|
12395
12402
|
llmKeyId: uuid("llm_key_id").references(() => entityLlmKeys.id, { onDelete: "set null" }),
|
|
12403
|
+
// Ordered LLM-key fallback chain (Guard 2). When the primary key
|
|
12404
|
+
// (llmKeyId) exhausts retries / times out / hits quota mid-job, the runner
|
|
12405
|
+
// fails over to these in order; all-down fails loud (`all_providers_failed`).
|
|
12406
|
+
// Empty = no failover (default). Each link is a (keyId, model) pair so a
|
|
12407
|
+
// fallback runs on a CHOSEN model (empty model ⇒ that provider's catalog
|
|
12408
|
+
// default). FK integrity is enforced in the app layer; a deleted key is
|
|
12409
|
+
// skipped at resolution time.
|
|
12410
|
+
fallbackChain: jsonb("fallback_chain").$type().default(sql`'[]'::jsonb`),
|
|
12396
12411
|
active: boolean("active").default(true),
|
|
12397
12412
|
isDefault: boolean("is_default").default(false),
|
|
12398
12413
|
role: text("role").default("agent"),
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- Guard 2 (provider failover): ordered LLM-key fallback chain per agent.
|
|
2
|
+
-- When the agent's primary key (llm_key_id) exhausts retries / times out /
|
|
3
|
+
-- hits quota mid-job, the runner fails over to these keys in order; all-down
|
|
4
|
+
-- fails loud (`all_providers_failed`). Empty default = no failover.
|
|
5
|
+
ALTER TABLE "agents"
|
|
6
|
+
ADD COLUMN IF NOT EXISTS "fallback_llm_key_ids" uuid[] DEFAULT '{}'::uuid[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- T2 (per-model LLM capabilities): cache a key's tool-calling capability so the
|
|
2
|
+
-- runtime can pick the right tool_choice WITHOUT a failed first call. NULL =
|
|
3
|
+
-- unknown (runtime assumes supported; the tool_choice floor catches a wrong
|
|
4
|
+
-- guess). Set from the model catalog or the live "Test" capability probe.
|
|
5
|
+
ALTER TABLE "entity_llm_keys"
|
|
6
|
+
ADD COLUMN IF NOT EXISTS "supports_tools" boolean,
|
|
7
|
+
ADD COLUMN IF NOT EXISTS "supports_forced_tool_choice" boolean;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- Simplify LLM providers: a key is now JUST credentials (provider + API key +
|
|
2
|
+
-- base URL + active). The model is chosen per-AGENT, and tool capability is
|
|
3
|
+
-- read from the code model catalog at runtime — so these per-key columns are
|
|
4
|
+
-- dead weight. Drop them. (0030 fallback_llm_key_ids stays — failover is still a
|
|
5
|
+
-- per-key concern.)
|
|
6
|
+
ALTER TABLE "entity_llm_keys"
|
|
7
|
+
DROP COLUMN IF EXISTS "default_model",
|
|
8
|
+
DROP COLUMN IF EXISTS "supports_tools",
|
|
9
|
+
DROP COLUMN IF EXISTS "supports_forced_tool_choice";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- Per-fallback model selection (Guard 2). The failover chain now stores
|
|
2
|
+
-- (keyId, model) pairs instead of bare key ids, so each fallback runs on a
|
|
3
|
+
-- CHOSEN model rather than its provider's catalog default. Backfill existing
|
|
4
|
+
-- id arrays with an empty model ('' ⇒ runtime uses the catalog default), then
|
|
5
|
+
-- drop the old column.
|
|
6
|
+
ALTER TABLE "agents"
|
|
7
|
+
ADD COLUMN IF NOT EXISTS "fallback_chain" jsonb DEFAULT '[]'::jsonb;
|
|
8
|
+
|
|
9
|
+
UPDATE "agents"
|
|
10
|
+
SET "fallback_chain" = COALESCE(
|
|
11
|
+
(
|
|
12
|
+
SELECT jsonb_agg(jsonb_build_object('keyId', kid::text, 'model', ''))
|
|
13
|
+
FROM unnest("fallback_llm_key_ids") AS kid
|
|
14
|
+
),
|
|
15
|
+
'[]'::jsonb
|
|
16
|
+
)
|
|
17
|
+
WHERE "fallback_llm_key_ids" IS NOT NULL
|
|
18
|
+
AND array_length("fallback_llm_key_ids", 1) > 0;
|
|
19
|
+
|
|
20
|
+
ALTER TABLE "agents"
|
|
21
|
+
DROP COLUMN IF EXISTS "fallback_llm_key_ids";
|
|
@@ -211,6 +211,34 @@
|
|
|
211
211
|
"when": 1780900000000,
|
|
212
212
|
"tag": "0029_backfill_root_agent",
|
|
213
213
|
"breakpoints": true
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"idx": 30,
|
|
217
|
+
"version": "7",
|
|
218
|
+
"when": 1781000000000,
|
|
219
|
+
"tag": "0030_agent_fallback_llm_keys",
|
|
220
|
+
"breakpoints": true
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"idx": 31,
|
|
224
|
+
"version": "7",
|
|
225
|
+
"when": 1781100000000,
|
|
226
|
+
"tag": "0031_llm_key_capabilities",
|
|
227
|
+
"breakpoints": true
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"idx": 32,
|
|
231
|
+
"version": "7",
|
|
232
|
+
"when": 1781200000000,
|
|
233
|
+
"tag": "0032_drop_llm_key_model_caps",
|
|
234
|
+
"breakpoints": true
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"idx": 33,
|
|
238
|
+
"version": "7",
|
|
239
|
+
"when": 1781300000000,
|
|
240
|
+
"tag": "0033_agent_fallback_chain",
|
|
241
|
+
"breakpoints": true
|
|
214
242
|
}
|
|
215
243
|
]
|
|
216
244
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodal-agents",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Local-first AI agent platform with a web dashboard — install in one command.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"@ai-sdk/openai": "^3.0.63",
|
|
47
47
|
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
48
48
|
"@ai-sdk/provider": "^3.0.10",
|
|
49
|
+
"@openrouter/ai-sdk-provider": "^2.9.0",
|
|
49
50
|
"ollama-ai-provider-v2": "^3.5.0",
|
|
50
51
|
"googleapis": "^171.4.0",
|
|
51
52
|
"@notionhq/client": "^2.3.0",
|