noumen 0.5.0 → 0.8.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.
Files changed (137) hide show
  1. package/README.md +237 -93
  2. package/dist/a2a/index.d.ts +5 -7
  3. package/dist/a2a/index.js +3 -4
  4. package/dist/a2a/index.js.map +1 -1
  5. package/dist/acp/index.d.ts +5 -7
  6. package/dist/acp/index.js +0 -1
  7. package/dist/acp/index.js.map +1 -1
  8. package/dist/{agent-C3eDRsxs.d.ts → agent-D0gl-qYi.d.ts} +259 -31
  9. package/dist/{chunk-WPCYGZOE.js → chunk-5HY4IYNT.js} +2062 -2545
  10. package/dist/chunk-5HY4IYNT.js.map +1 -0
  11. package/dist/chunk-BC5BLWBC.js +21 -0
  12. package/dist/chunk-BC5BLWBC.js.map +1 -0
  13. package/dist/{chunk-XZN4QZLK.js → chunk-CX4BL6PC.js} +25 -15
  14. package/dist/chunk-CX4BL6PC.js.map +1 -0
  15. package/dist/{chunk-5GEX6ZSB.js → chunk-HQISH4D7.js} +60 -1
  16. package/dist/chunk-HQISH4D7.js.map +1 -0
  17. package/dist/{chunk-Y45R3PQL.js → chunk-NUCJXOUV.js} +32 -18
  18. package/dist/{chunk-Y45R3PQL.js.map → chunk-NUCJXOUV.js.map} +1 -1
  19. package/dist/chunk-OPFFLQZL.js +40 -0
  20. package/dist/chunk-OPFFLQZL.js.map +1 -0
  21. package/dist/chunk-PDEAJ272.js +660 -0
  22. package/dist/chunk-PDEAJ272.js.map +1 -0
  23. package/dist/chunk-PKHLGGEC.js +115 -0
  24. package/dist/chunk-PKHLGGEC.js.map +1 -0
  25. package/dist/chunk-XQTNXRE7.js +176 -0
  26. package/dist/chunk-XQTNXRE7.js.map +1 -0
  27. package/dist/chunk-XZPAA5TO.js +817 -0
  28. package/dist/chunk-XZPAA5TO.js.map +1 -0
  29. package/dist/cli/index.js +77 -42
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/client/index.d.ts +1 -2
  32. package/dist/client/index.js +0 -2
  33. package/dist/client/index.js.map +1 -1
  34. package/dist/client-JJFLE6RT.js +9 -0
  35. package/dist/{computer-BPdxSo6X.d.ts → computer-DzMR92tK.d.ts} +1 -1
  36. package/dist/docker.d.ts +2 -2
  37. package/dist/docker.js +0 -1
  38. package/dist/docker.js.map +1 -1
  39. package/dist/e2b.d.ts +2 -2
  40. package/dist/e2b.js +0 -1
  41. package/dist/e2b.js.map +1 -1
  42. package/dist/freestyle.d.ts +2 -2
  43. package/dist/freestyle.js +0 -1
  44. package/dist/freestyle.js.map +1 -1
  45. package/dist/{headless-FFU2DESQ.js → headless-25DU4MJQ.js} +1 -3
  46. package/dist/{headless-FFU2DESQ.js.map → headless-25DU4MJQ.js.map} +1 -1
  47. package/dist/{history-snip-64GYP4ZL.js → history-snip-HAWNAYKY.js} +1 -2
  48. package/dist/index.d.ts +358 -72
  49. package/dist/index.js +68 -55
  50. package/dist/jsonrpc/index.js +0 -1
  51. package/dist/local.d.ts +168 -0
  52. package/dist/local.js +40 -0
  53. package/dist/local.js.map +1 -0
  54. package/dist/lsp/index.d.ts +4 -5
  55. package/dist/lsp/index.js +0 -1
  56. package/dist/{lsp-PS3BWIHC.js → lsp-3APWNKB2.js} +1 -2
  57. package/dist/{manager-DLXK63XC.js → manager-Z5EQ7YYV.js} +1 -2
  58. package/dist/mcp/index.d.ts +16 -8
  59. package/dist/mcp/index.js +5 -6
  60. package/dist/mcp/index.js.map +1 -1
  61. package/dist/{mcp-auth-AEI2R4ZC.js → mcp-auth-NOIQPF7W.js} +1 -2
  62. package/dist/{provider-factory-KI7OZUY3.js → provider-factory-KNBSHXJ6.js} +3 -3
  63. package/dist/{render-GRN4ZSSW.js → render-4VEODRK7.js} +1 -2
  64. package/dist/{resolve-GDSHNMG6.js → resolve-AGQZFMKD.js} +3 -3
  65. package/dist/sandbox-DAqQo0Tj.d.ts +49 -0
  66. package/dist/sandbox-index-ODNREIFA.js +32 -0
  67. package/dist/sandbox-index-ODNREIFA.js.map +1 -0
  68. package/dist/server/index.d.ts +18 -7
  69. package/dist/server/index.js +9 -5
  70. package/dist/server/index.js.map +1 -1
  71. package/dist/{server-Cu9gv1dk.d.ts → server-DFXdlqyX.d.ts} +1 -1
  72. package/dist/{spinner-OJNR6NFO.js → spinner-72JEISPK.js} +1 -2
  73. package/dist/sprites.d.ts +2 -2
  74. package/dist/sprites.js +0 -1
  75. package/dist/sprites.js.map +1 -1
  76. package/dist/ssh.d.ts +2 -2
  77. package/dist/ssh.js +0 -1
  78. package/dist/ssh.js.map +1 -1
  79. package/dist/{types-BA87bHPV.d.ts → types-BX4ALqoN.d.ts} +76 -4
  80. package/dist/{types-LrU4LRmX.d.ts → types-DLZNyF5t.d.ts} +164 -2
  81. package/dist/unsandboxed.d.ts +59 -0
  82. package/dist/unsandboxed.js +32 -0
  83. package/dist/unsandboxed.js.map +1 -0
  84. package/dist/{uuid-RVN2T26F.js → uuid-CVTNAPEB.js} +1 -2
  85. package/dist/{zod-7YXKWYMC.js → zod-VKURGPRT.js} +1 -2
  86. package/package.json +35 -50
  87. package/dist/cache-DsRqxx6v.d.ts +0 -38
  88. package/dist/chunk-5GEX6ZSB.js.map +0 -1
  89. package/dist/chunk-CS6WNDCF.js +0 -171
  90. package/dist/chunk-CS6WNDCF.js.map +0 -1
  91. package/dist/chunk-DGUM43GV.js +0 -11
  92. package/dist/chunk-EKOGVTBT.js +0 -472
  93. package/dist/chunk-EKOGVTBT.js.map +0 -1
  94. package/dist/chunk-HEQQQGK5.js +0 -131
  95. package/dist/chunk-HEQQQGK5.js.map +0 -1
  96. package/dist/chunk-L3L3FG5T.js +0 -16
  97. package/dist/chunk-L3L3FG5T.js.map +0 -1
  98. package/dist/chunk-WPCYGZOE.js.map +0 -1
  99. package/dist/chunk-WTLK2ZAR.js +0 -94
  100. package/dist/chunk-WTLK2ZAR.js.map +0 -1
  101. package/dist/chunk-XZN4QZLK.js.map +0 -1
  102. package/dist/client-CRRO2376.js +0 -10
  103. package/dist/providers/anthropic.d.ts +0 -19
  104. package/dist/providers/anthropic.js +0 -35
  105. package/dist/providers/anthropic.js.map +0 -1
  106. package/dist/providers/bedrock.d.ts +0 -39
  107. package/dist/providers/bedrock.js +0 -56
  108. package/dist/providers/bedrock.js.map +0 -1
  109. package/dist/providers/gemini.d.ts +0 -17
  110. package/dist/providers/gemini.js +0 -262
  111. package/dist/providers/gemini.js.map +0 -1
  112. package/dist/providers/ollama.d.ts +0 -13
  113. package/dist/providers/ollama.js +0 -20
  114. package/dist/providers/ollama.js.map +0 -1
  115. package/dist/providers/openai.d.ts +0 -21
  116. package/dist/providers/openai.js +0 -9
  117. package/dist/providers/openrouter.d.ts +0 -16
  118. package/dist/providers/openrouter.js +0 -24
  119. package/dist/providers/openrouter.js.map +0 -1
  120. package/dist/providers/vertex.d.ts +0 -42
  121. package/dist/providers/vertex.js +0 -67
  122. package/dist/providers/vertex.js.map +0 -1
  123. package/dist/sandbox-9qeMTNrD.d.ts +0 -126
  124. package/dist/types-CD0rUKKT.d.ts +0 -109
  125. package/dist/uuid-RVN2T26F.js.map +0 -1
  126. package/dist/zod-7YXKWYMC.js.map +0 -1
  127. /package/dist/{chunk-DGUM43GV.js.map → client-JJFLE6RT.js.map} +0 -0
  128. /package/dist/{client-CRRO2376.js.map → history-snip-HAWNAYKY.js.map} +0 -0
  129. /package/dist/{history-snip-64GYP4ZL.js.map → lsp-3APWNKB2.js.map} +0 -0
  130. /package/dist/{lsp-PS3BWIHC.js.map → manager-Z5EQ7YYV.js.map} +0 -0
  131. /package/dist/{manager-DLXK63XC.js.map → mcp-auth-NOIQPF7W.js.map} +0 -0
  132. /package/dist/{mcp-auth-AEI2R4ZC.js.map → provider-factory-KNBSHXJ6.js.map} +0 -0
  133. /package/dist/{provider-factory-KI7OZUY3.js.map → render-4VEODRK7.js.map} +0 -0
  134. /package/dist/{providers/openai.js.map → resolve-AGQZFMKD.js.map} +0 -0
  135. /package/dist/{render-GRN4ZSSW.js.map → spinner-72JEISPK.js.map} +0 -0
  136. /package/dist/{resolve-GDSHNMG6.js.map → uuid-CVTNAPEB.js.map} +0 -0
  137. /package/dist/{spinner-OJNR6NFO.js.map → zod-VKURGPRT.js.map} +0 -0
package/README.md CHANGED
@@ -14,28 +14,37 @@ Any provider. Any sandbox. One package.
14
14
  pnpm add noumen
15
15
  ```
16
16
 
17
- Then install the provider SDK you need:
17
+ Then install the Vercel AI SDK package for the provider you want:
18
18
 
19
19
  ```bash
20
- pnpm add openai # for OpenAI / OpenRouter / Ollama
21
- pnpm add @anthropic-ai/sdk # for Anthropic
22
- pnpm add @google/genai # for Gemini
23
- # Ollama requires no SDK — just install https://ollama.com
20
+ pnpm add @ai-sdk/openai # OpenAI
21
+ pnpm add @ai-sdk/anthropic # Anthropic
22
+ pnpm add @ai-sdk/google # Google Gemini
23
+ pnpm add @openrouter/ai-sdk-provider # OpenRouter
24
+ pnpm add @ai-sdk/amazon-bedrock # AWS Bedrock
25
+ pnpm add @ai-sdk/google-vertex # Google Vertex AI
26
+ pnpm add ollama-ai-provider-v2 # Ollama (local)
24
27
  ```
25
28
 
29
+ noumen wraps any Vercel AI SDK `LanguageModel` via a single `AiSdkProvider` adapter — install only the packages for the providers you actually use.
30
+
26
31
  ## Quick Start
27
32
 
28
33
  ```typescript
29
- import { Agent } from "noumen";
34
+ import { LocalAgent } from "noumen/local";
30
35
 
31
- const agent = new Agent({ provider: "anthropic", cwd: "." });
36
+ const agent = LocalAgent({ provider: "anthropic", cwd: "." });
32
37
 
33
38
  for await (const event of agent.run("Add a health-check endpoint to server.ts")) {
34
39
  if (event.type === "text_delta") process.stdout.write(event.text);
35
40
  }
36
41
  ```
37
42
 
38
- Three lines to a working agent. The string provider auto-detects your `ANTHROPIC_API_KEY` from the environment, and `cwd` defaults to a local sandbox.
43
+ A working agent in three lines. `LocalAgent` is a convenience factory that constructs an [`Agent`](#embedding) wired to a `LocalSandbox` (OS-level sandboxing via `@anthropic-ai/sandbox-runtime`) — use it whenever you want the host's filesystem and shell, isolated. The string provider auto-detects your `ANTHROPIC_API_KEY` from the environment.
44
+
45
+ Want raw host access with no isolation? Swap `noumen/local` → `noumen/unsandboxed` and `LocalAgent` → `UnsandboxedAgent`. Want a remote sandbox? Use `new Agent({ provider, sandbox })` directly — see [Sandboxes](#sandboxes) for every backend.
46
+
47
+ > **Why the subpath import?** The root barrel (`import { Agent } from "noumen"`) deliberately never pulls a default sandbox into the module graph — that keeps `noumen` lightweight for apps that bundle with Next.js NFT or serverless-webpack and only use a remote sandbox. Opting into a local sandbox is an explicit import line. See [Sandboxes](#sandboxes).
39
48
 
40
49
  ### Execute (run to completion)
41
50
 
@@ -52,11 +61,14 @@ console.log(`Done — ${result.toolCalls} tool calls`);
52
61
  ### Full control
53
62
 
54
63
  ```typescript
55
- import { Agent, LocalSandbox } from "noumen";
56
- import { OpenAIProvider } from "noumen/openai";
64
+ import { Agent, AiSdkProvider } from "noumen";
65
+ import { LocalSandbox } from "noumen/local";
66
+ import { createOpenAI } from "@ai-sdk/openai";
67
+
68
+ const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });
57
69
 
58
70
  const agent = new Agent({
59
- provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
71
+ provider: new AiSdkProvider({ model: openai.chat("gpt-5") }),
60
72
  sandbox: LocalSandbox({ cwd: "/my/project" }),
61
73
  });
62
74
 
@@ -82,12 +94,16 @@ for await (const event of thread.run("Refactor the auth module")) {
82
94
  For zero-config setup, use a preset that configures everything for you:
83
95
 
84
96
  ```typescript
85
- import { codingAgent } from "noumen";
86
- import { OpenAIProvider } from "noumen/openai";
97
+ import { codingAgent, AiSdkProvider } from "noumen";
98
+ import { LocalSandbox } from "noumen/local";
99
+ import { createOpenAI } from "@ai-sdk/openai";
100
+
101
+ const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY! });
87
102
 
88
103
  const agent = codingAgent({
89
- provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY! }),
104
+ provider: new AiSdkProvider({ model: openai.chat("gpt-5") }),
90
105
  cwd: "/my/project",
106
+ sandbox: LocalSandbox({ cwd: "/my/project" }),
91
107
  });
92
108
 
93
109
  await agent.init();
@@ -100,6 +116,8 @@ for await (const event of thread.run("Refactor the auth module")) {
100
116
  await agent.close();
101
117
  ```
102
118
 
119
+ Presets require an explicit `sandbox` for the same bundler-hygiene reason — pick a backend from its subpath (`noumen/local`, `noumen/unsandboxed`, `noumen/docker`, …).
120
+
103
121
  Three presets are available:
104
122
 
105
123
  | Preset | Mode | Includes |
@@ -249,143 +267,234 @@ npx noumen doctor
249
267
 
250
268
  ## Providers
251
269
 
270
+ noumen wraps any [Vercel AI SDK](https://sdk.vercel.ai) `LanguageModel` via a single `AiSdkProvider` adapter. Install the `@ai-sdk/*` package for the vendor you want, hand its model instance to `AiSdkProvider`, and pass the result to `Agent`. Every provider follows the same three-line pattern:
271
+
272
+ ```typescript
273
+ import { AiSdkProvider } from "noumen";
274
+ import { createOpenAI } from "@ai-sdk/openai";
275
+
276
+ const provider = new AiSdkProvider({
277
+ model: createOpenAI({ apiKey: process.env.OPENAI_API_KEY })("gpt-5"),
278
+ });
279
+ ```
280
+
281
+ | Option on `AiSdkProvider` | Description |
282
+ | --- | --- |
283
+ | `model` | Any AI SDK `LanguageModelV2` / `V3` instance. Required. |
284
+ | `defaultModel` | Override the model id reported by `provider.defaultModel`. |
285
+ | `providerFamily` | `"openai" \| "anthropic" \| "google"` — controls how noumen maps thinking / reasoning / cache options. Inferred from the model by default; set explicitly when going through a custom proxy. |
286
+ | `cacheConfig` | `{ enabled: true }` inserts an Anthropic `cache_control` breakpoint and honors `ChatParams.skipCacheWrite`. No-op for non-Anthropic families. |
287
+
288
+ Per-call options (`thinking`, `reasoningEffort`, `outputFormat`, `skipCacheWrite`, etc.) continue to flow through `ChatParams` / `AgentOptions` exactly like before — the adapter routes them to the right `providerOptions.*` entry for the detected family.
289
+
252
290
  ### OpenAI
253
291
 
292
+ ```bash
293
+ pnpm add @ai-sdk/openai
294
+ ```
295
+
254
296
  ```typescript
255
- import { OpenAIProvider } from "noumen/openai";
297
+ import { AiSdkProvider } from "noumen";
298
+ import { createOpenAI } from "@ai-sdk/openai";
256
299
 
257
- const provider = new OpenAIProvider({
258
- apiKey: "sk-...",
259
- model: "gpt-4o", // default
260
- baseURL: "https://...", // optional, for compatible APIs
300
+ const openai = createOpenAI({
301
+ apiKey: process.env.OPENAI_API_KEY,
302
+ baseURL: "https://...", // optional, for Azure / proxies / compatible APIs
261
303
  });
304
+
305
+ // `.chat(id)` pins to chat/completions. Drop it to use the Responses API.
306
+ const provider = new AiSdkProvider({ model: openai.chat("gpt-5") });
262
307
  ```
263
308
 
264
309
  ### Anthropic
265
310
 
311
+ ```bash
312
+ pnpm add @ai-sdk/anthropic
313
+ ```
314
+
266
315
  ```typescript
267
- import { AnthropicProvider } from "noumen/anthropic";
316
+ import { AiSdkProvider } from "noumen";
317
+ import { createAnthropic } from "@ai-sdk/anthropic";
318
+
319
+ const anthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
268
320
 
269
- const provider = new AnthropicProvider({
270
- apiKey: "sk-ant-...",
271
- model: "claude-sonnet-4", // default
321
+ const provider = new AiSdkProvider({
322
+ model: anthropic("claude-opus-4.6"),
323
+ providerFamily: "anthropic",
324
+ cacheConfig: { enabled: true }, // prompt caching
272
325
  });
273
326
  ```
274
327
 
275
328
  ### Google Gemini
276
329
 
330
+ ```bash
331
+ pnpm add @ai-sdk/google
332
+ ```
333
+
277
334
  ```typescript
278
- import { GeminiProvider } from "noumen/gemini";
335
+ import { AiSdkProvider } from "noumen";
336
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
337
+
338
+ const google = createGoogleGenerativeAI({ apiKey: process.env.GEMINI_API_KEY });
279
339
 
280
- const provider = new GeminiProvider({
281
- apiKey: "...", // Google AI Studio API key
282
- model: "gemini-2.5-flash", // default
340
+ const provider = new AiSdkProvider({
341
+ model: google("gemini-2.5-flash"),
342
+ providerFamily: "google",
283
343
  });
284
344
  ```
285
345
 
286
346
  ### OpenRouter
287
347
 
348
+ ```bash
349
+ pnpm add @openrouter/ai-sdk-provider
350
+ ```
351
+
288
352
  ```typescript
289
- import { OpenRouterProvider } from "noumen/openrouter";
353
+ import { AiSdkProvider } from "noumen";
354
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
355
+
356
+ const openrouter = createOpenRouter({
357
+ apiKey: process.env.OPENROUTER_API_KEY,
358
+ headers: {
359
+ "HTTP-Referer": "https://myapp.com", // optional, for openrouter.ai rankings
360
+ "X-Title": "My Agent", // optional
361
+ },
362
+ });
290
363
 
291
- const provider = new OpenRouterProvider({
292
- apiKey: "sk-or-...",
293
- model: "anthropic/claude-sonnet-4", // default
294
- appName: "My Agent", // optional, for openrouter.ai rankings
295
- appUrl: "https://myapp.com", // optional
364
+ const provider = new AiSdkProvider({
365
+ model: openrouter.chat("anthropic/claude-opus-4.6"),
296
366
  });
297
367
  ```
298
368
 
299
- ### AWS Bedrock (Anthropic)
369
+ ### AWS Bedrock
300
370
 
301
- Route Anthropic models through AWS Bedrock. Requires `@anthropic-ai/bedrock-sdk`:
371
+ Route Claude (and any other Bedrock-hosted model) through AWS Bedrock.
302
372
 
303
373
  ```bash
304
- pnpm add @anthropic-ai/bedrock-sdk
374
+ pnpm add @ai-sdk/amazon-bedrock
305
375
  ```
306
376
 
307
377
  ```typescript
308
- import { BedrockAnthropicProvider } from "noumen/bedrock";
309
-
310
- const provider = new BedrockAnthropicProvider({
311
- region: "us-west-2", // default: us-east-1
312
- model: "us.anthropic.claude-sonnet-4-v1:0", // default
313
- credentials: { // optional, falls back to default chain
314
- accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
315
- secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
316
- sessionToken: process.env.AWS_SESSION_TOKEN,
317
- },
318
- cacheControl: { enabled: true }, // optional prompt caching
378
+ import { AiSdkProvider } from "noumen";
379
+ import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
380
+
381
+ const bedrock = createAmazonBedrock({
382
+ region: process.env.AWS_REGION ?? "us-east-1",
383
+ // Credentials resolved from the standard AWS credential chain
384
+ // (env vars, ~/.aws/credentials, IAM roles) unless you pass
385
+ // explicit accessKeyId / secretAccessKey / sessionToken.
319
386
  });
320
- ```
321
387
 
322
- When `credentials` is omitted, the SDK uses the standard AWS credential chain (env vars, `~/.aws/credentials`, IAM roles, etc.).
388
+ const provider = new AiSdkProvider({
389
+ model: bedrock("us.anthropic.claude-opus-4.6-v1:0"),
390
+ providerFamily: "anthropic",
391
+ cacheConfig: { enabled: true },
392
+ });
393
+ ```
323
394
 
324
- ### Google Vertex AI (Anthropic)
395
+ ### Google Vertex AI
325
396
 
326
- Route Anthropic models through Google Cloud Vertex AI. Requires `@anthropic-ai/vertex-sdk` and `google-auth-library`:
397
+ Route Claude or native Gemini through Google Cloud Vertex AI.
327
398
 
328
399
  ```bash
329
- pnpm add @anthropic-ai/vertex-sdk google-auth-library
400
+ pnpm add @ai-sdk/google-vertex
330
401
  ```
331
402
 
332
403
  ```typescript
333
- import { VertexAnthropicProvider } from "noumen/vertex";
404
+ import { AiSdkProvider } from "noumen";
405
+ import { createVertex } from "@ai-sdk/google-vertex";
334
406
 
335
- const provider = new VertexAnthropicProvider({
336
- projectId: "my-gcp-project",
337
- region: "us-east5", // default
338
- model: "claude-sonnet-4", // default
339
- cacheControl: { enabled: true }, // optional prompt caching
407
+ const vertex = createVertex({
408
+ project: process.env.GOOGLE_CLOUD_PROJECT,
409
+ location: "us-east5",
410
+ // googleAuthOptions: { keyFile: "/path/to/service-account.json" },
340
411
  });
341
- ```
342
-
343
- When `googleAuth` is omitted, the provider creates a `GoogleAuth` instance using application default credentials. You can pass your own `googleAuth` instance for custom authentication:
344
412
 
345
- ```typescript
346
- import { GoogleAuth } from "google-auth-library";
413
+ // Claude on Vertex
414
+ const claudeProvider = new AiSdkProvider({
415
+ model: vertex.anthropic("claude-opus-4.6"),
416
+ providerFamily: "anthropic",
417
+ cacheConfig: { enabled: true },
418
+ });
347
419
 
348
- const provider = new VertexAnthropicProvider({
349
- projectId: "my-project",
350
- googleAuth: new GoogleAuth({ keyFile: "/path/to/service-account.json" }),
420
+ // Native Gemini on Vertex
421
+ const geminiProvider = new AiSdkProvider({
422
+ model: vertex("gemini-2.5-pro"),
423
+ providerFamily: "google",
351
424
  });
352
425
  ```
353
426
 
354
427
  ### Ollama (Local)
355
428
 
356
- Run models locally with [Ollama](https://ollama.com). No API key needed — just install Ollama and pull a model:
429
+ Run models locally with [Ollama](https://ollama.com). No API key needed — just install Ollama, pull a model, and add the Vercel AI SDK provider:
357
430
 
358
431
  ```bash
359
432
  ollama pull qwen2.5-coder:32b
360
433
  ollama serve
434
+ pnpm add ollama-ai-provider-v2
361
435
  ```
362
436
 
363
437
  ```typescript
364
- import { OllamaProvider } from "noumen/ollama";
438
+ import { AiSdkProvider } from "noumen";
439
+ import { createOllama } from "ollama-ai-provider-v2";
365
440
 
366
- const provider = new OllamaProvider({
367
- model: "qwen2.5-coder:32b", // default
368
- baseURL: "http://localhost:11434/v1", // default
441
+ const ollama = createOllama({
442
+ // baseURL: "http://192.168.1.10:11434/api", // override for remote Ollama
369
443
  });
444
+
445
+ const provider = new AiSdkProvider({ model: ollama("qwen2.5-coder:32b") });
370
446
  ```
371
447
 
372
448
  The CLI auto-detects a running Ollama server when no cloud API keys are set, so you can simply run `noumen` with Ollama serving in the background.
373
449
 
450
+ ### String shorthand
451
+
452
+ For quick setup and the CLI, pass a provider name string — noumen dynamically imports the right `@ai-sdk/*` package and wraps it in `AiSdkProvider` for you:
453
+
454
+ ```typescript
455
+ const agent = LocalAgent({ provider: "anthropic", cwd: "." });
456
+ // Equivalent to manually constructing AiSdkProvider with @ai-sdk/anthropic.
457
+ ```
458
+
459
+ Supported names: `openai`, `anthropic`, `gemini`, `openrouter`, `bedrock`, `vertex`, `ollama`.
460
+
461
+ ### Custom / metered proxies
462
+
463
+ Any AI SDK factory accepts a `baseURL` and custom headers, so routing through your own metered gateway is a one-liner:
464
+
465
+ ```typescript
466
+ const gateway = createOpenAI({
467
+ baseURL: "https://my-proxy.example.com/openai",
468
+ apiKey: userJwt, // forwarded as Authorization: Bearer <jwt>
469
+ });
470
+ const provider = new AiSdkProvider({ model: gateway.chat("gpt-5") });
471
+ ```
472
+
374
473
  ## Sandboxes
375
474
 
376
475
  A `Sandbox` bundles a `VirtualFs` (filesystem) and `VirtualComputer` (shell execution) into one object. Every file read/write and shell command the agent executes goes through these interfaces — swap the sandbox to control what the agent can access.
377
476
 
378
- Local factories live on the root barrel; each remote backend ships on its own subpath so its optional peer dep only enters the module graph when you opt in:
477
+ `sandbox` is **required** on `Agent` and every preset. The root barrel (`import { Agent } from "noumen"`) never imports a sandbox factory, so callers pick a backend explicitly from its subpath. That keeps `node:child_process` and `node:fs/promises` out of the static module graph for consumers that only use a remote sandbox — critical for bundlers like Next.js NFT and serverless-webpack that trace dependencies.
379
478
 
380
479
  | Factory | Import | Peer dep |
381
480
  | --- | --- | --- |
382
- | `LocalSandbox`, `UnsandboxedLocal` | `noumen` | `@anthropic-ai/sandbox-runtime` (bundled) |
481
+ | `LocalSandbox` | `noumen/local` | `@anthropic-ai/sandbox-runtime` (bundled) |
482
+ | `UnsandboxedLocal` | `noumen/unsandboxed` | — |
383
483
  | `SpritesSandbox` | `noumen/sprites` | — |
384
484
  | `DockerSandbox` | `noumen/docker` | `dockerode` |
385
485
  | `E2BSandbox` | `noumen/e2b` | `e2b` |
386
486
  | `FreestyleSandbox` | `noumen/freestyle` | `freestyle-sandboxes` |
387
487
  | `SshSandbox` | `noumen/ssh` | `ssh2` |
388
488
 
489
+ For the two local backends, shortcut factories bundle `Agent` + sandbox together:
490
+
491
+ | Shortcut | Import | Equivalent to |
492
+ | --- | --- | --- |
493
+ | `LocalAgent` | `noumen/local` | `new Agent({ ..., sandbox: LocalSandbox({ cwd }) })` |
494
+ | `UnsandboxedAgent` | `noumen/unsandboxed` | `new Agent({ ..., sandbox: UnsandboxedLocal({ cwd }) })` |
495
+
496
+ Remote sandboxes stay on the `new Agent({ provider, sandbox })` path — there's no `DockerAgent` shortcut because remote backends carry config (tokens, templates, connection state) that's clearer at the call site.
497
+
389
498
  ### Local — OS-level sandboxing
390
499
 
391
500
  Backed by `@anthropic-ai/sandbox-runtime`. Uses macOS Seatbelt or Linux bubblewrap to restrict filesystem and network access at the OS level — no containers needed:
@@ -395,20 +504,34 @@ pnpm add @anthropic-ai/sandbox-runtime
395
504
  ```
396
505
 
397
506
  ```typescript
398
- import { LocalSandbox } from "noumen";
507
+ import { LocalAgent } from "noumen/local";
399
508
 
400
- const sandbox = LocalSandbox({ cwd: "/my/project" });
509
+ // Shortcut Agent + LocalSandbox in one call:
510
+ const agent = LocalAgent({ provider: "anthropic", cwd: "/my/project" });
401
511
 
402
- // Customize restrictions:
403
- const restricted = LocalSandbox({
512
+ // Customize sandbox restrictions via `localSandbox`:
513
+ const restricted = LocalAgent({
514
+ provider: "anthropic",
404
515
  cwd: "/my/project",
405
- sandbox: {
406
- filesystem: { denyRead: ["/etc/shadow"] },
407
- network: { allowedDomains: ["api.openai.com"] },
516
+ localSandbox: {
517
+ sandbox: {
518
+ filesystem: { denyRead: ["/etc/shadow"] },
519
+ network: { allowedDomains: ["api.openai.com"] },
520
+ },
408
521
  },
409
522
  });
410
523
  ```
411
524
 
525
+ Or drop down to the sandbox factory directly when you need to share the sandbox across multiple agents / presets:
526
+
527
+ ```typescript
528
+ import { Agent } from "noumen";
529
+ import { LocalSandbox } from "noumen/local";
530
+
531
+ const sandbox = LocalSandbox({ cwd: "/my/project" });
532
+ const agent = new Agent({ provider: "anthropic", sandbox });
533
+ ```
534
+
412
535
  Defaults: writes allowed only in `cwd`, reads allowed everywhere, network unrestricted.
413
536
 
414
537
  ### UnsandboxedLocal — no isolation
@@ -416,9 +539,17 @@ Defaults: writes allowed only in `cwd`, reads allowed everywhere, network unrest
416
539
  Backed by `fs/promises` and `child_process` with no OS-level restrictions. Use for development or trusted environments:
417
540
 
418
541
  ```typescript
419
- import { UnsandboxedLocal } from "noumen";
542
+ import { UnsandboxedAgent } from "noumen/unsandboxed";
543
+
544
+ // Shortcut — Agent + UnsandboxedLocal in one call:
545
+ const agent = UnsandboxedAgent({ provider: "anthropic", cwd: "/my/project" });
546
+
547
+ // Or compose manually:
548
+ import { Agent } from "noumen";
549
+ import { UnsandboxedLocal } from "noumen/unsandboxed";
420
550
 
421
551
  const sandbox = UnsandboxedLocal({ cwd: "/my/project" });
552
+ const plain = new Agent({ provider: "anthropic", sandbox });
422
553
  ```
423
554
 
424
555
  ### sprites.dev — full sandbox
@@ -636,8 +767,10 @@ The interfaces are intentionally minimal (one method for shell, eight for filesy
636
767
 
637
768
  ## Options
638
769
 
770
+ Snippets below use `LocalAgent` (`import { LocalAgent } from "noumen/local"`) for brevity. Every option is also valid on `new Agent({ ..., sandbox })` and on the presets (`codingAgent`, `planningAgent`, `reviewAgent`) — the shape is identical, only the sandbox plumbing differs.
771
+
639
772
  ```typescript
640
- const agent = new Agent({
773
+ const agent = LocalAgent({
641
774
  provider: "anthropic",
642
775
  cwd: "/my/project",
643
776
  options: {
@@ -648,9 +781,15 @@ const agent = new Agent({
648
781
  autoCompactThreshold: 100_000, // token threshold for auto-compact
649
782
  systemPrompt: "...", // override the built-in system prompt
650
783
  skills: [{ name: "...", content: "..." }],
651
- skillsPaths: [".claude/skills"], // paths to SKILL.md files on the sandbox filesystem
784
+ skillsPaths: [".claude/skills"], // extra paths to SKILL.md files (adds to auto-discovered .noumen/skills + .claude/skills)
652
785
  projectContext: true, // load NOUMEN.md / CLAUDE.md from project
653
786
 
787
+ // Dot-directory layout (controls where .noumen / .claude state lives).
788
+ // Default: [".noumen", ".claude"]. First name wins for writes; all names
789
+ // are scanned for reads, and every name is protected by the dangerous-path
790
+ // permission check.
791
+ dotDirs: { names: [".noumen", ".claude"] },
792
+
654
793
  // Extended thinking / reasoning (see below)
655
794
  thinking: { type: "enabled", budgetTokens: 10000 },
656
795
 
@@ -770,7 +909,7 @@ Enable model reasoning/thinking for supported providers. Each provider maps the
770
909
  - **Gemini**: Sets `thinkingConfig.thinkingBudget`
771
910
 
772
911
  ```typescript
773
- const agent = new Agent({
912
+ const agent = LocalAgent({
774
913
  provider: "anthropic",
775
914
  cwd: ".",
776
915
  options: {
@@ -795,7 +934,7 @@ Disable explicitly with `{ type: "disabled" }`, or omit the option entirely for
795
934
  Automatic retries with exponential backoff, Retry-After header support, context overflow recovery, and model fallback. Handles 429 (rate limit), 529 (overloaded), 500/502/503 (server errors), and connection failures.
796
935
 
797
936
  ```typescript
798
- const agent = new Agent({
937
+ const agent = LocalAgent({
799
938
  provider: "anthropic",
800
939
  cwd: ".",
801
940
  options: {
@@ -804,7 +943,7 @@ const agent = new Agent({
804
943
  });
805
944
 
806
945
  // Or customize:
807
- const agent2 = new Agent({
946
+ const agent2 = LocalAgent({
808
947
  provider: "anthropic",
809
948
  cwd: ".",
810
949
  options: {
@@ -830,7 +969,7 @@ On context overflow (input + max_tokens > context limit), the engine automatical
830
969
  Track token usage and estimate USD costs across all model calls. Includes built-in pricing for Claude, GPT-4o, Gemini, and o-series models.
831
970
 
832
971
  ```typescript
833
- const agent = new Agent({
972
+ const agent = LocalAgent({
834
973
  provider: "anthropic",
835
974
  cwd: ".",
836
975
  options: {
@@ -856,7 +995,7 @@ console.log(`Output tokens: ${summary.totalOutputTokens}`);
856
995
  Supply custom pricing for unlisted models:
857
996
 
858
997
  ```typescript
859
- const agent = new Agent({
998
+ const agent = LocalAgent({
860
999
  provider: "anthropic",
861
1000
  cwd: ".",
862
1001
  options: {
@@ -875,17 +1014,17 @@ const agent = new Agent({
875
1014
 
876
1015
  ## Skills
877
1016
 
878
- Skills are markdown instructions injected into the system prompt. Provide them inline or load from `SKILL.md` files on the virtual filesystem:
1017
+ Skills are markdown instructions injected into the system prompt. They are auto-discovered from `<cwd>/.noumen/skills/` and `<cwd>/.claude/skills/` (and the same paths under `$HOME`), and can also be provided inline or loaded from explicit paths:
879
1018
 
880
1019
  ```typescript
881
- const agent = new Agent({
1020
+ const agent = LocalAgent({
882
1021
  provider: "anthropic",
883
1022
  cwd: ".",
884
1023
  options: {
885
1024
  skills: [
886
1025
  { name: "Testing", content: "Always write vitest tests for new code." },
887
1026
  ],
888
- skillsPaths: [".claude/skills", "~/.config/skills"],
1027
+ skillsPaths: ["~/.config/skills"], // additive to auto-discovery
889
1028
  },
890
1029
  });
891
1030
 
@@ -893,6 +1032,8 @@ const agent = new Agent({
893
1032
  await agent.init();
894
1033
  ```
895
1034
 
1035
+ Auto-discovery follows the configured `dotDirs` list (default `[".noumen", ".claude"]`). On name collisions, project skills win over home skills, and the **first** dot-dir in the list wins within a scope — so `.noumen/skills/foo` overrides `.claude/skills/foo`. Only `<dot-dir>/skills/<name>/SKILL.md` is discovered; loose `SKILL.md` files at the dot-dir root are ignored.
1036
+
896
1037
  ## Project Context (NOUMEN.md / CLAUDE.md)
897
1038
 
898
1039
  Drop a `NOUMEN.md` or `CLAUDE.md` in your project root to give the agent persistent instructions:
@@ -907,6 +1048,8 @@ Enable it with `projectContext: true` in your `Agent` options. The loader discov
907
1048
 
908
1049
  This is fully compatible with `CLAUDE.md`. If your project already has one, noumen picks it up automatically. Both `NOUMEN.md` and `CLAUDE.md` can coexist in the same directory. The format supports `@path` includes, conditional rules via `paths:` frontmatter in `.noumen/rules/` directories, and hierarchical overriding.
909
1050
 
1051
+ The set of dot-directory names is configurable via `dotDirs` (default `[".noumen", ".claude"]`). The same list drives `NOUMEN.md`/`CLAUDE.md` discovery, auto-discovered skills (under `<dot-dir>/skills/`), CLI config lookup (`<dot-dir>/config.json`), and agent-managed state (sessions, checkpoints, worktrees, OAuth tokens). Writes always go to the **first** name in the list; reads fall back through the rest in order.
1052
+
910
1053
  See **[noumen.dev/docs/context](https://noumen.dev/docs/context)** for full configuration options.
911
1054
 
912
1055
  ## Sessions
@@ -924,7 +1067,7 @@ const sessions = await agent.listSessions();
924
1067
  18 hook events across six categories — intercept tool calls, session lifecycle, permissions, file writes, model switches, compaction, retry, memory, and errors:
925
1068
 
926
1069
  ```typescript
927
- const agent = new Agent({
1070
+ const agent = LocalAgent({
928
1071
  provider: "anthropic", cwd: ".",
929
1072
  options: {
930
1073
  hooks: [
@@ -1007,7 +1150,8 @@ await swarm.waitForAll();
1007
1150
  Persist knowledge across sessions:
1008
1151
 
1009
1152
  ```typescript
1010
- import { FileMemoryProvider, LocalFs } from "noumen";
1153
+ import { FileMemoryProvider } from "noumen";
1154
+ import { LocalFs } from "noumen/local";
1011
1155
 
1012
1156
  options: {
1013
1157
  memory: {
@@ -1,12 +1,10 @@
1
- import { A as Agent } from '../agent-C3eDRsxs.js';
1
+ import { a as Agent } from '../agent-D0gl-qYi.js';
2
2
  import { A as AgentSkill, a as AgentCard, T as TaskSendParams, b as Task, c as TaskStreamEvent } from '../types-NIyVwQ4h.js';
3
3
  export { d as A2A_METHODS, e as Artifact, D as DataPart, F as FilePart, M as Message, P as Part, f as TaskState, g as TaskStatus, h as TextPart } from '../types-NIyVwQ4h.js';
4
- import '../types-LrU4LRmX.js';
5
- import '../sandbox-9qeMTNrD.js';
6
- import '../computer-BPdxSo6X.js';
7
- import '../types-BA87bHPV.js';
8
- import '../types-CD0rUKKT.js';
9
- import '../cache-DsRqxx6v.js';
4
+ import '../types-DLZNyF5t.js';
5
+ import '../sandbox-DAqQo0Tj.js';
6
+ import '../computer-DzMR92tK.js';
7
+ import '../types-BX4ALqoN.js';
10
8
  import '../types-2kTLUCnD.js';
11
9
  import '@modelcontextprotocol/sdk/client/index.js';
12
10
  import '@modelcontextprotocol/sdk/client/auth.js';
package/dist/a2a/index.js CHANGED
@@ -1,6 +1,3 @@
1
- import {
2
- generateUUID
3
- } from "../chunk-3HEYCV26.js";
4
1
  import {
5
2
  INTERNAL_ERROR,
6
3
  INVALID_PARAMS,
@@ -12,8 +9,10 @@ import {
12
9
  isRequest,
13
10
  parseMessage
14
11
  } from "../chunk-AMYIJSAZ.js";
12
+ import {
13
+ generateUUID
14
+ } from "../chunk-3HEYCV26.js";
15
15
  import "../chunk-JACGEMTF.js";
16
- import "../chunk-DGUM43GV.js";
17
16
 
18
17
  // src/a2a/server.ts
19
18
  import { createServer } from "http";