@ixo/oracle-runtime-workers 0.2.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.
- package/README.md +110 -0
- package/package.json +77 -0
- package/src/attachments/classify.ts +114 -0
- package/src/attachments/content-blocks.ts +51 -0
- package/src/attachments/download.ts +235 -0
- package/src/attachments/extract.ts +241 -0
- package/src/attachments/index.ts +84 -0
- package/src/attachments/magic.ts +133 -0
- package/src/attachments/pipeline.ts +409 -0
- package/src/attachments/retention.ts +205 -0
- package/src/attachments/route.ts +41 -0
- package/src/attachments/sandbox-archive.ts +90 -0
- package/src/attachments/sanitize.ts +35 -0
- package/src/attachments/types.ts +86 -0
- package/src/attachments/view.ts +107 -0
- package/src/core/env.ts +200 -0
- package/src/core/index.ts +513 -0
- package/src/core/llm.ts +842 -0
- package/src/core/main-agent-types.ts +123 -0
- package/src/core/main-agent.ts +399 -0
- package/src/core/manifest.ts +365 -0
- package/src/core/meta-tools.ts +232 -0
- package/src/core/middlewares/byo-history-sanitizer.ts +165 -0
- package/src/core/middlewares/capability-gate.ts +76 -0
- package/src/core/middlewares/index.ts +18 -0
- package/src/core/middlewares/page-context.ts +98 -0
- package/src/core/middlewares/safety-guardrail.ts +117 -0
- package/src/core/middlewares/summarization.ts +99 -0
- package/src/core/middlewares/tool-repetition-guard.ts +125 -0
- package/src/core/middlewares/tool-validation.ts +83 -0
- package/src/core/middlewares/work-status.ts +57 -0
- package/src/core/openrouter-pricing.ts +124 -0
- package/src/core/plugin-loader.ts +192 -0
- package/src/core/plugins/index.ts +6 -0
- package/src/core/plugins/skills/index.ts +8 -0
- package/src/core/plugins/skills/skills-tools.ts +356 -0
- package/src/core/plugins/skills/skills.plugin.ts +113 -0
- package/src/core/plugins/weather/index.ts +8 -0
- package/src/core/plugins/weather/weather-client.ts +153 -0
- package/src/core/plugins/weather/weather-middleware.ts +27 -0
- package/src/core/plugins/weather/weather-sub-agent.ts +65 -0
- package/src/core/plugins/weather/weather-tools.ts +103 -0
- package/src/core/plugins/weather/weather.plugin.ts +227 -0
- package/src/core/prompt-composer.ts +469 -0
- package/src/core/registries.ts +642 -0
- package/src/core/runtime-context.ts +619 -0
- package/src/core/state.ts +108 -0
- package/src/core/sub-agent-fallback.ts +187 -0
- package/src/core/subagent-as-tool.ts +322 -0
- package/src/core/template.ts +245 -0
- package/src/core/utils.ts +246 -0
- package/src/core/wrap-plugin-tool.ts +100 -0
- package/src/do/ambient.ts +266 -0
- package/src/do/contracts.ts +562 -0
- package/src/do/debug-timers.ts +120 -0
- package/src/do/fresh-stub.ts +32 -0
- package/src/do/gateway-retry.ts +73 -0
- package/src/do/secrets-adapter.ts +32 -0
- package/src/do/size-alerts.ts +76 -0
- package/src/do/sse-stream.ts +472 -0
- package/src/do/transcript.ts +192 -0
- package/src/do/turn-body.ts +84 -0
- package/src/do/turn-metadata.ts +146 -0
- package/src/do/ucan-service.ts +339 -0
- package/src/do/user-oracle-do.ts +3035 -0
- package/src/gateway-worker.ts +82 -0
- package/src/index.ts +237 -0
- package/src/llm/byo-adapter.ts +59 -0
- package/src/llm/byo-catalog.ts +520 -0
- package/src/llm/byo-client.ts +280 -0
- package/src/llm/byo-routes.ts +255 -0
- package/src/llm/byo-service.ts +836 -0
- package/src/llm/chatgpt-oauth.ts +430 -0
- package/src/llm/provider-error.ts +283 -0
- package/src/matrix/gateway-do.ts +918 -0
- package/src/matrix/ingest.ts +209 -0
- package/src/matrix/replay-format.ts +34 -0
- package/src/matrix/reply-chain.ts +109 -0
- package/src/matrix/room-state-codec.ts +115 -0
- package/src/matrix/user-homeserver.ts +106 -0
- package/src/matrix/work-status.ts +294 -0
- package/src/memory/session-history-indexer.ts +328 -0
- package/src/owner-store/ixo-vfs-store.ts +570 -0
- package/src/owner-store/matrix-media-store.ts +136 -0
- package/src/owner-store/migrating-store.ts +185 -0
- package/src/owner-store/owner-copy-errors.ts +175 -0
- package/src/owner-store/retry.ts +45 -0
- package/src/owner-store/tus-upload.ts +333 -0
- package/src/owner-store/types.ts +0 -0
- package/src/plugin-api/define-plugin.ts +45 -0
- package/src/plugin-api/index.ts +56 -0
- package/src/plugin-api/oracle-plugin.ts +145 -0
- package/src/plugin-api/tool-helper.ts +82 -0
- package/src/plugin-api/types.ts +816 -0
- package/src/plugin-api/ucan-errors.ts +16 -0
- package/src/plugins/agui/agui-agent.ts +115 -0
- package/src/plugins/agui/agui.plugin.ts +148 -0
- package/src/plugins/agui/index.ts +2 -0
- package/src/plugins/attachments/attachments.plugin.ts +54 -0
- package/src/plugins/attachments/index.ts +6 -0
- package/src/plugins/attachments/view-attachment-tool.ts +91 -0
- package/src/plugins/base64.ts +26 -0
- package/src/plugins/composio/composio-tools.ts +365 -0
- package/src/plugins/composio/composio-ucan.ts +43 -0
- package/src/plugins/composio/composio.plugin.ts +214 -0
- package/src/plugins/composio/index.ts +15 -0
- package/src/plugins/domain-indexer/domain-indexer-agent.ts +57 -0
- package/src/plugins/domain-indexer/domain-indexer-tools.ts +253 -0
- package/src/plugins/domain-indexer/domain-indexer.plugin.ts +100 -0
- package/src/plugins/domain-indexer/index.ts +3 -0
- package/src/plugins/editor/blocknote-bridge.ts +120 -0
- package/src/plugins/editor/content-session.ts +331 -0
- package/src/plugins/editor/content-tools.ts +686 -0
- package/src/plugins/editor/document-model.ts +0 -0
- package/src/plugins/editor/editor-access-denied-tool.ts +58 -0
- package/src/plugins/editor/editor-agent.ts +34 -0
- package/src/plugins/editor/editor-config.ts +64 -0
- package/src/plugins/editor/editor-mx.ts +128 -0
- package/src/plugins/editor/editor.plugin.ts +143 -0
- package/src/plugins/editor/failures.ts +154 -0
- package/src/plugins/editor/index.ts +31 -0
- package/src/plugins/editor/jsdom-shim.ts +55 -0
- package/src/plugins/editor/prompts.ts +59 -0
- package/src/plugins/editor/prop-policy.ts +147 -0
- package/src/plugins/editor/provider.ts +386 -0
- package/src/plugins/editor/room-membership.ts +95 -0
- package/src/plugins/editor/standalone-editor-tool.ts +200 -0
- package/src/plugins/firecrawl/firecrawl-agent.ts +93 -0
- package/src/plugins/firecrawl/firecrawl-tools.ts +220 -0
- package/src/plugins/firecrawl/firecrawl.plugin.ts +105 -0
- package/src/plugins/firecrawl/index.ts +15 -0
- package/src/plugins/flows/action-metadata.ts +3505 -0
- package/src/plugins/flows/actions.ts +190 -0
- package/src/plugins/flows/edit.ts +314 -0
- package/src/plugins/flows/errors.ts +38 -0
- package/src/plugins/flows/explain.ts +43 -0
- package/src/plugins/flows/flow-doc.ts +111 -0
- package/src/plugins/flows/flows.plugin.ts +129 -0
- package/src/plugins/flows/forms.ts +330 -0
- package/src/plugins/flows/index.ts +2 -0
- package/src/plugins/flows/linkage.ts +147 -0
- package/src/plugins/flows/port-types.ts +53 -0
- package/src/plugins/flows/prompts.ts +65 -0
- package/src/plugins/flows/read.ts +392 -0
- package/src/plugins/flows/references.ts +66 -0
- package/src/plugins/flows/test-support.ts +165 -0
- package/src/plugins/flows/tools/authoring.ts +516 -0
- package/src/plugins/flows/tools/discovery.ts +119 -0
- package/src/plugins/flows/tools/forms.ts +142 -0
- package/src/plugins/flows/tools/inspect.ts +165 -0
- package/src/plugins/flows/tools/linkage.ts +117 -0
- package/src/plugins/flows/tools/settings.ts +184 -0
- package/src/plugins/flows/translator.ts +328 -0
- package/src/plugins/flows/types.ts +210 -0
- package/src/plugins/flows/ydoc-helpers.ts +543 -0
- package/src/plugins/index.ts +70 -0
- package/src/plugins/mcp-call-timeout.ts +38 -0
- package/src/plugins/mcp-tool-adapter.ts +87 -0
- package/src/plugins/memory/index.ts +17 -0
- package/src/plugins/memory/memory-tools.ts +463 -0
- package/src/plugins/memory/memory-ucan.ts +51 -0
- package/src/plugins/memory/memory.plugin.ts +122 -0
- package/src/plugins/memory/types.ts +147 -0
- package/src/plugins/portal/action-log.ts +34 -0
- package/src/plugins/portal/index.ts +2 -0
- package/src/plugins/portal/portal.plugin.ts +203 -0
- package/src/plugins/sandbox/index.ts +34 -0
- package/src/plugins/sandbox/sandbox-bridge.ts +295 -0
- package/src/plugins/sandbox/sandbox-mcp.ts +127 -0
- package/src/plugins/sandbox/sandbox-write-blob.ts +103 -0
- package/src/plugins/sandbox/sandbox.plugin.ts +599 -0
- package/src/plugins/tasks/index.ts +17 -0
- package/src/plugins/tasks/manifest.ts +81 -0
- package/src/plugins/tasks/middleware.ts +219 -0
- package/src/plugins/tasks/tasks-tools.ts +414 -0
- package/src/plugins/tasks/tasks.plugin.ts +74 -0
- package/src/plugins/ucan-failure.ts +133 -0
- package/src/plugins/user-preferences/index.ts +22 -0
- package/src/plugins/user-preferences/schema.ts +31 -0
- package/src/plugins/user-preferences/user-preferences-store.ts +172 -0
- package/src/plugins/user-preferences/user-preferences-tool.ts +131 -0
- package/src/plugins/user-preferences/user-preferences.plugin.ts +137 -0
- package/src/plugins/vfs/index.ts +40 -0
- package/src/plugins/vfs/vfs-auth.ts +56 -0
- package/src/plugins/vfs/vfs-client.ts +655 -0
- package/src/plugins/vfs/vfs-content.ts +181 -0
- package/src/plugins/vfs/vfs-errors.ts +163 -0
- package/src/plugins/vfs/vfs-sandbox-tools.ts +272 -0
- package/src/plugins/vfs/vfs-tools.ts +635 -0
- package/src/plugins/vfs/vfs.plugin.ts +201 -0
- package/src/realtime/frontend-call-registry.ts +163 -0
- package/src/realtime/realtime-endpoint.ts +619 -0
- package/src/realtime/session-socket-hub.ts +249 -0
- package/src/realtime/socket-io-codec.ts +187 -0
- package/src/secrets/jwe.ts +74 -0
- package/src/secrets/pin-cipher.ts +43 -0
- package/src/secrets/secrets-service.ts +319 -0
- package/src/shell/app.ts +564 -0
- package/src/shell/auth.ts +290 -0
- package/src/sqlite/blob-codec.ts +100 -0
- package/src/sqlite/blob-compactor.ts +146 -0
- package/src/sqlite/cache-config.ts +45 -0
- package/src/sqlite/database.ts +643 -0
- package/src/sqlite/do-vfs.ts +1485 -0
- package/src/sqlite/index.ts +61 -0
- package/src/sqlite/serialization.ts +370 -0
- package/src/sqlite/sessions-store.ts +311 -0
- package/src/sqlite/sqlite-saver.ts +919 -0
- package/src/sqlite/vacuum-policy.ts +77 -0
- package/src/sqlite/wa-sqlite-loader.ts +123 -0
- package/src/sqlite/wasm.d.ts +10 -0
- package/src/tasks/schedule.ts +174 -0
- package/src/tasks/scheduler.ts +753 -0
- package/src/tasks/spec.ts +125 -0
- package/src/tasks/store.ts +351 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { OraclePlugin, type PluginEnv } from '../../plugin-api/oracle-plugin';
|
|
3
|
+
import type {
|
|
4
|
+
MergedConfig,
|
|
5
|
+
PluginManifest,
|
|
6
|
+
PluginTool,
|
|
7
|
+
RuntimeContext,
|
|
8
|
+
UserContextData,
|
|
9
|
+
} from '../../plugin-api/types';
|
|
10
|
+
import {
|
|
11
|
+
createDefaultMemoryMcpFactory,
|
|
12
|
+
DEFAULT_MEMORY_TOOLS,
|
|
13
|
+
fetchMemoryTools,
|
|
14
|
+
type MemoryMcpFactory,
|
|
15
|
+
} from './memory-tools';
|
|
16
|
+
|
|
17
|
+
const configSchema = z.object({
|
|
18
|
+
MEMORY_MCP_URL: z.string().url('MEMORY_MCP_URL must be a valid HTTP(S) URL.'),
|
|
19
|
+
MEMORY_ENGINE_URL: z
|
|
20
|
+
.string()
|
|
21
|
+
.url('MEMORY_ENGINE_URL must be a valid HTTP(S) URL.'),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const manifest: PluginManifest = {
|
|
25
|
+
title: 'Memory',
|
|
26
|
+
summary:
|
|
27
|
+
'Durable memory across conversations: who the user is, what you have made for them, and what worked.',
|
|
28
|
+
whenToUse: [
|
|
29
|
+
'First contact (no prior context loaded): greet, ask their name and what they want help with, then save what they tell you.',
|
|
30
|
+
'You learn something durable about the user — name, role, ongoing project, a constraint, a relationship.',
|
|
31
|
+
'You create an artifact for the user (file, document, edit, generated content): record what it is, what it is for, and the structural choices you made.',
|
|
32
|
+
'The user expresses satisfaction or dissatisfaction with something you produced: capture what worked or what did not — tone, length, structure, style — against that artifact entry.',
|
|
33
|
+
'The user references something they told you before, or something you made before.',
|
|
34
|
+
],
|
|
35
|
+
whenNotToUse: [
|
|
36
|
+
'Ephemeral conversation-only state (use the current message thread).',
|
|
37
|
+
'Behavioral preferences about how to respond (call the user-preferences tool instead).',
|
|
38
|
+
'Public web facts that are not specific to this user (use a web-search capability).',
|
|
39
|
+
'Anything the user asked you to forget or framed as temporary.',
|
|
40
|
+
],
|
|
41
|
+
tags: ['memory', 'recall', 'artifacts', 'personalization'],
|
|
42
|
+
category: 'memory',
|
|
43
|
+
visibility: 'always',
|
|
44
|
+
stability: 'stable',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export interface MemoryPluginOptions {
|
|
48
|
+
/**
|
|
49
|
+
* Override the MCP-tools factory. Defaults to an HTTP MCP client against
|
|
50
|
+
* `MEMORY_MCP_URL` authenticated with a per-request UCAN invocation.
|
|
51
|
+
*/
|
|
52
|
+
mcpFactory?: (memoryMcpUrl: string) => MemoryMcpFactory;
|
|
53
|
+
/**
|
|
54
|
+
* Filter the upstream tool surface. Defaults to {@link DEFAULT_MEMORY_TOOLS}
|
|
55
|
+
* (search + add + delete-episode + clear). Pass an explicit list to expose
|
|
56
|
+
* `add_oracle_knowledge`, `delete_edge`, etc.
|
|
57
|
+
*/
|
|
58
|
+
selectedTools?: readonly string[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolveMemoryUrl(config: MergedConfig): string {
|
|
62
|
+
const parsed = configSchema.parse(config);
|
|
63
|
+
return parsed.MEMORY_MCP_URL;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Memory plugin. Surfaces upstream Memory Engine MCP tools directly — the
|
|
68
|
+
* agent sees the upstream names (`memory-engine__search_memory_engine`,
|
|
69
|
+
* `memory-engine__add_memory`, ...) with the upstream's own schemas. This
|
|
70
|
+
* matches the pattern that worked in production and avoids schema-mismatch
|
|
71
|
+
* failures from a local wrapper layer.
|
|
72
|
+
*
|
|
73
|
+
* Tool list is fetched per-request via `getRequestTools` because the MCP
|
|
74
|
+
* headers depend on the in-flight user's UCAN delegation.
|
|
75
|
+
*/
|
|
76
|
+
export class MemoryPlugin extends OraclePlugin {
|
|
77
|
+
static readonly NAME = 'memory';
|
|
78
|
+
|
|
79
|
+
readonly name = MemoryPlugin.NAME;
|
|
80
|
+
|
|
81
|
+
readonly version = '1.0.0';
|
|
82
|
+
|
|
83
|
+
readonly manifest = manifest;
|
|
84
|
+
|
|
85
|
+
override readonly configSchema = configSchema;
|
|
86
|
+
|
|
87
|
+
override readonly autoDetectHint = 'MEMORY_MCP_URL';
|
|
88
|
+
|
|
89
|
+
private readonly mcpFactory: (memoryMcpUrl: string) => MemoryMcpFactory;
|
|
90
|
+
|
|
91
|
+
private readonly selectedTools: readonly string[];
|
|
92
|
+
|
|
93
|
+
constructor(options: MemoryPluginOptions = {}) {
|
|
94
|
+
super();
|
|
95
|
+
this.mcpFactory = options.mcpFactory ?? createDefaultMemoryMcpFactory;
|
|
96
|
+
this.selectedTools = options.selectedTools ?? DEFAULT_MEMORY_TOOLS;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
override autoDetect(env: PluginEnv): boolean {
|
|
100
|
+
return (
|
|
101
|
+
typeof env.MEMORY_MCP_URL === 'string' && env.MEMORY_MCP_URL.length > 0
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
override async getRequestTools(rtCtx: RuntimeContext): Promise<PluginTool[]> {
|
|
106
|
+
const memoryUrl = resolveMemoryUrl(rtCtx.config);
|
|
107
|
+
const factory = this.mcpFactory(memoryUrl);
|
|
108
|
+
return fetchMemoryTools(rtCtx, factory, this.selectedTools);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
override getSharedState(): Record<
|
|
112
|
+
string,
|
|
113
|
+
(
|
|
114
|
+
state: { userContext?: UserContextData },
|
|
115
|
+
runCtx: RuntimeContext,
|
|
116
|
+
) => unknown
|
|
117
|
+
> {
|
|
118
|
+
return {
|
|
119
|
+
userProfile: (state) => state.userContext,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// ─── Shared primitives ────────────────────────────────────────────────────────
|
|
2
|
+
|
|
3
|
+
export type ComparisonOperator =
|
|
4
|
+
| '='
|
|
5
|
+
| '<>'
|
|
6
|
+
| '>'
|
|
7
|
+
| '<'
|
|
8
|
+
| '>='
|
|
9
|
+
| '<='
|
|
10
|
+
| 'IS NULL'
|
|
11
|
+
| 'IS NOT NULL';
|
|
12
|
+
|
|
13
|
+
/** A single date filter condition. `date` can be omitted for IS NULL / IS NOT NULL. */
|
|
14
|
+
export interface DateFilter {
|
|
15
|
+
date?: string; // ISO-8601 datetime string, e.g. "2025-01-01T00:00:00Z"
|
|
16
|
+
comparison_operator: ComparisonOperator;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Date filters are passed as groups of OR-conditions combined with AND between groups:
|
|
21
|
+
* [[a, b], [c]] → (a OR b) AND (c)
|
|
22
|
+
*/
|
|
23
|
+
export type DateFilterGroups = DateFilter[][];
|
|
24
|
+
|
|
25
|
+
export type SearchStrategy =
|
|
26
|
+
| 'balanced'
|
|
27
|
+
| 'diverse'
|
|
28
|
+
| 'precise'
|
|
29
|
+
| 'contextual'
|
|
30
|
+
| 'recent_memory'
|
|
31
|
+
| 'facts_only'
|
|
32
|
+
| 'entities_only'
|
|
33
|
+
| 'topics_only';
|
|
34
|
+
|
|
35
|
+
export type KnowledgeLevel = 'user' | 'oracle' | 'both';
|
|
36
|
+
|
|
37
|
+
export type EntityType =
|
|
38
|
+
// Personal Identity
|
|
39
|
+
| 'Person'
|
|
40
|
+
| 'Trait'
|
|
41
|
+
| 'Value'
|
|
42
|
+
| 'Identity'
|
|
43
|
+
| 'Attribute'
|
|
44
|
+
// Mental & Emotional
|
|
45
|
+
| 'Emotion'
|
|
46
|
+
| 'Stress'
|
|
47
|
+
| 'CopingStrategy'
|
|
48
|
+
// Professional & Work
|
|
49
|
+
| 'Job'
|
|
50
|
+
| 'Project'
|
|
51
|
+
| 'Skill'
|
|
52
|
+
| 'Tool'
|
|
53
|
+
| 'Organization'
|
|
54
|
+
// Goals & Growth
|
|
55
|
+
| 'Goal'
|
|
56
|
+
| 'Milestone'
|
|
57
|
+
// Behaviors & Patterns
|
|
58
|
+
| 'Habit'
|
|
59
|
+
| 'Routine'
|
|
60
|
+
| 'Pattern'
|
|
61
|
+
// Interests & Entertainment
|
|
62
|
+
| 'Interest'
|
|
63
|
+
| 'Hobby'
|
|
64
|
+
| 'Content'
|
|
65
|
+
// Preferences
|
|
66
|
+
| 'Preference'
|
|
67
|
+
| 'Product'
|
|
68
|
+
// Knowledge & Learning
|
|
69
|
+
| 'Expertise'
|
|
70
|
+
| 'LearningGoal'
|
|
71
|
+
| 'Resource'
|
|
72
|
+
// Places & Experiences
|
|
73
|
+
| 'Location'
|
|
74
|
+
| 'Experience'
|
|
75
|
+
| 'Event'
|
|
76
|
+
// Social & Groups
|
|
77
|
+
| 'Group'
|
|
78
|
+
| 'Pet'
|
|
79
|
+
// Communication
|
|
80
|
+
| 'CommunicationStyle'
|
|
81
|
+
| 'Language'
|
|
82
|
+
// Tasks & Beliefs
|
|
83
|
+
| 'Task'
|
|
84
|
+
| 'Belief'
|
|
85
|
+
| 'Cause'
|
|
86
|
+
// Instructions
|
|
87
|
+
| 'Procedure'
|
|
88
|
+
// IXO/Qi Ontology
|
|
89
|
+
| 'Agent'
|
|
90
|
+
| 'SmartAccount'
|
|
91
|
+
| 'OutcomeUnit'
|
|
92
|
+
| 'Claim'
|
|
93
|
+
| 'Evaluation'
|
|
94
|
+
| 'ServiceEvent'
|
|
95
|
+
| 'Payment'
|
|
96
|
+
| 'VerifiableCredential';
|
|
97
|
+
|
|
98
|
+
export type EdgeType =
|
|
99
|
+
// Personal Memory
|
|
100
|
+
| 'Knows'
|
|
101
|
+
| 'WorksWith'
|
|
102
|
+
| 'Causes'
|
|
103
|
+
| 'Enables'
|
|
104
|
+
| 'Blocks'
|
|
105
|
+
| 'PartOf'
|
|
106
|
+
| 'BelongsTo'
|
|
107
|
+
| 'Practices'
|
|
108
|
+
| 'Uses'
|
|
109
|
+
| 'Pursuing'
|
|
110
|
+
| 'Requires'
|
|
111
|
+
| 'Achieved'
|
|
112
|
+
| 'EmployedAt'
|
|
113
|
+
| 'WorksOn'
|
|
114
|
+
| 'Manages'
|
|
115
|
+
| 'LivesAt'
|
|
116
|
+
| 'VisitedLocation'
|
|
117
|
+
| 'LocatedIn'
|
|
118
|
+
| 'Prefers'
|
|
119
|
+
| 'Likes'
|
|
120
|
+
| 'Dislikes'
|
|
121
|
+
| 'InterestedIn'
|
|
122
|
+
| 'ExpertiseIn'
|
|
123
|
+
| 'Studying'
|
|
124
|
+
| 'LearnedFrom'
|
|
125
|
+
| 'Triggers'
|
|
126
|
+
| 'Motivates'
|
|
127
|
+
| 'ManagesVia'
|
|
128
|
+
| 'Influences'
|
|
129
|
+
| 'Supports'
|
|
130
|
+
| 'MemberOf'
|
|
131
|
+
| 'Owns'
|
|
132
|
+
| 'CurrentlyIs'
|
|
133
|
+
| 'WasPreviously'
|
|
134
|
+
| 'AlignedWith'
|
|
135
|
+
| 'ConflictsWith'
|
|
136
|
+
| 'RelatesTo'
|
|
137
|
+
// IXO/Qi Ontology
|
|
138
|
+
| 'OWNS'
|
|
139
|
+
| 'CONTROLS'
|
|
140
|
+
| 'SUBMITS_CLAIM'
|
|
141
|
+
| 'HAS_EVALUATION'
|
|
142
|
+
| 'RESULTS_IN_OUTCOME'
|
|
143
|
+
| 'TRIGGERS_PAYMENT'
|
|
144
|
+
| 'PAYS_FOR_SERVICE'
|
|
145
|
+
| 'HAS_IDENTITY';
|
|
146
|
+
|
|
147
|
+
// ─── Tool input types ─────────────────────────────────────────────────────────
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Node runtime's `logActionToMatrix`: a best-effort `ixo.action.log`
|
|
3
|
+
* room event recording a frontend action (browser tool / AG-UI action) and
|
|
4
|
+
* its outcome, posted only when the turn has a room. Never throws.
|
|
5
|
+
*/
|
|
6
|
+
import type { RuntimeContext } from '../../plugin-api/types';
|
|
7
|
+
|
|
8
|
+
export const ACTION_LOG_EVENT_TYPE = 'ixo.action.log';
|
|
9
|
+
|
|
10
|
+
export interface LoggedAction {
|
|
11
|
+
name: string;
|
|
12
|
+
args: Record<string, unknown>;
|
|
13
|
+
result: unknown;
|
|
14
|
+
error?: string;
|
|
15
|
+
success: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function logActionToMatrix(
|
|
19
|
+
ctx: Pick<RuntimeContext, 'matrix' | 'session' | 'logger'>,
|
|
20
|
+
action: LoggedAction,
|
|
21
|
+
): void {
|
|
22
|
+
const roomId = ctx.session.roomId;
|
|
23
|
+
if (!roomId) return;
|
|
24
|
+
void ctx.matrix
|
|
25
|
+
.postEvent(roomId, ACTION_LOG_EVENT_TYPE, {
|
|
26
|
+
action,
|
|
27
|
+
threadId: ctx.session.id,
|
|
28
|
+
})
|
|
29
|
+
.catch((err: unknown) => {
|
|
30
|
+
ctx.logger.warn?.(
|
|
31
|
+
`[portal] action log for ${action.name} not posted: ${err instanceof Error ? err.message : String(err)}`,
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portal plugin — the Workers port of the Node runtime's `PortalPlugin`.
|
|
3
|
+
*
|
|
4
|
+
* Every request-time tool comes from the client: the Portal declares its
|
|
5
|
+
* browser tools in the turn body (`tools[]` → `state.browserTools`, each a
|
|
6
|
+
* `{ name, description, schema }` JSON-schema descriptor), and this plugin
|
|
7
|
+
* turns each into an agent tool that runs IN THE BROWSER over the realtime
|
|
8
|
+
* channel (`ctx.frontend.callBrowserTool` → `browser_tool_call` socket event
|
|
9
|
+
* → the client answers `tool_result`).
|
|
10
|
+
*
|
|
11
|
+
* Runtime-supplied arguments: a descriptor may declare `oracleUserId`; it is
|
|
12
|
+
* hidden from the model and filled from `MATRIX_ORACLE_ADMIN_USER_ID` (the
|
|
13
|
+
* Portal's `create_page_room` uses it to invite the assistant into the new
|
|
14
|
+
* page), exactly as on Node.
|
|
15
|
+
*/
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
import type { BrowserToolCall } from '../../core/state';
|
|
18
|
+
import { clientSchemaToZod } from '../../core/utils';
|
|
19
|
+
import { OraclePlugin } from '../../plugin-api/oracle-plugin';
|
|
20
|
+
import { tool } from '../../plugin-api/tool-helper';
|
|
21
|
+
import type {
|
|
22
|
+
PluginManifest,
|
|
23
|
+
PluginTool,
|
|
24
|
+
RuntimeContext,
|
|
25
|
+
} from '../../plugin-api/types';
|
|
26
|
+
import { logActionToMatrix } from './action-log';
|
|
27
|
+
|
|
28
|
+
const manifest: PluginManifest = {
|
|
29
|
+
title: 'Portal',
|
|
30
|
+
summary:
|
|
31
|
+
"Browser-side actions on the user's Portal UI — opens URLs, manipulates the DOM, runs FE-defined browser tools.",
|
|
32
|
+
whenToUse: [
|
|
33
|
+
'User asks for an action the Portal FE exposes as a browser tool (declared in `state.browserTools`).',
|
|
34
|
+
"A task needs a browser-side capability the server can't do alone — open a URL in the user's tab, click a Portal button, fill a form.",
|
|
35
|
+
],
|
|
36
|
+
whenNotToUse: [
|
|
37
|
+
'No browser tools are declared on this request (no tools are contributed).',
|
|
38
|
+
'The task can be completed purely server-side (use a server tool or sub-agent).',
|
|
39
|
+
],
|
|
40
|
+
examples: [
|
|
41
|
+
{
|
|
42
|
+
user: 'Open my workspace and navigate to the Reports page.',
|
|
43
|
+
thought:
|
|
44
|
+
'Portal exposes navigation as a browser tool — call the FE-declared tool (e.g. `open_url`) directly with the target URL.',
|
|
45
|
+
tool: 'open_url',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
tags: ['portal', 'browser', 'ui'],
|
|
49
|
+
category: 'ui',
|
|
50
|
+
visibility: 'on-demand',
|
|
51
|
+
stability: 'stable',
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const BROWSER_TOOL_TIMEOUT_MS = 15_000;
|
|
55
|
+
|
|
56
|
+
const BROWSER_TOOL_SHAPE = z.object({
|
|
57
|
+
name: z.string(),
|
|
58
|
+
description: z.string(),
|
|
59
|
+
schema: z.record(z.string(), z.unknown()),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const ARGS_RECORD_SHAPE = z.record(z.string(), z.unknown());
|
|
63
|
+
|
|
64
|
+
export function parseBrowserTools(value: unknown): BrowserToolCall[] {
|
|
65
|
+
if (!Array.isArray(value)) return [];
|
|
66
|
+
const out: BrowserToolCall[] = [];
|
|
67
|
+
for (const entry of value) {
|
|
68
|
+
const parsed = BROWSER_TOOL_SHAPE.safeParse(entry);
|
|
69
|
+
if (parsed.success) out.push(parsed.data);
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function parseArgs(input: unknown): Record<string, unknown> {
|
|
75
|
+
const parsed = ARGS_RECORD_SHAPE.safeParse(input ?? {});
|
|
76
|
+
return parsed.success ? parsed.data : {};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Descriptor argument → config key whose value the runtime injects. */
|
|
80
|
+
const RUNTIME_SUPPLIED_ARGS: Record<string, string> = {
|
|
81
|
+
oracleUserId: 'MATRIX_ORACLE_ADMIN_USER_ID',
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
85
|
+
return typeof value === 'object' && value !== null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function stripRuntimeSuppliedArgs(
|
|
89
|
+
schema: Record<string, unknown>,
|
|
90
|
+
): Record<string, unknown> {
|
|
91
|
+
const properties = schema.properties;
|
|
92
|
+
if (!isRecord(properties)) return schema;
|
|
93
|
+
const declared = Object.keys(RUNTIME_SUPPLIED_ARGS).filter(
|
|
94
|
+
(key) => key in properties,
|
|
95
|
+
);
|
|
96
|
+
if (declared.length === 0) return schema;
|
|
97
|
+
const nextProperties: Record<string, unknown> = { ...properties };
|
|
98
|
+
for (const key of declared) delete nextProperties[key];
|
|
99
|
+
const next: Record<string, unknown> = {
|
|
100
|
+
...schema,
|
|
101
|
+
properties: nextProperties,
|
|
102
|
+
};
|
|
103
|
+
if (Array.isArray(schema.required)) {
|
|
104
|
+
next.required = schema.required.filter(
|
|
105
|
+
(name) => typeof name !== 'string' || !declared.includes(name),
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
return next;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function withRuntimeSuppliedArgs(
|
|
112
|
+
args: Record<string, unknown>,
|
|
113
|
+
descriptor: BrowserToolCall,
|
|
114
|
+
config: Record<string, unknown>,
|
|
115
|
+
): Record<string, unknown> {
|
|
116
|
+
const properties = descriptor.schema.properties;
|
|
117
|
+
if (!isRecord(properties)) return args;
|
|
118
|
+
const next = { ...args };
|
|
119
|
+
for (const [argName, configKey] of Object.entries(RUNTIME_SUPPLIED_ARGS)) {
|
|
120
|
+
if (!(argName in properties)) continue;
|
|
121
|
+
const value = config[configKey];
|
|
122
|
+
if (typeof value === 'string' && value.length > 0) next[argName] = value;
|
|
123
|
+
}
|
|
124
|
+
return next;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function buildBrowserTool(
|
|
128
|
+
descriptor: BrowserToolCall,
|
|
129
|
+
): PluginTool | null {
|
|
130
|
+
const schema = clientSchemaToZod(
|
|
131
|
+
stripRuntimeSuppliedArgs(descriptor.schema),
|
|
132
|
+
descriptor.name,
|
|
133
|
+
);
|
|
134
|
+
if (!schema) return null;
|
|
135
|
+
return tool(
|
|
136
|
+
async (input, ctx: RuntimeContext) => {
|
|
137
|
+
const sessionId = ctx.session.id;
|
|
138
|
+
if (!sessionId) {
|
|
139
|
+
throw new Error('sessionId is required for browser tools');
|
|
140
|
+
}
|
|
141
|
+
const frontend = ctx.frontend;
|
|
142
|
+
if (!frontend) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`Browser tool ${descriptor.name} needs the realtime channel, which this host does not provide.`,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (!frontend.hasClient(sessionId)) {
|
|
148
|
+
throw new Error(
|
|
149
|
+
`No browser is connected to session ${sessionId}, so browser tool ${descriptor.name} cannot run — the client must open the realtime (socket.io) channel for this session first.`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
const args = withRuntimeSuppliedArgs(
|
|
153
|
+
parseArgs(input),
|
|
154
|
+
descriptor,
|
|
155
|
+
ctx.config,
|
|
156
|
+
);
|
|
157
|
+
// Node uses `tc-<requestId>`; the suffix keeps two browser tool calls in
|
|
158
|
+
// one turn from sharing an id (the client echoes it back verbatim).
|
|
159
|
+
const toolCallId = `tc-${ctx.session.requestId || 'noreq'}-${crypto
|
|
160
|
+
.randomUUID()
|
|
161
|
+
.slice(0, 8)}`;
|
|
162
|
+
const result = await frontend.callBrowserTool({
|
|
163
|
+
sessionId,
|
|
164
|
+
toolCallId,
|
|
165
|
+
toolName: descriptor.name,
|
|
166
|
+
args,
|
|
167
|
+
timeoutMs: BROWSER_TOOL_TIMEOUT_MS,
|
|
168
|
+
});
|
|
169
|
+
logActionToMatrix(ctx, {
|
|
170
|
+
name: descriptor.name,
|
|
171
|
+
args,
|
|
172
|
+
result,
|
|
173
|
+
success: true,
|
|
174
|
+
});
|
|
175
|
+
return result;
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: descriptor.name,
|
|
179
|
+
description: descriptor.description,
|
|
180
|
+
schema,
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function readBrowserTools(rtCtx: RuntimeContext): BrowserToolCall[] {
|
|
186
|
+
return parseBrowserTools(rtCtx.history.state.browserTools);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export class PortalPlugin extends OraclePlugin {
|
|
190
|
+
readonly name = 'portal';
|
|
191
|
+
|
|
192
|
+
readonly version = '1.0.0';
|
|
193
|
+
|
|
194
|
+
readonly manifest = manifest;
|
|
195
|
+
|
|
196
|
+
override async getRequestTools(rtCtx: RuntimeContext): Promise<PluginTool[]> {
|
|
197
|
+
const browserTools = readBrowserTools(rtCtx);
|
|
198
|
+
if (browserTools.length === 0) return [];
|
|
199
|
+
return browserTools
|
|
200
|
+
.map(buildBrowserTool)
|
|
201
|
+
.filter((t): t is PluginTool => t !== null);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export {
|
|
2
|
+
defaultSandboxMcpClientFactory,
|
|
3
|
+
getSandboxBridge,
|
|
4
|
+
hasShellUnsafeChars,
|
|
5
|
+
inferMimeFromPath,
|
|
6
|
+
isUnderWorkspaceData,
|
|
7
|
+
readSandboxFile,
|
|
8
|
+
readSandboxResult,
|
|
9
|
+
SANDBOX_NO_FILE_SENTINEL,
|
|
10
|
+
SANDBOX_NOT_AUTHORIZED_MESSAGE,
|
|
11
|
+
SANDBOX_WRITE_FILE_TOOL_NAME,
|
|
12
|
+
WORKSPACE_DATA_PREFIX,
|
|
13
|
+
writeSandboxFile,
|
|
14
|
+
type SandboxBridge,
|
|
15
|
+
type SandboxOutcome,
|
|
16
|
+
} from './sandbox-bridge';
|
|
17
|
+
export {
|
|
18
|
+
createDefaultAuthBuilder,
|
|
19
|
+
parseOracleSecrets,
|
|
20
|
+
SANDBOX_RUN_TOOL_NAME,
|
|
21
|
+
type SandboxAuthBuilder,
|
|
22
|
+
type SandboxHeaderInputs,
|
|
23
|
+
} from './sandbox-mcp';
|
|
24
|
+
export {
|
|
25
|
+
createSandboxWriteBlobTool,
|
|
26
|
+
type CreateSandboxWriteBlobToolParams,
|
|
27
|
+
} from './sandbox-write-blob';
|
|
28
|
+
export {
|
|
29
|
+
SandboxPlugin,
|
|
30
|
+
type SandboxMcpClientFactory,
|
|
31
|
+
type SandboxMcpClientLike,
|
|
32
|
+
type SandboxMcpTool,
|
|
33
|
+
type SandboxPluginOptions,
|
|
34
|
+
} from './sandbox.plugin';
|