nuabase 2.3.3 → 2.3.5

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 (65) hide show
  1. package/README.md +96 -31
  2. package/dist/cjs/chunks/logger-Co5uZG0A.cjs +90 -0
  3. package/dist/cjs/index.cjs +1510 -1444
  4. package/dist/cjs/local-agent.cjs +886 -0
  5. package/dist/esm/chunks/logger-DnkHzkX_.mjs +88 -0
  6. package/dist/esm/index.mjs +1511 -1445
  7. package/dist/esm/local-agent.mjs +884 -0
  8. package/dist/types/__tests__/helpers/client-factory.d.ts +33 -11
  9. package/dist/types/__tests__/helpers/index.d.ts +2 -1
  10. package/dist/types/backend/direct.d.ts +20 -8
  11. package/dist/types/backend/types.d.ts +9 -4
  12. package/dist/types/index.d.cts +3 -2
  13. package/dist/types/index.d.mts +3 -2
  14. package/dist/types/local-agent.d.cts +2 -0
  15. package/dist/types/local-agent.d.mts +2 -0
  16. package/dist/types/nua-llm-core/index.d.ts +23 -0
  17. package/dist/types/nua-llm-core/lib/error-utils.d.ts +6 -0
  18. package/dist/types/nua-llm-core/lib/logger.d.ts +44 -0
  19. package/dist/types/nua-llm-core/lib/nua-errors.d.ts +12 -0
  20. package/dist/types/nua-llm-core/lib/prompt-template-utils.d.ts +2 -0
  21. package/dist/types/nua-llm-core/lib/schema-utils.d.ts +1 -0
  22. package/dist/types/nua-llm-core/lib/stable-stringify.d.ts +1 -0
  23. package/dist/types/nua-llm-core/lib/strict-json-schema.d.ts +7 -0
  24. package/dist/types/nua-llm-core/lib/types.d.ts +8 -0
  25. package/dist/types/nua-llm-core/lib/validate-mappable-input-data.d.ts +4 -0
  26. package/dist/types/nua-llm-core/local-agent.d.ts +7 -0
  27. package/dist/types/nua-llm-core/modules/agent/agent-loop.d.ts +10 -0
  28. package/dist/types/nua-llm-core/modules/agent/agent-turn.d.ts +17 -0
  29. package/dist/types/nua-llm-core/modules/agent/provider-formatters.d.ts +22 -0
  30. package/dist/types/nua-llm-core/modules/agent/run-agent.d.ts +7 -0
  31. package/dist/types/nua-llm-core/modules/agent/types.d.ts +90 -0
  32. package/dist/types/nua-llm-core/modules/cast/cast-request.d.ts +32 -0
  33. package/dist/types/nua-llm-core/modules/cast/envelope.d.ts +9 -0
  34. package/dist/types/nua-llm-core/modules/cast/list-schema.d.ts +32 -0
  35. package/dist/types/nua-llm-core/modules/cast/prompts/list-prompt.d.ts +3 -0
  36. package/dist/types/nua-llm-core/modules/cast/prompts/render-prompt.d.ts +7 -0
  37. package/dist/types/nua-llm-core/modules/cast/prompts/value-prompt.d.ts +3 -0
  38. package/dist/types/nua-llm-core/modules/cast/run-cast.d.ts +44 -0
  39. package/dist/types/nua-llm-core/modules/engine/engine-router.d.ts +23 -0
  40. package/dist/types/nua-llm-core/modules/engine/http/http-engine.d.ts +12 -0
  41. package/dist/types/nua-llm-core/modules/engine/http/provider-call.d.ts +33 -0
  42. package/dist/types/nua-llm-core/modules/engine/http/provider-config.d.ts +65 -0
  43. package/dist/types/nua-llm-core/modules/engine/http/provider-engines.d.ts +35 -0
  44. package/dist/types/nua-llm-core/modules/engine/llm-engine.d.ts +73 -0
  45. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/claude-code.d.ts +2 -0
  46. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/codex.d.ts +2 -0
  47. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/failure-classification.d.ts +4 -0
  48. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/index.d.ts +3 -0
  49. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/types.d.ts +61 -0
  50. package/dist/types/nua-llm-core/modules/engine/local-agent/agent-id.d.ts +4 -0
  51. package/dist/types/nua-llm-core/modules/engine/local-agent/create-local-agent.d.ts +36 -0
  52. package/dist/types/nua-llm-core/modules/engine/local-agent/detect.d.ts +20 -0
  53. package/dist/types/nua-llm-core/modules/engine/local-agent/local-agent-engine.d.ts +32 -0
  54. package/dist/types/nua-llm-core/modules/engine/local-agent/local-agent.d.ts +25 -0
  55. package/dist/types/nua-llm-core/modules/engine/local-agent/process-runner.d.ts +16 -0
  56. package/dist/types/nua-llm-core/modules/engine/local-agent/semaphore.d.ts +8 -0
  57. package/dist/types/nua-llm-core/modules/execution/llm-response-extraction.d.ts +5 -0
  58. package/dist/types/nua-llm-core/modules/json-schema-validation/ajv-instances.d.ts +12 -0
  59. package/dist/types/nua-llm-core/modules/json-schema-validation/nua-json-schema-value-validation.d.ts +10 -0
  60. package/dist/types/nua-llm-core/modules/json-schema-validation/validate-json-schema.d.ts +2 -0
  61. package/dist/types/nua-llm-core/modules/model-info/index.d.ts +15 -0
  62. package/dist/types/nua-llm-core/modules/streaming/sse-parser.d.ts +7 -0
  63. package/dist/types/nua-llm-core/nua-llm-client.d.ts +37 -0
  64. package/dist/types/nua.d.ts +8 -2
  65. package/package.json +19 -2
package/README.md CHANGED
@@ -146,33 +146,43 @@ Every call returns a discriminated union. When `success` is `false`, you get an
146
146
 
147
147
  **Success**
148
148
 
149
- | Field | Type | Description |
150
- | ----------- | --------------------------------------------------------- | ------------------------------------------------------- |
151
- | `success` | `true` | Indicates that the request completed successfully. |
152
- | `data` | `T` (for `get`) or `Array<{ [pk]: value; [output]: T }>` (for `list`) | The typed result matching your schema. |
153
- | `usage` | `{ promptTokens, completionTokens, totalTokens }` | Token usage statistics for the LLM request. |
154
- | `model` | `string` | The LLM model used for this request. |
155
- | `latencyMs` | `number` | Request latency in milliseconds. |
156
- | `source` | `'gateway'` \| `'direct'` | Which backend processed the request. |
157
- | `meta` | `object` | Additional metadata (varies by source). |
149
+ | Field | Type | Description |
150
+ | ----------- | --------------------------------------------------------------------- | -------------------------------------------------- |
151
+ | `success` | `true` | Indicates that the request completed successfully. |
152
+ | `data` | `T` (for `get`) or `Array<{ [pk]: value; [output]: T }>` (for `list`) | The typed result matching your schema. |
153
+ | `usage` | `{ promptTokens, completionTokens, totalTokens }` | Token usage statistics for the LLM request. |
154
+ | `model` | `string` | The LLM model used for this request. |
155
+ | `latencyMs` | `number` | Request latency in milliseconds. |
156
+ | `source` | `'gateway'` \| `'direct'` | Which backend processed the request. |
157
+ | `meta` | `object` | Additional metadata (varies by source). |
158
158
 
159
159
  **Gateway-specific metadata** (`meta` when `source` is `'gateway'`):
160
160
 
161
- | Field | Type | Description |
162
- | ------------ | --------- | ---------------------------------------------- |
163
- | `requestId` | `string` | Unique identifier for tracing. |
164
- | `cached` | `boolean` | Whether the result was served from cache. |
165
- | `llmUsage` | `object` | Token usage from LLM calls. |
166
- | `cacheUsage` | `object` | Token usage served from cache. |
161
+ | Field | Type | Description |
162
+ | ------------ | --------- | ----------------------------------------- |
163
+ | `requestId` | `string` | Unique identifier for tracing. |
164
+ | `cached` | `boolean` | Whether the result was served from cache. |
165
+ | `llmUsage` | `object` | Token usage from LLM calls. |
166
+ | `cacheUsage` | `object` | Token usage served from cache. |
167
+
168
+ **Direct-specific metadata** (`meta` when `source` is `'direct'`):
169
+
170
+ | Field | Type | Description |
171
+ | ------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------- |
172
+ | `engine` | `'http'` \| `'local-agent'` | Whether an LLM provider's API or a coding agent on this machine answered. |
173
+ | `schemaEnforcement` | `'in-prompt'` \| `'native'` | Whether the schema was described in the prompt or enforced by the engine. Output is validated either way. |
174
+ | `provider` | `string` | `engine: 'http'` only. The LLM provider. |
175
+ | `agent` | `'claude-code'` \| `'codex'` | `engine: 'local-agent'` only. Which coding agent answered. |
176
+ | `costUsdEstimate` | `number \| undefined` | `engine: 'local-agent'` only. The agent's own estimate. On a subscription this is not what you pay. |
167
177
 
168
178
  **Error**
169
179
 
170
- | Field | Type | Description |
171
- | ----------- | ----------------------------- | -------------------------------------------------------- |
172
- | `success` | `false` | Indicates the request failed. |
173
- | `error` | `string` | Message describing the error. |
174
- | `source` | `'gateway'` \| `'direct'` | Which backend returned the error. |
175
- | `latencyMs` | `number` | Time until failure in milliseconds. |
180
+ | Field | Type | Description |
181
+ | ----------- | ------------------------- | ----------------------------------- |
182
+ | `success` | `false` | Indicates the request failed. |
183
+ | `error` | `string` | Message describing the error. |
184
+ | `source` | `'gateway'` \| `'direct'` | Which backend returned the error. |
185
+ | `latencyMs` | `number` | Time until failure in milliseconds. |
176
186
 
177
187
  ## SDK API
178
188
 
@@ -185,10 +195,65 @@ Creates a client that connects to the Nuabase API gateway. Use this for producti
185
195
  - `baseUrl?: string` – Override the API host. Defaults to `https://api.nuabase.com`.
186
196
 
187
197
  **`Nua.direct(config)`**
188
- Creates a client that calls LLM providers directly (in-process). Use this for serverless, edge functions, or CLI tools where you don't need the gateway infrastructure.
198
+ Creates a client that runs casts in this process instead of through the gateway. Use this for serverless, edge functions, or CLI tools where you don't need the gateway infrastructure. It runs on one of two kinds of engine, chosen by the config.
199
+
200
+ With API keys for LLM providers:
201
+
202
+ - `providers: { groq?: { apiKey: string }, cerebras?: { apiKey: string }, gemini?: { apiKey: string }, openrouter?: { apiKey: string } }` – Provider credentials.
203
+ - `model?: ModelInput` – Optional default model. Omit it to use `{ alias: 'fast' }`.
204
+
205
+ Model inputs are objects, not provider-prefixed strings:
206
+
207
+ ```ts
208
+ await nua.get('Extract the company name', {
209
+ output: { name: 'companyName', schema: z.string() },
210
+ model: { provider: 'openrouter', model: 'z-ai/glm-5.2' },
211
+ });
212
+
213
+ await nua.get('Extract the company name', {
214
+ output: { name: 'companyName', schema: z.string() },
215
+ model: { alias: 'fast' },
216
+ });
217
+ ```
218
+
219
+ With a coding agent on this machine (Node.js only):
220
+
221
+ - `localAgent: LocalAgent` – Created with `localAgent()` or `findLocalAgent()` from `nuabase/local-agent`.
222
+
223
+ ```ts
224
+ import { Nua } from 'nuabase';
225
+ import { detectLocalAgents, findLocalAgent, localAgent } from 'nuabase/local-agent';
226
+
227
+ const nua = Nua.direct({ localAgent: localAgent({ agent: 'claude-code', model: 'haiku' }) });
228
+
229
+ // Or use the first agent that is installed and logged in:
230
+ const auto = Nua.direct({ localAgent: await findLocalAgent() });
231
+
232
+ const agents = await detectLocalAgents();
233
+ // [{ agent: 'claude-code', installed: true, loggedIn: true, version: '...', binaryPath: '...' }, ...]
234
+ ```
235
+
236
+ This runs a coding-agent CLI already installed and logged in on this machine, in its headless mode (`claude -p` or `codex exec`). Calls use the user's own Claude or ChatGPT subscription, so no API key is needed. `get()` and `list()` behave as with providers: the output is validated against your schema and typed the same way. Queue operations are not supported. `nuabase/local-agent` is a separate entry point so that browser bundles of `nuabase` never include it.
237
+
238
+ The agent is set up once, when you create it. If you install an agent or log in after that, create a new one.
239
+
240
+ **`localAgent(config)`** sets up a named agent. It throws right away if the agent's executable cannot be found; if the agent is not logged in, the first call fails with that error.
241
+
242
+ - `agent: 'claude-code' | 'codex'`
243
+ - `binaryPath?: string` – Path to the agent executable. Defaults to looking it up on `PATH`. On Windows, point this at a native executable; `.cmd` shims are not supported.
244
+ - and the options below.
245
+
246
+ **`findLocalAgent(options?)`** returns a promise of the first agent that is installed and logged in, trying Claude Code first. It rejects when there is none. Checking runs each CLI's version and login-status commands, which make no model calls.
247
+
248
+ Options for both:
249
+
250
+ - `model?: string` – The agent's own model name, e.g. `'haiku'` for Claude Code, for calls that name no model. Defaults to the agent's default. Per-call `model: { alias }` works for aliases the agent understands (`haiku`, `sonnet`, `opus` for Claude Code).
251
+ - `timeoutMs?: number` – Per-call limit. Defaults to `180000`.
252
+ - `concurrency?: number` – Maximum agent processes at once. Defaults to `2`.
253
+ - `auth?: 'subscription' | 'inherit'` – `subscription` (default) hides `ANTHROPIC_API_KEY`, `OPENAI_API_KEY` and similar variables from the agent so it bills the logged-in plan rather than an API key.
254
+ - `logger?` – An object with `debug`, `info`, `warn` and `error` methods, where calls and retries are logged. Defaults to the console.
189
255
 
190
- - `model: string` – The model to use (e.g., `'gpt-4o-mini'`).
191
- - `providers: { openai?: { apiKey: string }, ... }` – Provider credentials.
256
+ How it works: each call runs the agent in a fresh, empty temporary directory with its tools, project settings and MCP servers turned off. The schema is wrapped as `{ value: ... }` (the agents require an object at the top level) and passed to the agent's own schema option. Codex only accepts OpenAI strict-mode schemas, so a schema with optional properties or open-ended objects is instead described in the prompt, and the output is validated as usual. If an agent rejects a schema, the call is retried with the schema in the prompt. `maxTokens` has no CLI equivalent and is ignored. Calls count against the user's plan limits; check each vendor's terms before offering this to other users.
192
257
 
193
258
  ### Methods
194
259
 
@@ -196,7 +261,7 @@ Creates a client that calls LLM providers directly (in-process). Use this for se
196
261
  Returns a simple string response from the LLM.
197
262
 
198
263
  ```ts
199
- const result = await nua.get("Tell me a joke");
264
+ const result = await nua.get('Tell me a joke');
200
265
  if (result.success) console.log(result.data); // string
201
266
  ```
202
267
 
@@ -208,8 +273,8 @@ Returns a typed single value. Parameters:
208
273
  - `options.output: { name: string; schema: ZodSchema }` – Output name and Zod schema.
209
274
 
210
275
  ```ts
211
- const result = await nua.get("Extract the address", {
212
- input: "123 Main St, Springfield, IL 62701",
276
+ const result = await nua.get('Extract the address', {
277
+ input: '123 Main St, Springfield, IL 62701',
213
278
  output: { name: 'address', schema: AddressSchema },
214
279
  });
215
280
  if (result.success) console.log(result.data); // typed as z.infer<typeof AddressSchema>
@@ -224,20 +289,20 @@ Processes an array of items. Parameters:
224
289
  - `options.output: { name: string; schema: ZodSchema }` – Output configuration.
225
290
 
226
291
  ```ts
227
- const result = await nua.list("Classify each lead", {
292
+ const result = await nua.list('Classify each lead', {
228
293
  input: leads,
229
294
  primaryKey: 'id',
230
295
  output: { name: 'classification', schema: ClassificationSchema },
231
296
  });
232
297
  if (result.success) {
233
- result.data.forEach(row => console.log(row.id, row.classification));
298
+ result.data.forEach((row) => console.log(row.id, row.classification));
234
299
  }
235
300
  ```
236
301
 
237
- **`nua.queueGet(prompt, options?)`** *(Gateway mode only)*
302
+ **`nua.queueGet(prompt, options?)`** _(Gateway mode only)_
238
303
  Submits an async job for single-value operations. Returns `{ success: true, jobId }`.
239
304
 
240
- **`nua.queueList(prompt, options)`** *(Gateway mode only)*
305
+ **`nua.queueList(prompt, options)`** _(Gateway mode only)_
241
306
  Submits an async job for array operations. Returns `{ success: true, jobId }`.
242
307
 
243
308
  ## Next Steps
@@ -0,0 +1,90 @@
1
+ 'use strict';
2
+
3
+ var logger = {};
4
+
5
+ var hasRequiredLogger;
6
+ function requireLogger() {
7
+ if (hasRequiredLogger) return logger;
8
+ hasRequiredLogger = 1;
9
+ Object.defineProperty(logger, "__esModule", { value: true });
10
+ logger.logLlmCallError = logger.logLlmCallComplete = logger.logLlmCallStart = logger.generateSpanId = logger.ConsoleLogger = void 0;
11
+ logger.pickHeaders = pickHeaders;
12
+ logger.normalizeError = normalizeError;
13
+ class ConsoleLogger {
14
+ debug(message, context) {
15
+ console.debug(`[DEBUG] ${message}`, context || "");
16
+ }
17
+ info(message, context) {
18
+ console.info(`[INFO] ${message}`, context || "");
19
+ }
20
+ warn(message, context) {
21
+ console.warn(`[WARN] ${message}`, context || "");
22
+ }
23
+ error(message, context) {
24
+ console.error(`[ERROR] ${message}`, context || "");
25
+ }
26
+ }
27
+ logger.ConsoleLogger = ConsoleLogger;
28
+ const generateSpanId = () => crypto.randomUUID();
29
+ logger.generateSpanId = generateSpanId;
30
+ function pickHeaders(headers, allowlist, redactSet) {
31
+ const result = {};
32
+ for (const [key, value] of Object.entries(headers)) {
33
+ const lowerKey = key.toLowerCase();
34
+ if (redactSet?.has(lowerKey)) {
35
+ result[key] = "[REDACTED]";
36
+ } else if (allowlist.has(lowerKey)) {
37
+ result[key] = Array.isArray(value) ? value.join(", ") : value ?? "";
38
+ }
39
+ }
40
+ return result;
41
+ }
42
+ function normalizeError(error) {
43
+ return error instanceof Error ? { message: error.message, stack: error.stack } : String(error);
44
+ }
45
+ const LLM_RESPONSE_HEADER_ALLOWLIST = /* @__PURE__ */ new Set([
46
+ "x-request-id",
47
+ "x-ratelimit-limit-requests",
48
+ "x-ratelimit-limit-tokens",
49
+ "x-ratelimit-remaining-requests",
50
+ "x-ratelimit-remaining-tokens",
51
+ "x-groq-region"
52
+ ]);
53
+ const logLlmCallStart = (logger2, spanId, service, method, request) => {
54
+ logger2.info("LLM call started", {
55
+ type: "llm_call_start",
56
+ span_id: spanId,
57
+ service,
58
+ method,
59
+ ...request
60
+ });
61
+ };
62
+ logger.logLlmCallStart = logLlmCallStart;
63
+ const logLlmCallComplete = (logger2, spanId, service, method, response, duration) => {
64
+ const { headers, ...rest } = response;
65
+ logger2.info("LLM call completed", {
66
+ type: "llm_call_complete",
67
+ span_id: spanId,
68
+ service,
69
+ method,
70
+ ...rest,
71
+ ...pickHeaders(headers, LLM_RESPONSE_HEADER_ALLOWLIST),
72
+ duration_ms: duration
73
+ });
74
+ };
75
+ logger.logLlmCallComplete = logLlmCallComplete;
76
+ const logLlmCallError = (logger2, spanId, service, method, error, duration) => {
77
+ logger2.error("LLM call failed", {
78
+ type: "llm_call_error",
79
+ span_id: spanId,
80
+ service,
81
+ method,
82
+ error: normalizeError(error),
83
+ duration_ms: duration
84
+ });
85
+ };
86
+ logger.logLlmCallError = logLlmCallError;
87
+ return logger;
88
+ }
89
+
90
+ exports.requireLogger = requireLogger;