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.
- package/README.md +96 -31
- package/dist/cjs/chunks/logger-Co5uZG0A.cjs +90 -0
- package/dist/cjs/index.cjs +1510 -1444
- package/dist/cjs/local-agent.cjs +886 -0
- package/dist/esm/chunks/logger-DnkHzkX_.mjs +88 -0
- package/dist/esm/index.mjs +1511 -1445
- package/dist/esm/local-agent.mjs +884 -0
- package/dist/types/__tests__/helpers/client-factory.d.ts +33 -11
- package/dist/types/__tests__/helpers/index.d.ts +2 -1
- package/dist/types/backend/direct.d.ts +20 -8
- package/dist/types/backend/types.d.ts +9 -4
- package/dist/types/index.d.cts +3 -2
- package/dist/types/index.d.mts +3 -2
- package/dist/types/local-agent.d.cts +2 -0
- package/dist/types/local-agent.d.mts +2 -0
- package/dist/types/nua-llm-core/index.d.ts +23 -0
- package/dist/types/nua-llm-core/lib/error-utils.d.ts +6 -0
- package/dist/types/nua-llm-core/lib/logger.d.ts +44 -0
- package/dist/types/nua-llm-core/lib/nua-errors.d.ts +12 -0
- package/dist/types/nua-llm-core/lib/prompt-template-utils.d.ts +2 -0
- package/dist/types/nua-llm-core/lib/schema-utils.d.ts +1 -0
- package/dist/types/nua-llm-core/lib/stable-stringify.d.ts +1 -0
- package/dist/types/nua-llm-core/lib/strict-json-schema.d.ts +7 -0
- package/dist/types/nua-llm-core/lib/types.d.ts +8 -0
- package/dist/types/nua-llm-core/lib/validate-mappable-input-data.d.ts +4 -0
- package/dist/types/nua-llm-core/local-agent.d.ts +7 -0
- package/dist/types/nua-llm-core/modules/agent/agent-loop.d.ts +10 -0
- package/dist/types/nua-llm-core/modules/agent/agent-turn.d.ts +17 -0
- package/dist/types/nua-llm-core/modules/agent/provider-formatters.d.ts +22 -0
- package/dist/types/nua-llm-core/modules/agent/run-agent.d.ts +7 -0
- package/dist/types/nua-llm-core/modules/agent/types.d.ts +90 -0
- package/dist/types/nua-llm-core/modules/cast/cast-request.d.ts +32 -0
- package/dist/types/nua-llm-core/modules/cast/envelope.d.ts +9 -0
- package/dist/types/nua-llm-core/modules/cast/list-schema.d.ts +32 -0
- package/dist/types/nua-llm-core/modules/cast/prompts/list-prompt.d.ts +3 -0
- package/dist/types/nua-llm-core/modules/cast/prompts/render-prompt.d.ts +7 -0
- package/dist/types/nua-llm-core/modules/cast/prompts/value-prompt.d.ts +3 -0
- package/dist/types/nua-llm-core/modules/cast/run-cast.d.ts +44 -0
- package/dist/types/nua-llm-core/modules/engine/engine-router.d.ts +23 -0
- package/dist/types/nua-llm-core/modules/engine/http/http-engine.d.ts +12 -0
- package/dist/types/nua-llm-core/modules/engine/http/provider-call.d.ts +33 -0
- package/dist/types/nua-llm-core/modules/engine/http/provider-config.d.ts +65 -0
- package/dist/types/nua-llm-core/modules/engine/http/provider-engines.d.ts +35 -0
- package/dist/types/nua-llm-core/modules/engine/llm-engine.d.ts +73 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/claude-code.d.ts +2 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/codex.d.ts +2 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/failure-classification.d.ts +4 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/index.d.ts +3 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/types.d.ts +61 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/agent-id.d.ts +4 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/create-local-agent.d.ts +36 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/detect.d.ts +20 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/local-agent-engine.d.ts +32 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/local-agent.d.ts +25 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/process-runner.d.ts +16 -0
- package/dist/types/nua-llm-core/modules/engine/local-agent/semaphore.d.ts +8 -0
- package/dist/types/nua-llm-core/modules/execution/llm-response-extraction.d.ts +5 -0
- package/dist/types/nua-llm-core/modules/json-schema-validation/ajv-instances.d.ts +12 -0
- package/dist/types/nua-llm-core/modules/json-schema-validation/nua-json-schema-value-validation.d.ts +10 -0
- package/dist/types/nua-llm-core/modules/json-schema-validation/validate-json-schema.d.ts +2 -0
- package/dist/types/nua-llm-core/modules/model-info/index.d.ts +15 -0
- package/dist/types/nua-llm-core/modules/streaming/sse-parser.d.ts +7 -0
- package/dist/types/nua-llm-core/nua-llm-client.d.ts +37 -0
- package/dist/types/nua.d.ts +8 -2
- 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
|
|
150
|
-
| ----------- |
|
|
151
|
-
| `success` | `true`
|
|
152
|
-
| `data` | `T` (for `get`) or `Array<{ [pk]: value; [output]: T }>` (for `list`) | The typed result matching your schema.
|
|
153
|
-
| `usage` | `{ promptTokens, completionTokens, totalTokens }`
|
|
154
|
-
| `model` | `string`
|
|
155
|
-
| `latencyMs` | `number`
|
|
156
|
-
| `source` | `'gateway'` \| `'direct'`
|
|
157
|
-
| `meta` | `object`
|
|
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
|
|
171
|
-
| ----------- |
|
|
172
|
-
| `success` | `false`
|
|
173
|
-
| `error` | `string`
|
|
174
|
-
| `source` | `'gateway'` \| `'direct'`
|
|
175
|
-
| `latencyMs` | `number`
|
|
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
|
|
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
|
-
|
|
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(
|
|
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(
|
|
212
|
-
input:
|
|
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(
|
|
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?)`**
|
|
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)`**
|
|
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;
|