@ixo/oracle-runtime-workers 0.13.0 → 0.15.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 (205) hide show
  1. package/README.md +32 -10
  2. package/package.json +13 -8
  3. package/src/artifacts/config.ts +158 -0
  4. package/src/artifacts/crypto.ts +94 -0
  5. package/src/artifacts/routes.ts +73 -0
  6. package/src/artifacts/store.ts +238 -0
  7. package/src/artifacts/sweep.ts +200 -0
  8. package/src/artifacts/tool.ts +103 -0
  9. package/src/artifacts/viewer-page.ts +614 -0
  10. package/src/attachments/download.ts +168 -45
  11. package/src/attachments/index.ts +9 -0
  12. package/src/attachments/magic.ts +33 -0
  13. package/src/attachments/pipeline.ts +105 -49
  14. package/src/attachments/sandbox-archive.ts +9 -8
  15. package/src/attachments/view-cache.ts +142 -0
  16. package/src/attachments/view.ts +53 -12
  17. package/src/channels/auth.ts +267 -0
  18. package/src/channels/contract.ts +137 -0
  19. package/src/channels/turns.ts +270 -0
  20. package/src/core/budgeted-llm.ts +223 -0
  21. package/src/core/capability-router.ts +273 -0
  22. package/src/core/context-budget.ts +97 -10
  23. package/src/core/env.ts +111 -0
  24. package/src/core/execution-profile.ts +17 -0
  25. package/src/core/index.ts +267 -9
  26. package/src/core/llm.ts +30 -9
  27. package/src/core/main-agent-types.ts +41 -1
  28. package/src/core/main-agent.ts +367 -65
  29. package/src/core/manifest.ts +34 -0
  30. package/src/core/meta-tools.ts +128 -18
  31. package/src/core/middlewares/capability-gate.ts +130 -12
  32. package/src/core/middlewares/context-guard.ts +55 -24
  33. package/src/core/middlewares/index.ts +20 -2
  34. package/src/core/middlewares/page-context.ts +46 -2
  35. package/src/core/middlewares/return-direct-first.ts +47 -0
  36. package/src/core/middlewares/summarization.ts +152 -10
  37. package/src/core/middlewares/tool-execution.ts +323 -0
  38. package/src/core/middlewares/tool-repetition-guard.ts +202 -35
  39. package/src/core/middlewares/turn-boundary.ts +162 -0
  40. package/src/core/openrouter-pricing.ts +155 -22
  41. package/src/core/prompt-composer.ts +112 -7
  42. package/src/core/registries.ts +253 -48
  43. package/src/core/request-admission.ts +159 -0
  44. package/src/core/runtime-context.ts +107 -8
  45. package/src/core/state.ts +1 -1
  46. package/src/core/sub-agent-fallback.ts +21 -2
  47. package/src/core/subagent-as-tool.ts +78 -43
  48. package/src/core/tool-access.ts +189 -0
  49. package/src/core/tool-scheduler.ts +125 -0
  50. package/src/core/turn-budget.ts +205 -0
  51. package/src/core/turn-time-note.ts +43 -0
  52. package/src/core/user-kv.ts +446 -0
  53. package/src/core/wrap-plugin-tool.ts +20 -0
  54. package/src/delivery/plan.ts +278 -0
  55. package/src/delivery/profile.ts +161 -0
  56. package/src/delivery/prompt.ts +27 -0
  57. package/src/delivery/schema.ts +61 -0
  58. package/src/delivery/shaper.ts +389 -0
  59. package/src/delivery/types.ts +84 -0
  60. package/src/do/ambient.ts +51 -15
  61. package/src/do/contracts.ts +170 -6
  62. package/src/do/idle-eviction.ts +38 -0
  63. package/src/do/matrix-turn-ledger.ts +24 -5
  64. package/src/do/result-store-test-do.ts +137 -3
  65. package/src/do/result-store.ts +239 -58
  66. package/src/do/room-mirror.ts +29 -0
  67. package/src/do/run-buffer.ts +64 -9
  68. package/src/do/run-coordinator.ts +451 -76
  69. package/src/do/run-request.ts +2 -0
  70. package/src/do/run-store-test-do.ts +301 -1
  71. package/src/do/run-store.ts +385 -43
  72. package/src/do/secrets-adapter.ts +22 -3
  73. package/src/do/sse-stream.ts +60 -9
  74. package/src/do/transcript.ts +48 -5
  75. package/src/do/turn-body.ts +105 -5
  76. package/src/do/ucan-service.ts +204 -34
  77. package/src/do/user-oracle-do.ts +1883 -264
  78. package/src/feedback/config.ts +127 -0
  79. package/src/feedback/contract.ts +148 -0
  80. package/src/feedback/linear-sink.ts +285 -0
  81. package/src/feedback/privacy.ts +150 -0
  82. package/src/feedback/reservation.ts +298 -0
  83. package/src/feedback/submit.ts +247 -0
  84. package/src/index.ts +138 -6
  85. package/src/llm/byo-adapter.ts +27 -6
  86. package/src/llm/byo-catalog.ts +13 -0
  87. package/src/llm/byo-model-fallback.ts +248 -0
  88. package/src/llm/byo-service.ts +45 -8
  89. package/src/llm/provider-error.ts +139 -2
  90. package/src/matrix/gateway-do.ts +504 -108
  91. package/src/matrix/group-chat.ts +66 -23
  92. package/src/matrix/inbox-store.ts +16 -1
  93. package/src/matrix/ingest.ts +79 -14
  94. package/src/matrix/media-deadline.ts +130 -0
  95. package/src/matrix/replay-format.ts +5 -3
  96. package/src/matrix/reply-parts.ts +92 -0
  97. package/src/matrix/room-alias.ts +96 -0
  98. package/src/matrix/user-homeserver.ts +166 -7
  99. package/src/owner-store/ixo-vfs-store.ts +170 -43
  100. package/src/owner-store/migrating-store.ts +31 -15
  101. package/src/owner-store/types.ts +18 -3
  102. package/src/plugin-api/index.ts +43 -2
  103. package/src/plugin-api/oracle-plugin.ts +35 -0
  104. package/src/plugin-api/request-admission.ts +41 -0
  105. package/src/plugin-api/tool-helper.ts +25 -1
  106. package/src/plugin-api/tool-plane.ts +92 -0
  107. package/src/plugin-api/types.ts +194 -6
  108. package/src/plugins/agui/agui.plugin.ts +31 -16
  109. package/src/plugins/composio/composio-tools.ts +57 -6
  110. package/src/plugins/composio/composio-ucan.ts +3 -2
  111. package/src/plugins/composio/composio.plugin.ts +2 -0
  112. package/src/plugins/delegated-capabilities.ts +25 -0
  113. package/src/plugins/editor/content-session.ts +173 -83
  114. package/src/plugins/editor/content-tools.ts +76 -17
  115. package/src/plugins/editor/editor-mx.ts +28 -9
  116. package/src/plugins/editor/editor.plugin.ts +3 -1
  117. package/src/plugins/editor/failures.ts +28 -7
  118. package/src/plugins/editor/prompts.ts +2 -1
  119. package/src/plugins/editor/provider.ts +553 -40
  120. package/src/plugins/editor/standalone-editor-tool.ts +61 -18
  121. package/src/plugins/firecrawl/firecrawl-tools.ts +13 -5
  122. package/src/plugins/flows/action-metadata.ts +111 -11
  123. package/src/plugins/flows/actions.ts +18 -0
  124. package/src/plugins/flows/decision-context.ts +31 -0
  125. package/src/plugins/flows/edit.ts +223 -52
  126. package/src/plugins/flows/errors.ts +22 -1
  127. package/src/plugins/flows/flow-doc.ts +92 -9
  128. package/src/plugins/flows/flows.plugin.ts +11 -5
  129. package/src/plugins/flows/forms.ts +34 -0
  130. package/src/plugins/flows/index.ts +2 -0
  131. package/src/plugins/flows/input-policy.ts +140 -0
  132. package/src/plugins/flows/prompts.ts +14 -11
  133. package/src/plugins/flows/read.ts +49 -9
  134. package/src/plugins/flows/ref-syntax.ts +129 -0
  135. package/src/plugins/flows/test-homeserver.ts +245 -0
  136. package/src/plugins/flows/tools/authoring.ts +216 -112
  137. package/src/plugins/flows/tools/discovery.ts +4 -1
  138. package/src/plugins/flows/tools/forms.ts +21 -2
  139. package/src/plugins/flows/tools/settings.ts +34 -13
  140. package/src/plugins/flows/translator.ts +13 -10
  141. package/src/plugins/flows/types.ts +167 -42
  142. package/src/plugins/index.ts +11 -1
  143. package/src/plugins/ixo-transaction/chain-ids.ts +43 -0
  144. package/src/plugins/ixo-transaction/index.ts +2 -0
  145. package/src/plugins/ixo-transaction/ixo-transaction.plugin.ts +119 -0
  146. package/src/plugins/ixo-transaction/receipts.ts +99 -0
  147. package/src/plugins/ixo-transaction/tools.ts +329 -0
  148. package/src/plugins/ixo-transaction/wallet-signing.ts +202 -0
  149. package/src/plugins/mcp-tool-adapter.ts +23 -2
  150. package/src/plugins/memory/memory-tools.ts +7 -2
  151. package/src/plugins/memory/memory-ucan.ts +3 -2
  152. package/src/plugins/memory/memory.plugin.ts +2 -0
  153. package/src/plugins/pod-creator/blueprint-store.ts +163 -0
  154. package/src/plugins/pod-creator/blueprint-types.ts +61 -0
  155. package/src/plugins/pod-creator/bounded-map.ts +87 -0
  156. package/src/plugins/pod-creator/capsule-content-client.ts +285 -0
  157. package/src/plugins/pod-creator/chain-gateway.ts +110 -0
  158. package/src/plugins/pod-creator/config.ts +85 -0
  159. package/src/plugins/pod-creator/create-session-store.ts +180 -0
  160. package/src/plugins/pod-creator/create-tools.ts +538 -0
  161. package/src/plugins/pod-creator/design-pod-roles.ts +111 -0
  162. package/src/plugins/pod-creator/index.ts +65 -0
  163. package/src/plugins/pod-creator/orchestration-tools.ts +172 -0
  164. package/src/plugins/pod-creator/pod-creator.plugin.ts +190 -0
  165. package/src/plugins/pod-creator/stage.ts +201 -0
  166. package/src/plugins/pod-creator/sub-agents.ts +189 -0
  167. package/src/plugins/portal/action-log.ts +21 -1
  168. package/src/plugins/portal/declared-tools.ts +90 -0
  169. package/src/plugins/portal/portal.plugin.ts +42 -16
  170. package/src/plugins/sandbox/sandbox-bridge.ts +79 -10
  171. package/src/plugins/sandbox/sandbox-mcp.ts +3 -2
  172. package/src/plugins/sandbox/sandbox-write-blob.ts +11 -1
  173. package/src/plugins/sandbox/sandbox.plugin.ts +8 -16
  174. package/src/plugins/tasks/manifest.ts +1 -1
  175. package/src/plugins/tasks/middleware.ts +20 -7
  176. package/src/plugins/tasks/tasks-tools.ts +30 -3
  177. package/src/plugins/tasks/tasks.plugin.ts +64 -11
  178. package/src/plugins/user-preferences/schema.ts +12 -1
  179. package/src/plugins/user-preferences/user-preferences-store.ts +38 -13
  180. package/src/plugins/user-preferences/user-preferences-tool.ts +3 -2
  181. package/src/plugins/vfs/vfs-client.ts +250 -71
  182. package/src/plugins/vfs/vfs-content.ts +30 -11
  183. package/src/plugins/vfs/vfs-errors.ts +22 -0
  184. package/src/plugins/vfs/vfs-sandbox-tools.ts +12 -5
  185. package/src/plugins/vfs/vfs-tools.ts +60 -20
  186. package/src/realtime/frontend-call-registry.ts +228 -81
  187. package/src/realtime/realtime-endpoint.ts +215 -44
  188. package/src/realtime/session-socket-hub.ts +47 -2
  189. package/src/secrets/secrets-service.ts +9 -3
  190. package/src/shell/app.ts +529 -82
  191. package/src/shell/auth.ts +131 -37
  192. package/src/shell/turn-body-cap.ts +11 -13
  193. package/src/sqlite/blob-compactor.ts +61 -28
  194. package/src/sqlite/database.ts +156 -90
  195. package/src/sqlite/do-vfs.ts +416 -129
  196. package/src/sqlite/page-tier.ts +133 -40
  197. package/src/sqlite/serialization.ts +40 -0
  198. package/src/sqlite/sessions-store.ts +10 -2
  199. package/src/sqlite/sqlite-saver.ts +139 -19
  200. package/src/sqlite/user-kv-store.ts +317 -0
  201. package/src/tasks/schedule.ts +201 -12
  202. package/src/tasks/scheduler.ts +586 -98
  203. package/src/tasks/spec.ts +67 -3
  204. package/src/tasks/store.ts +292 -27
  205. package/src/tasks/topic-deliverables.ts +70 -0
@@ -18,7 +18,12 @@ import { z } from 'zod';
18
18
 
19
19
  import { filterForwardedMessages } from '../../core/subagent-as-tool';
20
20
  import { tool as pluginTool } from '../../plugin-api/tool-helper';
21
+ import {
22
+ canAccessToolPlane,
23
+ requireToolPlane,
24
+ } from '../../plugin-api/tool-plane';
21
25
  import type { PluginTool, RuntimeContext } from '../../plugin-api/types';
26
+ import { sharedDocumentSource, type DocumentOpener } from './content-session';
22
27
  import { createContentTools } from './content-tools';
23
28
  import { buildAppConfig, EDITOR_AGENT_TOOL_NAME } from './editor-agent';
24
29
  import type { BlocknoteToolsConfig } from './editor-config';
@@ -84,23 +89,42 @@ function lastMessageContent(messages: BaseMessage[]): string {
84
89
  export interface CreateStandaloneEditorToolOptions {
85
90
  /** Editor config built when the plugin's request tools are resolved. */
86
91
  toolsConfig: BlocknoteToolsConfig;
92
+ /** The contributing plugin: names an admin content tool's capability. */
93
+ pluginName: string;
94
+ /**
95
+ * Opens the target document. Defaults to the matrix-crdt opener; tests
96
+ * pass an in-memory one.
97
+ */
98
+ openDocument?: DocumentOpener;
87
99
  }
88
100
 
89
101
  /**
90
102
  * Bridge the content `PluginTool`s into LangChain tools for the inner agent,
91
103
  * reusing the outer request's `RuntimeContext` rather than rebuilding one.
104
+ * The handlers are called here, not through `wrapPluginTool`, so the plane
105
+ * check it applies is applied here too: an admin content tool the user's
106
+ * delegation does not grant is not bound, and the call re-checks it.
92
107
  */
93
108
  function toStructuredTools(
94
109
  tools: PluginTool[],
95
110
  ctx: RuntimeContext,
111
+ pluginName: string,
96
112
  ): StructuredTool[] {
97
- return tools.map((t) =>
98
- lcTool(async (args) => t.handler(args, ctx), {
99
- name: t.name,
100
- description: t.description,
101
- schema: t.schema,
102
- }),
103
- );
113
+ return tools
114
+ .filter((t) => canAccessToolPlane(ctx, pluginName, t))
115
+ .map((t) =>
116
+ lcTool(
117
+ async (args) => {
118
+ requireToolPlane(ctx, pluginName, t);
119
+ return t.handler(args, ctx);
120
+ },
121
+ {
122
+ name: t.name,
123
+ description: t.description,
124
+ schema: t.schema,
125
+ },
126
+ ),
127
+ );
104
128
  }
105
129
 
106
130
  /** The document the client reports as open, when there is one. */
@@ -130,6 +154,7 @@ export function createStandaloneEditorTool(
130
154
  return JSON.stringify(notAMember(roomId));
131
155
  }
132
156
 
157
+ let documents: ReturnType<typeof sharedDocumentSource> | undefined;
133
158
  try {
134
159
  const matrixClient = await resolveEditorMatrixClient({
135
160
  baseUrl: opts.toolsConfig.matrix.baseUrl,
@@ -138,14 +163,24 @@ export function createStandaloneEditorTool(
138
163
  matrixClient: opts.toolsConfig.matrixClient,
139
164
  });
140
165
 
141
- const contentTools = createContentTools({
142
- matrixClient,
143
- appConfig: buildAppConfig(opts.toolsConfig, {
144
- type: 'id',
145
- value: roomId,
146
- }),
147
- });
148
- const boundTools = toStructuredTools(contentTools, ctx);
166
+ // One session for the whole run: the room cannot change identity
167
+ // within a call, so every content tool reuses the same open doc.
168
+ documents = sharedDocumentSource(
169
+ {
170
+ matrixClient,
171
+ appConfig: buildAppConfig(opts.toolsConfig, {
172
+ type: 'id',
173
+ value: roomId,
174
+ }),
175
+ },
176
+ opts.openDocument,
177
+ );
178
+ const contentTools = createContentTools({ documents });
179
+ const boundTools = toStructuredTools(
180
+ contentTools,
181
+ ctx,
182
+ opts.pluginName,
183
+ );
149
184
 
150
185
  const agent = createAgent({
151
186
  model: ctx.llm.get('subagent'),
@@ -154,9 +189,12 @@ export function createStandaloneEditorTool(
154
189
  middleware: [],
155
190
  });
156
191
 
157
- const result = await agent.invoke({
158
- messages: [new HumanMessage(task)],
159
- });
192
+ // The turn's signal stops the inner agent's model calls and document
193
+ // writes when the user cancels or the turn times out.
194
+ const result = await agent.invoke(
195
+ { messages: [new HumanMessage(task)] },
196
+ { signal: ctx.abortSignal },
197
+ );
160
198
  const messages = result.messages as BaseMessage[];
161
199
  const text = lastMessageContent(messages);
162
200
 
@@ -184,11 +222,16 @@ export function createStandaloneEditorTool(
184
222
  },
185
223
  });
186
224
  } catch (err) {
225
+ // A cancelled turn is not a document error: let the cancellation
226
+ // propagate.
227
+ if (ctx.abortSignal.aborted) throw err;
187
228
  const message = err instanceof Error ? err.message : String(err);
188
229
  ctx.logger.error(
189
230
  `[editor] standalone failed for ${roomId}: ${message}`,
190
231
  );
191
232
  return `Error opening the document ${roomId}: ${message}`;
233
+ } finally {
234
+ await documents?.close();
192
235
  }
193
236
  },
194
237
  {
@@ -1,7 +1,11 @@
1
1
  import { MultiServerMCPClient } from '@langchain/mcp-adapters';
2
2
  import { withCallTimeout } from '../mcp-call-timeout';
3
+ import { adaptMcpClientTools } from '../mcp-tool-adapter';
3
4
 
4
- /** Our own per-call limit (never given to the SDK — see `mcp-call-timeout.ts`). */
5
+ /**
6
+ * Per-call limit: the MCP request's own timeout (`metadata.timeoutMs`, see
7
+ * `mcp-tool-adapter.ts`), also enforced by {@link withCallTimeout}.
8
+ */
5
9
  const FIRECRAWL_TOOL_TIMEOUT_MS = 120_000;
6
10
  import { z } from 'zod';
7
11
  import { tool } from '../../plugin-api/tool-helper';
@@ -112,10 +116,14 @@ export function createDefaultFirecrawlMcpFactory(
112
116
  try {
113
117
  const all = await client.getTools();
114
118
  return await run(
115
- all.filter(
116
- (t) =>
117
- t.name === FIRECRAWL_SCRAPE_MCP_NAME ||
118
- t.name === FIRECRAWL_SEARCH_MCP_NAME,
119
+ adaptMcpClientTools(
120
+ all.filter(
121
+ (t) =>
122
+ t.name === FIRECRAWL_SCRAPE_MCP_NAME ||
123
+ t.name === FIRECRAWL_SEARCH_MCP_NAME,
124
+ ),
125
+ console,
126
+ { requestTimeoutMs: FIRECRAWL_TOOL_TIMEOUT_MS },
119
127
  ),
120
128
  );
121
129
  } finally {
@@ -16,8 +16,10 @@
16
16
  * `describe_action`) and are not derivable from the registry.
17
17
  *
18
18
  * `requires` captures human/environment prerequisites the user must supply (a
19
- * claim collection, a template id, a connected account, a PIN) — the things the
20
- * agent must STOP and ASK the user for rather than invent. The multi-operation
19
+ * claim collection, a template id, a connected account) — the things the
20
+ * agent must STOP and ASK the user for rather than invent. A PIN is the
21
+ * exception: it is listed so the agent knows the step needs one, but the
22
+ * portal collects it at run time ({@link PIN_AT_RUN_TIME}). The multi-operation
21
23
  * actions (`qi/collection.lifecycle`, `qi/collection.users`) dispatch on an
22
24
  * `operation` input; their `inputPorts` note which fields apply to which op.
23
25
  *
@@ -30,6 +32,12 @@ export interface ActionPort {
30
32
  portType: string;
31
33
  /** True when the action's `run()` throws if this field is missing. */
32
34
  required?: boolean;
35
+ /**
36
+ * The value is a credential (PIN, mnemonic, password, token, API key). It
37
+ * is never stored in a flow document — every room member can read it — so
38
+ * an input with this name only accepts a `{{step.output.field}}` reference.
39
+ */
40
+ secret?: boolean;
33
41
  /** One-line, agent-facing description of what to put here. */
34
42
  description?: string;
35
43
  }
@@ -55,6 +63,13 @@ export interface OverlayEntry {
55
63
  * NOT listed here — they come from the registry's `outputSchema` (actions.ts
56
64
  * outputFields). Covers every registered action type.
57
65
  */
66
+ /**
67
+ * How every PIN prerequisite is described: the portal collects the PIN when
68
+ * the user runs the step, so the agent never asks for one and never stores one.
69
+ */
70
+ const PIN_AT_RUN_TIME =
71
+ 'Collected by the portal when the user runs the step — never ask for it in chat and never write it into the flow.';
72
+
58
73
  export const ACTION_METADATA: Record<string, OverlayEntry> = {
59
74
  // ── Claims & bids ─────────────────────────────────────────────────────────
60
75
  'qi/claim.submit': {
@@ -93,6 +108,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
93
108
  {
94
109
  path: 'pin',
95
110
  portType: 'string',
111
+ secret: true,
96
112
  required: false,
97
113
  description:
98
114
  'Verification PIN; if omitted the action requests it from the user at runtime.',
@@ -413,7 +429,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
413
429
  {
414
430
  path: 'collectionId',
415
431
  portType: 'claimCollectionId',
416
- required: true,
432
+ required: false,
417
433
  description:
418
434
  'Target collection — required for every op EXCEPT create (which mints a new one).',
419
435
  },
@@ -903,6 +919,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
903
919
  {
904
920
  path: 'mnemonic',
905
921
  portType: 'mnemonic',
922
+ secret: true,
906
923
  required: true,
907
924
  description:
908
925
  'Wallet mnemonic used to sign the IID creation. Typically wired from an upstream wallet step output (mnemonic).',
@@ -946,6 +963,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
946
963
  {
947
964
  path: 'mnemonic',
948
965
  portType: 'mnemonic',
966
+ secret: true,
949
967
  required: true,
950
968
  description:
951
969
  'Wallet mnemonic used to create the IID document and Matrix account. Typically wired from an upstream wallet step output (mnemonic).',
@@ -974,6 +992,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
974
992
  {
975
993
  path: 'pin',
976
994
  portType: 'string',
995
+ secret: true,
977
996
  required: true,
978
997
  description: 'PIN used to register the Matrix account.',
979
998
  },
@@ -999,7 +1018,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
999
1018
  requires: [
1000
1019
  {
1001
1020
  kind: 'pin',
1002
- description: 'A PIN is required to register the Matrix account.',
1021
+ description: `A PIN is required to register the Matrix account. ${PIN_AT_RUN_TIME}`,
1003
1022
  },
1004
1023
  {
1005
1024
  kind: 'oracleName',
@@ -1022,6 +1041,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1022
1041
  {
1023
1042
  path: 'mnemonic',
1024
1043
  portType: 'mnemonic',
1044
+ secret: true,
1025
1045
  required: true,
1026
1046
  description:
1027
1047
  'Wallet mnemonic used to register the Matrix account. Typically wired from an upstream wallet step output (mnemonic).',
@@ -1043,6 +1063,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1043
1063
  {
1044
1064
  path: 'pin',
1045
1065
  portType: 'string',
1066
+ secret: true,
1046
1067
  required: true,
1047
1068
  description: 'PIN used to register the Matrix account.',
1048
1069
  },
@@ -1061,7 +1082,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1061
1082
  requires: [
1062
1083
  {
1063
1084
  kind: 'pin',
1064
- description: 'A PIN is required to register the Matrix account.',
1085
+ description: `A PIN is required to register the Matrix account. ${PIN_AT_RUN_TIME}`,
1065
1086
  },
1066
1087
  {
1067
1088
  kind: 'oracleName',
@@ -1082,6 +1103,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1082
1103
  {
1083
1104
  path: 'mnemonic',
1084
1105
  portType: 'mnemonic',
1106
+ secret: true,
1085
1107
  required: true,
1086
1108
  description:
1087
1109
  'Oracle wallet BIP39 mnemonic, typically from the wallet.generate output.',
@@ -1109,6 +1131,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1109
1131
  {
1110
1132
  path: 'pin',
1111
1133
  portType: 'string',
1134
+ secret: true,
1112
1135
  required: true,
1113
1136
  description:
1114
1137
  'PIN used to sign the entity creation; typically from the form output.',
@@ -1116,6 +1139,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1116
1139
  {
1117
1140
  path: 'matrixAccessToken',
1118
1141
  portType: 'string',
1142
+ secret: true,
1119
1143
  required: true,
1120
1144
  description:
1121
1145
  'Oracle Matrix access token, typically from the matrix.register output.',
@@ -1215,7 +1239,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1215
1239
  },
1216
1240
  {
1217
1241
  kind: 'pin',
1218
- description: 'A PIN used to sign the entity creation — ask the user.',
1242
+ description: `A PIN used to sign the entity creation. ${PIN_AT_RUN_TIME}`,
1219
1243
  },
1220
1244
  ],
1221
1245
  },
@@ -1301,12 +1325,14 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1301
1325
  {
1302
1326
  path: 'matrixPassword',
1303
1327
  portType: 'string',
1328
+ secret: true,
1304
1329
  required: true,
1305
1330
  description: 'Matrix password, from the matrix.register output.',
1306
1331
  },
1307
1332
  {
1308
1333
  path: 'mnemonic',
1309
1334
  portType: 'mnemonic',
1335
+ secret: true,
1310
1336
  required: true,
1311
1337
  description:
1312
1338
  'Oracle wallet mnemonic, from the wallet.generate output; stored as SECP_MNEMONIC secret.',
@@ -1314,12 +1340,14 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1314
1340
  {
1315
1341
  path: 'matrixRecoveryPhrase',
1316
1342
  portType: 'string',
1343
+ secret: true,
1317
1344
  required: true,
1318
1345
  description: 'Matrix recovery phrase, from the matrix.register output.',
1319
1346
  },
1320
1347
  {
1321
1348
  path: 'pin',
1322
1349
  portType: 'string',
1350
+ secret: true,
1323
1351
  required: true,
1324
1352
  description:
1325
1353
  'PIN, from the form output; stored as MATRIX_VALUE_PIN secret.',
@@ -1346,6 +1374,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1346
1374
  {
1347
1375
  path: 'openRouterApiKeyPlaintext',
1348
1376
  portType: 'string',
1377
+ secret: true,
1349
1378
  description:
1350
1379
  'Optional plaintext OpenRouter API key passed through to the deploy output.',
1351
1380
  },
@@ -1448,7 +1477,10 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1448
1477
  description:
1449
1478
  'An OpenRouter API key, JWE-encrypted before submit (openRouterApiKeyJwe) — ask the user.',
1450
1479
  },
1451
- { kind: 'pin', description: 'A PIN stored as a secret — ask the user.' },
1480
+ {
1481
+ kind: 'pin',
1482
+ description: `A PIN stored as a secret. ${PIN_AT_RUN_TIME}`,
1483
+ },
1452
1484
  ],
1453
1485
  },
1454
1486
  'qi/oracle.storeSecrets': {
@@ -1499,12 +1531,14 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1499
1531
  {
1500
1532
  path: 'matrixPassword',
1501
1533
  portType: 'string',
1534
+ secret: true,
1502
1535
  required: true,
1503
1536
  description: 'Matrix password, from the matrix.register output.',
1504
1537
  },
1505
1538
  {
1506
1539
  path: 'mnemonic',
1507
1540
  portType: 'mnemonic',
1541
+ secret: true,
1508
1542
  required: true,
1509
1543
  description:
1510
1544
  'Oracle wallet mnemonic, from the wallet.generate output; stored as SECP_MNEMONIC.',
@@ -1512,12 +1546,14 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1512
1546
  {
1513
1547
  path: 'matrixRecoveryPhrase',
1514
1548
  portType: 'string',
1549
+ secret: true,
1515
1550
  required: true,
1516
1551
  description: 'Matrix recovery phrase, from the matrix.register output.',
1517
1552
  },
1518
1553
  {
1519
1554
  path: 'pin',
1520
1555
  portType: 'string',
1556
+ secret: true,
1521
1557
  required: true,
1522
1558
  description: 'PIN, from the form output; stored as MATRIX_VALUE_PIN.',
1523
1559
  },
@@ -1541,7 +1577,10 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1541
1577
  description:
1542
1578
  'An OpenRouter API key, JWE-encrypted before submit (openRouterApiKeyJwe) — ask the user.',
1543
1579
  },
1544
- { kind: 'pin', description: 'A PIN stored as a secret — ask the user.' },
1580
+ {
1581
+ kind: 'pin',
1582
+ description: `A PIN stored as a secret. ${PIN_AT_RUN_TIME}`,
1583
+ },
1545
1584
  ],
1546
1585
  },
1547
1586
  'qi/oracle.storeConfig': {
@@ -1704,12 +1743,14 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1704
1743
  {
1705
1744
  path: 'matrixPassword',
1706
1745
  portType: 'string',
1746
+ secret: true,
1707
1747
  required: true,
1708
1748
  description: 'Matrix password, from the matrix.register output.',
1709
1749
  },
1710
1750
  {
1711
1751
  path: 'mnemonic',
1712
1752
  portType: 'mnemonic',
1753
+ secret: true,
1713
1754
  required: true,
1714
1755
  description:
1715
1756
  'Oracle wallet mnemonic, from the wallet.generate output; stored as SECP_MNEMONIC.',
@@ -1717,12 +1758,14 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1717
1758
  {
1718
1759
  path: 'matrixRecoveryPhrase',
1719
1760
  portType: 'string',
1761
+ secret: true,
1720
1762
  required: true,
1721
1763
  description: 'Matrix recovery phrase, from the matrix.register output.',
1722
1764
  },
1723
1765
  {
1724
1766
  path: 'pin',
1725
1767
  portType: 'string',
1768
+ secret: true,
1726
1769
  required: true,
1727
1770
  description: 'PIN, from the form output; stored as MATRIX_VALUE_PIN.',
1728
1771
  },
@@ -1838,7 +1881,10 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1838
1881
  description:
1839
1882
  'An OpenRouter API key, JWE-encrypted before submit (openRouterApiKeyJwe) — ask the user.',
1840
1883
  },
1841
- { kind: 'pin', description: 'A PIN stored as a secret — ask the user.' },
1884
+ {
1885
+ kind: 'pin',
1886
+ description: `A PIN stored as a secret. ${PIN_AT_RUN_TIME}`,
1887
+ },
1842
1888
  ],
1843
1889
  },
1844
1890
  'qi/oracle.deploy': {
@@ -1880,6 +1926,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1880
1926
  {
1881
1927
  path: 'secrets',
1882
1928
  portType: 'object',
1929
+ secret: true,
1883
1930
  description: 'Optional map of secret name to value passed to deploy.',
1884
1931
  },
1885
1932
  ],
@@ -1917,6 +1964,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1917
1964
  {
1918
1965
  path: 'secrets',
1919
1966
  portType: 'object',
1967
+ secret: true,
1920
1968
  description:
1921
1969
  'Optional map of secret name to value passed to deploy setup.',
1922
1970
  },
@@ -1955,6 +2003,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1955
2003
  {
1956
2004
  path: 'secrets',
1957
2005
  portType: 'object',
2006
+ secret: true,
1958
2007
  description:
1959
2008
  'Optional map of secret name to value passed to deploy start.',
1960
2009
  },
@@ -1997,7 +2046,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
1997
2046
  {
1998
2047
  path: 'userMessage',
1999
2048
  portType: 'string',
2000
- required: true,
2049
+ required: false,
2001
2050
  description:
2002
2051
  'User-provided purpose text used to query the Domain Indexer (run() throws if both this and purposeDescription are empty).',
2003
2052
  },
@@ -2066,7 +2115,7 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
2066
2115
  {
2067
2116
  path: 'selectedEntityDid',
2068
2117
  portType: 'did',
2069
- required: true,
2118
+ required: false,
2070
2119
  description:
2071
2120
  'DID of the parent entity; required when not skipping (run() throws if absent and skipped is falsy).',
2072
2121
  },
@@ -3502,4 +3551,55 @@ export const ACTION_METADATA: Record<string, OverlayEntry> = {
3502
3551
  },
3503
3552
  ],
3504
3553
  },
3554
+
3555
+ // ── DAO governance proposals ─────────────────────────────────────────────
3556
+ // The registry ships these three without an input schema, so their inputs
3557
+ // are unknown here. Summaries and requirements state only what the action
3558
+ // manifest declares: a side effect, confirmation by default, a
3559
+ // `flow/block/execute` capability, and the output fields.
3560
+ 'qi/governance.member-proposal': {
3561
+ summary:
3562
+ 'Creates a DAO governance proposal that changes membership (the operation output is add, remove or update-weight). Side effect; asks for confirmation by default. Outputs the proposal id, status, proposal contract address, DAO core address, operation and creation time.',
3563
+ whenToUse: [
3564
+ 'A flow needs to put a DAO membership change (add, remove or re-weight a member) to a governance proposal.',
3565
+ ],
3566
+ tags: ['governance', 'proposals', 'dao'],
3567
+ requires: [
3568
+ {
3569
+ kind: 'inputsUndeclared',
3570
+ description:
3571
+ "The action registry does not declare this action's inputs — ask the user what the proposal needs; never invent DAO addresses, members or weights.",
3572
+ },
3573
+ ],
3574
+ },
3575
+ 'qi/governance.settings-proposal': {
3576
+ summary:
3577
+ 'Creates a DAO governance proposal that changes DAO settings. Side effect; asks for confirmation by default. Outputs the proposal id, status, proposal contract address, DAO core address and creation time.',
3578
+ whenToUse: [
3579
+ 'A flow needs to put a change to DAO settings to a governance proposal.',
3580
+ ],
3581
+ tags: ['governance', 'proposals', 'dao'],
3582
+ requires: [
3583
+ {
3584
+ kind: 'inputsUndeclared',
3585
+ description:
3586
+ "The action registry does not declare this action's inputs — ask the user what the proposal needs; never invent DAO addresses or settings.",
3587
+ },
3588
+ ],
3589
+ },
3590
+ 'qi/governance.transaction.send-funds': {
3591
+ summary:
3592
+ 'Creates a DAO governance proposal to send funds from the DAO to a recipient. Moves money once the proposal executes; side effect; asks for confirmation by default. Outputs the proposal id, status, proposal contract address, DAO core address, recipient and creation time.',
3593
+ whenToUse: [
3594
+ 'A flow needs a DAO to vote on spending funds to a recipient address.',
3595
+ ],
3596
+ tags: ['governance', 'proposals', 'dao', 'payments'],
3597
+ requires: [
3598
+ {
3599
+ kind: 'inputsUndeclared',
3600
+ description:
3601
+ "The action registry does not declare this action's inputs — ask the user for the DAO, the recipient and the amount; never invent addresses or amounts.",
3602
+ },
3603
+ ],
3604
+ },
3505
3605
  };
@@ -20,6 +20,8 @@ export const HOOK_TYPES = [
20
20
 
21
21
  export interface ActionSummary {
22
22
  action: string;
23
+ /** See {@link actionCategory}. */
24
+ category: string;
23
25
  summary: string;
24
26
  whenToUse: string[];
25
27
  tags: string[];
@@ -146,16 +148,32 @@ function outputFields(def: ActionDefinition): ActionField[] {
146
148
  }));
147
149
  }
148
150
 
151
+ /**
152
+ * An action's category: the namespace in its name — the part after "qi/" up
153
+ * to the first dot ("qi/claim.submit" → "claim", "qi/governance.transaction.send-funds"
154
+ * → "governance"); an action outside the "qi/" namespace is its own category
155
+ * ("oracle"). The registry declares no category, so the name is the only
156
+ * stable source.
157
+ */
158
+ export function actionCategory(type: string): string {
159
+ const local = type.startsWith('qi/') ? type.slice('qi/'.length) : type;
160
+ const dot = local.indexOf('.');
161
+ return (dot > 0 ? local.slice(0, dot) : local).toLowerCase();
162
+ }
163
+
149
164
  export function listActions(filter?: {
150
165
  category?: string;
151
166
  tag?: string;
152
167
  }): ActionSummary[] {
168
+ const category = filter?.category?.toLowerCase();
153
169
  const result: ActionSummary[] = [];
154
170
  for (const def of getAllActions()) {
155
171
  const overlay = overlayFor(def);
156
172
  if (filter?.tag && !(overlay.tags ?? []).includes(filter.tag)) continue;
173
+ if (category && actionCategory(def.type) !== category) continue;
157
174
  result.push({
158
175
  action: def.type,
176
+ category: actionCategory(def.type),
159
177
  summary: overlay.summary ?? '',
160
178
  whenToUse: overlay.whenToUse ?? [],
161
179
  tags: overlay.tags ?? [],
@@ -0,0 +1,31 @@
1
+ import type { RuntimeContext } from '../../plugin-api/types';
2
+ import { FlowError } from './errors';
3
+ import type { FlowSpecRead } from './types';
4
+
5
+ /**
6
+ * This module is re-exported from the plugin index, which the Worker
7
+ * evaluates at module scope. `flow-doc` and `read` reach `@ixo/editor` →
8
+ * `@ixo/matrix-crdt` → vscode-lib, which schedules a timer while it is
9
+ * evaluated — forbidden in workerd's global scope (see `flows.plugin.ts`) —
10
+ * so both are loaded on the first call, inside a request context.
11
+ */
12
+ export async function readFlowDecisionContext(
13
+ ctx: RuntimeContext,
14
+ ref?: string,
15
+ ): Promise<FlowSpecRead> {
16
+ ctx.abortSignal.throwIfAborted();
17
+ const [{ withFlowDoc }, { readFlowSpec }] = await Promise.all([
18
+ import('./flow-doc'),
19
+ import('./read'),
20
+ ]);
21
+ return withFlowDoc(ctx, ref, undefined, async (doc, roomId) => {
22
+ ctx.abortSignal.throwIfAborted();
23
+ const flow = readFlowSpec(doc, roomId);
24
+ if (!flow)
25
+ throw new FlowError(
26
+ 'flow_not_found',
27
+ 'That flow does not exist or has no steps yet.',
28
+ );
29
+ return flow;
30
+ });
31
+ }