@almadar/integrations 2.42.0 → 2.43.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.
@@ -147,6 +147,8 @@ interface IntegrationCallContext {
147
147
  declare class IntegrationFactory {
148
148
  private instances;
149
149
  private configs;
150
+ /** Names whose app-wide instance was registered directly (mock infrastructure). */
151
+ private registered;
150
152
  /**
151
153
  * Configure an integration (doesn't instantiate yet). A `principal` scopes
152
154
  * the config to that principal; the app-wide config (no principal) is the
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { e as IntegrationLogger, c as IntegrationErrorCode, a as IntegrationConfig, B as BaseIntegration, d as IntegrationFactory, g as IntegrationParams, h as IntegrationResult, I as IntegrationCallContext } from './BaseIntegration-D_iNTesu.js';
2
- export { b as IntegrationError, f as IntegrationParamValue, U as UnknownActionError, V as ValidationError, i as ValidationResult, j as getIntegrationFactory, r as resetIntegrationFactory, v as validateParams } from './BaseIntegration-D_iNTesu.js';
3
- import { e as CredentialStore, d as CredentialPersistence, H as HookDeclaration } from './store-DcennSSh.js';
4
- export { A as ArxivActions, C as CLIActions, a as CREDENTIAL_ENTITY_TYPE, b as CREDENTIAL_MASTER_KEY_ENV, c as CredentialEntry, D as DatabaseActions, f as DatabaseDriver, g as DatabaseQueryParamValue, h as DatabaseQueryParams, i as DatabaseQueryResult, j as DatabaseRow, k as DeepAgentActions, l as DockerActions, E as EmailActions, G as GitHubActions, I as IconifyActions, m as IntegrationActionName, n as IntegrationContracts, o as IntegrationName, L as LLMIntegrationActions, M as MLActions, O as OAuthActions, p as OtelActions, Q as QueueActions, R as RedisActions, S as StorageActions, q as StripeActions, T as TwilioActions, W as WebhookActions, r as WikimediaActions, Y as YouTubeActions, s as allCredentialEnvVars, t as declaredCredentialEnvVars, u as serviceHooks } from './store-DcennSSh.js';
1
+ import { e as IntegrationLogger, c as IntegrationErrorCode, a as IntegrationConfig, B as BaseIntegration, d as IntegrationFactory, g as IntegrationParams, h as IntegrationResult, I as IntegrationCallContext } from './BaseIntegration-Dgwn1ZR6.js';
2
+ export { b as IntegrationError, f as IntegrationParamValue, U as UnknownActionError, V as ValidationError, i as ValidationResult, j as getIntegrationFactory, r as resetIntegrationFactory, v as validateParams } from './BaseIntegration-Dgwn1ZR6.js';
3
+ import { e as CredentialStore, d as CredentialPersistence, H as HookDeclaration } from './store-DP3gfEfJ.js';
4
+ export { A as ArxivActions, C as CLIActions, a as CREDENTIAL_ENTITY_TYPE, b as CREDENTIAL_MASTER_KEY_ENV, c as CredentialEntry, D as DatabaseActions, f as DatabaseDriver, g as DatabaseQueryParamValue, h as DatabaseQueryParams, i as DatabaseQueryResult, j as DatabaseRow, k as DeepAgentActions, l as DockerActions, E as EmailActions, G as GitHubActions, I as IconifyActions, m as IntegrationActionName, n as IntegrationContracts, o as IntegrationName, L as LLMIntegrationActions, M as MLActions, O as OAuthActions, p as OtelActions, Q as QueueActions, R as RedisActions, S as StorageActions, q as StripeActions, T as TwilioActions, W as WebhookActions, r as WikimediaActions, Y as YouTubeActions, s as allCredentialEnvVars, t as declaredCredentialEnvVars, u as serviceHooks } from './store-DP3gfEfJ.js';
5
5
  import { LogMeta, EntityRow, EventPayload, ServiceHostPorts } from '@almadar/core';
6
- import { AgentChatMessage, AgentTool, AgentStep, ToolCallingClient } from '@almadar/llm';
6
+ import { AgentChatMessage, AgentTool, AgentActivity, ToolCallingClient } from '@almadar/llm';
7
7
  export { GitHubIntegration } from './integrations/github/index.js';
8
8
 
9
9
  /**
@@ -662,9 +662,14 @@ interface ToolLoopRequest {
662
662
  instructions?: string;
663
663
  maxSteps?: number;
664
664
  }
665
+ /** Which model answered, for each `llm_response` step. */
666
+ interface ToolLoopModel {
667
+ provider: string;
668
+ model: string;
669
+ }
665
670
  interface ToolLoopResult {
666
671
  reply: string;
667
- steps: AgentStep[];
672
+ steps: AgentActivity[];
668
673
  usage: {
669
674
  promptTokens: number;
670
675
  completionTokens: number;
@@ -672,7 +677,7 @@ interface ToolLoopResult {
672
677
  modelCalls: number;
673
678
  };
674
679
  }
675
- declare function runToolLoop(client: ToolCallingClient, host: ServiceHostPorts, request: ToolLoopRequest): Promise<ToolLoopResult>;
680
+ declare function runToolLoop(client: ToolCallingClient, host: ServiceHostPorts, request: ToolLoopRequest, model: ToolLoopModel, now?: () => number): Promise<ToolLoopResult>;
676
681
 
677
682
  declare class MLIntegration extends BaseIntegration {
678
683
  private readonly eventsUrl;
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import webpush from 'web-push';
13
13
  import { Readable } from 'stream';
14
14
  import { getAvailableProvider, LLMClient, EmbeddingClient } from '@almadar/llm';
15
15
  import { z } from 'zod';
16
- import { findInputByAddress, payloadSchemaToJsonSchema, EventPayloadSchema } from '@almadar/core';
16
+ import { traceActivityPayload, findInputByAddress, payloadSchemaToJsonSchema, EventPayloadSchema } from '@almadar/core';
17
17
  import { execSync, spawn } from 'child_process';
18
18
  import { tmpdir } from 'os';
19
19
  import * as oidc from 'openid-client';
@@ -422,6 +422,8 @@ var IntegrationFactory = class {
422
422
  constructor() {
423
423
  this.instances = /* @__PURE__ */ new Map();
424
424
  this.configs = /* @__PURE__ */ new Map();
425
+ /** Names whose app-wide instance was registered directly (mock infrastructure). */
426
+ this.registered = /* @__PURE__ */ new Set();
425
427
  }
426
428
  /**
427
429
  * Configure an integration (doesn't instantiate yet). A `principal` scopes
@@ -436,7 +438,8 @@ var IntegrationFactory = class {
436
438
  * back to the app-wide config when no per-principal config exists.
437
439
  */
438
440
  get(name, principal) {
439
- const key = instanceKey(name, principal);
441
+ const registered = this.registered.has(name) && !this.configs.has(instanceKey(name, principal));
442
+ const key = registered ? name : instanceKey(name, principal);
440
443
  const cached = this.instances.get(key);
441
444
  if (cached) {
442
445
  return cached;
@@ -480,6 +483,7 @@ var IntegrationFactory = class {
480
483
  * Register an integration instance directly (used by mock infrastructure)
481
484
  */
482
485
  registerInstance(name, instance, principal) {
486
+ if (principal === void 0) this.registered.add(name);
483
487
  this.instances.set(instanceKey(name, principal), instance);
484
488
  }
485
489
  /**
@@ -490,8 +494,10 @@ var IntegrationFactory = class {
490
494
  invalidate(name) {
491
495
  if (name === void 0) {
492
496
  this.instances.clear();
497
+ this.registered.clear();
493
498
  return;
494
499
  }
500
+ this.registered.delete(name);
495
501
  for (const key of this.instances.keys()) {
496
502
  if (key === name || key.startsWith(`${name}\0`)) {
497
503
  this.instances.delete(key);
@@ -503,6 +509,7 @@ var IntegrationFactory = class {
503
509
  */
504
510
  clear() {
505
511
  this.instances.clear();
512
+ this.registered.clear();
506
513
  }
507
514
  /**
508
515
  * Clear all instances and configs
@@ -510,6 +517,7 @@ var IntegrationFactory = class {
510
517
  reset() {
511
518
  this.instances.clear();
512
519
  this.configs.clear();
520
+ this.registered.clear();
513
521
  }
514
522
  };
515
523
  var _factory = null;
@@ -2513,7 +2521,7 @@ function parseArgs(args) {
2513
2521
  }
2514
2522
  return EventPayloadSchema.safeParse(value);
2515
2523
  }
2516
- async function runToolLoop(client, host, request) {
2524
+ async function runToolLoop(client, host, request, model, now = Date.now) {
2517
2525
  const tools = buildTools(host, request.tools);
2518
2526
  const defs = [...tools.values()].map((t) => t.def);
2519
2527
  const maxSteps = request.maxSteps ?? DEFAULT_MAX_STEPS;
@@ -2521,10 +2529,17 @@ async function runToolLoop(client, host, request) {
2521
2529
  ...request.instructions !== void 0 ? [{ role: "system", content: request.instructions }] : [],
2522
2530
  ...request.messages.map((m) => ({ role: m.role, content: m.content }))
2523
2531
  ];
2532
+ const userPrompt = [...request.messages].reverse().find((m) => m.role === "user")?.content ?? "";
2524
2533
  const steps = [];
2534
+ const record = (activity) => {
2535
+ steps.push(activity);
2536
+ host.message(traceActivityPayload(activity));
2537
+ };
2525
2538
  const usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0, modelCalls: 0 };
2526
2539
  while (usage.modelCalls < maxSteps) {
2540
+ const started = now();
2527
2541
  const turn = await client.callWithTools({ messages: conversation, tools: defs });
2542
+ const ended = now();
2528
2543
  usage.modelCalls += 1;
2529
2544
  if (turn.usage) {
2530
2545
  usage.promptTokens += turn.usage.promptTokens;
@@ -2533,23 +2548,41 @@ async function runToolLoop(client, host, request) {
2533
2548
  }
2534
2549
  conversation.push(turn.message);
2535
2550
  const calls = turn.message.tool_calls ?? [];
2551
+ record({
2552
+ type: "llm_response",
2553
+ content: turn.message.content ?? "",
2554
+ llm: {
2555
+ service: "llm",
2556
+ provider: model.provider,
2557
+ model: model.model,
2558
+ systemPrompt: request.instructions ?? "",
2559
+ userPrompt,
2560
+ ...calls.length > 0 ? { toolCallsJson: JSON.stringify(calls) } : {},
2561
+ durationMs: ended - started,
2562
+ ...turn.usage ? { promptTokens: turn.usage.promptTokens, completionTokens: turn.usage.completionTokens } : {}
2563
+ },
2564
+ timestamp: ended
2565
+ });
2536
2566
  if (calls.length === 0) return { reply: turn.message.content ?? "", steps, usage };
2537
2567
  for (const call of calls) {
2538
2568
  const args = call.function.arguments;
2539
2569
  const tool = tools.get(call.function.name);
2570
+ const kind = tool === void 0 ? "invalid" : tool.target.kind;
2571
+ const label = tool === void 0 ? call.function.name : tool.target.kind === "input" ? tool.target.address : tool.target.entity;
2572
+ record({ type: "tool_call", tool: label, kind, argsText: args, timestamp: now() });
2540
2573
  let content;
2541
2574
  if (!tool) {
2542
- steps.push({ kind: "invalid", target: call.function.name, args, ok: false, detail: "not an allowed tool" });
2543
2575
  content = JSON.stringify({ error: `'${call.function.name}' is not one of your tools` });
2576
+ record({ type: "tool_result", tool: label, kind, success: false, detail: "not an allowed tool", resultText: content, timestamp: now() });
2544
2577
  } else if (tool.target.kind === "read") {
2545
2578
  const rows = await host.read(tool.target.entity);
2546
- steps.push({ kind: "read", target: tool.target.entity, args, ok: true });
2547
2579
  content = JSON.stringify({ rows });
2580
+ record({ type: "tool_result", tool: label, kind, success: true, rows: rows.length, resultText: content, timestamp: now() });
2548
2581
  } else {
2549
2582
  const parsed = parseArgs(args);
2550
2583
  if (!parsed.success) {
2551
- steps.push({ kind: "input", target: tool.target.address, args, ok: false, detail: "arguments are not a JSON object" });
2552
2584
  content = JSON.stringify({ error: "arguments must be a JSON object" });
2585
+ record({ type: "tool_result", tool: label, kind, success: false, detail: "arguments are not a JSON object", resultText: content, timestamp: now() });
2553
2586
  } else {
2554
2587
  const { input } = tool.target;
2555
2588
  const response = await host.dispatchInput(input.orbital, {
@@ -2558,8 +2591,8 @@ async function runToolLoop(client, host, request) {
2558
2591
  payload: parsed.data
2559
2592
  });
2560
2593
  const detail = dispatchFailure(response);
2561
- steps.push({ kind: "input", target: tool.target.address, args, ok: detail === void 0, ...detail !== void 0 ? { detail } : {} });
2562
2594
  content = JSON.stringify(response);
2595
+ record({ type: "tool_result", tool: label, kind, success: detail === void 0, ...detail !== void 0 ? { detail } : {}, resultText: content, timestamp: now() });
2563
2596
  }
2564
2597
  }
2565
2598
  conversation.push({ role: "tool", content, tool_call_id: call.id });
@@ -2738,7 +2771,7 @@ Return ONLY valid JSON matching the schema.`,
2738
2771
  }
2739
2772
  const request = CallToolsParamsSchema.parse(params);
2740
2773
  const client = request.model !== void 0 ? new LLMClient({ provider: this.provider, model: request.model }) : this.getClient();
2741
- return runToolLoop(client, context.host, request);
2774
+ return runToolLoop(client, context.host, request, { provider: client.getProvider(), model: client.getModelName() });
2742
2775
  }
2743
2776
  async embed(params) {
2744
2777
  const { texts } = params;