@dudousxd/nestjs-agent-core 0.6.0 → 0.7.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.
package/dist/index.d.ts CHANGED
@@ -1258,6 +1258,22 @@ declare class QuotaExceededError extends Error {
1258
1258
  }
1259
1259
  /** Reject if `work` doesn't settle within `ms`. The underlying work is left to finish on its own. */
1260
1260
  declare function withToolTimeout<T>(work: Promise<T>, ms: number, toolName: string): Promise<T>;
1261
+ /**
1262
+ * Span-wrap one model call (`aviary:agent:llm.turn`). Exported so the durable dispatched-step
1263
+ * handler (which executes the genuine remote llm step) can emit the same span — core cannot wrap
1264
+ * `hooks.dispatchLlm` itself, because that call also runs (from cache) on replay.
1265
+ */
1266
+ declare function traceLlmTurn(runId: string, step: number, run: () => Promise<ModelTurnResult>): Promise<ModelTurnResult>;
1267
+ /**
1268
+ * Span-wrap one tool invocation (`aviary:agent:tool.execution`). The tool's raw output never
1269
+ * rides the span (only the start payload's name/type metadata + duration). Exported for the
1270
+ * durable dispatched-step handler, like {@link traceLlmTurn}.
1271
+ */
1272
+ declare function traceToolExecution<T>(runId: string, call: {
1273
+ toolCallId: string;
1274
+ toolName: string;
1275
+ toolType: 'read' | 'action';
1276
+ }, run: () => Promise<T>): Promise<T>;
1261
1277
  /**
1262
1278
  * The provider-agnostic agent turn, reused by both the inline and durable runners.
1263
1279
  * It drives the model→tools→model iteration; the runner supplies the `step`/`awaitApproval`
@@ -1317,7 +1333,35 @@ interface AgentRetrieved {
1317
1333
  /** How many passages the retriever returned. */
1318
1334
  count: number;
1319
1335
  }
1320
- /** Declaration-merge so `emit('agent', ...)` and telescope infer the agent payloads. */
1336
+ /** START payload of an `aviary:agent:llm.turn:*` span — one model call within a run. */
1337
+ interface AgentLlmTurnSpan {
1338
+ runId: string;
1339
+ /** Zero-based model-call index within the run (the loop's step counter). */
1340
+ step: number;
1341
+ }
1342
+ /** START payload of an `aviary:agent:tool.execution:*` span — one tool invocation. */
1343
+ interface AgentToolExecutionSpan {
1344
+ runId: string;
1345
+ toolCallId: string;
1346
+ toolName: string;
1347
+ toolType: 'read' | 'action';
1348
+ }
1349
+ /** START payload of an `aviary:agent:retrieval:*` span — inject-mode RAG retrieval. */
1350
+ interface AgentRetrievalSpan {
1351
+ runId: string;
1352
+ /** Length of the retrieval query in characters — never the query text itself. */
1353
+ queryLength: number;
1354
+ topK: number;
1355
+ }
1356
+ /** START payload of an `aviary:agent:follow-ups:*` span — the extra follow-up-suggestions call. */
1357
+ interface AgentFollowUpsSpan {
1358
+ runId: string;
1359
+ /** Zero-based model-call index of the final turn the follow-ups ride on. */
1360
+ step: number;
1361
+ /** How many follow-up questions were requested. */
1362
+ count: number;
1363
+ }
1364
+ /** Declaration-merge so `emit('agent', ...)`, `trace('agent', ...)` and telescope infer the agent payloads. */
1321
1365
  declare module '@dudousxd/nestjs-diagnostics' {
1322
1366
  interface ChannelRegistry {
1323
1367
  agent: {
@@ -1329,6 +1373,10 @@ declare module '@dudousxd/nestjs-diagnostics' {
1329
1373
  'run.failed': AgentRunFailed;
1330
1374
  delegated: AgentDelegated;
1331
1375
  retrieved: AgentRetrieved;
1376
+ 'llm.turn': AgentLlmTurnSpan;
1377
+ 'tool.execution': AgentToolExecutionSpan;
1378
+ retrieval: AgentRetrievalSpan;
1379
+ 'follow-ups': AgentFollowUpsSpan;
1332
1380
  };
1333
1381
  }
1334
1382
  }
@@ -1340,12 +1388,23 @@ declare function publishAgentRunFinished(payload: AgentRunFinished): void;
1340
1388
  declare function publishAgentRunFailed(payload: AgentRunFailed): void;
1341
1389
  declare function publishAgentDelegated(payload: AgentDelegated): void;
1342
1390
  declare function publishAgentRetrieved(payload: AgentRetrieved): void;
1343
- /** Every event key declared on `ChannelRegistry['agent']` above — derived, not hand-copied. */
1344
- type AgentDiagnosticEvent = keyof ChannelRegistry['agent'];
1345
1391
  /**
1346
- * All 8 events on `ChannelRegistry['agent']`, in a stable order — handy for wiring subscribers
1347
- * (mirrors nestjs-media's `MEDIA_DIAGNOSTIC_EVENTS`). A drift between this list and the registry is
1348
- * a compile error in both directions: an extra/misspelled entry fails this array's own
1392
+ * Events published ONLY as spans — via `trace('agent', ...)` on the five `:start`/`:end`/
1393
+ * `:asyncStart`/`:asyncEnd`/`:error` sub-channels — never as point events on the base channel.
1394
+ * They are deliberately NOT in {@link AGENT_DIAGNOSTIC_EVENTS}: the point-event watcher has
1395
+ * nothing to subscribe to on their base channels, and claiming their keys would be meaningless
1396
+ * (the generic bridge only records point traffic).
1397
+ */
1398
+ type AgentSpanEvent = 'llm.turn' | 'tool.execution' | 'retrieval' | 'follow-ups';
1399
+ /** All span-only events, in a stable order — for a future span recorder to derive sub-channels from. */
1400
+ declare const AGENT_SPAN_EVENTS: readonly AgentSpanEvent[];
1401
+ /** Every POINT event key declared on `ChannelRegistry['agent']` above — derived, not hand-copied. */
1402
+ type AgentDiagnosticEvent = Exclude<keyof ChannelRegistry['agent'], AgentSpanEvent>;
1403
+ /**
1404
+ * All 8 point events on `ChannelRegistry['agent']`, in a stable order — handy for wiring
1405
+ * subscribers (mirrors nestjs-media's `MEDIA_DIAGNOSTIC_EVENTS`). Span-only events (see
1406
+ * {@link AgentSpanEvent}) are excluded. A drift between this list and the registry is a compile
1407
+ * error in both directions: an extra/misspelled entry fails this array's own
1349
1408
  * `readonly AgentDiagnosticEvent[]` annotation immediately; a missing entry fails the
1350
1409
  * {@link AgentDiagnosticEventsCoverAllKeys} check below.
1351
1410
  */
@@ -1364,4 +1423,4 @@ type AgentDiagnosticKey = `agent:${AgentDiagnosticEvent}`;
1364
1423
  */
1365
1424
  declare function agentDiagnosticKey(event: AgentDiagnosticEvent): AgentDiagnosticKey;
1366
1425
 
1367
- export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_DIAGNOSTIC_EVENTS, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_RETRIEVER, AGENT_ROLES_POLICY, AGENT_RUNNER, AGENT_SINK, AGENT_STORE, AGENT_TOOL_REGISTRY, type Actor, type ActorDirectory, type ActorResolver, type ActorSpendRow, type AgentApprovalPort, type AgentCatalogEntry, type AgentDefinition, type AgentDelegated, type AgentDiagnosticEvent, type AgentDiagnosticKey, type AgentGovernanceQueries, type AgentLoopDeps, type AgentLoopHooks, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, type AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentStore, AgentStreamError, type AgentStreamEvent, type AgentToolCallEvent, type AiToolCtx, type AppendMessageInput, type AttachmentStagingStore, type CostUsage, type CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernanceRange, type GovernanceUsageInput, type LlmStepEnvelope, type MessageAttachment, type MessageRole, type MessageUsage, type ModelMessage, type ModelPrice, type ModelPriceInput, type ModelProvider, type ModelSpendRow, type ModelTurnArgs, type ModelTurnResult, type PageContext, type Passage, type PendingApprovalRow, type PromptBuilder, type PromptContext, type PromptContributor, QuotaExceededError, type QuotaState, type QuotaStore, type QuotaView, type RecentRunRow, type RecordRunEndInput, type RecordRunStartInput, type RecordToolCallInput, type RecordUsageInput, type RerankOptions, type Reranker, type RetrieveOptions, type Retriever, type RolesPolicy, type RunAgentBreakdownRow, type RunErrorBreakdownRow, type RunMetrics, type RunTrendPoint, type SinkWriter, type StageAttachmentInput, type StoredMessage, type StreamError, type ThreadActivityRow, type ThreadDetail, type ThreadMeta, type ThreadSpendRow, type ThreadSummary, type TokenStreamSink, type ToolCallActivityRow, type ToolCallRequest, type ToolCallStatus, type ToolDefinition, ToolForbiddenError, type ToolHandler, ToolInputInvalidError, type ToolKind, ToolNotFoundError, ToolRegistry, type ToolResult, type ToolSpec, type ToolStatRow, type ToolStepCtx, type ToolStepEnvelope, type UpdateThreadInput, type UpdateToolCallInput, type UsagePurpose, type UsageTrendPoint, agentDiagnosticKey, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, encodeStreamEvent, estimateCost, filterToolsByAllowList, filterToolsByRole, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, runAgentLoop, seedModelPrices, withToolTimeout };
1426
+ export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_DIAGNOSTIC_EVENTS, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_RETRIEVER, AGENT_ROLES_POLICY, AGENT_RUNNER, AGENT_SINK, AGENT_SPAN_EVENTS, AGENT_STORE, AGENT_TOOL_REGISTRY, type Actor, type ActorDirectory, type ActorResolver, type ActorSpendRow, type AgentApprovalPort, type AgentCatalogEntry, type AgentDefinition, type AgentDelegated, type AgentDiagnosticEvent, type AgentDiagnosticKey, type AgentFollowUpsSpan, type AgentGovernanceQueries, type AgentLlmTurnSpan, type AgentLoopDeps, type AgentLoopHooks, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrievalSpan, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, type AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentSpanEvent, type AgentStore, AgentStreamError, type AgentStreamEvent, type AgentToolCallEvent, type AgentToolExecutionSpan, type AiToolCtx, type AppendMessageInput, type AttachmentStagingStore, type CostUsage, type CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernanceRange, type GovernanceUsageInput, type LlmStepEnvelope, type MessageAttachment, type MessageRole, type MessageUsage, type ModelMessage, type ModelPrice, type ModelPriceInput, type ModelProvider, type ModelSpendRow, type ModelTurnArgs, type ModelTurnResult, type PageContext, type Passage, type PendingApprovalRow, type PromptBuilder, type PromptContext, type PromptContributor, QuotaExceededError, type QuotaState, type QuotaStore, type QuotaView, type RecentRunRow, type RecordRunEndInput, type RecordRunStartInput, type RecordToolCallInput, type RecordUsageInput, type RerankOptions, type Reranker, type RetrieveOptions, type Retriever, type RolesPolicy, type RunAgentBreakdownRow, type RunErrorBreakdownRow, type RunMetrics, type RunTrendPoint, type SinkWriter, type StageAttachmentInput, type StoredMessage, type StreamError, type ThreadActivityRow, type ThreadDetail, type ThreadMeta, type ThreadSpendRow, type ThreadSummary, type TokenStreamSink, type ToolCallActivityRow, type ToolCallRequest, type ToolCallStatus, type ToolDefinition, ToolForbiddenError, type ToolHandler, ToolInputInvalidError, type ToolKind, ToolNotFoundError, ToolRegistry, type ToolResult, type ToolSpec, type ToolStatRow, type ToolStepCtx, type ToolStepEnvelope, type UpdateThreadInput, type UpdateToolCallInput, type UsagePurpose, type UsageTrendPoint, agentDiagnosticKey, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, encodeStreamEvent, estimateCost, filterToolsByAllowList, filterToolsByRole, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, runAgentLoop, seedModelPrices, traceLlmTurn, traceToolExecution, withToolTimeout };
package/dist/index.js CHANGED
@@ -327,6 +327,7 @@ var DefaultRolesPolicy = class {
327
327
 
328
328
  // src/agent-loop.ts
329
329
  import { createHash } from "node:crypto";
330
+ import { trace } from "@dudousxd/nestjs-diagnostics";
330
331
 
331
332
  // src/diagnostics.ts
332
333
  import { emit } from "@dudousxd/nestjs-diagnostics";
@@ -362,6 +363,12 @@ function publishAgentRetrieved(payload) {
362
363
  emit("agent", "retrieved", payload);
363
364
  }
364
365
  __name(publishAgentRetrieved, "publishAgentRetrieved");
366
+ var AGENT_SPAN_EVENTS = [
367
+ "llm.turn",
368
+ "tool.execution",
369
+ "retrieval",
370
+ "follow-ups"
371
+ ];
365
372
  var AGENT_DIAGNOSTIC_EVENTS = [
366
373
  "run.started",
367
374
  "message",
@@ -503,6 +510,39 @@ async function generateFollowUps(model, messages, count) {
503
510
  };
504
511
  }
505
512
  __name(generateFollowUps, "generateFollowUps");
513
+ async function spanned(event, runId, payload, run, summarize) {
514
+ let value;
515
+ await trace("agent", event, async () => {
516
+ value = await run();
517
+ return summarize(value);
518
+ }, payload, {
519
+ traceId: runId
520
+ });
521
+ return value;
522
+ }
523
+ __name(spanned, "spanned");
524
+ function traceLlmTurn(runId, step, run) {
525
+ return spanned("llm.turn", runId, {
526
+ runId,
527
+ step
528
+ }, run, (turn) => ({
529
+ ...turn.modelId !== void 0 ? {
530
+ modelId: turn.modelId
531
+ } : {},
532
+ inputTokens: turn.usage.inputTokens,
533
+ outputTokens: turn.usage.outputTokens,
534
+ textLength: turn.text.length,
535
+ toolCalls: turn.toolCalls.length
536
+ }));
537
+ }
538
+ __name(traceLlmTurn, "traceLlmTurn");
539
+ function traceToolExecution(runId, call, run) {
540
+ return spanned("tool.execution", runId, {
541
+ runId,
542
+ ...call
543
+ }, run, () => ({}));
544
+ }
545
+ __name(traceToolExecution, "traceToolExecution");
506
546
  async function runAgentLoop(deps, input, hooks) {
507
547
  const maxSteps = deps.maxSteps ?? 8;
508
548
  let system = await resolveSystemPrompt(deps, input);
@@ -587,9 +627,16 @@ async function runAgentLoop(deps, input, hooks) {
587
627
  let injectedPassages;
588
628
  if (deps.retriever !== void 0) {
589
629
  const retriever = deps.retriever;
590
- const passages = await hooks.step("retrieve", () => retriever.retrieve(input.userText, {
591
- topK: deps.retrievalTopK ?? 5
592
- }));
630
+ const topK = deps.retrievalTopK ?? 5;
631
+ const passages = await hooks.step("retrieve", () => spanned("retrieval", hooks.runId, {
632
+ runId: hooks.runId,
633
+ queryLength: input.userText.length,
634
+ topK
635
+ }, () => retriever.retrieve(input.userText, {
636
+ topK
637
+ }), (retrieved) => ({
638
+ count: retrieved.length
639
+ })));
593
640
  if (passages.length > 0) {
594
641
  injectedPassages = passages;
595
642
  system = `${system}
@@ -629,12 +676,12 @@ ${buildContextBlock(passages)}`;
629
676
  });
630
677
  } else {
631
678
  const tools = await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList);
632
- turn = await hooks.step(`llm:${i}`, () => deps.model.runTurn({
679
+ turn = await hooks.step(`llm:${i}`, () => traceLlmTurn(hooks.runId, i, () => deps.model.runTurn({
633
680
  system,
634
681
  messages: modelMessages,
635
682
  tools,
636
683
  sink: writer
637
- }));
684
+ })));
638
685
  }
639
686
  const resolvedModelId = turn.modelId ?? deps.modelId ?? "unknown";
640
687
  const costUsd = resolveCostUsd(turn.usage, turn.costUsd, priceByModel.get(resolvedModelId));
@@ -671,13 +718,24 @@ ${buildContextBlock(passages)}`;
671
718
  let followUps;
672
719
  if (isFinalTurn && deps.followUpsCount !== void 0 && deps.followUpsCount > 0) {
673
720
  const count = deps.followUpsCount;
674
- const generated = await hooks.step(`followups:${i}`, () => generateFollowUps(deps.model, [
721
+ const generated = await hooks.step(`followups:${i}`, () => spanned("follow-ups", hooks.runId, {
722
+ runId: hooks.runId,
723
+ step: i,
724
+ count
725
+ }, () => generateFollowUps(deps.model, [
675
726
  ...modelMessages,
676
727
  {
677
728
  role: "assistant",
678
729
  content: turn.text
679
730
  }
680
- ], count));
731
+ ], count), (result) => ({
732
+ followUps: result.followUps.length,
733
+ inputTokens: result.usage.inputTokens,
734
+ outputTokens: result.usage.outputTokens,
735
+ ...result.modelId !== void 0 ? {
736
+ modelId: result.modelId
737
+ } : {}
738
+ })));
681
739
  if (generated.followUps.length > 0) {
682
740
  followUps = generated.followUps;
683
741
  }
@@ -884,7 +942,11 @@ ${buildContextBlock(passages)}`;
884
942
  };
885
943
  output = await hooks.dispatchTool(call, envelope);
886
944
  } else {
887
- const invocation = hooks.step(`tool:${call.id}`, () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy));
945
+ const invocation = hooks.step(`tool:${call.id}`, () => traceToolExecution(hooks.runId, {
946
+ toolCallId: call.id,
947
+ toolName: call.name,
948
+ toolType
949
+ }, () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy)));
888
950
  output = deps.toolTimeoutMs !== void 0 ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name) : await invocation;
889
951
  }
890
952
  const executionMs = Date.now() - startedAt2;
@@ -1001,6 +1063,7 @@ export {
1001
1063
  AGENT_ROLES_POLICY,
1002
1064
  AGENT_RUNNER,
1003
1065
  AGENT_SINK,
1066
+ AGENT_SPAN_EVENTS,
1004
1067
  AGENT_STORE,
1005
1068
  AGENT_TOOL_REGISTRY,
1006
1069
  AgentRegistry,
@@ -1031,6 +1094,8 @@ export {
1031
1094
  publishAgentToolCall,
1032
1095
  runAgentLoop,
1033
1096
  seedModelPrices,
1097
+ traceLlmTurn,
1098
+ traceToolExecution,
1034
1099
  withToolTimeout
1035
1100
  };
1036
1101
  //# sourceMappingURL=index.js.map