@dudousxd/nestjs-agent-opencode 0.2.1 → 0.4.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,5 +1,5 @@
1
1
  import { AgentEngine } from '@dudousxd/nestjs-agent';
2
- import { O as OpenCodeTurns, a as OpenCodeEngineSettings, b as OpenCodeHost, c as OpenCodeEngineOptions } from '../engine-0YkBLWZR.cjs';
2
+ import { O as OpenCodeTurns, a as OpenCodeEngineSettings, b as OpenCodeHost, c as OpenCodeEngineOptions } from '../engine-BNNxQAFV.cjs';
3
3
  import { AgentRunner, AgentStore, AgentRunInput, AgentRunStartOptions, HumanReply } from '@dudousxd/nestjs-agent-core';
4
4
  import { WorkflowService } from '@dudousxd/nestjs-durable';
5
5
  import { RunGateway, WorkflowCtx } from '@dudousxd/nestjs-durable-core';
@@ -1,5 +1,5 @@
1
1
  import { AgentEngine } from '@dudousxd/nestjs-agent';
2
- import { O as OpenCodeTurns, a as OpenCodeEngineSettings, b as OpenCodeHost, c as OpenCodeEngineOptions } from '../engine-0YkBLWZR.js';
2
+ import { O as OpenCodeTurns, a as OpenCodeEngineSettings, b as OpenCodeHost, c as OpenCodeEngineOptions } from '../engine-BNNxQAFV.js';
3
3
  import { AgentRunner, AgentStore, AgentRunInput, AgentRunStartOptions, HumanReply } from '@dudousxd/nestjs-agent-core';
4
4
  import { WorkflowService } from '@dudousxd/nestjs-durable';
5
5
  import { RunGateway, WorkflowCtx } from '@dudousxd/nestjs-durable-core';
@@ -125,14 +125,15 @@ OpenCodeMcpController = _ts_decorate([
125
125
 
126
126
  // src/mcp.ts
127
127
  import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
128
- import { REMEMBER_TOOL_DESCRIPTION, REMEMBER_TOOL_NAME, ToolNotFoundError, rememberInputSchema, schemaExtensionOf } from "@dudousxd/nestjs-agent-core";
128
+ import { GenuiRunRecorder, REMEMBER_TOOL_DESCRIPTION, REMEMBER_TOOL_NAME, ToolNotFoundError, rememberInputSchema, schemaExtensionOf } from "@dudousxd/nestjs-agent-core";
129
+ import { turnChannel } from "@dudousxd/nestjs-agent-core/genui";
129
130
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
130
131
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
131
132
  import { toJsonSchemaCompat } from "@modelcontextprotocol/sdk/server/zod-json-schema-compat.js";
132
133
  import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
133
134
 
134
135
  // src/turn.ts
135
- import { encodeStreamEvent, settleElicitation } from "@dudousxd/nestjs-agent-core";
136
+ import { encodeStreamEvent, resolveToolConfirmation, settleElicitation } from "@dudousxd/nestjs-agent-core";
136
137
  import { ConflictException } from "@nestjs/common";
137
138
 
138
139
  // src/forms.ts
@@ -1002,6 +1003,8 @@ ${delta}` : delta;
1002
1003
  }
1003
1004
  const ttlMs = requirement.ttlMs !== void 0 && Number.isFinite(requirement.ttlMs) && requirement.ttlMs > 0 ? Math.floor(requirement.ttlMs) : void 0;
1004
1005
  const expiresAt = ttlMs !== void 0 ? new Date(Date.now() + ttlMs).toISOString() : void 0;
1006
+ const tool = this.a.approvalPresentation?.(action);
1007
+ const confirmation = tool !== void 0 ? resolveToolConfirmation(tool.name, args, tool.presentation) : void 0;
1005
1008
  this.segment.calls.push({
1006
1009
  id: req.id,
1007
1010
  name: action,
@@ -1016,6 +1019,9 @@ ${delta}` : delta;
1016
1019
  toolType: "action",
1017
1020
  input: args,
1018
1021
  status: "pending_approval",
1022
+ ...confirmation !== void 0 ? {
1023
+ confirmation
1024
+ } : {},
1019
1025
  runId: this.a.runId,
1020
1026
  approver: requirement.approver,
1021
1027
  ...expiresAt !== void 0 ? {
@@ -1033,6 +1039,9 @@ ${delta}` : delta;
1033
1039
  kind: "approval-requested",
1034
1040
  id: req.id,
1035
1041
  approver: requirement.approver,
1042
+ ...confirmation !== void 0 ? {
1043
+ confirmation
1044
+ } : {},
1036
1045
  ...expiresAt !== void 0 ? {
1037
1046
  expiresAt
1038
1047
  } : {}
@@ -1438,6 +1447,8 @@ var OpenCodeMcpEndpoint2 = class {
1438
1447
  }
1439
1448
  turns;
1440
1449
  tokens;
1450
+ /** Genui telemetry of the UI calls OpenCode makes (its code mode calls tools here, not in the loop). */
1451
+ genui = new GenuiRunRecorder();
1441
1452
  constructor(turns, tokens) {
1442
1453
  this.turns = turns;
1443
1454
  this.tokens = tokens;
@@ -1569,7 +1580,7 @@ var OpenCodeMcpEndpoint2 = class {
1569
1580
  if (spec.kind === "action" && !await this.turns.spendApproval(turn.runId, name, turn.input)) {
1570
1581
  throw new OpenCodeToolRefusedError(`"${name}" is an action and nobody approved this call; ask for the permission first.`);
1571
1582
  }
1572
- return registry.invoke(name, args ?? {}, {
1583
+ const invoke = /* @__PURE__ */ __name(() => registry.invoke(name, args ?? {}, {
1573
1584
  actor,
1574
1585
  threadId: turn.ctx.threadId,
1575
1586
  runId: turn.runId,
@@ -1586,7 +1597,24 @@ var OpenCodeMcpEndpoint2 = class {
1586
1597
  } : {}
1587
1598
  }, this.turns.rolesPolicyFor(turn.input), allowed !== void 0 ? {
1588
1599
  allowedTools: allowed
1589
- } : {});
1600
+ } : {}), "invoke");
1601
+ return this.genui.track({
1602
+ store: this.turns.store,
1603
+ marker: spec.genui,
1604
+ runId: turn.runId,
1605
+ threadId: turn.ctx.threadId,
1606
+ actorRef: actor.id,
1607
+ ...turn.input.agentName !== void 0 ? {
1608
+ agentName: turn.input.agentName
1609
+ } : {},
1610
+ channel: turnChannel(turn.input.pageContext),
1611
+ modelId: turn.input.model ?? "opencode",
1612
+ call: {
1613
+ id: `mcp:${turn.runId}:${requestId}`,
1614
+ name,
1615
+ input: args ?? {}
1616
+ }
1617
+ }, invoke);
1590
1618
  }
1591
1619
  /** `remember`: one fact, at the actor's own scope only — as the loop serves it. */
1592
1620
  async remember(turn, args) {
@@ -1813,6 +1841,25 @@ var OpenCodeTurns = class {
1813
1841
  get toolsServer() {
1814
1842
  return this.settings.tools?.server ?? "aviary";
1815
1843
  }
1844
+ /** The app tool an OpenCode permission `action` names, and its presentation — `undefined` for a built-in. */
1845
+ presentationOf(action) {
1846
+ if (this.settings.tools === void 0) return void 0;
1847
+ const server = this.toolsServer;
1848
+ for (const prefix of [
1849
+ `${server}.`,
1850
+ `${server}_`
1851
+ ]) {
1852
+ if (!action.startsWith(prefix)) continue;
1853
+ const spec = this.registry.spec(action.slice(prefix.length));
1854
+ if (spec !== void 0) return {
1855
+ name: spec.name,
1856
+ ...spec.presentation !== void 0 ? {
1857
+ presentation: spec.presentation
1858
+ } : {}
1859
+ };
1860
+ }
1861
+ return void 0;
1862
+ }
1816
1863
  /** The roles policy a turn's tools are gated by (the agent's own). */
1817
1864
  rolesPolicyFor(input) {
1818
1865
  return this.deps.forAgent(input.agentName).rolesPolicy;
@@ -2545,6 +2592,9 @@ ${body}
2545
2592
  agentName: input.agentName
2546
2593
  } : {}
2547
2594
  }), "approvalFor"),
2595
+ // An app tool reaches OpenCode as `<server>.<name>` / `<server>_<name>`: its own presentation
2596
+ // words the approval card. OpenCode's built-ins (`bash`, `edit`) have none.
2597
+ approvalPresentation: /* @__PURE__ */ __name((action) => this.presentationOf(action), "approvalPresentation"),
2548
2598
  modelLabel: input.model ?? "opencode",
2549
2599
  priceStep: /* @__PURE__ */ __name((step) => this.priceStep(step), "priceStep"),
2550
2600
  ...spent !== void 0 ? {