@dudousxd/nestjs-agent 1.28.0 → 1.29.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.cts CHANGED
@@ -7,8 +7,8 @@ export * from '@dudousxd/nestjs-agent-core';
7
7
  export { FunctionalToolDefinition } from '@dudousxd/nestjs-agent-core';
8
8
  import { A2uiOptions } from '@dudousxd/nestjs-agent-core/a2ui';
9
9
  import { Request, Response } from 'express';
10
- import { A as AgentService, a as ActionProposalService } from './index-C-Zo8rTL.cjs';
11
- export { b as A2uiAdapterOptions, c as A2uiRunHandler, d as AttachmentLimits, C as ChatParams, e as ChatSendMode, f as ChatSendResult, D as DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES, g as DEFAULT_MAX_ATTACHMENT_BYTES, M as MAX_ATTACHMENTS_PER_MESSAGE, N as NO_USER_MESSAGE_CODE, Q as QueuedSend, T as ThreadDefaultAgentReader, h as ThreadModelReader, i as a2uiAdapter, j as attachmentLimits } from './index-C-Zo8rTL.cjs';
10
+ import { A as AgentService, a as ActionProposalService } from './index-D9EM7ivO.cjs';
11
+ export { b as A2uiAdapterOptions, c as A2uiRunHandler, d as AttachmentLimits, C as ChatParams, e as ChatSendMode, f as ChatSendResult, D as DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES, g as DEFAULT_MAX_ATTACHMENT_BYTES, M as MAX_ATTACHMENTS_PER_MESSAGE, N as NO_USER_MESSAGE_CODE, Q as QueuedSend, T as ThreadDefaultAgentReader, h as ThreadModelReader, i as a2uiAdapter, j as attachmentLimits } from './index-D9EM7ivO.cjs';
12
12
  import { StandardSchemaV1 } from '@standard-schema/spec';
13
13
  import { DiscoveryService, MetadataScanner } from '@nestjs/core';
14
14
  import '@dudousxd/nestjs-agent-core/genui';
@@ -33,6 +33,11 @@ interface AgUiAdapterOptions {
33
33
  * any client of AG-UI's A2UI binding — draws it. `true` maps the library builtins onto A2UI's
34
34
  * basic catalog; pass {@link A2uiOptions} for the app's own mappings or catalog. Inbound,
35
35
  * `forwardedProps.a2uiAction.userAction` is always read: the action becomes the user's turn.
36
+ *
37
+ * The basic catalog goes under the id the client advertises — `forwardedProps
38
+ * .a2uiClientCapabilities`, or the "A2UI catalog capabilities" context entry CopilotKit sends —
39
+ * and, when it advertises none, under the id AG-UI's A2UI binding uses
40
+ * (`A2UI_LEGACY_BASIC_CATALOG_ID`: CopilotKit 1.77, `@ag-ui/a2ui-middleware`).
36
41
  */
37
42
  a2ui?: boolean | A2uiOptions;
38
43
  }
@@ -73,6 +78,8 @@ declare class AgUiRunHandler {
73
78
  private decideProposals;
74
79
  /** Answer with a complete list of events, no run behind them. */
75
80
  private writeEvents;
81
+ /** A2UI for this request's client: the basic catalog under the id it advertises. Off when off. */
82
+ private a2uiFor;
76
83
  /**
77
84
  * Pipe a run to the client as AG-UI 1.0 over SSE: one event per `data:` line, from `RUN_STARTED`
78
85
  * to the run's terminal event. It ends when the run stops to ask — the library run stays parked,
package/dist/index.d.ts CHANGED
@@ -7,8 +7,8 @@ export * from '@dudousxd/nestjs-agent-core';
7
7
  export { FunctionalToolDefinition } from '@dudousxd/nestjs-agent-core';
8
8
  import { A2uiOptions } from '@dudousxd/nestjs-agent-core/a2ui';
9
9
  import { Request, Response } from 'express';
10
- import { A as AgentService, a as ActionProposalService } from './index-CBO7egb7.js';
11
- export { b as A2uiAdapterOptions, c as A2uiRunHandler, d as AttachmentLimits, C as ChatParams, e as ChatSendMode, f as ChatSendResult, D as DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES, g as DEFAULT_MAX_ATTACHMENT_BYTES, M as MAX_ATTACHMENTS_PER_MESSAGE, N as NO_USER_MESSAGE_CODE, Q as QueuedSend, T as ThreadDefaultAgentReader, h as ThreadModelReader, i as a2uiAdapter, j as attachmentLimits } from './index-CBO7egb7.js';
10
+ import { A as AgentService, a as ActionProposalService } from './index-APh8WN3z.js';
11
+ export { b as A2uiAdapterOptions, c as A2uiRunHandler, d as AttachmentLimits, C as ChatParams, e as ChatSendMode, f as ChatSendResult, D as DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES, g as DEFAULT_MAX_ATTACHMENT_BYTES, M as MAX_ATTACHMENTS_PER_MESSAGE, N as NO_USER_MESSAGE_CODE, Q as QueuedSend, T as ThreadDefaultAgentReader, h as ThreadModelReader, i as a2uiAdapter, j as attachmentLimits } from './index-APh8WN3z.js';
12
12
  import { StandardSchemaV1 } from '@standard-schema/spec';
13
13
  import { DiscoveryService, MetadataScanner } from '@nestjs/core';
14
14
  import '@dudousxd/nestjs-agent-core/genui';
@@ -33,6 +33,11 @@ interface AgUiAdapterOptions {
33
33
  * any client of AG-UI's A2UI binding — draws it. `true` maps the library builtins onto A2UI's
34
34
  * basic catalog; pass {@link A2uiOptions} for the app's own mappings or catalog. Inbound,
35
35
  * `forwardedProps.a2uiAction.userAction` is always read: the action becomes the user's turn.
36
+ *
37
+ * The basic catalog goes under the id the client advertises — `forwardedProps
38
+ * .a2uiClientCapabilities`, or the "A2UI catalog capabilities" context entry CopilotKit sends —
39
+ * and, when it advertises none, under the id AG-UI's A2UI binding uses
40
+ * (`A2UI_LEGACY_BASIC_CATALOG_ID`: CopilotKit 1.77, `@ag-ui/a2ui-middleware`).
36
41
  */
37
42
  a2ui?: boolean | A2uiOptions;
38
43
  }
@@ -73,6 +78,8 @@ declare class AgUiRunHandler {
73
78
  private decideProposals;
74
79
  /** Answer with a complete list of events, no run behind them. */
75
80
  private writeEvents;
81
+ /** A2UI for this request's client: the basic catalog under the id it advertises. Off when off. */
82
+ private a2uiFor;
76
83
  /**
77
84
  * Pipe a run to the client as AG-UI 1.0 over SSE: one event per `data:` line, from `RUN_STARTED`
78
85
  * to the run's terminal event. It ends when the run stops to ask — the library run stays parked,
package/dist/index.js CHANGED
@@ -6520,6 +6520,7 @@ AgentModule = _ts_decorate27([
6520
6520
 
6521
6521
  // src/ag-ui/ag-ui.adapter.ts
6522
6522
  import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER15, AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING5, AGENT_OPTIONS as AGENT_OPTIONS11 } from "@dudousxd/nestjs-agent-core";
6523
+ import { A2UI_LEGACY_BASIC_CATALOG_ID, negotiateA2uiCatalog, readAgUiA2uiCatalogIds } from "@dudousxd/nestjs-agent-core/a2ui";
6523
6524
  import { AG_UI_CUSTOM, actionProposalDecisionEvents, agUiEvents, agUiFramesFromNdjson, agUiSse, parseRunInput, planResume, readAnswersPayload, readApprovalPayload, readContext, readForwardedProps, readUserTurn } from "@dudousxd/nestjs-agent-core/ag-ui";
6524
6525
  import { uiActionText } from "@dudousxd/nestjs-agent-core/genui";
6525
6526
  import { BadRequestException as BadRequestException8, Body as Body7, Controller as Controller15, ForbiddenException as ForbiddenException4, HttpCode as HttpCode2, Inject as Inject26, Optional as Optional11, Post as Post8, Req as Req14, Res as Res3 } from "@nestjs/common";
@@ -6633,6 +6634,7 @@ var AgUiRunHandler = class {
6633
6634
  skip: first.address.position,
6634
6635
  answered: plan.decisions.map((decision) => decision.address.toolCallId),
6635
6636
  ...quiet,
6637
+ ...this.a2uiFor(input),
6636
6638
  preamble: warningEvents(warnings)
6637
6639
  });
6638
6640
  return;
@@ -6721,6 +6723,7 @@ var AgUiRunHandler = class {
6721
6723
  streamRunId: started.runId,
6722
6724
  streamThreadId: started.threadId,
6723
6725
  ...quiet,
6726
+ ...this.a2uiFor(input),
6724
6727
  preamble: warningEvents(warnings)
6725
6728
  });
6726
6729
  }
@@ -6867,6 +6870,13 @@ var AgUiRunHandler = class {
6867
6870
  for (const event of events) res.write(agUiSse(event));
6868
6871
  res.end();
6869
6872
  }
6873
+ /** A2UI for this request's client: the basic catalog under the id it advertises. Off when off. */
6874
+ a2uiFor(input) {
6875
+ if (this.a2ui === void 0) return {};
6876
+ return {
6877
+ a2ui: negotiateA2uiCatalog(this.a2ui, readAgUiA2uiCatalogIds(input), A2UI_LEGACY_BASIC_CATALOG_ID)
6878
+ };
6879
+ }
6870
6880
  /**
6871
6881
  * Pipe a run to the client as AG-UI 1.0 over SSE: one event per `data:` line, from `RUN_STARTED`
6872
6882
  * to the run's terminal event. It ends when the run stops to ask — the library run stays parked,
@@ -6886,12 +6896,8 @@ var AgUiRunHandler = class {
6886
6896
  };
6887
6897
  try {
6888
6898
  const frames = agUiFramesFromNdjson(this.agent.subscribe(runId));
6889
- const a2ui = this.a2ui !== void 0 ? {
6890
- a2ui: this.a2ui
6891
- } : {};
6892
6899
  for await (const event of agUiEvents(frames, {
6893
6900
  ...options,
6894
- ...a2ui,
6895
6901
  cursor
6896
6902
  })) {
6897
6903
  if (event.type === "RUN_FINISHED" || event.type === "RUN_ERROR") terminal = true;
@@ -6975,10 +6981,10 @@ __name(withCatalog, "withCatalog");
6975
6981
 
6976
6982
  // src/a2ui/a2ui.adapter.ts
6977
6983
  import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER16 } from "@dudousxd/nestjs-agent-core";
6978
- import { A2UI_APPROVE_ACTION, A2UI_REJECT_ACTION, A2uiProjector, readA2uiAction } from "@dudousxd/nestjs-agent-core/a2ui";
6984
+ import { A2UI_APPROVE_ACTION, A2UI_REJECT_ACTION, A2uiProjector, a2uiThreadReplay, negotiateA2uiCatalog as negotiateA2uiCatalog2, readA2uiAction, readA2uiClientCapabilities } from "@dudousxd/nestjs-agent-core/a2ui";
6979
6985
  import { agUiEvents as agUiEvents2, agUiFramesFromNdjson as agUiFramesFromNdjson2, decodeInterruptId } from "@dudousxd/nestjs-agent-core/ag-ui";
6980
6986
  import { uiActionText as uiActionText2, validateUiCapabilities as validateUiCapabilities2 } from "@dudousxd/nestjs-agent-core/genui";
6981
- import { BadRequestException as BadRequestException9, Body as Body8, Controller as Controller16, ForbiddenException as ForbiddenException5, HttpCode as HttpCode3, Inject as Inject27, Optional as Optional12, Post as Post9, Req as Req15, Res as Res4 } from "@nestjs/common";
6987
+ import { BadRequestException as BadRequestException9, Body as Body8, Controller as Controller16, ForbiddenException as ForbiddenException5, Get as Get13, HttpCode as HttpCode3, Inject as Inject27, Optional as Optional12, Param as Param7, Post as Post9, Query as Query7, Req as Req15, Res as Res4 } from "@nestjs/common";
6982
6988
  function _ts_decorate29(decorators, target, key, desc) {
6983
6989
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
6984
6990
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -7018,6 +7024,28 @@ function invalid2(code, message) {
7018
7024
  });
7019
7025
  }
7020
7026
  __name(invalid2, "invalid");
7027
+ function bodyField(body, key) {
7028
+ if (body[key] !== void 0) return body[key];
7029
+ return isRecord(body.metadata) ? body.metadata[key] : void 0;
7030
+ }
7031
+ __name(bodyField, "bodyField");
7032
+ function readDataModel(raw, maxBytes) {
7033
+ if (raw === void 0) return void 0;
7034
+ if (!isRecord(raw) || !isRecord(raw.surfaces)) {
7035
+ return "a2uiClientDataModel carries { version, surfaces }";
7036
+ }
7037
+ let size;
7038
+ try {
7039
+ size = new TextEncoder().encode(JSON.stringify(raw.surfaces)).length;
7040
+ } catch {
7041
+ return "a2uiClientDataModel must be JSON";
7042
+ }
7043
+ if (size > maxBytes) {
7044
+ return `a2uiClientDataModel may be at most ${maxBytes} bytes (this one is ${size})`;
7045
+ }
7046
+ return Object.keys(raw.surfaces).length > 0 ? raw.surfaces : void 0;
7047
+ }
7048
+ __name(readDataModel, "readDataModel");
7021
7049
  var A2uiRunHandler = class {
7022
7050
  static {
7023
7051
  __name(this, "A2uiRunHandler");
@@ -7027,17 +7055,43 @@ var A2uiRunHandler = class {
7027
7055
  projection;
7028
7056
  quietMs;
7029
7057
  maxActionBytes;
7030
- constructor(agent, actorResolver, projection, quietMs, maxActionBytes) {
7058
+ maxDataModelBytes;
7059
+ constructor(agent, actorResolver, projection, quietMs, maxActionBytes, maxDataModelBytes = void 0) {
7031
7060
  this.agent = agent;
7032
7061
  this.actorResolver = actorResolver;
7033
7062
  this.projection = projection;
7034
7063
  this.quietMs = quietMs;
7035
7064
  this.maxActionBytes = maxActionBytes;
7065
+ this.maxDataModelBytes = maxDataModelBytes;
7066
+ }
7067
+ /**
7068
+ * `GET <path>/a2ui/threads/:threadId`: a stored thread as `{ threadId, entries }`
7069
+ * (`a2uiThreadReplay`) — what a client draws again after a reload. Owner-scoped; a thread nobody
7070
+ * has answers `{ entries: [] }`. `?catalog=<id>` names the client's basic catalog id.
7071
+ */
7072
+ async replay(req, threadId, catalog) {
7073
+ const actor = await this.actorResolver.resolve(req);
7074
+ const owner = await this.agent.threadOwner(threadId);
7075
+ if (owner === null) return {
7076
+ threadId,
7077
+ entries: []
7078
+ };
7079
+ const thread = await this.agent.getThread(actor, threadId);
7080
+ const supported = typeof catalog === "string" ? [
7081
+ catalog
7082
+ ] : Array.isArray(catalog) ? catalog.filter((id) => typeof id === "string") : void 0;
7083
+ return {
7084
+ threadId,
7085
+ entries: a2uiThreadReplay(thread?.messages ?? [], negotiateA2uiCatalog2(this.projection, supported))
7086
+ };
7036
7087
  }
7037
7088
  async handle(req, res, raw) {
7038
7089
  const body = isRecord(raw) ? raw : {};
7039
7090
  const agentName = typeof body.agent === "string" && body.agent.length > 0 ? body.agent : void 0;
7040
7091
  const actor = await this.actorResolver.resolve(req);
7092
+ const projection = negotiateA2uiCatalog2(this.projection, readA2uiClientCapabilities(bodyField(body, "a2uiClientCapabilities")));
7093
+ const dataModel = readDataModel(bodyField(body, "a2uiClientDataModel"), this.maxDataModelBytes ?? 32768);
7094
+ if (typeof dataModel === "string") throw invalid2("invalid_data_model", dataModel);
7041
7095
  let action;
7042
7096
  if (body.action !== void 0) {
7043
7097
  const read = isRecord(body.action) ? readA2uiAction(body.action, {
@@ -7065,7 +7119,7 @@ var A2uiRunHandler = class {
7065
7119
  this.writeHead(res, {
7066
7120
  "X-Agent-Thread-Id": address.threadId
7067
7121
  });
7068
- const projector = new A2uiProjector(this.projection);
7122
+ const projector = new A2uiProjector(projection);
7069
7123
  const messageId = `proposal-${address.proposalId}`;
7070
7124
  for (const event of [
7071
7125
  {
@@ -7100,7 +7154,8 @@ var A2uiRunHandler = class {
7100
7154
  skip: address.position,
7101
7155
  answered: [
7102
7156
  address.toolCallId
7103
- ]
7157
+ ],
7158
+ projection
7104
7159
  });
7105
7160
  return;
7106
7161
  }
@@ -7135,10 +7190,16 @@ var A2uiRunHandler = class {
7135
7190
  } : {},
7136
7191
  ...uiCapabilities !== void 0 ? {
7137
7192
  uiCapabilities
7193
+ } : {},
7194
+ ...dataModel !== void 0 ? {
7195
+ pageContext: {
7196
+ a2uiDataModel: dataModel
7197
+ }
7138
7198
  } : {}
7139
7199
  });
7140
7200
  await this.stream(res, started.runId, {
7141
- threadId: started.threadId
7201
+ threadId: started.threadId,
7202
+ projection
7142
7203
  });
7143
7204
  }
7144
7205
  /** Open the JSON Lines response. */
@@ -7159,7 +7220,7 @@ var A2uiRunHandler = class {
7159
7220
  "X-Agent-Thread-Id": options.threadId
7160
7221
  } : {}
7161
7222
  });
7162
- const projector = new A2uiProjector(this.projection);
7223
+ const projector = new A2uiProjector(options.projection ?? this.projection);
7163
7224
  const write = /* @__PURE__ */ __name((messages) => {
7164
7225
  for (const message of messages) res.write(`${JSON.stringify(message)}
7165
7226
  `);
@@ -7196,7 +7257,7 @@ var A2uiRunHandler = class {
7196
7257
  };
7197
7258
  function a2uiAdapter(options = {}) {
7198
7259
  const path = (options.path ?? "a2ui").replace(/^\/+|\/+$/g, "");
7199
- const { path: _path, quietMs, maxActionBytes, ...projection } = options;
7260
+ const { path: _path, quietMs, maxActionBytes, maxDataModelBytes, ...projection } = options;
7200
7261
  let A2uiController = class A2uiController extends A2uiRunHandler {
7201
7262
  static {
7202
7263
  __name(this, "A2uiController");
@@ -7205,12 +7266,28 @@ function a2uiAdapter(options = {}) {
7205
7266
  super(agent, actorResolver, projection.catalog === void 0 && catalog !== void 0 ? {
7206
7267
  ...projection,
7207
7268
  catalog
7208
- } : projection, quietMs, maxActionBytes);
7269
+ } : projection, quietMs, maxActionBytes, maxDataModelBytes);
7270
+ }
7271
+ thread(req, threadId, catalog) {
7272
+ return this.replay(req, threadId, catalog);
7209
7273
  }
7210
7274
  run(req, res, body) {
7211
7275
  return this.handle(req, res, body);
7212
7276
  }
7213
7277
  };
7278
+ _ts_decorate29([
7279
+ Get13(`${path}/threads/:threadId`),
7280
+ _ts_param27(0, Req15()),
7281
+ _ts_param27(1, Param7("threadId")),
7282
+ _ts_param27(2, Query7("catalog")),
7283
+ _ts_metadata27("design:type", Function),
7284
+ _ts_metadata27("design:paramtypes", [
7285
+ typeof Request === "undefined" ? Object : Request,
7286
+ String,
7287
+ Object
7288
+ ]),
7289
+ _ts_metadata27("design:returntype", typeof ReturnType === "undefined" ? Object : ReturnType)
7290
+ ], A2uiController.prototype, "thread", null);
7214
7291
  _ts_decorate29([
7215
7292
  Post9(path),
7216
7293
  HttpCode3(200),