@dudousxd/nestjs-agent-opencode 0.2.1 → 0.3.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,6 +1,6 @@
1
1
  import { AgentDepsFactory, ChatQueueService, AgentEngine } from '@dudousxd/nestjs-agent';
2
2
  import { ConflictException, Logger, OnApplicationShutdown, Type, InjectionToken, Provider } from '@nestjs/common';
3
- import { ElicitationRequest, CostSource, AgentRunInput, SinkWriter, AgentStore, ApprovalRequirement, MessageUsage, AgentUiComponent, HumanReply, Actor, StoredMessage, ToolRegistry, TokenStreamSink, SkillsConfig, MemoryConfig, AgentPricingStore, PriceCatalogOptions, RolesPolicy, RememberToolInput, AiToolCtx } from '@dudousxd/nestjs-agent-core';
3
+ import { ElicitationRequest, CostSource, AgentRunInput, SinkWriter, AgentStore, ApprovalRequirement, ToolPresentation, MessageUsage, AgentUiComponent, HumanReply, Actor, StoredMessage, ToolRegistry, TokenStreamSink, SkillsConfig, MemoryConfig, AgentPricingStore, PriceCatalogOptions, RolesPolicy, RememberToolInput, AiToolCtx } from '@dudousxd/nestjs-agent-core';
4
4
  import { IncomingMessage, ServerResponse } from 'node:http';
5
5
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
6
 
@@ -297,6 +297,15 @@ interface OpenCodeTurnArgs {
297
297
  store: AgentStore;
298
298
  /** What an action needs before it runs (the module's `ApprovalPolicy`). */
299
299
  approvalFor: (action: string) => Promise<ApprovalRequirement>;
300
+ /**
301
+ * The app tool a permission `action` names, with its presentation: its `confirm` templates (filled
302
+ * from the call's arguments) word the approval card. `undefined` (or omitted) → an OpenCode
303
+ * built-in, worded from its name.
304
+ */
305
+ approvalPresentation?: (action: string) => {
306
+ name: string;
307
+ presentation?: ToolPresentation;
308
+ } | undefined;
300
309
  /** The model label usage is recorded under until OpenCode names the step's model. */
301
310
  modelLabel: string;
302
311
  /**
@@ -819,6 +828,11 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
819
828
  }): Promise<StepCost>;
820
829
  /** The tools server's name in OpenCode. */
821
830
  get toolsServer(): string;
831
+ /** The app tool an OpenCode permission `action` names, and its presentation — `undefined` for a built-in. */
832
+ presentationOf(action: string): {
833
+ name: string;
834
+ presentation?: ToolPresentation;
835
+ } | undefined;
822
836
  /** The roles policy a turn's tools are gated by (the agent's own). */
823
837
  rolesPolicyFor(input: Pick<AgentRunInput, 'agentName'>): RolesPolicy;
824
838
  /** The tools a turn may reach: the agent's allow-list, narrowed by its persona's. */
@@ -1,6 +1,6 @@
1
1
  import { AgentDepsFactory, ChatQueueService, AgentEngine } from '@dudousxd/nestjs-agent';
2
2
  import { ConflictException, Logger, OnApplicationShutdown, Type, InjectionToken, Provider } from '@nestjs/common';
3
- import { ElicitationRequest, CostSource, AgentRunInput, SinkWriter, AgentStore, ApprovalRequirement, MessageUsage, AgentUiComponent, HumanReply, Actor, StoredMessage, ToolRegistry, TokenStreamSink, SkillsConfig, MemoryConfig, AgentPricingStore, PriceCatalogOptions, RolesPolicy, RememberToolInput, AiToolCtx } from '@dudousxd/nestjs-agent-core';
3
+ import { ElicitationRequest, CostSource, AgentRunInput, SinkWriter, AgentStore, ApprovalRequirement, ToolPresentation, MessageUsage, AgentUiComponent, HumanReply, Actor, StoredMessage, ToolRegistry, TokenStreamSink, SkillsConfig, MemoryConfig, AgentPricingStore, PriceCatalogOptions, RolesPolicy, RememberToolInput, AiToolCtx } from '@dudousxd/nestjs-agent-core';
4
4
  import { IncomingMessage, ServerResponse } from 'node:http';
5
5
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
6
 
@@ -297,6 +297,15 @@ interface OpenCodeTurnArgs {
297
297
  store: AgentStore;
298
298
  /** What an action needs before it runs (the module's `ApprovalPolicy`). */
299
299
  approvalFor: (action: string) => Promise<ApprovalRequirement>;
300
+ /**
301
+ * The app tool a permission `action` names, with its presentation: its `confirm` templates (filled
302
+ * from the call's arguments) word the approval card. `undefined` (or omitted) → an OpenCode
303
+ * built-in, worded from its name.
304
+ */
305
+ approvalPresentation?: (action: string) => {
306
+ name: string;
307
+ presentation?: ToolPresentation;
308
+ } | undefined;
300
309
  /** The model label usage is recorded under until OpenCode names the step's model. */
301
310
  modelLabel: string;
302
311
  /**
@@ -819,6 +828,11 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
819
828
  }): Promise<StepCost>;
820
829
  /** The tools server's name in OpenCode. */
821
830
  get toolsServer(): string;
831
+ /** The app tool an OpenCode permission `action` names, and its presentation — `undefined` for a built-in. */
832
+ presentationOf(action: string): {
833
+ name: string;
834
+ presentation?: ToolPresentation;
835
+ } | undefined;
822
836
  /** The roles policy a turn's tools are gated by (the agent's own). */
823
837
  rolesPolicyFor(input: Pick<AgentRunInput, 'agentName'>): RolesPolicy;
824
838
  /** The tools a turn may reach: the agent's allow-list, narrowed by its persona's. */
package/dist/index.cjs CHANGED
@@ -1071,6 +1071,8 @@ ${delta}` : delta;
1071
1071
  }
1072
1072
  const ttlMs = requirement.ttlMs !== void 0 && Number.isFinite(requirement.ttlMs) && requirement.ttlMs > 0 ? Math.floor(requirement.ttlMs) : void 0;
1073
1073
  const expiresAt = ttlMs !== void 0 ? new Date(Date.now() + ttlMs).toISOString() : void 0;
1074
+ const tool = this.a.approvalPresentation?.(action);
1075
+ const confirmation = tool !== void 0 ? (0, import_nestjs_agent_core2.resolveToolConfirmation)(tool.name, args, tool.presentation) : void 0;
1074
1076
  this.segment.calls.push({
1075
1077
  id: req.id,
1076
1078
  name: action,
@@ -1085,6 +1087,9 @@ ${delta}` : delta;
1085
1087
  toolType: "action",
1086
1088
  input: args,
1087
1089
  status: "pending_approval",
1090
+ ...confirmation !== void 0 ? {
1091
+ confirmation
1092
+ } : {},
1088
1093
  runId: this.a.runId,
1089
1094
  approver: requirement.approver,
1090
1095
  ...expiresAt !== void 0 ? {
@@ -1102,6 +1107,9 @@ ${delta}` : delta;
1102
1107
  kind: "approval-requested",
1103
1108
  id: req.id,
1104
1109
  approver: requirement.approver,
1110
+ ...confirmation !== void 0 ? {
1111
+ confirmation
1112
+ } : {},
1105
1113
  ...expiresAt !== void 0 ? {
1106
1114
  expiresAt
1107
1115
  } : {}
@@ -1882,6 +1890,25 @@ var OpenCodeTurns = class {
1882
1890
  get toolsServer() {
1883
1891
  return this.settings.tools?.server ?? "aviary";
1884
1892
  }
1893
+ /** The app tool an OpenCode permission `action` names, and its presentation — `undefined` for a built-in. */
1894
+ presentationOf(action) {
1895
+ if (this.settings.tools === void 0) return void 0;
1896
+ const server = this.toolsServer;
1897
+ for (const prefix of [
1898
+ `${server}.`,
1899
+ `${server}_`
1900
+ ]) {
1901
+ if (!action.startsWith(prefix)) continue;
1902
+ const spec = this.registry.spec(action.slice(prefix.length));
1903
+ if (spec !== void 0) return {
1904
+ name: spec.name,
1905
+ ...spec.presentation !== void 0 ? {
1906
+ presentation: spec.presentation
1907
+ } : {}
1908
+ };
1909
+ }
1910
+ return void 0;
1911
+ }
1885
1912
  /** The roles policy a turn's tools are gated by (the agent's own). */
1886
1913
  rolesPolicyFor(input) {
1887
1914
  return this.deps.forAgent(input.agentName).rolesPolicy;
@@ -2614,6 +2641,9 @@ ${body}
2614
2641
  agentName: input.agentName
2615
2642
  } : {}
2616
2643
  }), "approvalFor"),
2644
+ // An app tool reaches OpenCode as `<server>.<name>` / `<server>_<name>`: its own presentation
2645
+ // words the approval card. OpenCode's built-ins (`bash`, `edit`) have none.
2646
+ approvalPresentation: /* @__PURE__ */ __name((action) => this.presentationOf(action), "approvalPresentation"),
2617
2647
  modelLabel: input.model ?? "opencode",
2618
2648
  priceStep: /* @__PURE__ */ __name((step) => this.priceStep(step), "priceStep"),
2619
2649
  ...spent !== void 0 ? {