@dudousxd/nestjs-agent 1.22.0 → 1.23.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.
@@ -1,7 +1,7 @@
1
1
  import { ResolveToolUiCatalog, ModelProvider, AgentStore, ToolRegistry, RolesPolicy, ApprovalPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, Persona, ToolTransientRetrySetting, Retriever, AgentPricingStore, HistoryPolicy, InputProcessor, OutputProcessor, AgentIntake, SkillsConfig, MemoryConfig, ToolSpec, ToolHandler, createFunctionalTool, QuotaProvider, QuotaQuery, QuotaReport, ActionApprovalMode, BackgroundActorResolver, TextActionProposalConfig, ModelCatalog, EmptyRoles, ActorResolver, AgentHistoryWindow, SkillProvider, ScopeResolver, MemoryProvider, AgentRegistry, PersonaCatalogEntry, ActionProposal, Actor, AttachmentStagingStore, ChatQueueStore, ChatQueueState, AgentRunner, AgentRunInput, AgentStreamEvent, QueuePauseReason } from '@dudousxd/nestjs-agent-core';
2
2
  import { Catalog } from '@dudousxd/nestjs-agent-core/genui';
3
3
  import { StandardSchemaV1 } from '@standard-schema/spec';
4
- import { Provider, FactoryProvider, Type, CanActivate, ModuleMetadata, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';
4
+ import { Provider, InjectionToken, Type, FactoryProvider, CanActivate, ModuleMetadata, OptionalFactoryDependency } from '@nestjs/common';
5
5
  import { GenuiCatalogResolver } from './genui/index.js';
6
6
 
7
7
  /** Everything `runAgentLoop` needs, minus the per-run `day` the runner stamps. */
@@ -72,6 +72,34 @@ interface AgentDeps {
72
72
  }
73
73
  declare function utcDay(date?: Date): string;
74
74
 
75
+ /**
76
+ * Something other than this library's loop that runs a turn — what `engine` on
77
+ * `AgentModule.forRoot` takes. An engine owns the turn end to end (the model calls, the tools, the
78
+ * context it keeps), and contributes the `AgentRunner` that `AGENT_RUNNER` binds to; everything
79
+ * around the turn stays the library's: the routes and the stream protocol, threads and the store,
80
+ * the sink, approvals and answers routed through `AgentService`, the queue and the quota.
81
+ *
82
+ * `openCode()` (`@dudousxd/nestjs-agent-opencode`) is the one that ships. An engine replaces the
83
+ * loop, so the options only the loop reads (`model`, processors, `outputSchema`, `maxSteps`,
84
+ * `history`, `retrieval`) do nothing under one; `model` becomes optional.
85
+ */
86
+ interface AgentEngine {
87
+ /** For logs and diagnostics. */
88
+ name: string;
89
+ /** The providers the engine needs, its runner among them. */
90
+ providers: Provider[];
91
+ /** The token of the engine's `AgentRunner`, which `AGENT_RUNNER` is bound to. */
92
+ runner: InjectionToken;
93
+ /** Providers the app may inject too (the module is global): e.g. what an MCP surface hooks into. */
94
+ exports?: InjectionToken[];
95
+ /**
96
+ * Controllers the engine mounts under the agent's path (e.g. the endpoint its own runtime calls
97
+ * back into). Not mounted on `surface: 'engine'`, and the module's `guards` are NOT applied: an
98
+ * engine's controller authenticates its own callers, which are not the app's users.
99
+ */
100
+ controllers?: Type<object>[];
101
+ }
102
+
75
103
  /**
76
104
  * Brand stamped onto a functional-tool provider instance so `AiToolDiscoveryService` picks it up
77
105
  * when it walks every provider at boot — the declarative alternative to a manual `registry.register`.
@@ -284,9 +312,16 @@ interface AgentModuleOptions {
284
312
  actionProposalText?: TextActionProposalConfig;
285
313
  /**
286
314
  * The LLM provider — `aiSdkModel(openai('gpt-5-mini'))`, or `aiSdkModels({ … })` for a model
287
- * picker (its catalog is used when `models` is omitted). The only required option.
315
+ * picker (its catalog is used when `models` is omitted). Required unless an `engine` runs the
316
+ * turns instead.
288
317
  */
289
- model: ModelProvider;
318
+ model?: ModelProvider;
319
+ /**
320
+ * Run turns on something other than this library's loop — e.g. `openCode({ host })`. The engine
321
+ * binds `AGENT_RUNNER`; the routes, store, sink, approvals and queue stay the library's. STATIC
322
+ * wiring, like `durable` (see {@link AgentEngine}). Omit → the loop, on `model`.
323
+ */
324
+ engine?: AgentEngine;
290
325
  /**
291
326
  * The base prompt of the default agent (and of any `@Agent` that declares none) — a string, or a
292
327
  * function of the turn's `{ actor, agentName, pageContext }`. Omit → `'You are a helpful
@@ -540,6 +575,11 @@ interface AgentModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
540
575
  surface?: AgentSurface;
541
576
  /** Wire protocols served alongside the native one — see `AgentModuleOptions.adapters`. STATIC. */
542
577
  adapters?: AgentProtocolAdapter[];
578
+ /**
579
+ * What runs the turns instead of the loop — see `AgentModuleOptions.engine`. STATIC, like
580
+ * `durable`: it decides which runner `AGENT_RUNNER` binds, before `useFactory` has resolved.
581
+ */
582
+ engine?: AgentEngine;
543
583
  }
544
584
 
545
585
  /**
@@ -760,4 +800,4 @@ declare class ChatQueueService {
760
800
  private freshAttachments;
761
801
  }
762
802
 
763
- export { AgentDepsFactory as A, ChatQueueService as C, type FunctionalTool as F, LedgerQuotaProvider as L, type QueuePlan as Q, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentProtocolAdapter as d, type AgentSkillsOptions as e, AGENT_TOOL_BRAND as f, type AgentAttachmentsOptions as g, type AgentDeps as h, type AgentMemoryOptions as i, type QueueSettleOutcome as j, type QueuedTurn as k, type QueuedTurnStarter as l, type QuotaLimits as m, type QuotaWindowLimits as n, defineTool as o, delegateToolName as p, provideAgentTool as q, provideAgentTools as r, utcDay as u };
803
+ export { AgentDepsFactory as A, ChatQueueService as C, type FunctionalTool as F, LedgerQuotaProvider as L, type QueuePlan as Q, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentProtocolAdapter as d, type AgentSkillsOptions as e, AGENT_TOOL_BRAND as f, type AgentAttachmentsOptions as g, type AgentDeps as h, type AgentEngine as i, type AgentMemoryOptions as j, type QueueSettleOutcome as k, type QueuedTurn as l, type QueuedTurnStarter as m, type QuotaLimits as n, type QuotaWindowLimits as o, defineTool as p, delegateToolName as q, provideAgentTool as r, provideAgentTools as s, utcDay as u };
@@ -1,7 +1,7 @@
1
1
  import { ResolveToolUiCatalog, ModelProvider, AgentStore, ToolRegistry, RolesPolicy, ApprovalPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, Persona, ToolTransientRetrySetting, Retriever, AgentPricingStore, HistoryPolicy, InputProcessor, OutputProcessor, AgentIntake, SkillsConfig, MemoryConfig, ToolSpec, ToolHandler, createFunctionalTool, QuotaProvider, QuotaQuery, QuotaReport, ActionApprovalMode, BackgroundActorResolver, TextActionProposalConfig, ModelCatalog, EmptyRoles, ActorResolver, AgentHistoryWindow, SkillProvider, ScopeResolver, MemoryProvider, AgentRegistry, PersonaCatalogEntry, ActionProposal, Actor, AttachmentStagingStore, ChatQueueStore, ChatQueueState, AgentRunner, AgentRunInput, AgentStreamEvent, QueuePauseReason } from '@dudousxd/nestjs-agent-core';
2
2
  import { Catalog } from '@dudousxd/nestjs-agent-core/genui';
3
3
  import { StandardSchemaV1 } from '@standard-schema/spec';
4
- import { Provider, FactoryProvider, Type, CanActivate, ModuleMetadata, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';
4
+ import { Provider, InjectionToken, Type, FactoryProvider, CanActivate, ModuleMetadata, OptionalFactoryDependency } from '@nestjs/common';
5
5
  import { GenuiCatalogResolver } from './genui/index.cjs';
6
6
 
7
7
  /** Everything `runAgentLoop` needs, minus the per-run `day` the runner stamps. */
@@ -72,6 +72,34 @@ interface AgentDeps {
72
72
  }
73
73
  declare function utcDay(date?: Date): string;
74
74
 
75
+ /**
76
+ * Something other than this library's loop that runs a turn — what `engine` on
77
+ * `AgentModule.forRoot` takes. An engine owns the turn end to end (the model calls, the tools, the
78
+ * context it keeps), and contributes the `AgentRunner` that `AGENT_RUNNER` binds to; everything
79
+ * around the turn stays the library's: the routes and the stream protocol, threads and the store,
80
+ * the sink, approvals and answers routed through `AgentService`, the queue and the quota.
81
+ *
82
+ * `openCode()` (`@dudousxd/nestjs-agent-opencode`) is the one that ships. An engine replaces the
83
+ * loop, so the options only the loop reads (`model`, processors, `outputSchema`, `maxSteps`,
84
+ * `history`, `retrieval`) do nothing under one; `model` becomes optional.
85
+ */
86
+ interface AgentEngine {
87
+ /** For logs and diagnostics. */
88
+ name: string;
89
+ /** The providers the engine needs, its runner among them. */
90
+ providers: Provider[];
91
+ /** The token of the engine's `AgentRunner`, which `AGENT_RUNNER` is bound to. */
92
+ runner: InjectionToken;
93
+ /** Providers the app may inject too (the module is global): e.g. what an MCP surface hooks into. */
94
+ exports?: InjectionToken[];
95
+ /**
96
+ * Controllers the engine mounts under the agent's path (e.g. the endpoint its own runtime calls
97
+ * back into). Not mounted on `surface: 'engine'`, and the module's `guards` are NOT applied: an
98
+ * engine's controller authenticates its own callers, which are not the app's users.
99
+ */
100
+ controllers?: Type<object>[];
101
+ }
102
+
75
103
  /**
76
104
  * Brand stamped onto a functional-tool provider instance so `AiToolDiscoveryService` picks it up
77
105
  * when it walks every provider at boot — the declarative alternative to a manual `registry.register`.
@@ -284,9 +312,16 @@ interface AgentModuleOptions {
284
312
  actionProposalText?: TextActionProposalConfig;
285
313
  /**
286
314
  * The LLM provider — `aiSdkModel(openai('gpt-5-mini'))`, or `aiSdkModels({ … })` for a model
287
- * picker (its catalog is used when `models` is omitted). The only required option.
315
+ * picker (its catalog is used when `models` is omitted). Required unless an `engine` runs the
316
+ * turns instead.
288
317
  */
289
- model: ModelProvider;
318
+ model?: ModelProvider;
319
+ /**
320
+ * Run turns on something other than this library's loop — e.g. `openCode({ host })`. The engine
321
+ * binds `AGENT_RUNNER`; the routes, store, sink, approvals and queue stay the library's. STATIC
322
+ * wiring, like `durable` (see {@link AgentEngine}). Omit → the loop, on `model`.
323
+ */
324
+ engine?: AgentEngine;
290
325
  /**
291
326
  * The base prompt of the default agent (and of any `@Agent` that declares none) — a string, or a
292
327
  * function of the turn's `{ actor, agentName, pageContext }`. Omit → `'You are a helpful
@@ -540,6 +575,11 @@ interface AgentModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
540
575
  surface?: AgentSurface;
541
576
  /** Wire protocols served alongside the native one — see `AgentModuleOptions.adapters`. STATIC. */
542
577
  adapters?: AgentProtocolAdapter[];
578
+ /**
579
+ * What runs the turns instead of the loop — see `AgentModuleOptions.engine`. STATIC, like
580
+ * `durable`: it decides which runner `AGENT_RUNNER` binds, before `useFactory` has resolved.
581
+ */
582
+ engine?: AgentEngine;
543
583
  }
544
584
 
545
585
  /**
@@ -760,4 +800,4 @@ declare class ChatQueueService {
760
800
  private freshAttachments;
761
801
  }
762
802
 
763
- export { AgentDepsFactory as A, ChatQueueService as C, type FunctionalTool as F, LedgerQuotaProvider as L, type QueuePlan as Q, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentProtocolAdapter as d, type AgentSkillsOptions as e, AGENT_TOOL_BRAND as f, type AgentAttachmentsOptions as g, type AgentDeps as h, type AgentMemoryOptions as i, type QueueSettleOutcome as j, type QueuedTurn as k, type QueuedTurnStarter as l, type QuotaLimits as m, type QuotaWindowLimits as n, defineTool as o, delegateToolName as p, provideAgentTool as q, provideAgentTools as r, utcDay as u };
803
+ export { AgentDepsFactory as A, ChatQueueService as C, type FunctionalTool as F, LedgerQuotaProvider as L, type QueuePlan as Q, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentProtocolAdapter as d, type AgentSkillsOptions as e, AGENT_TOOL_BRAND as f, type AgentAttachmentsOptions as g, type AgentDeps as h, type AgentEngine as i, type AgentMemoryOptions as j, type QueueSettleOutcome as k, type QueuedTurn as l, type QueuedTurnStarter as m, type QuotaLimits as n, type QuotaWindowLimits as o, defineTool as p, delegateToolName as q, provideAgentTool as r, provideAgentTools as s, utcDay as u };
@@ -2251,6 +2251,9 @@ var ChatQueueService2 = class _ChatQueueService {
2251
2251
  } : {},
2252
2252
  ...input.uiCapabilities !== void 0 ? {
2253
2253
  uiCapabilities: input.uiCapabilities
2254
+ } : {},
2255
+ ...input.hostContext !== void 0 ? {
2256
+ hostContext: input.hostContext
2254
2257
  } : {}
2255
2258
  });
2256
2259
  await store.setQueuePause(threadId, {
@@ -2336,6 +2339,9 @@ var ChatQueueService2 = class _ChatQueueService {
2336
2339
  ...message.uiCapabilities !== void 0 ? {
2337
2340
  uiCapabilities: message.uiCapabilities
2338
2341
  } : {},
2342
+ ...message.hostContext !== void 0 ? {
2343
+ hostContext: message.hostContext
2344
+ } : {},
2339
2345
  ...message.model !== void 0 ? {
2340
2346
  model: message.model
2341
2347
  } : {}
@@ -2706,6 +2712,9 @@ var AgentService = class {
2706
2712
  }
2707
2713
  const created = await this.store.createThread({
2708
2714
  actor: params.actor,
2715
+ ...agentName !== void 0 ? {
2716
+ agentName
2717
+ } : {},
2709
2718
  ...params.transient === true ? {
2710
2719
  transient: true
2711
2720
  } : {},
@@ -2718,7 +2727,7 @@ var AgentService = class {
2718
2727
  });
2719
2728
  threadId = created.id;
2720
2729
  } else {
2721
- await this.assertOwnsThread(params.actor, threadId);
2730
+ if (params.authorized !== true) await this.assertOwnsThread(params.actor, threadId);
2722
2731
  if (params.personaId !== void 0) {
2723
2732
  await this.pinThreadPersona(threadId, params.personaId);
2724
2733
  }
@@ -2744,6 +2753,9 @@ var AgentService = class {
2744
2753
  ...params.uiCapabilities !== void 0 ? {
2745
2754
  uiCapabilities: params.uiCapabilities
2746
2755
  } : {},
2756
+ ...params.hostContext !== void 0 ? {
2757
+ hostContext: params.hostContext
2758
+ } : {},
2747
2759
  ...model !== void 0 ? {
2748
2760
  model
2749
2761
  } : {}
@@ -2766,7 +2778,7 @@ var AgentService = class {
2766
2778
  });
2767
2779
  }
2768
2780
  if (live === null && mode !== "queue") {
2769
- const runId = crypto.randomUUID();
2781
+ const runId = this.runner.runIdFor?.(input) ?? crypto.randomUUID();
2770
2782
  if (await queue.queueStore().claimActiveStream(threadId, runId, stale !== null ? {
2771
2783
  replacing: stale
2772
2784
  } : {})) {
@@ -2834,6 +2846,9 @@ var AgentService = class {
2834
2846
  ...input.uiCapabilities !== void 0 ? {
2835
2847
  uiCapabilities: input.uiCapabilities
2836
2848
  } : {},
2849
+ ...input.hostContext !== void 0 ? {
2850
+ hostContext: input.hostContext
2851
+ } : {},
2837
2852
  ...interrupting !== void 0 ? {
2838
2853
  interrupt: true,
2839
2854
  at: "head"
@@ -6930,11 +6945,11 @@ function isQuotaProvider(quota) {
6930
6945
  __name(isQuotaProvider, "isQuotaProvider");
6931
6946
  function resolveCatalog(options) {
6932
6947
  if (options.models !== void 0) return options.models;
6933
- const carried = options.model.catalog;
6948
+ const carried = options.model?.catalog;
6934
6949
  return carried !== void 0 && typeof carried.list === "function" ? carried : void 0;
6935
6950
  }
6936
6951
  __name(resolveCatalog, "resolveCatalog");
6937
- function sharedProviders(durable) {
6952
+ function sharedProviders(durable, engine) {
6938
6953
  const providers = [
6939
6954
  {
6940
6955
  provide: import_nestjs_agent_core39.AGENT_TOOL_REGISTRY,
@@ -7065,7 +7080,12 @@ function sharedProviders(durable) {
7065
7080
  import_core4.ModulesContainer
7066
7081
  ]
7067
7082
  });
7068
- if (durable) {
7083
+ if (engine !== void 0) {
7084
+ providers.push(...engine.providers, {
7085
+ provide: import_nestjs_agent_core39.AGENT_RUNNER,
7086
+ useExisting: engine.runner
7087
+ });
7088
+ } else if (durable) {
7069
7089
  providers.push({
7070
7090
  provide: import_nestjs_agent_core39.AGENT_RUNNER,
7071
7091
  useFactory: /* @__PURE__ */ __name((durableRunner) => {
@@ -7090,8 +7110,9 @@ function sharedProviders(durable) {
7090
7110
  return providers;
7091
7111
  }
7092
7112
  __name(sharedProviders, "sharedProviders");
7093
- function exportsFor() {
7113
+ function exportsFor(engine) {
7094
7114
  return [
7115
+ ...engine?.exports ?? [],
7095
7116
  import_nestjs_agent_core39.AGENT_OPTIONS,
7096
7117
  import_nestjs_agent_core39.AGENT_TOOL_REGISTRY,
7097
7118
  import_nestjs_agent_core39.AGENT_REGISTRY,
@@ -7141,10 +7162,11 @@ function adapterProviders(adapters) {
7141
7162
  return (adapters ?? []).flatMap((adapter) => adapter.providers ?? []);
7142
7163
  }
7143
7164
  __name(adapterProviders, "adapterProviders");
7144
- function controllersForSurface(surface, adapters) {
7165
+ function controllersForSurface(surface, adapters, engine) {
7145
7166
  return surface === "engine" ? [] : [
7146
7167
  ...BASE_CONTROLLERS,
7147
- ...adapterControllers(adapters)
7168
+ ...adapterControllers(adapters),
7169
+ ...engine?.controllers ?? []
7148
7170
  ];
7149
7171
  }
7150
7172
  __name(controllersForSurface, "controllersForSurface");
@@ -7174,12 +7196,22 @@ function routerFor(path) {
7174
7196
  ]);
7175
7197
  }
7176
7198
  __name(routerFor, "routerFor");
7199
+ function assertRunnable(options) {
7200
+ if (options.engine !== void 0 && options.durable === true) {
7201
+ throw new Error(`AgentModule: \`durable: true\` runs turns on the library's loop, but the \`${options.engine.name}\` engine runs them instead. Drop \`durable\` (the engine decides how its turns survive a restart).`);
7202
+ }
7203
+ if (options.engine === void 0 && options.model === void 0) {
7204
+ throw new Error("AgentModule: set `model` (the loop runs the turns) or `engine` (something else does).");
7205
+ }
7206
+ }
7207
+ __name(assertRunnable, "assertRunnable");
7177
7208
  var AgentModule = class _AgentModule {
7178
7209
  static {
7179
7210
  __name(this, "AgentModule");
7180
7211
  }
7181
7212
  static forRoot(options) {
7182
7213
  const path = options.path ?? DEFAULT_PATH;
7214
+ assertRunnable(options);
7183
7215
  applyGuards(options.guards, options.adapters);
7184
7216
  return {
7185
7217
  module: _AgentModule,
@@ -7188,21 +7220,27 @@ var AgentModule = class _AgentModule {
7188
7220
  import_core4.DiscoveryModule,
7189
7221
  routerFor(path)
7190
7222
  ],
7191
- controllers: controllersForSurface(options.surface, options.adapters),
7223
+ controllers: controllersForSurface(options.surface, options.adapters, options.engine),
7192
7224
  providers: [
7193
7225
  {
7194
7226
  provide: import_nestjs_agent_core39.AGENT_OPTIONS,
7195
7227
  useValue: options
7196
7228
  },
7197
- ...sharedProviders(options.durable ?? false),
7229
+ ...sharedProviders(options.durable ?? false, options.engine),
7198
7230
  ...guardProviders(options.guards),
7199
7231
  ...adapterProviders(options.adapters)
7200
7232
  ],
7201
- exports: exportsFor()
7233
+ exports: exportsFor(options.engine)
7202
7234
  };
7203
7235
  }
7204
7236
  static forRootAsync(options) {
7205
7237
  const path = options.path ?? DEFAULT_PATH;
7238
+ if (options.engine !== void 0) {
7239
+ assertRunnable({
7240
+ engine: options.engine,
7241
+ durable: options.durable ?? false
7242
+ });
7243
+ }
7206
7244
  applyGuards(options.guards, options.adapters);
7207
7245
  return {
7208
7246
  module: _AgentModule,
@@ -7212,7 +7250,7 @@ var AgentModule = class _AgentModule {
7212
7250
  routerFor(path),
7213
7251
  ...options.imports ?? []
7214
7252
  ],
7215
- controllers: controllersForSurface(options.surface, options.adapters),
7253
+ controllers: controllersForSurface(options.surface, options.adapters, options.engine),
7216
7254
  providers: [
7217
7255
  {
7218
7256
  provide: import_nestjs_agent_core39.AGENT_OPTIONS,
@@ -7222,18 +7260,25 @@ var AgentModule = class _AgentModule {
7222
7260
  // anything today (AgentDurableModule takes its own mirror option — see its doc for why),
7223
7261
  // but it's stamped here too so the EFFECTIVE value is always observable off
7224
7262
  // AGENT_OPTIONS, sync or async alike.
7225
- useFactory: /* @__PURE__ */ __name(async (...args) => ({
7226
- ...await options.useFactory(...args),
7227
- durable: options.durable ?? false,
7228
- surface: options.surface ?? "both"
7229
- }), "useFactory"),
7263
+ useFactory: /* @__PURE__ */ __name(async (...args) => {
7264
+ const resolved = {
7265
+ ...await options.useFactory(...args),
7266
+ durable: options.durable ?? false,
7267
+ surface: options.surface ?? "both",
7268
+ ...options.engine !== void 0 ? {
7269
+ engine: options.engine
7270
+ } : {}
7271
+ };
7272
+ assertRunnable(resolved);
7273
+ return resolved;
7274
+ }, "useFactory"),
7230
7275
  inject: options.inject ?? []
7231
7276
  },
7232
- ...sharedProviders(options.durable ?? false),
7277
+ ...sharedProviders(options.durable ?? false, options.engine),
7233
7278
  ...guardProviders(options.guards),
7234
7279
  ...adapterProviders(options.adapters)
7235
7280
  ],
7236
- exports: exportsFor()
7281
+ exports: exportsFor(options.engine)
7237
7282
  };
7238
7283
  }
7239
7284
  };