nuabase 2.3.11 → 3.0.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 (80) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +233 -200
  3. package/dist/chunks/local-agent-Bj-QKikS.d.cts +270 -0
  4. package/dist/chunks/local-agent-Bj-QKikS.d.mts +270 -0
  5. package/dist/cjs/chunks/strict-json-schema-bKwaMWm1.cjs +145 -0
  6. package/dist/cjs/index.cjs +989 -11504
  7. package/dist/cjs/local-agent.cjs +819 -877
  8. package/dist/esm/chunks/strict-json-schema-Du2LLrVP.mjs +138 -0
  9. package/dist/esm/index.mjs +987 -11502
  10. package/dist/esm/local-agent.mjs +792 -878
  11. package/dist/index.d.cts +94 -0
  12. package/dist/index.d.mts +94 -0
  13. package/dist/local-agent.d.cts +150 -0
  14. package/dist/local-agent.d.mts +150 -0
  15. package/package.json +12 -17
  16. package/dist/cjs/chunks/strict-json-schema-DUE7RTxG.cjs +0 -177
  17. package/dist/esm/chunks/strict-json-schema-DI9qiH5h.mjs +0 -174
  18. package/dist/types/__tests__/helpers/client-factory.d.ts +0 -39
  19. package/dist/types/__tests__/helpers/index.d.ts +0 -2
  20. package/dist/types/backend/direct.d.ts +0 -29
  21. package/dist/types/backend/gateway.d.ts +0 -24
  22. package/dist/types/backend/types.d.ts +0 -68
  23. package/dist/types/index.d.cts +0 -7
  24. package/dist/types/index.d.mts +0 -7
  25. package/dist/types/lib/auth.d.ts +0 -14
  26. package/dist/types/lib/env.d.ts +0 -1
  27. package/dist/types/lib/error-response.d.ts +0 -6
  28. package/dist/types/lib/error-utils.d.ts +0 -6
  29. package/dist/types/local-agent.d.cts +0 -2
  30. package/dist/types/local-agent.d.mts +0 -2
  31. package/dist/types/nua-llm-core/index.d.ts +0 -23
  32. package/dist/types/nua-llm-core/lib/error-utils.d.ts +0 -6
  33. package/dist/types/nua-llm-core/lib/logger.d.ts +0 -44
  34. package/dist/types/nua-llm-core/lib/nua-errors.d.ts +0 -12
  35. package/dist/types/nua-llm-core/lib/prompt-template-utils.d.ts +0 -2
  36. package/dist/types/nua-llm-core/lib/schema-utils.d.ts +0 -1
  37. package/dist/types/nua-llm-core/lib/stable-stringify.d.ts +0 -1
  38. package/dist/types/nua-llm-core/lib/strict-json-schema.d.ts +0 -7
  39. package/dist/types/nua-llm-core/lib/types.d.ts +0 -8
  40. package/dist/types/nua-llm-core/lib/validate-mappable-input-data.d.ts +0 -4
  41. package/dist/types/nua-llm-core/local-agent.d.ts +0 -7
  42. package/dist/types/nua-llm-core/modules/agent/agent-loop.d.ts +0 -10
  43. package/dist/types/nua-llm-core/modules/agent/agent-turn.d.ts +0 -17
  44. package/dist/types/nua-llm-core/modules/agent/provider-formatters.d.ts +0 -22
  45. package/dist/types/nua-llm-core/modules/agent/run-agent.d.ts +0 -7
  46. package/dist/types/nua-llm-core/modules/agent/types.d.ts +0 -90
  47. package/dist/types/nua-llm-core/modules/cast/cast-request.d.ts +0 -32
  48. package/dist/types/nua-llm-core/modules/cast/envelope.d.ts +0 -9
  49. package/dist/types/nua-llm-core/modules/cast/list-schema.d.ts +0 -32
  50. package/dist/types/nua-llm-core/modules/cast/prompts/list-prompt.d.ts +0 -3
  51. package/dist/types/nua-llm-core/modules/cast/prompts/render-prompt.d.ts +0 -7
  52. package/dist/types/nua-llm-core/modules/cast/prompts/value-prompt.d.ts +0 -3
  53. package/dist/types/nua-llm-core/modules/cast/run-cast.d.ts +0 -44
  54. package/dist/types/nua-llm-core/modules/engine/engine-router.d.ts +0 -23
  55. package/dist/types/nua-llm-core/modules/engine/http/http-engine.d.ts +0 -13
  56. package/dist/types/nua-llm-core/modules/engine/http/provider-call.d.ts +0 -33
  57. package/dist/types/nua-llm-core/modules/engine/http/provider-config.d.ts +0 -70
  58. package/dist/types/nua-llm-core/modules/engine/http/provider-engines.d.ts +0 -35
  59. package/dist/types/nua-llm-core/modules/engine/llm-engine.d.ts +0 -73
  60. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/claude-code.d.ts +0 -2
  61. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/codex.d.ts +0 -2
  62. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/failure-classification.d.ts +0 -4
  63. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/index.d.ts +0 -3
  64. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/pi.d.ts +0 -2
  65. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/types.d.ts +0 -61
  66. package/dist/types/nua-llm-core/modules/engine/local-agent/agent-id.d.ts +0 -4
  67. package/dist/types/nua-llm-core/modules/engine/local-agent/create-local-agent.d.ts +0 -36
  68. package/dist/types/nua-llm-core/modules/engine/local-agent/detect.d.ts +0 -20
  69. package/dist/types/nua-llm-core/modules/engine/local-agent/local-agent-engine.d.ts +0 -32
  70. package/dist/types/nua-llm-core/modules/engine/local-agent/local-agent.d.ts +0 -25
  71. package/dist/types/nua-llm-core/modules/engine/local-agent/process-runner.d.ts +0 -16
  72. package/dist/types/nua-llm-core/modules/engine/local-agent/semaphore.d.ts +0 -8
  73. package/dist/types/nua-llm-core/modules/execution/llm-response-extraction.d.ts +0 -5
  74. package/dist/types/nua-llm-core/modules/json-schema-validation/ajv-instances.d.ts +0 -12
  75. package/dist/types/nua-llm-core/modules/json-schema-validation/nua-json-schema-value-validation.d.ts +0 -10
  76. package/dist/types/nua-llm-core/modules/json-schema-validation/validate-json-schema.d.ts +0 -2
  77. package/dist/types/nua-llm-core/modules/model-info/index.d.ts +0 -15
  78. package/dist/types/nua-llm-core/modules/streaming/sse-parser.d.ts +0 -7
  79. package/dist/types/nua-llm-core/nua-llm-client.d.ts +0 -37
  80. package/dist/types/nua.d.ts +0 -42
@@ -0,0 +1,270 @@
1
+ type NormalizedUsage = {
2
+ /** All prompt tokens, including any the provider read from or wrote to its prompt cache. */
3
+ promptTokens: number;
4
+ completionTokens: number;
5
+ totalTokens: number;
6
+ /** Prompt tokens the provider read from its prompt cache, billed at a discount. Undefined when not reported. */
7
+ promptCacheReadTokens?: number;
8
+ /** Prompt tokens the provider wrote to its prompt cache (Claude bills these at a premium). Undefined when not reported. */
9
+ promptCacheWriteTokens?: number;
10
+ };
11
+
12
+ interface Logger {
13
+ debug(message: string, context?: object): void;
14
+ info(message: string, context?: object): void;
15
+ warn(message: string, context?: object): void;
16
+ error(message: string, context?: object): void;
17
+ }
18
+
19
+ type JsonSchema = Record<string, unknown>;
20
+
21
+ declare const LLM_PROVIDER_IDS: readonly ["groq", "cerebras", "gemini", "openrouter", "deepseek"];
22
+ type LlmProviderId = (typeof LLM_PROVIDER_IDS)[number];
23
+
24
+ /** Supported coding-agent CLIs, in the order findLocalAgent() tries them. */
25
+ declare const LOCAL_AGENT_IDS: readonly ["claude-code", "codex", "pi"];
26
+ type LocalAgentId = (typeof LOCAL_AGENT_IDS)[number];
27
+ declare function isLocalAgentId(value: unknown): value is LocalAgentId;
28
+
29
+ /**
30
+ * How one attempt makes the model produce the output shape.
31
+ * - in-prompt: the prompt describes the schema; the reply is free text that should contain the JSON.
32
+ * - native: the engine enforces `schema` itself. It is the output schema wrapped in an
33
+ * envelope (see cast/envelope), already converted to the engine's own dialect.
34
+ */
35
+ type SchemaEnforcement = {
36
+ kind: "in-prompt";
37
+ } | {
38
+ kind: "native";
39
+ schema: JsonSchema;
40
+ };
41
+ type SchemaEnforcementKind = SchemaEnforcement["kind"];
42
+ /** One prompt for an engine to answer once, on the model the engine was created for. */
43
+ type AttemptRequest = {
44
+ prompt: string;
45
+ /** The start of `prompt` that repeats across calls of the same cast. Engines may cache it. */
46
+ reusablePrefix: string;
47
+ maxTokens: number;
48
+ enforcement: SchemaEnforcement;
49
+ };
50
+ type Answer =
51
+ /** A free-text reply that should contain the JSON result. */
52
+ {
53
+ kind: "text";
54
+ text: string;
55
+ }
56
+ /** The envelope object the engine enforced natively. */
57
+ | {
58
+ kind: "structured";
59
+ envelope: unknown;
60
+ };
61
+ /** Which engine produced an answer. */
62
+ type AnswerOrigin = {
63
+ engine: "http";
64
+ provider: LlmProviderId;
65
+ model: string;
66
+ } | {
67
+ engine: "local-agent";
68
+ agent: LocalAgentId;
69
+ /** The model the agent reports using, else the one requested; undefined when neither is known. */
70
+ model: string | undefined;
71
+ /** The agent's own estimate. On a subscription this is not what the user pays. */
72
+ costUsdEstimate: number | undefined;
73
+ };
74
+ type AttemptFailure = {
75
+ /**
76
+ * - transient: another attempt may succeed.
77
+ * - fatal: every attempt will fail the same way (bad API key, not logged in, out of quota, timed out).
78
+ * - schema-rejected: the engine refused the native schema; the in-prompt prompt may still work.
79
+ */
80
+ kind: "transient" | "fatal" | "schema-rejected";
81
+ message: string;
82
+ };
83
+ type AttemptOutcome = {
84
+ kind: "answered";
85
+ answer: Answer;
86
+ usage: NormalizedUsage;
87
+ origin: AnswerOrigin;
88
+ } | {
89
+ kind: "failed";
90
+ failure: AttemptFailure;
91
+ };
92
+ /**
93
+ * Answers prompts on one model: an LLM provider's HTTP API, or a coding-agent
94
+ * CLI on this machine. Expected failures come back as outcomes, not exceptions.
95
+ */
96
+ interface LlmEngine {
97
+ /** The envelope schema in the form this engine enforces natively, or null if it cannot. */
98
+ nativeSchema(envelopeSchema: JsonSchema): JsonSchema | null;
99
+ attempt(request: AttemptRequest): Promise<AttemptOutcome>;
100
+ }
101
+
102
+ type ProviderModel = {
103
+ provider: LlmProviderId;
104
+ model: string;
105
+ };
106
+ type ModelAliasName = "fast" | "gemini" | "qwen" | "sonnet" | "opus" | "haiku" | "kimi" | "deepseek" | "gpt";
107
+ type ModelInput = ProviderModel | {
108
+ alias: ModelAliasName;
109
+ };
110
+
111
+ /** The engine that runs a model choice, or why none can. */
112
+ type Route = {
113
+ kind: "routed";
114
+ engine: LlmEngine;
115
+ } | {
116
+ kind: "unroutable";
117
+ message: string;
118
+ };
119
+ /**
120
+ * Where a client's calls run. Every setup answers the same question: for this
121
+ * model choice, which engine runs it? Created by providerEngines() for LLM
122
+ * providers' APIs, or by localAgent() / findLocalAgent() in the Node-only
123
+ * "nua-llm-core/local-agent" entry point for a coding-agent CLI.
124
+ */
125
+ interface EngineRouter {
126
+ /** Where the engines log their calls. Casts log their retries here too. */
127
+ readonly logger: Logger;
128
+ /** `model` undefined means this router's default model. */
129
+ route(model: ModelInput | undefined): Route;
130
+ }
131
+
132
+ /** A process to run inside a fresh, empty working directory. */
133
+ type AgentInvocation = {
134
+ args: string[];
135
+ stdin: string;
136
+ /** Files written into the working directory before the process starts. */
137
+ files?: {
138
+ name: string;
139
+ content: string;
140
+ }[];
141
+ /** Files read back from the working directory after the process exits. */
142
+ outputFiles?: string[];
143
+ };
144
+ type AgentProcessResult = {
145
+ exitCode: number | null;
146
+ stdout: string;
147
+ stderr: string;
148
+ timedOut: boolean;
149
+ /** Contents of the requested output files; undefined when a file was not written. */
150
+ outputFiles: Record<string, string | undefined>;
151
+ };
152
+ /** What an agent's output says about one attempt. */
153
+ type AgentReply = {
154
+ kind: "answered";
155
+ answer: Answer;
156
+ usage: NormalizedUsage;
157
+ /** The model the agent reports having used, when it says. */
158
+ model: string | undefined;
159
+ costUsdEstimate: number | undefined;
160
+ } | {
161
+ kind: "failed";
162
+ failure: AttemptFailure;
163
+ };
164
+ /**
165
+ * How hard the agent's model thinks before it answers: the CLI's own reasoning
166
+ * or effort setting, at one of the levels every supported CLI has.
167
+ */
168
+ type AgentEffort = "low" | "medium" | "high";
169
+ /** How one cast runs on an agent. An undefined field leaves it to the CLI's default. */
170
+ type AgentCallOptions = {
171
+ /** The CLI's own model name. */
172
+ model?: string;
173
+ effort?: AgentEffort;
174
+ };
175
+ /**
176
+ * Who approves an interactive session's edits and commands:
177
+ * - ask: the user, step by step, as the CLI does by default.
178
+ * - auto: the CLI's own auto mode. Its reviewer approves routine steps and stops risky ones.
179
+ */
180
+ type SessionApproval = "ask" | "auto";
181
+ type AgentLoginStatus = {
182
+ loggedIn: boolean;
183
+ detail?: string;
184
+ };
185
+ /**
186
+ * Knows one coding-agent CLI: which models it offers, how to invoke it headless,
187
+ * and how to read its output. Adapters do no I/O; the process runner does the spawning.
188
+ */
189
+ interface AgentAdapter {
190
+ id: LocalAgentId;
191
+ /** Executable name looked up on PATH. */
192
+ binaryName: string;
193
+ /** Env vars that would make the CLI bill an API key instead of the user's subscription. */
194
+ apiKeyEnvVars: string[];
195
+ /** The CLI's own model name for each model alias it has an equivalent for. */
196
+ modelAliases: Partial<Record<ModelAliasName, string>>;
197
+ /** The envelope schema in the form this CLI accepts, or null if it can't enforce it. */
198
+ nativeSchema(envelopeSchema: JsonSchema): JsonSchema | null;
199
+ buildInvocation(request: AttemptRequest, options: AgentCallOptions): AgentInvocation;
200
+ readResult(result: AgentProcessResult, request: AttemptRequest): AgentReply;
201
+ loginStatusArgs: string[];
202
+ readLoginStatus(result: AgentProcessResult): AgentLoginStatus;
203
+ /**
204
+ * Options for an interactive session in the user's own project, which go
205
+ * before its first message. `model` is the CLI's own model name; undefined
206
+ * uses the CLI's default.
207
+ */
208
+ sessionArgs(model: string | undefined, approval: SessionApproval): string[];
209
+ }
210
+
211
+ /** Runs at most `limit` tasks at once; the rest wait in order. */
212
+ declare class Semaphore {
213
+ private readonly limit;
214
+ private active;
215
+ private readonly waiting;
216
+ constructor(limit: number);
217
+ run<T>(task: () => Promise<T>): Promise<T>;
218
+ }
219
+
220
+ /** How to run one installed agent's processes. Set up once and shared by all its engines. */
221
+ type AgentRunner = {
222
+ adapter: AgentAdapter;
223
+ binaryPath: string;
224
+ /** Env vars removed from the agent's environment. */
225
+ unsetEnv: string[];
226
+ /** Bounds how many agent processes run at once, across all models. */
227
+ limiter: Semaphore;
228
+ logger: Logger;
229
+ };
230
+ /** How one engine's attempts run: the CLI's options and how long each may take. */
231
+ type AgentCall = AgentCallOptions & {
232
+ /** Per-attempt limit. */
233
+ timeoutMs: number;
234
+ };
235
+
236
+ /** What `LocalAgent.with()` changes: how its casts run, not which processes run them. */
237
+ type LocalAgentCallOptions = AgentCallOptions & {
238
+ /** Per-call limit in milliseconds. */
239
+ timeoutMs?: number;
240
+ };
241
+ /**
242
+ * A coding-agent CLI on this machine, set up once and ready to run casts.
243
+ * Created by localAgent() or findLocalAgent().
244
+ */
245
+ declare class LocalAgent implements EngineRouter {
246
+ private readonly runner;
247
+ /** How calls that name no model run. */
248
+ private readonly call;
249
+ readonly agent: LocalAgentId;
250
+ readonly logger: Logger;
251
+ constructor(runner: AgentRunner,
252
+ /** How calls that name no model run. */
253
+ call: AgentCall);
254
+ /**
255
+ * The same agent with other call options, sharing this one's executable,
256
+ * environment, logger and limit on processes running at once. Options left
257
+ * out keep this agent's; a model or effort given as undefined is the CLI's
258
+ * default.
259
+ */
260
+ with(options: LocalAgentCallOptions): LocalAgent;
261
+ /**
262
+ * No model choice runs the default model. An alias runs the CLI's equivalent
263
+ * model, if it has one. Provider models cannot run on a local agent.
264
+ */
265
+ route(model: ModelInput | undefined): Route;
266
+ private routeTo;
267
+ }
268
+
269
+ export { LocalAgent as a, LOCAL_AGENT_IDS as f, isLocalAgentId as i };
270
+ export type { AnswerOrigin as A, LlmProviderId as L, ModelInput as M, NormalizedUsage as N, SchemaEnforcementKind as S, LocalAgentId as b, AgentEffort as c, Logger as d, SessionApproval as e, LocalAgentCallOptions as g };
@@ -0,0 +1,270 @@
1
+ type NormalizedUsage = {
2
+ /** All prompt tokens, including any the provider read from or wrote to its prompt cache. */
3
+ promptTokens: number;
4
+ completionTokens: number;
5
+ totalTokens: number;
6
+ /** Prompt tokens the provider read from its prompt cache, billed at a discount. Undefined when not reported. */
7
+ promptCacheReadTokens?: number;
8
+ /** Prompt tokens the provider wrote to its prompt cache (Claude bills these at a premium). Undefined when not reported. */
9
+ promptCacheWriteTokens?: number;
10
+ };
11
+
12
+ interface Logger {
13
+ debug(message: string, context?: object): void;
14
+ info(message: string, context?: object): void;
15
+ warn(message: string, context?: object): void;
16
+ error(message: string, context?: object): void;
17
+ }
18
+
19
+ type JsonSchema = Record<string, unknown>;
20
+
21
+ declare const LLM_PROVIDER_IDS: readonly ["groq", "cerebras", "gemini", "openrouter", "deepseek"];
22
+ type LlmProviderId = (typeof LLM_PROVIDER_IDS)[number];
23
+
24
+ /** Supported coding-agent CLIs, in the order findLocalAgent() tries them. */
25
+ declare const LOCAL_AGENT_IDS: readonly ["claude-code", "codex", "pi"];
26
+ type LocalAgentId = (typeof LOCAL_AGENT_IDS)[number];
27
+ declare function isLocalAgentId(value: unknown): value is LocalAgentId;
28
+
29
+ /**
30
+ * How one attempt makes the model produce the output shape.
31
+ * - in-prompt: the prompt describes the schema; the reply is free text that should contain the JSON.
32
+ * - native: the engine enforces `schema` itself. It is the output schema wrapped in an
33
+ * envelope (see cast/envelope), already converted to the engine's own dialect.
34
+ */
35
+ type SchemaEnforcement = {
36
+ kind: "in-prompt";
37
+ } | {
38
+ kind: "native";
39
+ schema: JsonSchema;
40
+ };
41
+ type SchemaEnforcementKind = SchemaEnforcement["kind"];
42
+ /** One prompt for an engine to answer once, on the model the engine was created for. */
43
+ type AttemptRequest = {
44
+ prompt: string;
45
+ /** The start of `prompt` that repeats across calls of the same cast. Engines may cache it. */
46
+ reusablePrefix: string;
47
+ maxTokens: number;
48
+ enforcement: SchemaEnforcement;
49
+ };
50
+ type Answer =
51
+ /** A free-text reply that should contain the JSON result. */
52
+ {
53
+ kind: "text";
54
+ text: string;
55
+ }
56
+ /** The envelope object the engine enforced natively. */
57
+ | {
58
+ kind: "structured";
59
+ envelope: unknown;
60
+ };
61
+ /** Which engine produced an answer. */
62
+ type AnswerOrigin = {
63
+ engine: "http";
64
+ provider: LlmProviderId;
65
+ model: string;
66
+ } | {
67
+ engine: "local-agent";
68
+ agent: LocalAgentId;
69
+ /** The model the agent reports using, else the one requested; undefined when neither is known. */
70
+ model: string | undefined;
71
+ /** The agent's own estimate. On a subscription this is not what the user pays. */
72
+ costUsdEstimate: number | undefined;
73
+ };
74
+ type AttemptFailure = {
75
+ /**
76
+ * - transient: another attempt may succeed.
77
+ * - fatal: every attempt will fail the same way (bad API key, not logged in, out of quota, timed out).
78
+ * - schema-rejected: the engine refused the native schema; the in-prompt prompt may still work.
79
+ */
80
+ kind: "transient" | "fatal" | "schema-rejected";
81
+ message: string;
82
+ };
83
+ type AttemptOutcome = {
84
+ kind: "answered";
85
+ answer: Answer;
86
+ usage: NormalizedUsage;
87
+ origin: AnswerOrigin;
88
+ } | {
89
+ kind: "failed";
90
+ failure: AttemptFailure;
91
+ };
92
+ /**
93
+ * Answers prompts on one model: an LLM provider's HTTP API, or a coding-agent
94
+ * CLI on this machine. Expected failures come back as outcomes, not exceptions.
95
+ */
96
+ interface LlmEngine {
97
+ /** The envelope schema in the form this engine enforces natively, or null if it cannot. */
98
+ nativeSchema(envelopeSchema: JsonSchema): JsonSchema | null;
99
+ attempt(request: AttemptRequest): Promise<AttemptOutcome>;
100
+ }
101
+
102
+ type ProviderModel = {
103
+ provider: LlmProviderId;
104
+ model: string;
105
+ };
106
+ type ModelAliasName = "fast" | "gemini" | "qwen" | "sonnet" | "opus" | "haiku" | "kimi" | "deepseek" | "gpt";
107
+ type ModelInput = ProviderModel | {
108
+ alias: ModelAliasName;
109
+ };
110
+
111
+ /** The engine that runs a model choice, or why none can. */
112
+ type Route = {
113
+ kind: "routed";
114
+ engine: LlmEngine;
115
+ } | {
116
+ kind: "unroutable";
117
+ message: string;
118
+ };
119
+ /**
120
+ * Where a client's calls run. Every setup answers the same question: for this
121
+ * model choice, which engine runs it? Created by providerEngines() for LLM
122
+ * providers' APIs, or by localAgent() / findLocalAgent() in the Node-only
123
+ * "nua-llm-core/local-agent" entry point for a coding-agent CLI.
124
+ */
125
+ interface EngineRouter {
126
+ /** Where the engines log their calls. Casts log their retries here too. */
127
+ readonly logger: Logger;
128
+ /** `model` undefined means this router's default model. */
129
+ route(model: ModelInput | undefined): Route;
130
+ }
131
+
132
+ /** A process to run inside a fresh, empty working directory. */
133
+ type AgentInvocation = {
134
+ args: string[];
135
+ stdin: string;
136
+ /** Files written into the working directory before the process starts. */
137
+ files?: {
138
+ name: string;
139
+ content: string;
140
+ }[];
141
+ /** Files read back from the working directory after the process exits. */
142
+ outputFiles?: string[];
143
+ };
144
+ type AgentProcessResult = {
145
+ exitCode: number | null;
146
+ stdout: string;
147
+ stderr: string;
148
+ timedOut: boolean;
149
+ /** Contents of the requested output files; undefined when a file was not written. */
150
+ outputFiles: Record<string, string | undefined>;
151
+ };
152
+ /** What an agent's output says about one attempt. */
153
+ type AgentReply = {
154
+ kind: "answered";
155
+ answer: Answer;
156
+ usage: NormalizedUsage;
157
+ /** The model the agent reports having used, when it says. */
158
+ model: string | undefined;
159
+ costUsdEstimate: number | undefined;
160
+ } | {
161
+ kind: "failed";
162
+ failure: AttemptFailure;
163
+ };
164
+ /**
165
+ * How hard the agent's model thinks before it answers: the CLI's own reasoning
166
+ * or effort setting, at one of the levels every supported CLI has.
167
+ */
168
+ type AgentEffort = "low" | "medium" | "high";
169
+ /** How one cast runs on an agent. An undefined field leaves it to the CLI's default. */
170
+ type AgentCallOptions = {
171
+ /** The CLI's own model name. */
172
+ model?: string;
173
+ effort?: AgentEffort;
174
+ };
175
+ /**
176
+ * Who approves an interactive session's edits and commands:
177
+ * - ask: the user, step by step, as the CLI does by default.
178
+ * - auto: the CLI's own auto mode. Its reviewer approves routine steps and stops risky ones.
179
+ */
180
+ type SessionApproval = "ask" | "auto";
181
+ type AgentLoginStatus = {
182
+ loggedIn: boolean;
183
+ detail?: string;
184
+ };
185
+ /**
186
+ * Knows one coding-agent CLI: which models it offers, how to invoke it headless,
187
+ * and how to read its output. Adapters do no I/O; the process runner does the spawning.
188
+ */
189
+ interface AgentAdapter {
190
+ id: LocalAgentId;
191
+ /** Executable name looked up on PATH. */
192
+ binaryName: string;
193
+ /** Env vars that would make the CLI bill an API key instead of the user's subscription. */
194
+ apiKeyEnvVars: string[];
195
+ /** The CLI's own model name for each model alias it has an equivalent for. */
196
+ modelAliases: Partial<Record<ModelAliasName, string>>;
197
+ /** The envelope schema in the form this CLI accepts, or null if it can't enforce it. */
198
+ nativeSchema(envelopeSchema: JsonSchema): JsonSchema | null;
199
+ buildInvocation(request: AttemptRequest, options: AgentCallOptions): AgentInvocation;
200
+ readResult(result: AgentProcessResult, request: AttemptRequest): AgentReply;
201
+ loginStatusArgs: string[];
202
+ readLoginStatus(result: AgentProcessResult): AgentLoginStatus;
203
+ /**
204
+ * Options for an interactive session in the user's own project, which go
205
+ * before its first message. `model` is the CLI's own model name; undefined
206
+ * uses the CLI's default.
207
+ */
208
+ sessionArgs(model: string | undefined, approval: SessionApproval): string[];
209
+ }
210
+
211
+ /** Runs at most `limit` tasks at once; the rest wait in order. */
212
+ declare class Semaphore {
213
+ private readonly limit;
214
+ private active;
215
+ private readonly waiting;
216
+ constructor(limit: number);
217
+ run<T>(task: () => Promise<T>): Promise<T>;
218
+ }
219
+
220
+ /** How to run one installed agent's processes. Set up once and shared by all its engines. */
221
+ type AgentRunner = {
222
+ adapter: AgentAdapter;
223
+ binaryPath: string;
224
+ /** Env vars removed from the agent's environment. */
225
+ unsetEnv: string[];
226
+ /** Bounds how many agent processes run at once, across all models. */
227
+ limiter: Semaphore;
228
+ logger: Logger;
229
+ };
230
+ /** How one engine's attempts run: the CLI's options and how long each may take. */
231
+ type AgentCall = AgentCallOptions & {
232
+ /** Per-attempt limit. */
233
+ timeoutMs: number;
234
+ };
235
+
236
+ /** What `LocalAgent.with()` changes: how its casts run, not which processes run them. */
237
+ type LocalAgentCallOptions = AgentCallOptions & {
238
+ /** Per-call limit in milliseconds. */
239
+ timeoutMs?: number;
240
+ };
241
+ /**
242
+ * A coding-agent CLI on this machine, set up once and ready to run casts.
243
+ * Created by localAgent() or findLocalAgent().
244
+ */
245
+ declare class LocalAgent implements EngineRouter {
246
+ private readonly runner;
247
+ /** How calls that name no model run. */
248
+ private readonly call;
249
+ readonly agent: LocalAgentId;
250
+ readonly logger: Logger;
251
+ constructor(runner: AgentRunner,
252
+ /** How calls that name no model run. */
253
+ call: AgentCall);
254
+ /**
255
+ * The same agent with other call options, sharing this one's executable,
256
+ * environment, logger and limit on processes running at once. Options left
257
+ * out keep this agent's; a model or effort given as undefined is the CLI's
258
+ * default.
259
+ */
260
+ with(options: LocalAgentCallOptions): LocalAgent;
261
+ /**
262
+ * No model choice runs the default model. An alias runs the CLI's equivalent
263
+ * model, if it has one. Provider models cannot run on a local agent.
264
+ */
265
+ route(model: ModelInput | undefined): Route;
266
+ private routeTo;
267
+ }
268
+
269
+ export { LocalAgent as a, LOCAL_AGENT_IDS as f, isLocalAgentId as i };
270
+ export type { AnswerOrigin as A, LlmProviderId as L, ModelInput as M, NormalizedUsage as N, SchemaEnforcementKind as S, LocalAgentId as b, AgentEffort as c, Logger as d, SessionApproval as e, LocalAgentCallOptions as g };
@@ -0,0 +1,145 @@
1
+ 'use strict';
2
+
3
+ class ConsoleLogger {
4
+ debug(message, context) {
5
+ console.debug(`[DEBUG] ${message}`, context || "");
6
+ }
7
+ info(message, context) {
8
+ console.info(`[INFO] ${message}`, context || "");
9
+ }
10
+ warn(message, context) {
11
+ console.warn(`[WARN] ${message}`, context || "");
12
+ }
13
+ error(message, context) {
14
+ console.error(`[ERROR] ${message}`, context || "");
15
+ }
16
+ }
17
+ const generateSpanId = () => crypto.randomUUID();
18
+ function pickHeaders(headers, allowlist, redactSet) {
19
+ const result = {};
20
+ for (const [key, value] of Object.entries(headers)) {
21
+ const lowerKey = key.toLowerCase();
22
+ if (allowlist.has(lowerKey)) {
23
+ result[key] = Array.isArray(value) ? value.join(", ") : value ?? "";
24
+ }
25
+ }
26
+ return result;
27
+ }
28
+ function normalizeError(error) {
29
+ return error instanceof Error ? { message: error.message, stack: error.stack } : String(error);
30
+ }
31
+ const LLM_RESPONSE_HEADER_ALLOWLIST = /* @__PURE__ */ new Set([
32
+ "x-request-id",
33
+ "x-ratelimit-limit-requests",
34
+ "x-ratelimit-limit-tokens",
35
+ "x-ratelimit-remaining-requests",
36
+ "x-ratelimit-remaining-tokens",
37
+ "x-groq-region"
38
+ ]);
39
+ const logLlmCallStart = (logger, spanId, service, method, request) => {
40
+ logger.info("LLM call started", {
41
+ type: "llm_call_start",
42
+ span_id: spanId,
43
+ service,
44
+ method,
45
+ ...request
46
+ });
47
+ };
48
+ const logLlmCallComplete = (logger, spanId, service, method, response, duration) => {
49
+ const { headers, ...rest } = response;
50
+ logger.info("LLM call completed", {
51
+ type: "llm_call_complete",
52
+ span_id: spanId,
53
+ service,
54
+ method,
55
+ ...rest,
56
+ ...pickHeaders(headers, LLM_RESPONSE_HEADER_ALLOWLIST),
57
+ duration_ms: duration
58
+ });
59
+ };
60
+ const logLlmCallError = (logger, spanId, service, method, error, duration) => {
61
+ logger.error("LLM call failed", {
62
+ type: "llm_call_error",
63
+ span_id: spanId,
64
+ service,
65
+ method,
66
+ error: normalizeError(error),
67
+ duration_ms: duration
68
+ });
69
+ };
70
+
71
+ const STRICT_UNSUPPORTED_KEYWORDS = /* @__PURE__ */ new Set([
72
+ "patternProperties",
73
+ "propertyNames",
74
+ "unevaluatedProperties",
75
+ "dependentRequired",
76
+ "dependentSchemas",
77
+ "if",
78
+ "then",
79
+ "else",
80
+ "not",
81
+ "allOf",
82
+ "oneOf"
83
+ ]);
84
+ function toStrictSchema(schema) {
85
+ return strictNode(schema);
86
+ }
87
+ function strictNode(node) {
88
+ if (typeof node !== "object" || node === null || Array.isArray(node)) {
89
+ return null;
90
+ }
91
+ const schema = node;
92
+ for (const key of Object.keys(schema)) {
93
+ if (STRICT_UNSUPPORTED_KEYWORDS.has(key)) return null;
94
+ }
95
+ const result = { ...schema };
96
+ delete result.$schema;
97
+ const isObject = schema.type === "object" || Array.isArray(schema.type) && schema.type.includes("object") || schema.properties !== void 0;
98
+ if (isObject) {
99
+ const properties = schema.properties ?? {};
100
+ if (schema.additionalProperties !== void 0 && schema.additionalProperties !== false) {
101
+ return null;
102
+ }
103
+ const required = new Set(schema.required ?? []);
104
+ const shapedProperties = {};
105
+ for (const [name, child] of Object.entries(properties)) {
106
+ if (!required.has(name)) return null;
107
+ const shaped = strictNode(child);
108
+ if (!shaped) return null;
109
+ shapedProperties[name] = shaped;
110
+ }
111
+ result.properties = shapedProperties;
112
+ result.required = Object.keys(shapedProperties);
113
+ result.additionalProperties = false;
114
+ }
115
+ if (schema.items !== void 0) {
116
+ const shaped = strictNode(schema.items);
117
+ if (!shaped) return null;
118
+ result.items = shaped;
119
+ }
120
+ if (schema.prefixItems !== void 0) return null;
121
+ if (schema.anyOf !== void 0) {
122
+ const variants = schema.anyOf.map(strictNode);
123
+ if (variants.some((v) => v === null)) return null;
124
+ result.anyOf = variants;
125
+ }
126
+ for (const defsKey of ["$defs", "definitions"]) {
127
+ if (schema[defsKey] !== void 0) {
128
+ const defs = {};
129
+ for (const [name, child] of Object.entries(schema[defsKey])) {
130
+ const shaped = strictNode(child);
131
+ if (!shaped) return null;
132
+ defs[name] = shaped;
133
+ }
134
+ result[defsKey] = defs;
135
+ }
136
+ }
137
+ return result;
138
+ }
139
+
140
+ exports.ConsoleLogger = ConsoleLogger;
141
+ exports.generateSpanId = generateSpanId;
142
+ exports.logLlmCallComplete = logLlmCallComplete;
143
+ exports.logLlmCallError = logLlmCallError;
144
+ exports.logLlmCallStart = logLlmCallStart;
145
+ exports.toStrictSchema = toStrictSchema;