@dudousxd/nestjs-agent-core 0.39.0 → 0.41.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 (40) hide show
  1. package/README.md +7 -0
  2. package/dist/ag-ui/index.cjs +123 -9
  3. package/dist/ag-ui/index.cjs.map +1 -1
  4. package/dist/ag-ui/index.d.cts +19 -3
  5. package/dist/ag-ui/index.d.ts +19 -3
  6. package/dist/ag-ui/index.js +122 -9
  7. package/dist/ag-ui/index.js.map +1 -1
  8. package/dist/{catalog-CrzetM3_.d.cts → catalog-BKS3Yxo6.d.cts} +2 -0
  9. package/dist/{catalog-CrzetM3_.d.ts → catalog-BKS3Yxo6.d.ts} +2 -0
  10. package/dist/genui/builtins.cjs +2 -0
  11. package/dist/genui/builtins.cjs.map +1 -1
  12. package/dist/genui/builtins.d.cts +1 -1
  13. package/dist/genui/builtins.d.ts +1 -1
  14. package/dist/genui/builtins.js +2 -0
  15. package/dist/genui/builtins.js.map +1 -1
  16. package/dist/genui/index.cjs +780 -106
  17. package/dist/genui/index.cjs.map +1 -1
  18. package/dist/genui/index.d.cts +5 -5
  19. package/dist/genui/index.d.ts +5 -5
  20. package/dist/genui/index.js +770 -105
  21. package/dist/genui/index.js.map +1 -1
  22. package/dist/guardrails/index.cjs +3 -1
  23. package/dist/guardrails/index.cjs.map +1 -1
  24. package/dist/guardrails/index.d.cts +5 -4
  25. package/dist/guardrails/index.d.ts +5 -4
  26. package/dist/guardrails/index.js +3 -1
  27. package/dist/guardrails/index.js.map +1 -1
  28. package/dist/index.cjs +3324 -380
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +388 -96
  31. package/dist/index.d.ts +388 -96
  32. package/dist/index.js +3279 -377
  33. package/dist/index.js.map +1 -1
  34. package/dist/{processors-6p9nrqEi.d.cts → processors-BXM-MNga.d.cts} +1 -1
  35. package/dist/{processors-Bp5XmF6V.d.ts → processors-ByDr5POu.d.ts} +1 -1
  36. package/dist/{stream-events-CbVEowYb.d.cts → stream-events-BGKLD6RX.d.ts} +664 -86
  37. package/dist/{stream-events-CbVEowYb.d.ts → stream-events-CF-6-Y6L.d.cts} +664 -86
  38. package/package.json +1 -1
  39. package/dist/tool-DZYLEKnl.d.cts +0 -121
  40. package/dist/tool-_iq4xRyk.d.ts +0 -121
package/README.md CHANGED
@@ -16,6 +16,13 @@ provider, a store, a sink) against the SPIs.
16
16
  import type { ModelProvider, AgentStore, ToolSpec, RolesPolicy } from '@dudousxd/nestjs-agent-core';
17
17
  ```
18
18
 
19
+ ## Component registries and server rendering
20
+
21
+ Tools support a `present` hook in both functional and decorated class forms. Register custom components per app, share React renderers between web screens and static exports, and generate paginated PNG/PDF tables and charts for your own delivery adapters.
22
+
23
+ See the [component rendering guide](../../docs/component-rendering.md) for complete examples, schemas, text fallbacks, and capture configuration.
24
+
25
+
19
26
  ## Key types
20
27
 
21
28
  - `ToolSpec` — `{ name, kind: 'read' | 'action' | 'agent', description, inputSchema, roles?, ability?, targetAgent?, detached?, terminal? }`. (`ToolKind` has three further members — `'ask'`, `'skill'` and `'memory'` — which no `ToolSpec` carries: they belong to the built-in tools the loop serves itself rather than from a handler. `ask` settles against a person, `skill` against the turn's journaled catalog, `remember` against the turn's journaled memory digest.) `inputSchema` is a [Standard Schema](https://standardschema.dev) (Zod, Valibot, ArkType); the loop validates via `~standard.validate`, throwing `ToolInputInvalidError` on failure.
@@ -24,6 +24,7 @@ __export(ag_ui_exports, {
24
24
  AG_UI_CUSTOM: () => AG_UI_CUSTOM,
25
25
  AG_UI_PROTOCOL_VERSION: () => AG_UI_PROTOCOL_VERSION,
26
26
  AgUiEncoder: () => AgUiEncoder,
27
+ actionProposalDecisionEvents: () => actionProposalDecisionEvents,
27
28
  agUiEvents: () => agUiEvents,
28
29
  agUiFramesFromNdjson: () => agUiFramesFromNdjson,
29
30
  agUiSse: () => agUiSse,
@@ -40,15 +41,21 @@ __export(ag_ui_exports, {
40
41
  module.exports = __toCommonJS(ag_ui_exports);
41
42
 
42
43
  // src/ag-ui/interrupt-id.ts
44
+ var KIND_CODES = {
45
+ approval: "a",
46
+ elicitation: "e",
47
+ proposal: "p"
48
+ };
43
49
  var PREFIX = "agora_";
44
50
  function encodeInterruptId(address) {
45
51
  const compact = [
46
- address.kind === "approval" ? "a" : "e",
52
+ KIND_CODES[address.kind],
47
53
  address.parked,
48
54
  address.stream,
49
55
  address.toolCallId,
50
56
  address.position
51
57
  ];
58
+ if (address.kind === "proposal") compact.push(address.proposalId, address.threadId);
52
59
  return PREFIX + Buffer.from(JSON.stringify(compact), "utf8").toString("base64url");
53
60
  }
54
61
  __name(encodeInterruptId, "encodeInterruptId");
@@ -56,17 +63,21 @@ function decodeInterruptId(id) {
56
63
  if (typeof id !== "string" || !id.startsWith(PREFIX)) return null;
57
64
  try {
58
65
  const parsed = JSON.parse(Buffer.from(id.slice(PREFIX.length), "base64url").toString("utf8"));
59
- if (!Array.isArray(parsed) || parsed.length !== 5) return null;
60
- const [kind, parked, stream, toolCallId, position] = parsed;
61
- if (kind !== "a" && kind !== "e" || typeof parked !== "string" || typeof stream !== "string" || typeof toolCallId !== "string" || typeof position !== "number" || !Number.isSafeInteger(position) || position < 0) {
66
+ if (!Array.isArray(parsed)) return null;
67
+ const [kind, parked, stream, toolCallId, position, proposalId, threadId] = parsed;
68
+ if (parsed.length !== (kind === "p" ? 7 : 5) || kind === "p" && (typeof proposalId !== "string" || typeof threadId !== "string") || kind !== "a" && kind !== "e" && kind !== "p" || typeof parked !== "string" || typeof stream !== "string" || typeof toolCallId !== "string" || typeof position !== "number" || !Number.isSafeInteger(position) || position < 0) {
62
69
  return null;
63
70
  }
64
71
  return {
65
- kind: kind === "a" ? "approval" : "elicitation",
72
+ kind: kind === "a" ? "approval" : kind === "e" ? "elicitation" : "proposal",
66
73
  parked,
67
74
  stream,
68
75
  toolCallId,
69
- position
76
+ position,
77
+ ...kind === "p" ? {
78
+ proposalId,
79
+ threadId
80
+ } : {}
70
81
  };
71
82
  } catch {
72
83
  return null;
@@ -90,6 +101,8 @@ var AG_UI_CUSTOM = {
90
101
  elicitation: "agora.elicitation",
91
102
  /** `{ usage, costUsd, reasoningMs }` of one model step. */
92
103
  stepUsage: "agora.step-usage",
104
+ /** A proposal decided by a text message or an interrupt resume, with no model run behind it. */
105
+ actionProposalDecision: "agora.action-proposal-decision",
93
106
  /** `{ message }` — input material this producer could not use and dropped. */
94
107
  warning: "agora.warning"
95
108
  };
@@ -277,6 +290,13 @@ var AgUiEncoder = class {
277
290
  ...event.version !== void 0 ? {
278
291
  version: event.version
279
292
  } : {},
293
+ // What a client that cannot draw the component shows instead.
294
+ ...event.fallbackText !== void 0 ? {
295
+ fallbackText: event.fallbackText
296
+ } : {},
297
+ ...event.componentVersions !== void 0 ? {
298
+ componentVersions: event.componentVersions
299
+ } : {},
280
300
  ...event.toolCallId !== void 0 ? {
281
301
  toolCallId: event.toolCallId
282
302
  } : {}
@@ -287,10 +307,14 @@ var AgUiEncoder = class {
287
307
  const parked = event.runId ?? this.options.streamRunId;
288
308
  const toolName = event.toolName ?? call?.name ?? "";
289
309
  const input = event.input ?? call?.input ?? null;
310
+ const proposal = event.target?.kind === "proposal" ? event.target : void 0;
290
311
  this.pending.set(event.id, {
291
- kind: "approval",
312
+ kind: proposal !== void 0 ? "proposal" : "approval",
292
313
  parked,
293
314
  toolCallId: event.id,
315
+ ...proposal !== void 0 ? {
316
+ proposalId: proposal.proposalId
317
+ } : {},
294
318
  interrupt: {
295
319
  reason: "tool_approval",
296
320
  message: event.reason ?? (toolName.length > 0 ? `Approve ${toolName}?` : "Approve?"),
@@ -302,7 +326,10 @@ var AgUiEncoder = class {
302
326
  metadata: {
303
327
  "agora.toolName": toolName,
304
328
  "agora.input": input,
305
- "agora.approver": event.approver
329
+ "agora.approver": event.approver,
330
+ ...event.target !== void 0 ? {
331
+ "agora.target": event.target
332
+ } : {}
306
333
  }
307
334
  }
308
335
  });
@@ -313,6 +340,12 @@ var AgUiEncoder = class {
313
340
  toolName,
314
341
  input,
315
342
  approver: event.approver,
343
+ ...event.target !== void 0 ? {
344
+ target: event.target
345
+ } : {},
346
+ ...event.confirmation !== void 0 ? {
347
+ confirmation: event.confirmation
348
+ } : {},
316
349
  ...event.expiresAt !== void 0 ? {
317
350
  expiresAt: event.expiresAt
318
351
  } : {},
@@ -540,7 +573,11 @@ var AgUiEncoder = class {
540
573
  parked: entry.parked,
541
574
  stream: this.options.streamRunId,
542
575
  toolCallId: entry.toolCallId,
543
- position: this.position
576
+ position: this.position,
577
+ ...entry.proposalId !== void 0 ? {
578
+ proposalId: entry.proposalId,
579
+ threadId: this.options.streamThreadId ?? this.options.threadId
580
+ } : {}
544
581
  }),
545
582
  ...entry.interrupt
546
583
  }));
@@ -693,6 +730,31 @@ var AgUiEncoder = class {
693
730
  }
694
731
  };
695
732
 
733
+ // src/genui/catalog.ts
734
+ var COMPONENT_NAME = /^[A-Za-z][A-Za-z0-9]{0,63}$/;
735
+
736
+ // src/genui/capabilities.ts
737
+ function validateUiCapabilities(value) {
738
+ if (!record(value) || Object.keys(value).some((key) => key !== "components") || !Array.isArray(value.components)) throw new TypeError("Invalid UI capabilities");
739
+ const seen = /* @__PURE__ */ new Set();
740
+ const components = value.components.map((component) => {
741
+ if (!record(component) || Object.keys(component).some((key) => key !== "name" && key !== "version") || typeof component.name !== "string" || !COMPONENT_NAME.test(component.name) || !Number.isSafeInteger(component.version) || Number(component.version) <= 0 || seen.has(component.name)) throw new TypeError("Invalid UI component capability");
742
+ seen.add(component.name);
743
+ return {
744
+ name: component.name,
745
+ version: Number(component.version)
746
+ };
747
+ });
748
+ return {
749
+ components
750
+ };
751
+ }
752
+ __name(validateUiCapabilities, "validateUiCapabilities");
753
+ function record(value) {
754
+ return typeof value === "object" && value !== null && !Array.isArray(value);
755
+ }
756
+ __name(record, "record");
757
+
696
758
  // src/ag-ui/input.ts
697
759
  function isRecord(value) {
698
760
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -724,6 +786,13 @@ function parseRunInput(body) {
724
786
  if (body.context !== void 0 && !Array.isArray(body.context)) {
725
787
  return "context must be an array";
726
788
  }
789
+ if (isRecord(body.forwardedProps) && Object.hasOwn(body.forwardedProps, "uiCapabilities")) {
790
+ try {
791
+ validateUiCapabilities(body.forwardedProps.uiCapabilities);
792
+ } catch {
793
+ return "forwardedProps.uiCapabilities must be valid UI capabilities";
794
+ }
795
+ }
727
796
  return body;
728
797
  }
729
798
  __name(parseRunInput, "parseRunInput");
@@ -828,6 +897,9 @@ function readForwardedProps(forwarded) {
828
897
  const model = pick("model");
829
898
  const persona = pick("persona");
830
899
  return {
900
+ ...Object.hasOwn(forwarded, "uiCapabilities") ? {
901
+ uiCapabilities: validateUiCapabilities(forwarded.uiCapabilities)
902
+ } : {},
831
903
  ...agent !== void 0 ? {
832
904
  agent
833
905
  } : {},
@@ -1043,11 +1115,53 @@ async function* agUiFramesFromNdjson(chunks) {
1043
1115
  }
1044
1116
  }
1045
1117
  __name(agUiFramesFromNdjson, "agUiFramesFromNdjson");
1118
+
1119
+ // src/ag-ui/proposal-decision.ts
1120
+ function actionProposalDecisionEvents(input) {
1121
+ const messageId = `${input.runId}:proposal-decision`;
1122
+ return [
1123
+ {
1124
+ type: "RUN_STARTED",
1125
+ threadId: input.threadId,
1126
+ runId: input.runId,
1127
+ protocolVersion: AG_UI_PROTOCOL_VERSION
1128
+ },
1129
+ {
1130
+ type: "CUSTOM",
1131
+ name: AG_UI_CUSTOM.actionProposalDecision,
1132
+ value: {
1133
+ threadId: input.threadId,
1134
+ proposalDecision: input.proposalDecision
1135
+ }
1136
+ },
1137
+ {
1138
+ type: "TEXT_MESSAGE_START",
1139
+ messageId,
1140
+ role: "assistant"
1141
+ },
1142
+ {
1143
+ type: "TEXT_MESSAGE_CONTENT",
1144
+ messageId,
1145
+ delta: input.text
1146
+ },
1147
+ {
1148
+ type: "TEXT_MESSAGE_END",
1149
+ messageId
1150
+ },
1151
+ {
1152
+ type: "RUN_FINISHED",
1153
+ threadId: input.threadId,
1154
+ runId: input.runId
1155
+ }
1156
+ ];
1157
+ }
1158
+ __name(actionProposalDecisionEvents, "actionProposalDecisionEvents");
1046
1159
  // Annotate the CommonJS export names for ESM import in node:
1047
1160
  0 && (module.exports = {
1048
1161
  AG_UI_CUSTOM,
1049
1162
  AG_UI_PROTOCOL_VERSION,
1050
1163
  AgUiEncoder,
1164
+ actionProposalDecisionEvents,
1051
1165
  agUiEvents,
1052
1166
  agUiFramesFromNdjson,
1053
1167
  agUiSse,