@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
@@ -6,13 +6,8 @@ import type {
6
6
  PluginTool,
7
7
  } from '../plugin-api/types';
8
8
  import type { CapabilityRequirement } from './manifest';
9
- import type {
10
- RegisteredSubAgent,
11
- SubAgentRegistry,
12
- ToolRegistry,
13
- } from './registries';
9
+ import type { RegisteredSubAgent } from './registries';
14
10
  import { computeSubAgentToolName } from './subagent-as-tool';
15
- import { NOOP_LOGGER } from './utils';
16
11
 
17
12
  /** `ctx.ucan.hasCapability` bound to the turn's delegation. */
18
13
  export type HasCapability = (resource: string, action: string) => boolean;
@@ -53,8 +48,8 @@ export interface TurnToolAccess<
53
48
  /**
54
49
  * Plugins that contributed tools or sub-agents of which none is left.
55
50
  * Treated like a plugin whose `requires` are unmet (left out of the
56
- * prompt, refused by `load_capability`, never preloaded) except that they
57
- * are hidden outright: `list_capabilities` does not list them.
51
+ * prompt, refused by `load_capability`, not offered to the router) except
52
+ * that they are hidden outright: `list_capabilities` does not list them.
58
53
  */
59
54
  hiddenPlugins: ReadonlySet<string>;
60
55
  }
@@ -145,30 +140,6 @@ export function resolveTurnToolAccess<
145
140
  return { tools, subAgents, withheldToolNames, hiddenPlugins };
146
141
  }
147
142
 
148
- /**
149
- * `hiddenPlugins` from the boot-time contributions alone, for the
150
- * capability router, which predicts before the turn's request-time tools are
151
- * collected. A plugin whose request-time tools would make it usable may be
152
- * left out here (the router does not offer it; `load_capability` still
153
- * can); one whose request-time tools are all withheld may be offered, and
154
- * the turn's build voids that preload (`createMainAgent`).
155
- */
156
- export async function bootHiddenPlugins(input: {
157
- registries: { tools: ToolRegistry; subAgents: SubAgentRegistry };
158
- buildCtx: PluginContext;
159
- has: HasCapability;
160
- }): Promise<ReadonlySet<string>> {
161
- const { registries, buildCtx, has } = input;
162
- return resolveTurnToolAccess({
163
- tools: await registries.tools.collectBoot(buildCtx),
164
- subAgents: registries.subAgents.collectBoot(buildCtx),
165
- buildCtx,
166
- has,
167
- // A failing sub-agent is reported by the turn's build, once.
168
- logger: NOOP_LOGGER,
169
- }).hiddenPlugins;
170
- }
171
-
172
143
  /**
173
144
  * The manifest as this turn may show it: `examples` naming a withheld tool
174
145
  * removed, so neither the Tier-1 prompt nor `load_capability` teaches the
@@ -1,5 +1,6 @@
1
1
  import { ToolMessage } from '@langchain/core/messages';
2
2
  import { Command } from '@langchain/langgraph';
3
+ import { withoutStructuredCopy } from './mcp-result';
3
4
  import { capToolResult, type ResultCapConfig } from './middlewares/result-cap';
4
5
  import { tool } from '@langchain/core/tools';
5
6
  import type { StructuredTool } from 'langchain';
@@ -125,7 +126,7 @@ export function wrapPluginTool(
125
126
  );
126
127
  if (pluginName !== undefined)
127
128
  requireToolPlane(ctx, pluginName, pluginTool);
128
- const output = await pluginTool.handler(args, ctx);
129
+ const output = withoutStructuredCopy(await pluginTool.handler(args, ctx));
129
130
  // A tool's own message (a result that says the tool did not run) is
130
131
  // returned whole, never capped into text.
131
132
  if (
@@ -1,3 +1,11 @@
1
+ import type {
2
+ CheckClaimDispatch,
3
+ CheckDispatch,
4
+ } from '@ixo/action-interactions';
5
+ import type {
6
+ InteractionCommand,
7
+ InteractionOutcome,
8
+ } from '../action-interactions/store';
1
9
  import type {
2
10
  ChannelAttachment,
3
11
  ChannelControlInput,
@@ -63,6 +71,7 @@ import type { DomainContextProvenance } from '../core/domain-context';
63
71
 
64
72
  /** Bindings every oracle Worker must declare (see the example `wrangler.jsonc`). */
65
73
  export interface OracleWorkerEnv {
74
+ ACTION_INTERACTIONS_ENABLED?: string;
66
75
  TOPIC_DELIVERABLES_ENABLED?: string;
67
76
  ACTION_PROPOSALS_RPC_TESTNET?: string;
68
77
  ACTION_PROPOSALS_RPC_DEVNET?: string;
@@ -271,6 +280,8 @@ export interface OracleWorkerEnv {
271
280
  LLM_STREAM_IDLE_TIMEOUT_MS?: string;
272
281
  LLM_BYO_STREAM_IDLE_TIMEOUT_MS?: string;
273
282
  LLM_STREAM_RETRIES?: string;
283
+ /** Most tokens one platform model call may generate, reasoning included (default 16384; 0 = the model's limit). */
284
+ LLM_MAX_OUTPUT_TOKENS?: string;
274
285
  /** LangGraph steps one turn may take before `GraphRecursionError` (default 600; Node hard-codes 200). */
275
286
  TURN_RECURSION_LIMIT?: string;
276
287
  /** Turn budget: tool attempts (default 120) and deadline in ms (600000). */
@@ -295,7 +306,12 @@ export interface OracleWorkerEnv {
295
306
  MODEL_CONTEXT_TOKENS?: string;
296
307
  MODEL_CONTEXT_OVERRIDES?: string;
297
308
  CONTEXT_SUMMARIZE_FRACTION?: string;
309
+ CONTEXT_SUMMARIZE_MAX_TOKENS?: string;
298
310
  CONTEXT_PRUNE_FRACTION?: string;
311
+ CONTEXT_PRUNE_MAX_TOKENS?: string;
312
+ CONTEXT_STALE_RESULT_TURNS?: string;
313
+ CONTEXT_CACHE_COLD_MS?: string;
314
+ CONTEXT_PLUGIN_IDLE_TURNS?: string;
299
315
  CONTEXT_RESULT_CAP_FRACTION?: string;
300
316
  CONTEXT_RESULT_CAP_MAX_CHARS?: string;
301
317
  CONTEXT_REQUEST_FRACTION?: string;
@@ -327,9 +343,14 @@ export interface OracleWorkerEnv {
327
343
  /**
328
344
  * Capability router (needs a `DECISION_PROVIDER`). `off` (default) never
329
345
  * evaluates; `shadow` evaluates and logs the verdict without preloading;
330
- * `on` preloads the predicted on-demand plugin's tools for the turn.
346
+ * `on` loads the predicted plugins on the thread before the first model
347
+ * call.
331
348
  */
332
349
  CAPABILITY_ROUTER?: CapabilityRouterMode;
350
+ /** The score a preload needs on a warm turn (default 0.8; above 1, never). */
351
+ CAPABILITY_ROUTER_WARM_THRESHOLD?: string;
352
+ /** The score a preload needs on a cold turn (default 0.7). */
353
+ CAPABILITY_ROUTER_COLD_THRESHOLD?: string;
333
354
  /** Applies exclusively to authenticated channel admission; Portal/Matrix turns never route. */
334
355
  CHANNEL_SEMANTIC_ROUTING?: 'off' | 'shadow' | 'on';
335
356
  CHANNEL_SEMANTIC_ROUTING_BINDINGS?: string;
@@ -770,6 +791,29 @@ export interface StorageStatus {
770
791
  * piped straight to the client.
771
792
  */
772
793
  export interface UserOracleObject extends Rpc.DurableObjectBranded {
794
+ readActionInteractionTask(
795
+ identity: TurnIdentity,
796
+ sessionId: string,
797
+ taskId: string,
798
+ ): Promise<InteractionOutcome<string>>;
799
+ checkDispatch(
800
+ identity: TurnIdentity,
801
+ input: CheckDispatch,
802
+ ): Promise<InteractionOutcome<string>>;
803
+ checkClaimDispatch(
804
+ identity: TurnIdentity,
805
+ input: CheckClaimDispatch,
806
+ ): Promise<InteractionOutcome<string>>;
807
+ actionInteraction(
808
+ identity: TurnIdentity,
809
+ command: InteractionCommand,
810
+ ): Promise<InteractionOutcome<string>>;
811
+ readActionInteraction(
812
+ identity: TurnIdentity,
813
+ sessionId: string,
814
+ id?: string,
815
+ references?: boolean,
816
+ ): Promise<InteractionOutcome<string>>;
773
817
  recordHubActionOutcome(outcome: ActionOutcomeV1): Promise<void>;
774
818
  topicDeliverable(
775
819
  identity: TurnIdentity,
@@ -140,6 +140,45 @@ export function visibleText(message: BaseMessage): string {
140
140
  return contentToText(visibleContent(message));
141
141
  }
142
142
 
143
+ /**
144
+ * Whether a stored message is one the user sees in the transcript. System and
145
+ * tool messages never are, nor a failed reply, nor anything the runtime wrote
146
+ * for the model about an attachment: the extracted text of a file (an AI
147
+ * message with an `attachment`) and `view_attachment` re-attaching a payload,
148
+ * nor a chat gateway's delivery notice.
149
+ */
150
+ export function visibleToUser(message: BaseMessage): boolean {
151
+ if (message.type === 'system' || message.type === 'tool') return false;
152
+ const kw = (message.additional_kwargs ?? {}) as Record<string, unknown>;
153
+ if (kw.isError) return false;
154
+ if (message.type === 'ai' && Boolean(kw.attachment)) return false;
155
+ // A chat gateway's delivery notice: the model's, never a user message.
156
+ return !isAttachmentViewMessage(message) && !isDeliveryNoticeMessage(message);
157
+ }
158
+
159
+ /**
160
+ * The latest turns as the user saw them, oldest first and each as
161
+ * `user: …` or `assistant: …` cut to `maxChars`, from messages listed newest
162
+ * first. Only what `visibleToUser` lets through, without summaries and rows
163
+ * with no visible text.
164
+ */
165
+ export function recentTurnTexts(
166
+ newestFirst: readonly BaseMessage[],
167
+ limit: number,
168
+ maxChars: number,
169
+ ): string[] {
170
+ const turns: string[] = [];
171
+ for (const message of newestFirst) {
172
+ if (turns.length === limit) break;
173
+ if (isSummarizationMessage(message) || !visibleToUser(message)) continue;
174
+ const text = visibleText(message).trim();
175
+ if (!text) continue;
176
+ const speaker = message.type === 'human' ? 'user' : 'assistant';
177
+ turns.push(`${speaker}: ${text.slice(0, maxChars)}`);
178
+ }
179
+ return turns.reverse();
180
+ }
181
+
143
182
  /**
144
183
  * The summarization middleware's bookkeeping message — never shown to users.
145
184
  * LangChain 1.4 writes it as a HUMAN message tagged
@@ -171,18 +210,8 @@ export async function transformTranscript(
171
210
  for (const message of messages) {
172
211
  const toolMsg = message.type === 'tool' ? (message as ToolMessage) : null;
173
212
  const kw = (message.additional_kwargs ?? {}) as Record<string, unknown>;
174
- const isExtractionContext = message.type === 'ai' && Boolean(kw.attachment);
175
213
 
176
- if (
177
- message.type !== 'system' &&
178
- message.type !== 'tool' &&
179
- !kw.isError &&
180
- !isExtractionContext &&
181
- // `view_attachment` re-attaching an offloaded payload — model-facing.
182
- !isAttachmentViewMessage(message) &&
183
- // A chat gateway's delivery notice — the model's, never a user message.
184
- !isDeliveryNoticeMessage(message)
185
- ) {
214
+ if (visibleToUser(message)) {
186
215
  const reasoning = reasoningToText(kw.reasoning);
187
216
  const attachments =
188
217
  message.type === 'human'
@@ -62,6 +62,16 @@ export interface PriorMetadataState {
62
62
  sessionRunId?: string;
63
63
  currentEntityDid?: string;
64
64
  loadedPlugins?: string[];
65
+ /** The plugins whose operating guides the prompt carried (`operating-guides.ts`). */
66
+ promptGuides?: string[];
67
+ /** The plugins whose usage the thread's messages carry (`operating-guides.ts`). */
68
+ capabilityUsage?: string[];
69
+ }
70
+
71
+ function strings(value: unknown): string[] | undefined {
72
+ return Array.isArray(value)
73
+ ? value.filter((entry): entry is string => typeof entry === 'string')
74
+ : undefined;
65
75
  }
66
76
 
67
77
  function priorString(
@@ -75,15 +85,17 @@ function priorString(
75
85
  export function priorMetadataState(
76
86
  prior: Record<string, unknown>,
77
87
  ): PriorMetadataState {
78
- const loaded = prior['loadedPlugins'];
88
+ const loaded = strings(prior['loadedPlugins']);
89
+ const promptGuides = strings(prior['promptGuides']);
90
+ const capabilityUsage = strings(prior['capabilityUsage']);
79
91
  return {
80
92
  editorRoomId: priorString(prior, 'editorRoomId'),
81
93
  spaceId: priorString(prior, 'spaceId'),
82
94
  sessionRunId: priorString(prior, 'sessionRunId'),
83
95
  currentEntityDid: priorString(prior, 'currentEntityDid'),
84
- ...(Array.isArray(loaded)
85
- ? { loadedPlugins: loaded.filter((p) => typeof p === 'string') }
86
- : {}),
96
+ ...(loaded ? { loadedPlugins: loaded } : {}),
97
+ ...(promptGuides ? { promptGuides } : {}),
98
+ ...(capabilityUsage ? { capabilityUsage } : {}),
87
99
  };
88
100
  }
89
101