@ixo/oracle-runtime-workers 0.38.0 → 0.40.1

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 (90) hide show
  1. package/package.json +5 -4
  2. package/src/action-interactions/routes.ts +78 -0
  3. package/src/action-interactions/store.ts +1038 -0
  4. package/src/channels/replies.ts +8 -4
  5. package/src/core/capability-expiry.ts +62 -0
  6. package/src/core/capability-router.ts +126 -95
  7. package/src/core/context-budget.ts +116 -4
  8. package/src/core/domain-context/document.ts +74 -2
  9. package/src/core/domain-context/index.ts +1 -0
  10. package/src/core/domain-context/resolver.ts +9 -6
  11. package/src/core/domain-context/turn-context.ts +62 -13
  12. package/src/core/domain-context/types.ts +17 -0
  13. package/src/core/env.ts +21 -2
  14. package/src/core/index.ts +4 -0
  15. package/src/core/llm.ts +29 -0
  16. package/src/core/main-agent-types.ts +45 -4
  17. package/src/core/main-agent.ts +210 -122
  18. package/src/core/manifest.ts +109 -24
  19. package/src/core/mcp-result.ts +56 -0
  20. package/src/core/meta-tools.ts +258 -110
  21. package/src/core/middlewares/capability-gate.ts +77 -28
  22. package/src/core/middlewares/context-guard.ts +154 -21
  23. package/src/core/middlewares/result-cap.ts +1 -1
  24. package/src/core/middlewares/summarization.ts +9 -0
  25. package/src/core/middlewares/tool-marks.ts +11 -2
  26. package/src/core/middlewares/tool-repetition-guard.ts +61 -1
  27. package/src/core/middlewares/turn-boundary.ts +22 -12
  28. package/src/core/operating-guides.ts +126 -0
  29. package/src/core/plugins/skills/skills-tools.ts +6 -31
  30. package/src/core/plugins/skills/skills.plugin.ts +4 -3
  31. package/src/core/plugins/weather/weather.plugin.ts +1 -0
  32. package/src/core/prompt-composer.ts +188 -111
  33. package/src/core/read-result-tool.ts +48 -14
  34. package/src/core/registries.ts +13 -5
  35. package/src/core/state.ts +4 -3
  36. package/src/core/sub-agent-fallback.ts +1 -0
  37. package/src/core/subagent-as-tool.ts +4 -1
  38. package/src/core/tool-access.ts +3 -32
  39. package/src/core/wrap-plugin-tool.ts +2 -1
  40. package/src/do/contracts.ts +45 -1
  41. package/src/do/transcript.ts +40 -11
  42. package/src/do/turn-metadata.ts +16 -4
  43. package/src/do/user-oracle-do.ts +358 -62
  44. package/src/index.ts +1 -0
  45. package/src/memory/session-history-indexer.ts +60 -14
  46. package/src/plugin-api/oracle-plugin.ts +4 -5
  47. package/src/plugin-api/types.ts +32 -3
  48. package/src/plugins/action-proposals/action-proposals.plugin.ts +7 -2
  49. package/src/plugins/agui/agui.plugin.ts +1 -0
  50. package/src/plugins/compact-schema.ts +80 -0
  51. package/src/plugins/composio/composio.plugin.ts +1 -0
  52. package/src/plugins/domain-indexer/domain-indexer.plugin.ts +4 -3
  53. package/src/plugins/editor/editor.plugin.ts +4 -0
  54. package/src/plugins/firecrawl/firecrawl-agent.ts +2 -0
  55. package/src/plugins/firecrawl/firecrawl.plugin.ts +1 -0
  56. package/src/plugins/flows/flows.plugin.ts +37 -6
  57. package/src/plugins/flows/prompts.ts +1 -1
  58. package/src/plugins/flows/tools/authoring.ts +5 -7
  59. package/src/plugins/flows/tools/discovery.ts +1 -4
  60. package/src/plugins/flows/tools/forms.ts +2 -8
  61. package/src/plugins/flows/tools/linkage.ts +1 -4
  62. package/src/plugins/flows/tools/settings.ts +1 -4
  63. package/src/plugins/flows/translator.ts +16 -5
  64. package/src/plugins/flows/types.ts +27 -48
  65. package/src/plugins/hub-actions/hub-actions.plugin.ts +30 -4
  66. package/src/plugins/index.ts +2 -2
  67. package/src/plugins/ixo-chain/ixo-chain.plugin.ts +29 -5
  68. package/src/plugins/ixo-chain/kinds/core.ts +2 -2
  69. package/src/plugins/ixo-chain/kinds/types.ts +34 -5
  70. package/src/plugins/ixo-chain/queries.ts +10 -1
  71. package/src/plugins/ixo-transaction/ixo-transaction.plugin.ts +1 -0
  72. package/src/plugins/matrix-group-chats/index.ts +1 -0
  73. package/src/plugins/memory/memory-tools.ts +4 -4
  74. package/src/plugins/memory/memory.plugin.ts +27 -1
  75. package/src/plugins/memory/oracle-document-tools.ts +24 -49
  76. package/src/plugins/pod-creator/pod-creator.plugin.ts +1 -0
  77. package/src/plugins/portal/portal.plugin.ts +3 -1
  78. package/src/plugins/sandbox/sandbox-write-blob.ts +3 -15
  79. package/src/plugins/sandbox/sandbox.plugin.ts +19 -2
  80. package/src/plugins/tasks/manifest.ts +1 -0
  81. package/src/plugins/tasks/tasks-tools.ts +34 -39
  82. package/src/plugins/user-preferences/user-preferences-tool.ts +11 -37
  83. package/src/plugins/user-preferences/user-preferences.plugin.ts +4 -0
  84. package/src/plugins/vfs/vfs-tools.ts +6 -6
  85. package/src/plugins/vfs/vfs.plugin.ts +4 -5
  86. package/src/plugins/yoma/yoma.plugin.ts +1 -0
  87. package/src/shell/app.ts +241 -6
  88. package/src/sqlite/serialization.ts +12 -0
  89. package/src/sqlite/sqlite-saver.ts +17 -0
  90. package/src/tasks/schedule-input.ts +5 -22
@@ -98,18 +98,11 @@ export const stepInputsSchema = z
98
98
  export const conditionSchema = z.object({
99
99
  source: z
100
100
  .enum(['configured_input', 'runtime_output'])
101
- .describe(
102
- 'Read authored inputs or successful runtime output. Required for newly authored conditions.',
103
- ),
104
- fromStep: stepIdSchema.describe(
105
- 'Id of the upstream step whose value is checked.',
106
- ),
107
- field: nameSchema.describe('Field on the upstream step to inspect.'),
108
- is: z.enum(CONDITION_OPERATORS).describe('Comparison operator.'),
109
- value: z
110
- .unknown()
111
- .optional()
112
- .describe('Value to compare against (omit for isEmpty/isNotEmpty).'),
101
+ .describe('Read authored inputs or successful runtime output.'),
102
+ fromStep: stepIdSchema.describe('The upstream step.'),
103
+ field: nameSchema.describe('Its field to inspect.'),
104
+ is: z.enum(CONDITION_OPERATORS),
105
+ value: z.unknown().optional().describe('Omit for isEmpty/isNotEmpty.'),
113
106
  });
114
107
 
115
108
  export const semanticGateSchema = z
@@ -128,20 +121,18 @@ export const hookSchema = z.object({
128
121
  });
129
122
 
130
123
  export const dueSchema = z.object({
131
- at: nameSchema.optional().describe('Absolute due date (ISO 8601).'),
124
+ at: nameSchema.optional().describe('Absolute (ISO 8601).'),
132
125
  within: nameSchema
133
126
  .optional()
134
- .describe(
135
- 'Duration from when the step becomes active (ISO 8601 duration).',
136
- ),
127
+ .describe('ISO 8601 duration from when the step becomes active.'),
137
128
  afterCommitment: nameSchema
138
129
  .optional()
139
- .describe('Duration from commitment (ISO 8601 duration).'),
130
+ .describe('ISO 8601 duration from commitment.'),
140
131
  });
141
132
 
142
133
  export const onEventSchema = z.object({
143
- fromStep: stepIdSchema.describe('Upstream step that emits the event.'),
144
- event: nameSchema.describe('Event name the upstream step emits.'),
134
+ fromStep: stepIdSchema.describe('The upstream step.'),
135
+ event: nameSchema.describe('The event it emits.'),
145
136
  });
146
137
 
147
138
  /**
@@ -150,38 +141,34 @@ export const onEventSchema = z.object({
150
141
  * is only attached on read (see FlowStepRead).
151
142
  */
152
143
  export const flowStepSchema = z.object({
153
- id: stepIdSchema.describe(
154
- 'Stable, human-readable step id, e.g. "load-batches".',
155
- ),
144
+ id: stepIdSchema.describe('Stable and readable, e.g. "load-batches".'),
156
145
  action: nameSchema
157
146
  .min(1)
158
- .describe('Action name from list_actions (e.g. "qi/email.send").'),
147
+ .describe('From list_actions, e.g. "qi/email.send".'),
159
148
  title: nameSchema.optional(),
160
149
  description: descriptionSchema.optional(),
161
150
  phase: nameSchema
162
151
  .min(1)
163
152
  .optional()
164
- .describe(
165
- 'Stable semantic group for this step, such as "discovery" or "deployment".',
166
- ),
153
+ .describe('Stable semantic group, e.g. "discovery".'),
167
154
  execution: z
168
155
  .enum(['human-only', 'agent-capable'])
169
156
  .optional()
170
157
  .describe(
171
- 'Whether only a person may run this step or a suitably skilled, authorised Flow Agent may run it.',
158
+ 'Only a person may run it, or also a suitably skilled, authorised Flow Agent.',
172
159
  ),
173
160
 
174
161
  inputs: stepInputsSchema
175
162
  .optional()
176
163
  .describe(
177
- 'Inputs for the action. A value may be a reference to an upstream output, written as "{{step-id.output.field}}". ' +
178
- 'Never put a PIN, mnemonic, password, token or API key here: the portal collects those when the user runs the step.',
164
+ 'A value may reference upstream output: "{{step-id.output.field}}". ' +
165
+ 'Never a PIN, mnemonic, password, token or API key: the portal collects those at run time.',
179
166
  ),
180
167
  form: z
181
168
  .record(z.string(), z.unknown())
182
169
  .optional()
183
170
  .describe(
184
- 'For human form steps: pre-filled answers keyed by question name. Pre-fill only — the user submits in the portal.',
171
+ 'Form steps: pre-filled answers by question name; the user submits in the portal.',
185
172
  ),
186
173
 
187
174
  after: z
@@ -189,13 +176,11 @@ export const flowStepSchema = z.object({
189
176
  .max(MAX_FLOW_STEPS)
190
177
  .optional()
191
178
  .describe(
192
- 'Order this step after the named steps. Pair with an input reference for a real data dependency. This is ordering only, not an auto-trigger.',
179
+ 'Ordering only, not an auto-trigger; pair with an input reference for a data dependency.',
193
180
  ),
194
181
  runWhen: conditionSchema
195
182
  .optional()
196
- .describe(
197
- 'Gate this step on an upstream configured input or runtime output.',
198
- ),
183
+ .describe('Gate on an upstream configured input or runtime output.'),
199
184
  conditions: z
200
185
  .array(conditionSchema)
201
186
  .max(
@@ -203,7 +188,7 @@ export const flowStepSchema = z.object({
203
188
  `A step may have at most ${MAX_CONDITIONS_PER_STEP} conditions.`,
204
189
  )
205
190
  .optional()
206
- .describe('Multiple activation gates (all must pass).'),
191
+ .describe('Several gates, all must pass.'),
207
192
  semanticGate: semanticGateSchema
208
193
  .optional()
209
194
  .describe(
@@ -212,24 +197,23 @@ export const flowStepSchema = z.object({
212
197
  onEvent: onEventSchema
213
198
  .optional()
214
199
  .describe(
215
- 'Advanced: auto-trigger this step when an upstream step emits an event. Only valid for event-capable upstream actions; validate_flow enforces this.',
200
+ 'Advanced: run when an upstream step emits an event; event-capable actions only.',
216
201
  ),
217
202
 
218
203
  trigger: z
219
204
  .enum(['manual', 'flow-start'])
220
205
  .optional()
221
- .describe('When the step runs. Default "manual".'),
206
+ .describe('Default "manual".'),
222
207
  due: dueSchema.optional(),
223
208
 
224
209
  assignTo: didSchema
225
210
  .optional()
226
211
  .describe(
227
- 'The DID assigned to this step. Assigning AUTHORISES that DID to run the step (it is written to the ' +
228
- "step's authorised actors) — only assign a DID the user named and confirmed.",
212
+ 'Assigning AUTHORISES this DID to run the step: only a DID the user named and confirmed.',
229
213
  ),
230
214
  commitTo: nameSchema
231
215
  .optional()
232
- .describe('Commitment window (ISO 8601 duration).'),
216
+ .describe('Commitment window, ISO 8601 duration.'),
233
217
 
234
218
  on: z
235
219
  .record(z.string(), z.array(hookSchema))
@@ -243,12 +227,12 @@ export const flowStepSchema = z.object({
243
227
  )
244
228
  .optional()
245
229
  .describe(
246
- 'Governed skill ids required for agent-capable execution. The first is used for Flow Agent matching.',
230
+ 'Governed skill ids for agent-capable execution; the first matches the Flow Agent.',
247
231
  ),
248
232
  requireConfirmation: z
249
233
  .boolean()
250
234
  .optional()
251
- .describe('Hint the portal to force a confirmation before this step runs.'),
235
+ .describe('The portal confirms before this step runs.'),
252
236
  });
253
237
 
254
238
  /**
@@ -266,12 +250,7 @@ export const sizedFlowStepSchema = flowStepSchema.refine(
266
250
  */
267
251
  export const flowSpecSchema = z
268
252
  .object({
269
- ref: z
270
- .string()
271
- .optional()
272
- .describe(
273
- 'Opaque flow handle. Omit when creating; the plugin assigns it.',
274
- ),
253
+ ref: z.string().optional().describe('Omit when creating.'),
275
254
  title: nameSchema.min(1),
276
255
  goal: descriptionSchema.optional(),
277
256
  steps: z
@@ -28,6 +28,7 @@ import type {
28
28
  } from '../../plugin-api/types';
29
29
  import { ixoAddressOf } from '../../core/user-identity';
30
30
  import { toolNotRunMessage } from '../../core/tool-not-run';
31
+ import { compactJsonSchema } from '../compact-schema';
31
32
  import {
32
33
  CHAIN_TX_CATALOG,
33
34
  CHAIN_TX_GENERAL_RULES,
@@ -80,8 +81,22 @@ export const requestOperationJsonSchema = {
80
81
  (branch) => !RUNTIME_BUILT_KINDS.includes(String(branchKind(branch))),
81
82
  ),
82
83
  };
83
- const operationSchema = z.fromJSONSchema(requestOperationJsonSchema);
84
- const requestSchema = z.strictObject({ operation: operationSchema });
84
+ /**
85
+ * What the tool binds: each kind's fields, required keys and types, without
86
+ * the protocol's limits and patterns, over a third of its characters. The
87
+ * handler checks a call against {@link strictOperations}, then
88
+ * `parseOperation`.
89
+ */
90
+ const requestSchema = z.strictObject({
91
+ operation: z.fromJSONSchema(compactJsonSchema(requestOperationJsonSchema)),
92
+ });
93
+ /** Each requestable kind's whole protocol schema, for a refusal naming the field. */
94
+ const strictOperations = new Map(
95
+ requestOperationJsonSchema.oneOf.map((branch) => [
96
+ String(branchKind(branch)),
97
+ z.fromJSONSchema(branch),
98
+ ]),
99
+ );
85
100
  const statusSchema = z.strictObject({
86
101
  actionId: z.string().regex(/^[A-Za-z0-9_-]{32}$/),
87
102
  });
@@ -641,6 +656,16 @@ async function requestHubAction(
641
656
  const parsed = requestSchema.safeParse(input);
642
657
  if (!parsed.success)
643
658
  return { status: 'unavailable', reason: 'An operation is required.' };
659
+ const limits = strictOperations
660
+ .get(String(kind))
661
+ ?.safeParse(parsed.data.operation);
662
+ if (limits && !limits.success)
663
+ return {
664
+ status: 'unavailable',
665
+ reason: `The requested operation is unsupported or incomplete (${limits.error.issues
666
+ .map((issue) => `${pathText(issue.path)}: ${issue.message}`)
667
+ .join('; ')}).`,
668
+ };
644
669
  if (ctx.config.HUB_ACTIONS_ENABLED !== 'true' || !ctx.hubActions)
645
670
  return {
646
671
  status: 'unavailable',
@@ -1179,6 +1204,7 @@ const manifest: PluginManifest = {
1179
1204
  tags: ['actions', 'channels'],
1180
1205
  category: 'integration',
1181
1206
  visibility: 'on-demand',
1207
+ brief: 'prepare chain transactions to sign in Auth Hub',
1182
1208
  stability: 'experimental',
1183
1209
  };
1184
1210
 
@@ -1227,7 +1253,7 @@ export class HubActionsPlugin extends OraclePlugin {
1227
1253
  {
1228
1254
  name: 'hub_action_options',
1229
1255
  description:
1230
- "Read this authenticated owner’s confirmed Gmail and Calendar connections, requestable documents, action resources and bank tokens (`transfer.tokens`: denom, symbol, decimals, verified, balance in base units). Use each returned service, identifier and label before preparing a related Hub review. A Gmail profile connection does not authorize sending. For a token that is not verified, name its full denom and say it is unverified; its amounts are base units. ownerDid is the authenticated user's DID and ownerAddress their IXO account address.",
1256
+ "Read the owner’s confirmed Gmail and Calendar connections, requestable documents, action resources and bank tokens (`transfer.tokens`: denom, symbol, decimals, verified, balance in base units). Use each returned service, identifier and label to prepare a related Hub review. A Gmail profile connection does not authorize sending. For a token that is not verified, name its full denom and say it is unverified; its amounts are base units. ownerDid is the authenticated user's DID and ownerAddress their IXO account address.",
1231
1257
  schema: discoverSchema,
1232
1258
  effect: 'read',
1233
1259
  handler: hubActionOptions,
@@ -1235,7 +1261,7 @@ export class HubActionsPlugin extends OraclePlugin {
1235
1261
  {
1236
1262
  name: 'request_hub_action',
1237
1263
  description:
1238
- 'Prepare a supported operation for the authenticated channel owner to review in Auth Hub. Never approves, signs, or executes. For email, propose one plain-text message to one recipient using a confirmed Gmail send connection. Supply only the operation candidate; the runtime supplies identity and turn binding. Coin sends and other chain transactions have their own tool (request_chain_transaction). Never prepare a replacement email after an unknown send without the user checking Gmail’s Sent folder and asking again.',
1264
+ 'Prepare a supported operation for the authenticated channel owner to review in Auth Hub. Never approves, signs, or executes. For email, propose one plain-text message to one recipient using a confirmed Gmail send connection. Supply only the operation candidate; the runtime supplies identity and turn binding. Coin sends and other chain transactions have their own tool (request_chain_transaction). Never prepare a replacement email after an unknown send without the user checking Gmail’s Sent folder and asking again. Limits are checked on the call; `startsAt` and `endsAt` are ISO 8601 with an offset, a saved `filename` ends in .txt, a form field `id` is lower_snake_case.',
1239
1265
  schema: requestSchema,
1240
1266
  effect: 'write',
1241
1267
  handler: requestHubAction,
@@ -8,8 +8,8 @@ export { HubActionsPlugin } from './hub-actions/hub-actions.plugin';
8
8
  * plugins. Each is gated the same way as on Node: `autoDetect` on its env
9
9
  * key where one exists (memory / sandbox / firecrawl / composio), always-on
10
10
  * otherwise (domain-indexer; ixo-chain unless `IXO_CHAIN_TOOLS=off`; vfs
11
- * self-gates on `ctx.ucan.hasSigningKey()`; pod-creator and ixo-chain are
12
- * on-demand and stay hidden until `load_capability`).
11
+ * self-gates on `ctx.ucan.hasSigningKey()`; sandbox, vfs, pod-creator and
12
+ * ixo-chain are on-demand and stay hidden until `load_capability`).
13
13
  *
14
14
  * A host opts in by spreading `BUNDLED_WORKERS_PLUGINS` into
15
15
  * `createOracleWorker({ plugins })` — plugins whose env keys are absent are
@@ -23,7 +23,7 @@ import {
23
23
  type Source,
24
24
  } from './http';
25
25
  import { KINDS, kindByName, kindNames } from './kinds/registry';
26
- import type { KindDef } from './kinds/types';
26
+ import { argKeys, type KindDef } from './kinds/types';
27
27
  import {
28
28
  chainLookup,
29
29
  cutRow,
@@ -426,11 +426,11 @@ const manifest: PluginManifest = {
426
426
  {
427
427
  user: 'Did I get paid for my claims in collection 8250?',
428
428
  thought:
429
- "The user's claims there (evaluation and payment status) and the collection's payment terms, in one lookup.",
429
+ "The user's claims there (agent: their own address; evaluation and payment status) and the collection's payment terms, in one lookup.",
430
430
  tool: 'chain_lookup',
431
431
  args: {
432
432
  requests: [
433
- { kind: 'claims', args: { collectionId: '8250' } },
433
+ { kind: 'claims', args: { agent: 'ixo1…', collectionId: '8250' } },
434
434
  { kind: 'claim_collection', args: { id: '8250' } },
435
435
  ],
436
436
  },
@@ -452,10 +452,11 @@ const manifest: PluginManifest = {
452
452
  // Hosts that want it on every turn set `visibility: 'always'` through
453
453
  // `manifestOverrides`.
454
454
  visibility: 'on-demand',
455
+ brief: 'read the IXO chain: balances, entities, claims, tokens',
455
456
  stability: 'beta',
456
457
  };
457
458
 
458
- /** Read-only and transfer rule; also in the tool descriptions, as a capability-router preload shows no operating guide. */
459
+ /** Read-only and transfer rule; also in the tool descriptions, so each tool reads correctly on its own. */
459
460
  const READ_ONLY_RULE =
460
461
  "Read-only. For a transfer use this turn's transfer tools; on a channel read `hub_action_options` first (the Hub applies the account's limits).";
461
462
  /** Chain text is written by anyone; also in the `chain_lookup` description. */
@@ -478,6 +479,29 @@ const LOOKUP_UNITS_RULE =
478
479
  const NAMES_RULE =
479
480
  'Call people and things by their `names` entry; give an address or DID only when asked; beside a `selfChosen` name the user did not pick, also give the short address (first 12 … last 6 characters).';
480
481
 
482
+ /**
483
+ * What the list of arguments alone would mislead on: `claims` with a
484
+ * `collectionId` reads as the collection's claims, but it stays one agent's.
485
+ */
486
+ const ARG_NOTES: Record<string, string> = {
487
+ claims: ' [default: user]',
488
+ claim_collection: ' [totals]',
489
+ };
490
+
491
+ /**
492
+ * Every kind's arguments besides `address` and `first`, from the kinds' own
493
+ * schemas: known without a `describe_chain_kinds` round trip, and they cannot
494
+ * drift.
495
+ */
496
+ export const KIND_ARGS = KINDS.flatMap((kind) => {
497
+ const keys = argKeys(kind.args).keys.filter(
498
+ (key) => key !== 'address' && key !== 'first',
499
+ );
500
+ return keys.length
501
+ ? [`${kind.name}(${keys.join(',')})${ARG_NOTES[kind.name] ?? ''}`]
502
+ : [];
503
+ }).join(' ');
504
+
481
505
  /** Says the overview is broad and costly; its units, text and names rules are `chain_lookup`'s, bound beside it. */
482
506
  const OVERVIEW_DESCRIPTION = [
483
507
  "A broad look at an IXO account (default: the user's) by `sections` (default: all): per section: counts, top 3 rows, `more` (the request for the rest).",
@@ -543,7 +567,7 @@ export class IxoChainPlugin extends OraclePlugin {
543
567
  name: 'chain_lookup',
544
568
  description: [
545
569
  'IXO chain data: 1–8 `requests` `{ kind, args }`, each answered on its own (`ok`, or `reason` + `retryable`).',
546
- "`describe_chain_kinds` gives a kind's `args`; account args: ixo1… or did:ixo:ixo1… (default: the user); lists: `first` 1–20.",
570
+ `\`args\`: account args take ixo1… or did:ixo:ixo1… (default: the user); \`address\` on most kinds, \`first\` 1–20 on lists; others: ${KIND_ARGS}. \`describe_chain_kinds\` explains a kind.`,
547
571
  '`source`: `chain` live, `blocksync` indexed (seconds behind).',
548
572
  LOOKUP_UNITS_RULE,
549
573
  NETWORK_RULE,
@@ -63,7 +63,7 @@ const STATUSES =
63
63
  const claimsKind = defineKind({
64
64
  name: 'claims',
65
65
  summary:
66
- 'Claims an agent submitted (default: the user), newest first, with evaluation and payment status.',
66
+ "One agent's claims (default: the user; `collectionId` needs `agent`), newest first, with evaluation and payment status. A collection's totals are in `claim_collection`.",
67
67
  explain: [
68
68
  'Each claim: claimId, collectionId, agent, submissionDate, `evaluation` (status, date) and `paymentsStatus` per payment leg (e.g. `approval: PAID`).',
69
69
  STATUSES,
@@ -73,7 +73,7 @@ const claimsKind = defineKind({
73
73
  source: 'blocksync',
74
74
  list: true,
75
75
  args: CORE_ARGS.claims,
76
- example: { collectionId: '8250', first: 5 },
76
+ example: { first: 5 },
77
77
  plan: (args, ctx) => blocksyncPlan({ kind: 'claims', ...args }, ctx),
78
78
  });
79
79
 
@@ -9,7 +9,7 @@
9
9
  * {@link defineKind}: `chain_lookup`'s tool schema only names the kind, so
10
10
  * the catalogue does not cost context on every turn.
11
11
  */
12
- import type { z } from 'zod';
12
+ import { z } from 'zod';
13
13
  import type { UserIdentity } from '../../../core/user-identity';
14
14
  import type { TokenDisplay } from '../denoms';
15
15
  import type { ChainCall, Failure, Outcome, Source } from '../http';
@@ -109,8 +109,37 @@ export interface KindDef {
109
109
  plan(rawArgs: unknown, ctx: KindContext): KindPlan | KindInvalid;
110
110
  }
111
111
 
112
- /** The argument problems as one sentence naming what the kind expects. */
113
- function invalidArgs(name: string, error: z.ZodError): KindInvalid {
112
+ /** The names a kind's arguments take, in schema order, with the required ones. */
113
+ export function argKeys(args: z.ZodType): {
114
+ keys: string[];
115
+ required: string[];
116
+ } {
117
+ const { properties = {}, required = [] } = z.toJSONSchema(args, {
118
+ io: 'input',
119
+ unrepresentable: 'any',
120
+ });
121
+ return { keys: Object.keys(properties), required };
122
+ }
123
+
124
+ /** A kind's valid keys as a clause of its refusal. */
125
+ function validKeys(args: z.ZodType): string {
126
+ const { keys, required } = argKeys(args);
127
+ if (!keys.length) return 'This kind takes no args.';
128
+ const list = keys
129
+ .map((key) => (required.includes(key) ? `${key} (required)` : key))
130
+ .join(', ');
131
+ return `Its args: ${list}.`;
132
+ }
133
+
134
+ /**
135
+ * The argument problems as one sentence, with the kind's valid keys, so the
136
+ * model can correct the request without describing the kind first.
137
+ */
138
+ function invalidArgs(
139
+ name: string,
140
+ error: z.ZodError,
141
+ args: z.ZodType,
142
+ ): KindInvalid {
114
143
  const issues = error.issues
115
144
  .slice(0, 3)
116
145
  .map((issue) =>
@@ -120,7 +149,7 @@ function invalidArgs(name: string, error: z.ZodError): KindInvalid {
120
149
  )
121
150
  .join('; ');
122
151
  return {
123
- invalid: `Invalid args for kind "${name}" (${issues}). Call describe_chain_kinds with ["${name}"] for its arguments.`,
152
+ invalid: `Invalid args for kind "${name}" (${issues}). ${validKeys(args)} describe_chain_kinds with ["${name}"] explains them.`,
124
153
  };
125
154
  }
126
155
 
@@ -150,7 +179,7 @@ export function defineKind<S extends z.ZodType>(spec: {
150
179
  const parsed = spec.args.safeParse(rawArgs ?? {});
151
180
  return parsed.success
152
181
  ? spec.plan(parsed.data, ctx)
153
- : invalidArgs(spec.name, parsed.error);
182
+ : invalidArgs(spec.name, parsed.error, spec.args);
154
183
  },
155
184
  };
156
185
  }
@@ -69,7 +69,9 @@ export const CORE_ARGS = {
69
69
  collectionId: z
70
70
  .string()
71
71
  .optional()
72
- .describe('Only claims in this collection, e.g. "8250".'),
72
+ .describe(
73
+ 'Only this agent\'s claims in this collection, e.g. "8250"; needs `agent`.',
74
+ ),
73
75
  first: firstArg,
74
76
  after: z
75
77
  .string()
@@ -290,6 +292,13 @@ export function requestField(
290
292
  ): FieldPlan {
291
293
  switch (request.kind) {
292
294
  case 'claims': {
295
+ // A collection alone would quietly mean "the user's claims in it",
296
+ // which a question about the collection never asks: whose claims is
297
+ // said, or the collection's own counts are read instead.
298
+ if (request.collectionId !== undefined && request.agent === undefined)
299
+ return invalid(
300
+ `claims lists one agent's claims. For collection ${request.collectionId} as a whole (count, approved, rejected), use claim_collection with id "${request.collectionId}"; for one agent's claims in it, pass agent too (the user's own address for theirs).`,
301
+ );
293
302
  const agent = accountOf(request.agent, identity, 'agent');
294
303
  if (!agent.ok) return invalid(agent.detail);
295
304
  if (
@@ -96,6 +96,7 @@ const manifest: PluginManifest = {
96
96
  tags: ['ixo', 'transaction', 'wallet', 'portal', 'cosmos'],
97
97
  category: 'integration',
98
98
  visibility: 'on-demand',
99
+ brief: 'prepare chain transactions for wallet signing in Portal',
99
100
  stability: 'experimental',
100
101
  };
101
102
 
@@ -91,6 +91,7 @@ const manifest: PluginManifest = {
91
91
  tags: ['matrix', 'group-chat', 'memory'],
92
92
  category: 'communication',
93
93
  visibility: 'on-demand',
94
+ brief: 'search what was said in this group room',
94
95
  stability: 'beta',
95
96
  };
96
97
 
@@ -30,10 +30,10 @@ export const MEMORY_CLEAR_MCP_NAME = 'memory-engine__clear';
30
30
  * knowledge from chat without a per-oracle code change: the Memory Engine
31
31
  * itself checks on chain that the caller is a member (controller, owner,
32
32
  * Matrix admin or DAO member) of the oracle's domain entity and refuses
33
- * everyone else, so listing the tool for every user
34
- * costs one tool description and grants nothing. Forks that want a different
35
- * surface (drop `clear`, add `delete_edge`) pass an explicit list via plugin
36
- * options.
33
+ * everyone else, so offering the tool to every user grants nothing. Forks
34
+ * that want a different surface (drop `clear`, add `delete_edge`) pass an
35
+ * explicit list via plugin options. Everything but search and add stays
36
+ * behind `load_capability` (the plugin manifest's `onDemandTools`).
37
37
  */
38
38
  export const DEFAULT_MEMORY_TOOLS = [
39
39
  MEMORY_SEARCH_MCP_NAME,
@@ -12,10 +12,18 @@ import {
12
12
  createDefaultMemoryMcpFactory,
13
13
  DEFAULT_MEMORY_TOOLS,
14
14
  fetchMemoryTools,
15
+ MEMORY_ADD_ORACLE_KNOWLEDGE_MCP_NAME,
16
+ MEMORY_CLEAR_MCP_NAME,
17
+ MEMORY_DELETE_EDGE_MCP_NAME,
18
+ MEMORY_DELETE_EPISODE_MCP_NAME,
15
19
  type MemoryMcpFactory,
16
20
  } from './memory-tools';
17
21
  import { oracleEntityDidSchema } from './memory-entity';
18
- import { createOracleDocumentTools } from './oracle-document-tools';
22
+ import {
23
+ ADD_ORACLE_DOCUMENT_TOOL_NAME,
24
+ createOracleDocumentTools,
25
+ DELETE_ORACLE_DOCUMENT_TOOL_NAME,
26
+ } from './oracle-document-tools';
19
27
 
20
28
  const configSchema = z.object({
21
29
  MEMORY_MCP_URL: z.string().url('MEMORY_MCP_URL must be a valid HTTP(S) URL.'),
@@ -51,6 +59,24 @@ const manifest: PluginManifest = {
51
59
  tags: ['memory', 'recall', 'artifacts', 'personalization'],
52
60
  category: 'memory',
53
61
  visibility: 'always',
62
+ brief: 'add or delete oracle documents, knowledge; delete memories',
63
+ // Recall and saving are bound on every call. A message about memory says
64
+ // "Memory" to the router, and only the rare admin work needs the rest: on
65
+ // the first full lab run none of its 31 preloads was used.
66
+ routable: false,
67
+ // Search and add stay bound: they serve ordinary conversation. So does
68
+ // `list_oracle_documents`: with the domain's document index in the prompt,
69
+ // a catalogue line alone did not get a model to look past that index. These
70
+ // serve a controller curating the oracle, or a user asking to forget, and
71
+ // carry most of the plugin's tool text.
72
+ onDemandTools: [
73
+ MEMORY_ADD_ORACLE_KNOWLEDGE_MCP_NAME,
74
+ MEMORY_DELETE_EPISODE_MCP_NAME,
75
+ MEMORY_DELETE_EDGE_MCP_NAME,
76
+ MEMORY_CLEAR_MCP_NAME,
77
+ ADD_ORACLE_DOCUMENT_TOOL_NAME,
78
+ DELETE_ORACLE_DOCUMENT_TOOL_NAME,
79
+ ],
54
80
  stability: 'stable',
55
81
  requires: [MEMORY_CAPABILITY],
56
82
  };