@~lyre/ai-agents 0.5.1 → 0.5.4

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/dist/index.d.ts CHANGED
@@ -51,6 +51,33 @@ type Message = {
51
51
  type ClientDefaults = {
52
52
  apiKey?: string;
53
53
  model?: ModelLike;
54
+ /**
55
+ * Remote agent source (e.g. Axis Intelligence). When set, a run for an agent NOT registered locally
56
+ * fetches its definition from `${remoteBaseUrl}/agents/{slug}/definition`, runs it locally against the
57
+ * provider, and reports the result to `${remoteBaseUrl}/runs`. Tools the definition names that aren't
58
+ * registered locally become proxy tools that POST to `${remoteBaseUrl}/tools/{slug}/call`.
59
+ */
60
+ remoteBaseUrl?: string;
61
+ /** Bearer token (service key) sent to the remote source for fetch/proxy/report calls. */
62
+ remoteToken?: string;
63
+ };
64
+ /** A tool spec carried by a remote agent definition (name-only for built-ins; schema for apiTools). */
65
+ type RemoteToolSpec = {
66
+ name: string;
67
+ description?: string | null;
68
+ inputSchema?: any;
69
+ /** The slug the consumer POSTs to `${remoteBaseUrl}/tools/{proxySlug}/call`. Null for built-ins. */
70
+ proxySlug?: string | null;
71
+ };
72
+ /** A registered remote proxy tool — materialized (with the run's context) into an AI-SDK tool at run time
73
+ * in buildTools, so the tool call sent to the source carries the run's scope (appId/tenantId/etc.). */
74
+ type ProxyToolSpec = {
75
+ name: string;
76
+ description: string;
77
+ inputSchema: any;
78
+ proxySlug: string;
79
+ base: string;
80
+ headers: Record<string, string>;
54
81
  };
55
82
  type AgentDefinition = {
56
83
  /** Stable identifier; used as the lookup key. Defaults to `name`. */
@@ -212,8 +239,15 @@ type RunObjectResult<T = unknown> = {
212
239
  */
213
240
  declare class Registry {
214
241
  readonly tools: Map<string, ToolDefinition>;
242
+ readonly proxyTools: Map<string, ProxyToolSpec>;
215
243
  readonly agents: Map<string, Agent>;
216
244
  registerTool<I, O>(tool: ToolDefinition<I, O>): ToolDefinition<I, O>;
245
+ /** Register a remote proxy tool spec by name (materialized with run context in buildTools). */
246
+ registerProxyTool(spec: ProxyToolSpec): void;
247
+ /** True if a tool with this name is registered (either shape). */
248
+ hasTool(name: string): boolean;
249
+ /** True if an agent with this id/name is registered. */
250
+ hasAgent(idOrName: string): boolean;
217
251
  createAgent(definition: AgentDefinition): Agent;
218
252
  resolveAgent(input: string | AgentDefinition): Agent;
219
253
  resolveTools(agent: Agent): ToolDefinition[];
@@ -269,4 +303,4 @@ declare const SUPPORTED_PROVIDERS: string[];
269
303
  */
270
304
  declare function resolveModelString(model: string, apiKey?: string): LanguageModel | string;
271
305
 
272
- export { type Agent, type AgentDefinition, AiAgentsClient, type ClientDefaults, type Message, type ModelId, type ModelLike, Registry, type RunObjectParams, type RunObjectResult, type RunParams, type RunResult, SUPPORTED_PROVIDERS, type StreamEvent, type ToolContext, type ToolDefinition, createClient, resolveModelString, run, runObject, runStream };
306
+ export { type Agent, type AgentDefinition, AiAgentsClient, type ClientDefaults, type Message, type ModelId, type ModelLike, type ProxyToolSpec, Registry, type RemoteToolSpec, type RunObjectParams, type RunObjectResult, type RunParams, type RunResult, SUPPORTED_PROVIDERS, type StreamEvent, type ToolContext, type ToolDefinition, createClient, resolveModelString, run, runObject, runStream };
package/dist/index.js CHANGED
@@ -5,11 +5,26 @@ import {
5
5
  // src/agents.ts
6
6
  var Registry = class {
7
7
  tools = /* @__PURE__ */ new Map();
8
+ // Remote proxy tool specs — materialized into AI-SDK tools at run time in buildTools, so each call can
9
+ // fold the run's CONTEXT (scope: appId/tenantId/targetApps/…) into the request sent to the source.
10
+ proxyTools = /* @__PURE__ */ new Map();
8
11
  agents = /* @__PURE__ */ new Map();
9
12
  registerTool(tool2) {
10
13
  this.tools.set(tool2.name, tool2);
11
14
  return tool2;
12
15
  }
16
+ /** Register a remote proxy tool spec by name (materialized with run context in buildTools). */
17
+ registerProxyTool(spec) {
18
+ this.proxyTools.set(spec.name, spec);
19
+ }
20
+ /** True if a tool with this name is registered (either shape). */
21
+ hasTool(name) {
22
+ return this.tools.has(name) || this.proxyTools.has(name);
23
+ }
24
+ /** True if an agent with this id/name is registered. */
25
+ hasAgent(idOrName) {
26
+ return this.agents.has(idOrName);
27
+ }
13
28
  createAgent(definition) {
14
29
  const agent = {
15
30
  id: definition.id ?? definition.name,
@@ -80,7 +95,103 @@ function resolveModelString(model, apiKey) {
80
95
  return model;
81
96
  }
82
97
 
98
+ // src/remote.ts
99
+ import { tool as aiTool, jsonSchema } from "ai";
100
+ function authHeaders(defaults) {
101
+ const h = { "Content-Type": "application/json" };
102
+ if (defaults.remoteToken) h.Authorization = `Bearer ${defaults.remoteToken}`;
103
+ return h;
104
+ }
105
+ async function ensureRemoteAgent(registry, agentSlug, defaults) {
106
+ if (!defaults.remoteBaseUrl) return null;
107
+ if (registry.hasAgent(agentSlug)) return agentSlug;
108
+ const base = defaults.remoteBaseUrl.replace(/\/+$/, "");
109
+ let def;
110
+ try {
111
+ const res = await fetch(`${base}/agents/${encodeURIComponent(agentSlug)}/definition`, {
112
+ method: "GET",
113
+ headers: authHeaders(defaults)
114
+ });
115
+ if (!res.ok) return null;
116
+ def = await res.json();
117
+ } catch {
118
+ return null;
119
+ }
120
+ for (const spec of def.tools ?? []) {
121
+ if (!spec?.name || registry.hasTool(spec.name)) continue;
122
+ if (!spec.proxySlug) continue;
123
+ registry.registerProxyTool({
124
+ name: spec.name,
125
+ description: spec.description ?? `Proxied tool "${spec.proxySlug}".`,
126
+ inputSchema: spec.inputSchema ?? { type: "object", properties: {} },
127
+ proxySlug: spec.proxySlug,
128
+ base,
129
+ headers: authHeaders(defaults)
130
+ });
131
+ }
132
+ registry.createAgent({
133
+ id: def.slug,
134
+ name: def.slug,
135
+ model: def.model,
136
+ instructions: def.instructions ?? "",
137
+ temperature: def.temperature,
138
+ maxOutputTokens: def.maxOutputTokens,
139
+ tools: (def.tools ?? []).map((t) => t.name)
140
+ });
141
+ return def.slug;
142
+ }
143
+ function buildProxyTool(spec, context) {
144
+ const schema = spec.inputSchema ?? { type: "object", properties: {} };
145
+ const scope = pickScope(context);
146
+ return aiTool({
147
+ description: spec.description,
148
+ inputSchema: jsonSchema(schema),
149
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
150
+ execute: async (input) => {
151
+ const res = await fetch(`${spec.base}/tools/${encodeURIComponent(spec.proxySlug)}/call`, {
152
+ method: "POST",
153
+ headers: spec.headers,
154
+ body: JSON.stringify({ input, ...scope })
155
+ });
156
+ if (!res.ok) {
157
+ const text = await res.text().catch(() => "");
158
+ return { error: `Proxied tool "${spec.proxySlug}" failed: HTTP ${res.status} ${text}`.trim() };
159
+ }
160
+ const body = await res.json().catch(() => ({}));
161
+ return body.output ?? body;
162
+ }
163
+ });
164
+ }
165
+ function pickScope(context) {
166
+ const out = {};
167
+ for (const key of ["appId", "tenantId", "scopeMode", "targetApps", "collectionIds", "range"]) {
168
+ if (context[key] !== void 0 && context[key] !== null) out[key] = context[key];
169
+ }
170
+ if (context.toolContext && typeof context.toolContext === "object") {
171
+ out.toolContext = context.toolContext;
172
+ }
173
+ return out;
174
+ }
175
+ async function reportRun(defaults, report) {
176
+ if (!defaults.remoteBaseUrl) return;
177
+ const base = defaults.remoteBaseUrl.replace(/\/+$/, "");
178
+ try {
179
+ await fetch(`${base}/runs`, {
180
+ method: "POST",
181
+ headers: authHeaders(defaults),
182
+ body: JSON.stringify(report)
183
+ });
184
+ } catch {
185
+ }
186
+ }
187
+
83
188
  // src/run.ts
189
+ async function resolveAgentMaybeRemote(registry, agentInput, defaults) {
190
+ if (typeof agentInput === "string" && defaults?.remoteBaseUrl && !registry.hasAgent(agentInput)) {
191
+ await ensureRemoteAgent(registry, agentInput, defaults);
192
+ }
193
+ return registry.resolveAgent(agentInput);
194
+ }
84
195
  function resolveModel(agent, defaults) {
85
196
  const model = agent.model ?? defaults?.model;
86
197
  if (typeof model === "string") return resolveModelString(model, defaults?.apiKey);
@@ -109,6 +220,11 @@ function buildTools(registry, agent, context) {
109
220
  execute: async (input, opts) => def.execute(input, { toolCallId: opts.toolCallId, app: context })
110
221
  });
111
222
  }
223
+ const allowed = agent.tools && agent.tools.length > 0 ? new Set(agent.tools) : null;
224
+ for (const [name, spec] of registry.proxyTools) {
225
+ if (allowed && !allowed.has(name)) continue;
226
+ if (!out[name]) out[name] = buildProxyTool(spec, context);
227
+ }
112
228
  return out;
113
229
  }
114
230
  function buildRunOptions(params) {
@@ -127,7 +243,8 @@ function buildRunOptions(params) {
127
243
  return opts;
128
244
  }
129
245
  async function run(registry, params, defaults) {
130
- const agent = registry.resolveAgent(params.agent);
246
+ const startedAt = Date.now();
247
+ const agent = await resolveAgentMaybeRemote(registry, params.agent, defaults);
131
248
  const messages = buildMessages(agent, params);
132
249
  const tools = buildTools(registry, agent, params.context ?? {});
133
250
  const result = await generateText({
@@ -140,7 +257,7 @@ async function run(registry, params, defaults) {
140
257
  stopWhen: ({ steps }) => steps.length >= (params.maxSteps ?? 8),
141
258
  providerOptions: agent.providerOptions
142
259
  });
143
- return {
260
+ const runResult = {
144
261
  text: result.text,
145
262
  finishReason: result.finishReason,
146
263
  usage: {
@@ -161,11 +278,36 @@ async function run(registry, params, defaults) {
161
278
  ...params.output ? { object: result.experimental_output } : {},
162
279
  raw: result
163
280
  };
281
+ void reportRun(defaults ?? {}, buildRunReport(agent, params, runResult, true, null, startedAt));
282
+ return runResult;
283
+ }
284
+ function buildRunReport(agent, params, result, ok, error, startedAt) {
285
+ return {
286
+ operation: "agent_ask",
287
+ agentSlug: agent.name,
288
+ model: typeof agent.model === "string" ? agent.model : null,
289
+ question: params.message ?? null,
290
+ requestPayload: { message: params.message ?? null, context: params.context ?? null },
291
+ responsePayload: { text: result.text, object: result.object ?? null, finishReason: result.finishReason ?? null },
292
+ toolCalls: result.toolCalls,
293
+ toolResults: result.toolResults,
294
+ inputTokens: result.usage.inputTokens,
295
+ outputTokens: result.usage.outputTokens,
296
+ totalTokens: result.usage.totalTokens,
297
+ latencyMs: Date.now() - startedAt,
298
+ ok,
299
+ error
300
+ };
164
301
  }
165
302
  async function* runStream(registry, params, defaults) {
166
- const agent = registry.resolveAgent(params.agent);
303
+ const startedAt = Date.now();
304
+ const agent = await resolveAgentMaybeRemote(registry, params.agent, defaults);
167
305
  const messages = buildMessages(agent, params);
168
306
  const tools = buildTools(registry, agent, params.context ?? {});
307
+ let reportText = "";
308
+ let reportObject;
309
+ const reportToolCalls = [];
310
+ const reportToolResults = [];
169
311
  const result = streamText({
170
312
  model: resolveModel(agent, defaults),
171
313
  messages,
@@ -185,13 +327,17 @@ async function* runStream(registry, params, defaults) {
185
327
  };
186
328
  for await (const part of result.fullStream) {
187
329
  switch (part.type) {
188
- case "text-delta":
189
- yield { type: "text-delta", text: part.text ?? part.delta ?? "" };
330
+ case "text-delta": {
331
+ const t = part.text ?? part.delta ?? "";
332
+ reportText += t;
333
+ yield { type: "text-delta", text: t };
190
334
  break;
335
+ }
191
336
  case "finish-step":
192
337
  addUsage(part.usage);
193
338
  break;
194
339
  case "tool-call":
340
+ reportToolCalls.push({ toolCallId: part.toolCallId, toolName: part.toolName, input: part.input ?? part.args });
195
341
  yield {
196
342
  type: "tool-call",
197
343
  toolCallId: part.toolCallId,
@@ -200,6 +346,7 @@ async function* runStream(registry, params, defaults) {
200
346
  };
201
347
  break;
202
348
  case "tool-result":
349
+ reportToolResults.push({ toolCallId: part.toolCallId, toolName: part.toolName, output: part.output ?? part.result });
203
350
  yield {
204
351
  type: "tool-result",
205
352
  toolCallId: part.toolCallId,
@@ -221,19 +368,43 @@ async function* runStream(registry, params, defaults) {
221
368
  if (params.output) {
222
369
  object = await result.experimental_output;
223
370
  }
371
+ reportObject = object;
372
+ const usage = {
373
+ inputTokens: finalUsage?.inputTokens ?? accumulatedUsage.inputTokens,
374
+ outputTokens: finalUsage?.outputTokens ?? accumulatedUsage.outputTokens,
375
+ totalTokens: finalUsage?.totalTokens ?? accumulatedUsage.totalTokens
376
+ };
377
+ void reportRun(
378
+ defaults ?? {},
379
+ buildRunReport(
380
+ agent,
381
+ params,
382
+ { text: reportText, usage, toolCalls: reportToolCalls, toolResults: reportToolResults, object: reportObject, finishReason: part.finishReason },
383
+ true,
384
+ null,
385
+ startedAt
386
+ )
387
+ );
224
388
  yield {
225
389
  type: "finish",
226
390
  finishReason: part.finishReason,
227
- usage: {
228
- inputTokens: finalUsage?.inputTokens ?? accumulatedUsage.inputTokens,
229
- outputTokens: finalUsage?.outputTokens ?? accumulatedUsage.outputTokens,
230
- totalTokens: finalUsage?.totalTokens ?? accumulatedUsage.totalTokens
231
- },
391
+ usage,
232
392
  ...params.output ? { object } : {}
233
393
  };
234
394
  break;
235
395
  }
236
396
  case "error":
397
+ void reportRun(
398
+ defaults ?? {},
399
+ buildRunReport(
400
+ agent,
401
+ params,
402
+ { text: reportText, usage: accumulatedUsage, toolCalls: reportToolCalls, toolResults: reportToolResults, object: reportObject },
403
+ false,
404
+ part.error instanceof Error ? part.error.message : String(part.error),
405
+ startedAt
406
+ )
407
+ );
237
408
  yield { type: "error", error: part.error };
238
409
  break;
239
410
  }
@@ -272,7 +443,12 @@ var AiAgentsClient = class {
272
443
  defaults;
273
444
  constructor(config) {
274
445
  this.registry = new Registry();
275
- this.defaults = { apiKey: config?.apiKey, model: config?.model };
446
+ this.defaults = {
447
+ apiKey: config?.apiKey,
448
+ model: config?.model,
449
+ remoteBaseUrl: config?.remoteBaseUrl,
450
+ remoteToken: config?.remoteToken
451
+ };
276
452
  }
277
453
  registerTool(tool2) {
278
454
  return this.registry.registerTool(tool2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@~lyre/ai-agents",
3
- "version": "0.5.1",
3
+ "version": "0.5.4",
4
4
  "description": "Multi-provider AI agents SDK for SvelteKit + Node. Thin agent/tool/run/runStream surface over the Vercel AI SDK — OpenAI, Anthropic, Google Gemini, Mistral, Cohere. Zod-typed tools, full streaming event surface, optional HTML sanitizer.",
5
5
  "type": "module",
6
6
  "sideEffects": false,