nodal-agents 0.6.0 → 0.6.2

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.
Files changed (118) hide show
  1. package/README.md +6 -5
  2. package/cli.js +287 -0
  3. package/migrations/0050_jobs_search_fts.sql +4 -0
  4. package/migrations/meta/_journal.json +7 -0
  5. package/package.json +1 -1
  6. package/runner.js +2111 -1406
  7. package/web/.next/BUILD_ID +1 -1
  8. package/web/.next/app-path-routes-manifest.json +5 -5
  9. package/web/.next/build-manifest.json +2 -2
  10. package/web/.next/server/app/(dashboard)/agents/[id]/edit/page.js +2 -2
  11. package/web/.next/server/app/(dashboard)/agents/[id]/edit/page_client-reference-manifest.js +1 -1
  12. package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page.js +2 -2
  13. package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page_client-reference-manifest.js +1 -1
  14. package/web/.next/server/app/(dashboard)/agents/page.js +1 -1
  15. package/web/.next/server/app/(dashboard)/agents/page_client-reference-manifest.js +1 -1
  16. package/web/.next/server/app/(dashboard)/approvals/page.js +1 -1
  17. package/web/.next/server/app/(dashboard)/approvals/page_client-reference-manifest.js +1 -1
  18. package/web/.next/server/app/(dashboard)/automations/page.js +1 -1
  19. package/web/.next/server/app/(dashboard)/automations/page_client-reference-manifest.js +1 -1
  20. package/web/.next/server/app/(dashboard)/billing/page.js +1 -1
  21. package/web/.next/server/app/(dashboard)/billing/page_client-reference-manifest.js +1 -1
  22. package/web/.next/server/app/(dashboard)/chat/page.js +2 -2
  23. package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
  24. package/web/.next/server/app/(dashboard)/connectors/page.js +2 -2
  25. package/web/.next/server/app/(dashboard)/connectors/page_client-reference-manifest.js +1 -1
  26. package/web/.next/server/app/(dashboard)/credentials/page_client-reference-manifest.js +1 -1
  27. package/web/.next/server/app/(dashboard)/jobs/[id]/page.js +2 -2
  28. package/web/.next/server/app/(dashboard)/jobs/[id]/page_client-reference-manifest.js +1 -1
  29. package/web/.next/server/app/(dashboard)/jobs/page.js +1 -1
  30. package/web/.next/server/app/(dashboard)/jobs/page_client-reference-manifest.js +1 -1
  31. package/web/.next/server/app/(dashboard)/learned-skills/page.js +1 -1
  32. package/web/.next/server/app/(dashboard)/learned-skills/page_client-reference-manifest.js +1 -1
  33. package/web/.next/server/app/(dashboard)/llm-providers/page.js +2 -2
  34. package/web/.next/server/app/(dashboard)/llm-providers/page_client-reference-manifest.js +1 -1
  35. package/web/.next/server/app/(dashboard)/logs/page.js +1 -1
  36. package/web/.next/server/app/(dashboard)/logs/page_client-reference-manifest.js +1 -1
  37. package/web/.next/server/app/(dashboard)/mcp/page.js +1 -1
  38. package/web/.next/server/app/(dashboard)/mcp/page_client-reference-manifest.js +1 -1
  39. package/web/.next/server/app/(dashboard)/memories/page.js +1 -1
  40. package/web/.next/server/app/(dashboard)/memories/page_client-reference-manifest.js +1 -1
  41. package/web/.next/server/app/(dashboard)/page.js +1 -1
  42. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  43. package/web/.next/server/app/(dashboard)/settings/page.js +2 -2
  44. package/web/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
  45. package/web/.next/server/app/(dashboard)/settings/root-context/page.js +1 -1
  46. package/web/.next/server/app/(dashboard)/settings/root-context/page_client-reference-manifest.js +1 -1
  47. package/web/.next/server/app/(dashboard)/skills/[id]/edit/page.js +1 -1
  48. package/web/.next/server/app/(dashboard)/skills/[id]/edit/page_client-reference-manifest.js +1 -1
  49. package/web/.next/server/app/(dashboard)/skills/new/page_client-reference-manifest.js +1 -1
  50. package/web/.next/server/app/(dashboard)/skills/page.js +1 -1
  51. package/web/.next/server/app/(dashboard)/skills/page_client-reference-manifest.js +1 -1
  52. package/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  53. package/web/.next/server/app/_global-error.html +1 -1
  54. package/web/.next/server/app/_global-error.rsc +1 -1
  55. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  56. package/web/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  57. package/web/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  58. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  59. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  60. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  61. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  62. package/web/.next/server/app/_not-found.html +1 -1
  63. package/web/.next/server/app/_not-found.rsc +1 -1
  64. package/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  65. package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  66. package/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  67. package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  68. package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  69. package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  70. package/web/.next/server/app/login/page_client-reference-manifest.js +1 -1
  71. package/web/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
  72. package/web/.next/server/app/onboarding.html +1 -1
  73. package/web/.next/server/app/onboarding.rsc +1 -1
  74. package/web/.next/server/app/onboarding.segments/_full.segment.rsc +1 -1
  75. package/web/.next/server/app/onboarding.segments/_head.segment.rsc +1 -1
  76. package/web/.next/server/app/onboarding.segments/_index.segment.rsc +1 -1
  77. package/web/.next/server/app/onboarding.segments/_tree.segment.rsc +1 -1
  78. package/web/.next/server/app/onboarding.segments/onboarding/__PAGE__.segment.rsc +1 -1
  79. package/web/.next/server/app/onboarding.segments/onboarding.segment.rsc +1 -1
  80. package/web/.next/server/app-paths-manifest.json +5 -5
  81. package/web/.next/server/chunks/1445.js +1 -1
  82. package/web/.next/server/chunks/1761.js +1 -1
  83. package/web/.next/server/chunks/3024.js +1 -1
  84. package/web/.next/server/chunks/3971.js +1 -1
  85. package/web/.next/server/chunks/4370.js +16 -16
  86. package/web/.next/server/chunks/4574.js +1 -1
  87. package/web/.next/server/chunks/6012.js +1 -1
  88. package/web/.next/server/chunks/7928.js +1 -1
  89. package/web/.next/server/middleware-build-manifest.js +1 -1
  90. package/web/.next/server/pages/404.html +1 -1
  91. package/web/.next/server/pages/500.html +1 -1
  92. package/web/.next/server/server-reference-manifest.js +1 -1
  93. package/web/.next/server/server-reference-manifest.json +1 -1
  94. package/web/.next/static/chunks/{4905-65b5713d2e04086d.js → 4905-272003c6fbcb2e79.js} +1 -1
  95. package/web/.next/static/chunks/6097-556f092e99ee921a.js +1 -0
  96. package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/{page-e3522f5beaa39d00.js → page-43d9d097194e9298.js} +4 -4
  97. package/web/.next/static/chunks/app/(dashboard)/connectors/{page-e155c796daf03636.js → page-372db1197ad8e674.js} +1 -1
  98. package/web/.next/static/chunks/app/(dashboard)/mcp/page-d9b4e0a0a5bee7a8.js +1 -0
  99. package/web/public/connector-icons/apify.svg +5 -0
  100. package/web/public/connector-icons/blender.svg +12 -0
  101. package/web/public/connector-icons/composio.png +0 -0
  102. package/web/public/connector-icons/fetch.svg +17 -0
  103. package/web/public/connector-icons/firecrawl.svg +1 -0
  104. package/web/public/connector-icons/google-calendar.svg +17 -0
  105. package/web/public/connector-icons/keyshot.svg +36 -0
  106. package/web/public/connector-icons/linear.svg +1 -0
  107. package/web/public/connector-icons/n8n.svg +1 -0
  108. package/web/public/connector-icons/perplexity.svg +1 -0
  109. package/web/public/connector-icons/photoshop.svg +12 -0
  110. package/web/public/connector-icons/playwright.svg +1 -0
  111. package/web/public/connector-icons/supabase.svg +1 -0
  112. package/web/public/connector-icons/tavily.svg +1 -0
  113. package/web/public/connector-icons/unity.svg +10 -0
  114. package/web/public/connector-icons/unreal-engine.svg +1 -0
  115. package/web/.next/static/chunks/6097-d568d74074f2dad0.js +0 -1
  116. package/web/.next/static/chunks/app/(dashboard)/mcp/page-cc885192e6efce48.js +0 -1
  117. /package/web/.next/static/{kbJ7RnqJJkxulS2bJpJy2 → hP-2bfxkCKqsl8LMX58Y7}/_buildManifest.js +0 -0
  118. /package/web/.next/static/{kbJ7RnqJJkxulS2bJpJy2 → hP-2bfxkCKqsl8LMX58Y7}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -10,6 +10,7 @@ A self-hosted platform for building and orchestrating a **team of AI agents** on
10
10
  [![Node](https://img.shields.io/badge/node-22%2B-339933?logo=node.js&logoColor=white)](https://nodejs.org)
11
11
  [![TypeScript](https://img.shields.io/badge/typescript-strict-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org)
12
12
  [![Docs](https://img.shields.io/badge/docs-online-3565ff)](https://kwintspiracy.github.io/nodal-agents/)
13
+ [![Changelog](https://img.shields.io/badge/changelog-v0.6.2-d4ff2e)](CHANGELOG.md)
13
14
 
14
15
  | Home dashboard — light theme | Agent detail — dark theme |
15
16
  | :---: | :---: |
@@ -60,7 +61,7 @@ Every agent runs on the model **you** choose, with the tools **you** grant, in a
60
61
  ### 🤝 Agents that actually finish
61
62
 
62
63
  - **Orchestrators that finish** — pick the delegation style per request: route to one specialist and resume on its result, or fan work out to many sub-agents in parallel and compile the answer.
63
- - **Memory that compounds** — persistent facts auto-injected into every job, plus chat-thread continuity (your agent remembers what it said 30 seconds ago and yesterday).
64
+ - **Memory that compounds** — durable facts auto-injected into every job, ranked by relevance to the task at hand; full-text `search_history` recall over everything the team has ever done; and a background curator that keeps the fact store clean. Plus chat-thread continuity that actually holds a conversation across slow tasks and natural pauses.
64
65
  - **Self-improving (opt-in)** — after a substantial job an agent can reflect and write itself a reusable skill; a weekly curator consolidates and prunes them. Every learned skill is reviewable, assignable, and revocable.
65
66
  - **Self-extending ROOT** — designate an orchestrator as ROOT and let it create skills, agents, MCP servers, and connectors on your behalf — gated by per-grant toggles and an autonomy level (propose-confirm → fully-autonomous).
66
67
  - **Human-in-the-loop** — risky tools pause for approval, and the prompt leads with the agent's plain-language explanation of *what* it wants to do and *why* (plus any ⚠️ impact) — not a wall of raw shell.
@@ -72,11 +73,11 @@ Every agent runs on the model **you** choose, with the tools **you** grant, in a
72
73
  **Models** — Anthropic · OpenAI · Google · Groq · Mistral · OpenRouter · **native DeepSeek** (`api.deepseek.com`) · **native MiniMax** (`api.minimax.io`) · any local model (LM Studio, Ollama). One key per provider; each agent picks its own model.
73
74
 
74
75
  **Connectors** — multi-instance (Gmail perso *and* boulot on one install), managed from the dashboard:
75
- - *OAuth* — Gmail · Google Drive · Sheets · Docs · Calendar · Notion · Airtable
76
- - *API key* — Notion · Airtable · Apify · Firecrawl · Tavily
76
+ - *OAuth* — Airtable · Calendar · Docs · Gmail · Google Drive · Notion · Sheets
77
+ - *API key* — Airtable · Apify · Firecrawl · Notion · Tavily
77
78
 
78
79
  **MCP servers** — over Streamable HTTP *and* stdio, plus add/edit your own:
79
- Stripe · GitHub · Supabase · Notion · Linear · Sentry · n8n · PostgreSQL · Playwright · Perplexity · Apify · Filesystem · Git · Fetch · Sequential Thinking · Composio · Cogni Cortex
80
+ Apify · Blender · Cogni Cortex · Composio · Fetch · Filesystem · Git · GitHub · KeyShot · Linear · n8n · Notion · Perplexity · Photoshop · Playwright · PostgreSQL · Sentry · Stripe · Supabase · Unity · Unreal Engine
80
81
 
81
82
  **Skills** — built-in: office editing (Excel/Word/PowerPoint), shell execution, Obsidian, Telegram etiquette, task planning, markdown output, citation discipline, research methodology, results delivery, language mirroring, HTML design. Plus **install any community `SKILL.md`** from GitHub / skills.sh / ClawHub — and agents can **write their own**.
82
83
 
@@ -164,7 +165,7 @@ pnpm deps:check
164
165
 
165
166
  ## Status
166
167
 
167
- Used daily by the maintainer; stable enough for personal production. **Pre-1.0** — breaking changes are still possible between minors.
168
+ Used daily by the maintainer; stable enough for personal production. **Pre-1.0** — breaking changes are still possible between minors. See the [changelog](CHANGELOG.md) for what shipped in each release.
168
169
 
169
170
  **On the roadmap** (genuine, not vaporware):
170
171
 
package/cli.js CHANGED
@@ -12171,9 +12171,288 @@ var init_community_skill_catalog = __esm({
12171
12171
  });
12172
12172
 
12173
12173
  // ../../packages/shared/src/model-catalog.ts
12174
+ var MODEL_CATALOG, VISION_MODEL_IDS;
12174
12175
  var init_model_catalog = __esm({
12175
12176
  "../../packages/shared/src/model-catalog.ts"() {
12176
12177
  "use strict";
12178
+ MODEL_CATALOG = {
12179
+ // ─── Native DeepSeek (api.deepseek.com) ─────────────────────────────────────
12180
+ // Model IDs verified against DeepSeek API docs (June 2026).
12181
+ // Context windows from DeepSeek's documentation: both deepseek-chat and
12182
+ // deepseek-reasoner support 64K output / 128K context.
12183
+ deepseek: [
12184
+ {
12185
+ modelId: "deepseek-chat",
12186
+ label: "DeepSeek Chat (V3)",
12187
+ // deepseek-chat is the production alias for DeepSeek V3. Standard tool
12188
+ // calling with forced tool_choice supported.
12189
+ capabilities: { tools: true, forcedToolChoice: true },
12190
+ contextWindow: 128e3
12191
+ },
12192
+ {
12193
+ modelId: "deepseek-reasoner",
12194
+ label: "DeepSeek Reasoner (R1)",
12195
+ // DeepSeek R1 — a reasoning/thinking model. Requires `thinking: {type: 'enabled'}`
12196
+ // in the request (the deepseek.ts provider sets this automatically when
12197
+ // reasoning:true). Also requires reasoning_content to be echoed back on
12198
+ // assistant messages with tool_calls (the deepseek fetch shim handles this).
12199
+ capabilities: { tools: true, forcedToolChoice: true, reasoning: true },
12200
+ contextWindow: 128e3
12201
+ }
12202
+ ],
12203
+ // ─── Native MiniMax (api.minimax.io/anthropic) ───────────────────────────────
12204
+ // Current MiniMax text models, from the official docs
12205
+ // (platform.minimax.io/docs/api-reference/text-chat — June 2026). The M2/M3
12206
+ // line supersedes M1, which is no longer listed, so it's dropped here. The
12207
+ // full lineup also includes M2.1/M2.5 and `-highspeed` variants — use the
12208
+ // model picker's "Custom…" field for those; this is the curated short list.
12209
+ // forcedToolChoice:false across the M-series — the MiniMax endpoint rejects a
12210
+ // forced tool_choice with a 400/404 (observed on M3 via OpenRouter); the
12211
+ // runtime completion floor covers it. Context windows are docs-sourced where
12212
+ // available, else a conservative 200K until a live probe confirms.
12213
+ minimax: [
12214
+ {
12215
+ modelId: "MiniMax-M3",
12216
+ label: "MiniMax M3",
12217
+ // Newest flagship — a reasoning model (adaptive `thinking`), 1M context.
12218
+ capabilities: { tools: true, forcedToolChoice: false, reasoning: true },
12219
+ contextWindow: 1048576
12220
+ },
12221
+ {
12222
+ modelId: "MiniMax-M2.7",
12223
+ label: "MiniMax M2.7",
12224
+ // Latest M2-series — non-reasoning per MiniMax docs.
12225
+ capabilities: { tools: true, forcedToolChoice: false },
12226
+ contextWindow: 2e5
12227
+ },
12228
+ {
12229
+ modelId: "MiniMax-M2",
12230
+ label: "MiniMax M2",
12231
+ // Stable previous-generation baseline — non-reasoning.
12232
+ capabilities: { tools: true, forcedToolChoice: false },
12233
+ contextWindow: 2e5
12234
+ }
12235
+ ],
12236
+ anthropic: [
12237
+ {
12238
+ modelId: "claude-opus-4-8",
12239
+ label: "Claude Opus 4.8",
12240
+ capabilities: { tools: true, forcedToolChoice: true },
12241
+ contextWindow: 2e5
12242
+ },
12243
+ {
12244
+ modelId: "claude-sonnet-4-6",
12245
+ label: "Claude Sonnet 4.6",
12246
+ capabilities: { tools: true, forcedToolChoice: true },
12247
+ contextWindow: 2e5
12248
+ },
12249
+ {
12250
+ modelId: "claude-haiku-4-5-20251001",
12251
+ label: "Claude Haiku 4.5",
12252
+ capabilities: { tools: true, forcedToolChoice: true },
12253
+ contextWindow: 2e5
12254
+ }
12255
+ ],
12256
+ openai: [
12257
+ {
12258
+ modelId: "gpt-5",
12259
+ label: "GPT-5",
12260
+ capabilities: { tools: true, forcedToolChoice: true },
12261
+ contextWindow: 4e5
12262
+ },
12263
+ {
12264
+ modelId: "gpt-5-mini",
12265
+ label: "GPT-5 mini",
12266
+ capabilities: { tools: true, forcedToolChoice: true },
12267
+ contextWindow: 4e5
12268
+ }
12269
+ ],
12270
+ google: [
12271
+ {
12272
+ modelId: "gemini-2.0-flash",
12273
+ label: "Gemini 2.0 Flash",
12274
+ capabilities: { tools: true, forcedToolChoice: true },
12275
+ contextWindow: 1048576
12276
+ },
12277
+ {
12278
+ modelId: "gemini-2.5-pro",
12279
+ label: "Gemini 2.5 Pro",
12280
+ capabilities: { tools: true, forcedToolChoice: true },
12281
+ contextWindow: 1048576
12282
+ }
12283
+ ],
12284
+ groq: [
12285
+ {
12286
+ modelId: "llama-3.3-70b-versatile",
12287
+ label: "Llama 3.3 70B",
12288
+ capabilities: { tools: true, forcedToolChoice: true },
12289
+ contextWindow: 131072
12290
+ }
12291
+ ],
12292
+ mistral: [
12293
+ {
12294
+ modelId: "mistral-large-latest",
12295
+ label: "Mistral Large",
12296
+ capabilities: { tools: true, forcedToolChoice: true },
12297
+ contextWindow: 131072
12298
+ }
12299
+ ],
12300
+ // OpenRouter models are namespaced by sub-vendor (anthropic/, deepseek/, …).
12301
+ // The UI groups them by that vendor (see modelGroupLabel). Tested + working
12302
+ // routes. `forcedToolChoice` is per-model: most accept tool_choice:'required';
12303
+ // MiniMax M3 does not (some of its OpenRouter endpoints reject the forced
12304
+ // value), so it runs on 'auto' + the runtime floor.
12305
+ openrouter: [
12306
+ // Anthropic
12307
+ {
12308
+ modelId: "anthropic/claude-haiku-4.5",
12309
+ label: "Claude Haiku 4.5",
12310
+ capabilities: { tools: true, forcedToolChoice: true },
12311
+ contextWindow: 2e5
12312
+ },
12313
+ {
12314
+ modelId: "anthropic/claude-opus-4.7",
12315
+ label: "Claude Opus 4.7",
12316
+ capabilities: { tools: true, forcedToolChoice: true },
12317
+ contextWindow: 1e6
12318
+ },
12319
+ {
12320
+ modelId: "anthropic/claude-opus-4.7-fast",
12321
+ label: "Claude Opus 4.7 (fast)",
12322
+ capabilities: { tools: true, forcedToolChoice: true },
12323
+ contextWindow: 1e6
12324
+ },
12325
+ {
12326
+ modelId: "anthropic/claude-opus-4.8",
12327
+ label: "Claude Opus 4.8",
12328
+ capabilities: { tools: true, forcedToolChoice: true },
12329
+ contextWindow: 1e6
12330
+ },
12331
+ {
12332
+ modelId: "anthropic/claude-opus-4.8-fast",
12333
+ label: "Claude Opus 4.8 (fast)",
12334
+ capabilities: { tools: true, forcedToolChoice: true },
12335
+ contextWindow: 1e6
12336
+ },
12337
+ {
12338
+ modelId: "anthropic/claude-sonnet-4.6",
12339
+ label: "Claude Sonnet 4.6",
12340
+ capabilities: { tools: true, forcedToolChoice: true },
12341
+ contextWindow: 1e6
12342
+ },
12343
+ // DeepSeek
12344
+ {
12345
+ modelId: "deepseek/deepseek-v3.2",
12346
+ label: "DeepSeek V3.2",
12347
+ capabilities: { tools: true, forcedToolChoice: true },
12348
+ contextWindow: 131072
12349
+ },
12350
+ {
12351
+ modelId: "deepseek/deepseek-v4-flash",
12352
+ label: "DeepSeek V4 Flash",
12353
+ // DeepSeek V4 is a reasoning model (reasoning_content / reasoning effort).
12354
+ // Flagging reasoning makes the OpenRouter provider enable reasoning + round-trip
12355
+ // its reasoning_details across tool calls — without it the model misbehaves
12356
+ // (gathers then emits no answer). Matches how Hermes drives DeepSeek.
12357
+ capabilities: { tools: true, forcedToolChoice: true, reasoning: true },
12358
+ contextWindow: 1048576,
12359
+ providerOrder: ["deepseek"]
12360
+ },
12361
+ {
12362
+ modelId: "deepseek/deepseek-v4-pro",
12363
+ label: "DeepSeek V4 Pro",
12364
+ capabilities: { tools: true, forcedToolChoice: true, reasoning: true },
12365
+ contextWindow: 1048576,
12366
+ providerOrder: ["deepseek"]
12367
+ },
12368
+ // Google
12369
+ {
12370
+ modelId: "google/gemini-3.1-flash-lite-preview",
12371
+ label: "Gemini 3.1 Flash Lite (preview)",
12372
+ capabilities: { tools: true, forcedToolChoice: true },
12373
+ contextWindow: 1048576
12374
+ },
12375
+ {
12376
+ modelId: "google/gemini-3.1-pro-preview",
12377
+ label: "Gemini 3.1 Pro (preview)",
12378
+ capabilities: { tools: true, forcedToolChoice: true },
12379
+ contextWindow: 1048576
12380
+ },
12381
+ {
12382
+ modelId: "google/gemini-3.5-flash",
12383
+ label: "Gemini 3.5 Flash",
12384
+ capabilities: { tools: true, forcedToolChoice: true },
12385
+ contextWindow: 1048576
12386
+ },
12387
+ {
12388
+ modelId: "google/gemma-4-31b-it",
12389
+ label: "Gemma 4 31B-IT",
12390
+ capabilities: { tools: true, forcedToolChoice: true },
12391
+ contextWindow: 262144
12392
+ },
12393
+ // MiniMax
12394
+ {
12395
+ modelId: "minimax/minimax-m3",
12396
+ label: "MiniMax M3",
12397
+ // A reasoning model. Some of its OpenRouter endpoints reject a FORCED
12398
+ // tool_choice ('required') → we send 'auto' (forcedToolChoice:false).
12399
+ // reasoning:true makes the provider return reasoning_details so the runner
12400
+ // can round-trip them across tool-call turns.
12401
+ capabilities: { tools: true, forcedToolChoice: false, reasoning: true },
12402
+ contextWindow: 1048576
12403
+ },
12404
+ // Z.ai (GLM)
12405
+ {
12406
+ modelId: "z-ai/glm-5.2",
12407
+ label: "GLM 5.2",
12408
+ // A reasoning model (reasoning effort high/xhigh), strong at coding + tool
12409
+ // use. reasoning:true → provider returns reasoning_details for round-trip.
12410
+ // forcedToolChoice:false: send 'auto' (don't risk a rejected 'required' on
12411
+ // a reasoning model; workers are 'auto' after turn 1 anyway).
12412
+ capabilities: { tools: true, forcedToolChoice: false, reasoning: true },
12413
+ contextWindow: 1048576
12414
+ },
12415
+ // Moonshot (Kimi)
12416
+ {
12417
+ modelId: "moonshotai/kimi-k2.7-code",
12418
+ label: "Kimi K2.7 Code",
12419
+ // Always operates in thinking mode and preserves reasoning_content across
12420
+ // turns (like DeepSeek) → reasoning:true is required so the provider
12421
+ // round-trips reasoning_details. forcedToolChoice:false for the same reason
12422
+ // as the other reasoning models.
12423
+ capabilities: { tools: true, forcedToolChoice: false, reasoning: true },
12424
+ contextWindow: 262144
12425
+ }
12426
+ ]
12427
+ };
12428
+ VISION_MODEL_IDS = /* @__PURE__ */ new Set([
12429
+ // OpenRouter (verified via /api/v1/models)
12430
+ "anthropic/claude-haiku-4.5",
12431
+ "anthropic/claude-opus-4.7",
12432
+ "anthropic/claude-opus-4.7-fast",
12433
+ "anthropic/claude-opus-4.8",
12434
+ "anthropic/claude-opus-4.8-fast",
12435
+ "anthropic/claude-sonnet-4.6",
12436
+ "google/gemini-3.1-flash-lite-preview",
12437
+ "google/gemini-3.1-pro-preview",
12438
+ "google/gemini-3.5-flash",
12439
+ "google/gemma-4-31b-it",
12440
+ "minimax/minimax-m3",
12441
+ "moonshotai/kimi-k2.7-code",
12442
+ // Native-provider forms
12443
+ "claude-opus-4-8",
12444
+ "claude-sonnet-4-6",
12445
+ "claude-haiku-4-5-20251001",
12446
+ "gpt-5",
12447
+ "gpt-5-mini",
12448
+ "gemini-2.0-flash",
12449
+ "gemini-2.5-pro",
12450
+ "mistral-large-latest",
12451
+ "MiniMax-M3"
12452
+ ]);
12453
+ for (const entries of Object.values(MODEL_CATALOG)) {
12454
+ for (const e of entries) e.capabilities.vision = VISION_MODEL_IDS.has(e.modelId);
12455
+ }
12177
12456
  }
12178
12457
  });
12179
12458
 
@@ -12516,6 +12795,14 @@ var init_jobs = __esm({
12516
12795
  chatId: text("chat_id"),
12517
12796
  systemPrompt: text("system_prompt"),
12518
12797
  messages: jsonb("messages").default(sql`'[]'::jsonb`),
12798
+ /**
12799
+ * Flattened plain-text transcript (task + assistant text + tool outputs +
12800
+ * result) for full-text episodic search. Populated at job completion by
12801
+ * flattenTranscript(). A generated `search_tsv tsvector` column + GIN index
12802
+ * (raw SQL, migration 0050 — not expressible in the Drizzle schema builder)
12803
+ * makes it queryable by the `search_history` builtin.
12804
+ */
12805
+ searchText: text("search_text"),
12519
12806
  toolsUsed: text("tools_used").array().default(sql`'{}'::text[]`),
12520
12807
  turn: integer("turn").default(0),
12521
12808
  result: text("result"),
@@ -0,0 +1,4 @@
1
+ ALTER TABLE "agent_jobs" ADD COLUMN "search_text" text;--> statement-breakpoint
2
+ ALTER TABLE "agent_jobs" ADD COLUMN "search_tsv" tsvector GENERATED ALWAYS AS (to_tsvector('simple', coalesce("search_text", ''))) STORED;--> statement-breakpoint
3
+ CREATE INDEX "idx_agent_jobs_search_tsv" ON "agent_jobs" USING gin ("search_tsv");--> statement-breakpoint
4
+ UPDATE "agent_jobs" SET "search_text" = trim(coalesce("task", '') || ' ' || coalesce("result", '')) WHERE "search_text" IS NULL AND (coalesce("task", '') <> '' OR coalesce("result", '') <> '');
@@ -344,6 +344,13 @@
344
344
  "when": 1782900000000,
345
345
  "tag": "0049_skill_assignment_files_writable",
346
346
  "breakpoints": true
347
+ },
348
+ {
349
+ "idx": 50,
350
+ "version": "7",
351
+ "when": 1783000000000,
352
+ "tag": "0050_jobs_search_fts",
353
+ "breakpoints": true
347
354
  }
348
355
  ]
349
356
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodal-agents",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Local-first AI agent platform with a web dashboard — install in one command.",
5
5
  "license": "MIT",
6
6
  "repository": {