@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.
- package/README.md +32 -10
- package/package.json +13 -8
- package/src/artifacts/config.ts +158 -0
- package/src/artifacts/crypto.ts +94 -0
- package/src/artifacts/routes.ts +73 -0
- package/src/artifacts/store.ts +238 -0
- package/src/artifacts/sweep.ts +200 -0
- package/src/artifacts/tool.ts +103 -0
- package/src/artifacts/viewer-page.ts +614 -0
- package/src/attachments/download.ts +168 -45
- package/src/attachments/index.ts +9 -0
- package/src/attachments/magic.ts +33 -0
- package/src/attachments/pipeline.ts +105 -49
- package/src/attachments/sandbox-archive.ts +9 -8
- package/src/attachments/view-cache.ts +142 -0
- package/src/attachments/view.ts +53 -12
- package/src/channels/auth.ts +267 -0
- package/src/channels/contract.ts +137 -0
- package/src/channels/turns.ts +270 -0
- package/src/core/budgeted-llm.ts +223 -0
- package/src/core/capability-router.ts +273 -0
- package/src/core/context-budget.ts +97 -10
- package/src/core/env.ts +111 -0
- package/src/core/execution-profile.ts +17 -0
- package/src/core/index.ts +267 -9
- package/src/core/llm.ts +30 -9
- package/src/core/main-agent-types.ts +41 -1
- package/src/core/main-agent.ts +367 -65
- package/src/core/manifest.ts +34 -0
- package/src/core/meta-tools.ts +128 -18
- package/src/core/middlewares/capability-gate.ts +130 -12
- package/src/core/middlewares/context-guard.ts +55 -24
- package/src/core/middlewares/index.ts +20 -2
- package/src/core/middlewares/page-context.ts +46 -2
- package/src/core/middlewares/return-direct-first.ts +47 -0
- package/src/core/middlewares/summarization.ts +152 -10
- package/src/core/middlewares/tool-execution.ts +323 -0
- package/src/core/middlewares/tool-repetition-guard.ts +202 -35
- package/src/core/middlewares/turn-boundary.ts +162 -0
- package/src/core/openrouter-pricing.ts +155 -22
- package/src/core/prompt-composer.ts +112 -7
- package/src/core/registries.ts +253 -48
- package/src/core/request-admission.ts +159 -0
- package/src/core/runtime-context.ts +107 -8
- package/src/core/state.ts +1 -1
- package/src/core/sub-agent-fallback.ts +21 -2
- package/src/core/subagent-as-tool.ts +78 -43
- package/src/core/tool-access.ts +189 -0
- package/src/core/tool-scheduler.ts +125 -0
- package/src/core/turn-budget.ts +205 -0
- package/src/core/turn-time-note.ts +43 -0
- package/src/core/user-kv.ts +446 -0
- package/src/core/wrap-plugin-tool.ts +20 -0
- package/src/delivery/plan.ts +278 -0
- package/src/delivery/profile.ts +161 -0
- package/src/delivery/prompt.ts +27 -0
- package/src/delivery/schema.ts +61 -0
- package/src/delivery/shaper.ts +389 -0
- package/src/delivery/types.ts +84 -0
- package/src/do/ambient.ts +51 -15
- package/src/do/contracts.ts +170 -6
- package/src/do/idle-eviction.ts +38 -0
- package/src/do/matrix-turn-ledger.ts +24 -5
- package/src/do/result-store-test-do.ts +137 -3
- package/src/do/result-store.ts +239 -58
- package/src/do/room-mirror.ts +29 -0
- package/src/do/run-buffer.ts +64 -9
- package/src/do/run-coordinator.ts +451 -76
- package/src/do/run-request.ts +2 -0
- package/src/do/run-store-test-do.ts +301 -1
- package/src/do/run-store.ts +385 -43
- package/src/do/secrets-adapter.ts +22 -3
- package/src/do/sse-stream.ts +60 -9
- package/src/do/transcript.ts +48 -5
- package/src/do/turn-body.ts +105 -5
- package/src/do/ucan-service.ts +204 -34
- package/src/do/user-oracle-do.ts +1883 -264
- package/src/feedback/config.ts +127 -0
- package/src/feedback/contract.ts +148 -0
- package/src/feedback/linear-sink.ts +285 -0
- package/src/feedback/privacy.ts +150 -0
- package/src/feedback/reservation.ts +298 -0
- package/src/feedback/submit.ts +247 -0
- package/src/index.ts +138 -6
- package/src/llm/byo-adapter.ts +27 -6
- package/src/llm/byo-catalog.ts +13 -0
- package/src/llm/byo-model-fallback.ts +248 -0
- package/src/llm/byo-service.ts +45 -8
- package/src/llm/provider-error.ts +139 -2
- package/src/matrix/gateway-do.ts +504 -108
- package/src/matrix/group-chat.ts +66 -23
- package/src/matrix/inbox-store.ts +16 -1
- package/src/matrix/ingest.ts +79 -14
- package/src/matrix/media-deadline.ts +130 -0
- package/src/matrix/replay-format.ts +5 -3
- package/src/matrix/reply-parts.ts +92 -0
- package/src/matrix/room-alias.ts +96 -0
- package/src/matrix/user-homeserver.ts +166 -7
- package/src/owner-store/ixo-vfs-store.ts +170 -43
- package/src/owner-store/migrating-store.ts +31 -15
- package/src/owner-store/types.ts +18 -3
- package/src/plugin-api/index.ts +43 -2
- package/src/plugin-api/oracle-plugin.ts +35 -0
- package/src/plugin-api/request-admission.ts +41 -0
- package/src/plugin-api/tool-helper.ts +25 -1
- package/src/plugin-api/tool-plane.ts +92 -0
- package/src/plugin-api/types.ts +194 -6
- package/src/plugins/agui/agui.plugin.ts +31 -16
- package/src/plugins/composio/composio-tools.ts +57 -6
- package/src/plugins/composio/composio-ucan.ts +3 -2
- package/src/plugins/composio/composio.plugin.ts +2 -0
- package/src/plugins/delegated-capabilities.ts +25 -0
- package/src/plugins/editor/content-session.ts +173 -83
- package/src/plugins/editor/content-tools.ts +76 -17
- package/src/plugins/editor/editor-mx.ts +28 -9
- package/src/plugins/editor/editor.plugin.ts +3 -1
- package/src/plugins/editor/failures.ts +28 -7
- package/src/plugins/editor/prompts.ts +2 -1
- package/src/plugins/editor/provider.ts +553 -40
- package/src/plugins/editor/standalone-editor-tool.ts +61 -18
- package/src/plugins/firecrawl/firecrawl-tools.ts +13 -5
- package/src/plugins/flows/action-metadata.ts +111 -11
- package/src/plugins/flows/actions.ts +18 -0
- package/src/plugins/flows/decision-context.ts +31 -0
- package/src/plugins/flows/edit.ts +223 -52
- package/src/plugins/flows/errors.ts +22 -1
- package/src/plugins/flows/flow-doc.ts +92 -9
- package/src/plugins/flows/flows.plugin.ts +11 -5
- package/src/plugins/flows/forms.ts +34 -0
- package/src/plugins/flows/index.ts +2 -0
- package/src/plugins/flows/input-policy.ts +140 -0
- package/src/plugins/flows/prompts.ts +14 -11
- package/src/plugins/flows/read.ts +49 -9
- package/src/plugins/flows/ref-syntax.ts +129 -0
- package/src/plugins/flows/test-homeserver.ts +245 -0
- package/src/plugins/flows/tools/authoring.ts +216 -112
- package/src/plugins/flows/tools/discovery.ts +4 -1
- package/src/plugins/flows/tools/forms.ts +21 -2
- package/src/plugins/flows/tools/settings.ts +34 -13
- package/src/plugins/flows/translator.ts +13 -10
- package/src/plugins/flows/types.ts +167 -42
- package/src/plugins/index.ts +11 -1
- package/src/plugins/ixo-transaction/chain-ids.ts +43 -0
- package/src/plugins/ixo-transaction/index.ts +2 -0
- package/src/plugins/ixo-transaction/ixo-transaction.plugin.ts +119 -0
- package/src/plugins/ixo-transaction/receipts.ts +99 -0
- package/src/plugins/ixo-transaction/tools.ts +329 -0
- package/src/plugins/ixo-transaction/wallet-signing.ts +202 -0
- package/src/plugins/mcp-tool-adapter.ts +23 -2
- package/src/plugins/memory/memory-tools.ts +7 -2
- package/src/plugins/memory/memory-ucan.ts +3 -2
- package/src/plugins/memory/memory.plugin.ts +2 -0
- package/src/plugins/pod-creator/blueprint-store.ts +163 -0
- package/src/plugins/pod-creator/blueprint-types.ts +61 -0
- package/src/plugins/pod-creator/bounded-map.ts +87 -0
- package/src/plugins/pod-creator/capsule-content-client.ts +285 -0
- package/src/plugins/pod-creator/chain-gateway.ts +110 -0
- package/src/plugins/pod-creator/config.ts +85 -0
- package/src/plugins/pod-creator/create-session-store.ts +180 -0
- package/src/plugins/pod-creator/create-tools.ts +538 -0
- package/src/plugins/pod-creator/design-pod-roles.ts +111 -0
- package/src/plugins/pod-creator/index.ts +65 -0
- package/src/plugins/pod-creator/orchestration-tools.ts +172 -0
- package/src/plugins/pod-creator/pod-creator.plugin.ts +190 -0
- package/src/plugins/pod-creator/stage.ts +201 -0
- package/src/plugins/pod-creator/sub-agents.ts +189 -0
- package/src/plugins/portal/action-log.ts +21 -1
- package/src/plugins/portal/declared-tools.ts +90 -0
- package/src/plugins/portal/portal.plugin.ts +42 -16
- package/src/plugins/sandbox/sandbox-bridge.ts +79 -10
- package/src/plugins/sandbox/sandbox-mcp.ts +3 -2
- package/src/plugins/sandbox/sandbox-write-blob.ts +11 -1
- package/src/plugins/sandbox/sandbox.plugin.ts +8 -16
- package/src/plugins/tasks/manifest.ts +1 -1
- package/src/plugins/tasks/middleware.ts +20 -7
- package/src/plugins/tasks/tasks-tools.ts +30 -3
- package/src/plugins/tasks/tasks.plugin.ts +64 -11
- package/src/plugins/user-preferences/schema.ts +12 -1
- package/src/plugins/user-preferences/user-preferences-store.ts +38 -13
- package/src/plugins/user-preferences/user-preferences-tool.ts +3 -2
- package/src/plugins/vfs/vfs-client.ts +250 -71
- package/src/plugins/vfs/vfs-content.ts +30 -11
- package/src/plugins/vfs/vfs-errors.ts +22 -0
- package/src/plugins/vfs/vfs-sandbox-tools.ts +12 -5
- package/src/plugins/vfs/vfs-tools.ts +60 -20
- package/src/realtime/frontend-call-registry.ts +228 -81
- package/src/realtime/realtime-endpoint.ts +215 -44
- package/src/realtime/session-socket-hub.ts +47 -2
- package/src/secrets/secrets-service.ts +9 -3
- package/src/shell/app.ts +529 -82
- package/src/shell/auth.ts +131 -37
- package/src/shell/turn-body-cap.ts +11 -13
- package/src/sqlite/blob-compactor.ts +61 -28
- package/src/sqlite/database.ts +156 -90
- package/src/sqlite/do-vfs.ts +416 -129
- package/src/sqlite/page-tier.ts +133 -40
- package/src/sqlite/serialization.ts +40 -0
- package/src/sqlite/sessions-store.ts +10 -2
- package/src/sqlite/sqlite-saver.ts +139 -19
- package/src/sqlite/user-kv-store.ts +317 -0
- package/src/tasks/schedule.ts +201 -12
- package/src/tasks/scheduler.ts +586 -98
- package/src/tasks/spec.ts +67 -3
- package/src/tasks/store.ts +292 -27
- package/src/tasks/topic-deliverables.ts +70 -0
package/src/plugin-api/index.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Plugin authoring surface. A plugin written against `@ixo/oracle-runtime`
|
|
3
3
|
* that uses tools / sub-agents / middlewares / manifest / configSchema /
|
|
4
|
-
* autoDetect / getSharedState compiles unchanged against this
|
|
5
|
-
* only Node-specific hook (`getNestModules`) is replaced by
|
|
4
|
+
* autoDetect / getSharedState / getDecisions compiles unchanged against this
|
|
5
|
+
* module; the only Node-specific hook (`getNestModules`) is replaced by
|
|
6
|
+
* `getRoutes`.
|
|
6
7
|
*/
|
|
7
8
|
export { OraclePlugin } from './oracle-plugin';
|
|
9
|
+
export type {
|
|
10
|
+
RequestAdmissionContext,
|
|
11
|
+
RequestAdmissionResult,
|
|
12
|
+
RequestDisposition,
|
|
13
|
+
} from './request-admission';
|
|
8
14
|
export type {
|
|
9
15
|
PluginEnv,
|
|
10
16
|
PluginRoute,
|
|
@@ -13,8 +19,26 @@ export type {
|
|
|
13
19
|
export { defineOraclePlugin } from './define-plugin';
|
|
14
20
|
export type { DefineOraclePluginInput } from './define-plugin';
|
|
15
21
|
export { tool } from './tool-helper';
|
|
22
|
+
export {
|
|
23
|
+
ADMIN_TOOL_ACTION,
|
|
24
|
+
ADMIN_TOOL_RESOURCE,
|
|
25
|
+
adminToolCapability,
|
|
26
|
+
adminToolResource,
|
|
27
|
+
canAccessToolPlane,
|
|
28
|
+
requireToolPlane,
|
|
29
|
+
toolPlaneOf,
|
|
30
|
+
toolPlaneRequirement,
|
|
31
|
+
} from './tool-plane';
|
|
16
32
|
export type { ToolHelperOptions } from './tool-helper';
|
|
17
33
|
export { UcanMintUnavailableError } from './ucan-errors';
|
|
34
|
+
export {
|
|
35
|
+
USER_KV_MAX_ENTRIES_PER_NAMESPACE,
|
|
36
|
+
USER_KV_MAX_TOTAL_BYTES,
|
|
37
|
+
USER_KV_MAX_TOTAL_ENTRIES,
|
|
38
|
+
USER_KV_MAX_VALUE_BYTES,
|
|
39
|
+
UserKvLimitError,
|
|
40
|
+
} from '../core/user-kv';
|
|
41
|
+
export type { UserKvLimitKind } from '../core/user-kv';
|
|
18
42
|
export type {
|
|
19
43
|
ActionCallEventPayload,
|
|
20
44
|
AgentMiddleware,
|
|
@@ -49,8 +73,25 @@ export type {
|
|
|
49
73
|
RouterEventPayload,
|
|
50
74
|
RuntimeContext,
|
|
51
75
|
SecretIndex,
|
|
76
|
+
SessionSurface,
|
|
52
77
|
SharedAccessors,
|
|
53
78
|
ToolCallEventPayload,
|
|
79
|
+
ToolPlane,
|
|
54
80
|
UcanDelegation,
|
|
55
81
|
UserContextData,
|
|
82
|
+
UserKvSurface,
|
|
83
|
+
UserKvWriteOptions,
|
|
56
84
|
} from './types';
|
|
85
|
+
export { defineDecision } from '@ixo/common/ai/decisions';
|
|
86
|
+
export type {
|
|
87
|
+
DecisionAdapter,
|
|
88
|
+
DecisionAnswer,
|
|
89
|
+
DecisionDefinition,
|
|
90
|
+
DecisionEvaluateOptions,
|
|
91
|
+
DecisionEvaluation,
|
|
92
|
+
DecisionProviderResult,
|
|
93
|
+
DecisionQuestion,
|
|
94
|
+
DecisionRegistration,
|
|
95
|
+
DecisionRequest,
|
|
96
|
+
DefineDecisionOptions,
|
|
97
|
+
} from '@ixo/common/ai/decisions';
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import type { DecisionRegistration } from '@ixo/common/ai/decisions';
|
|
2
|
+
import type {
|
|
3
|
+
RequestAdmissionContext,
|
|
4
|
+
RequestAdmissionResult,
|
|
5
|
+
} from './request-admission';
|
|
1
6
|
import type { z } from 'zod';
|
|
2
7
|
import type { PluginRoute } from '../shell/app';
|
|
3
8
|
import type {
|
|
@@ -53,6 +58,19 @@ export abstract class OraclePlugin {
|
|
|
53
58
|
/** The agent's structured interface to this plugin. */
|
|
54
59
|
abstract readonly manifest: PluginManifest;
|
|
55
60
|
|
|
61
|
+
/**
|
|
62
|
+
* How the agent should work with this plugin once it is in use: the
|
|
63
|
+
* plugin's working rules, as plain text (markdown, starting at a `###`
|
|
64
|
+
* heading). Never part of the manifest, the Tier-1 capability block or
|
|
65
|
+
* `list_capabilities`, so it costs nothing on turns that do not use the
|
|
66
|
+
* plugin. `load_capability` returns it (once per turn) when it loads the
|
|
67
|
+
* plugin or the capability router preloaded it for the turn, and the
|
|
68
|
+
* system prompt carries it on every turn that starts with the plugin
|
|
69
|
+
* loaded on the thread (or `always` visible) and usable by the user's
|
|
70
|
+
* delegation.
|
|
71
|
+
*/
|
|
72
|
+
readonly operatingGuide?: string;
|
|
73
|
+
|
|
56
74
|
/** Hard dependencies — boot fails if any is missing. */
|
|
57
75
|
readonly dependsOn?: string[];
|
|
58
76
|
|
|
@@ -83,6 +101,13 @@ export abstract class OraclePlugin {
|
|
|
83
101
|
/** Sub-agents the runtime auto-wraps as tools. */
|
|
84
102
|
getSubAgents?(ctx: PluginContext): PluginSubAgent[];
|
|
85
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Bounded semantic decisions contributed by this plugin. Decisions are
|
|
106
|
+
* side-effect-free and are never exposed to the generative agent unless a
|
|
107
|
+
* plugin explicitly wraps one in a tool.
|
|
108
|
+
*/
|
|
109
|
+
getDecisions?(ctx: PluginContext): DecisionRegistration[];
|
|
110
|
+
|
|
86
111
|
/**
|
|
87
112
|
* Request-time tool contributions. Called once per `createMainAgent`
|
|
88
113
|
* invocation with the full per-request `RuntimeContext`, so the plugin
|
|
@@ -110,6 +135,16 @@ export abstract class OraclePlugin {
|
|
|
110
135
|
*/
|
|
111
136
|
getMiddlewares?(ctx: PluginContext): AgentMiddleware[];
|
|
112
137
|
|
|
138
|
+
/** Per-turn extensions for the ordinary agent; never cached across users. */
|
|
139
|
+
getRequestMiddlewares?(
|
|
140
|
+
ctx: RuntimeContext,
|
|
141
|
+
): AgentMiddleware[] | Promise<AgentMiddleware[]>;
|
|
142
|
+
|
|
143
|
+
/** Runs before agent preparation. Only authorized deterministic reads may be handled. */
|
|
144
|
+
getRequestAdmission?(
|
|
145
|
+
ctx: RequestAdmissionContext,
|
|
146
|
+
): RequestAdmissionResult | Promise<RequestAdmissionResult>;
|
|
147
|
+
|
|
113
148
|
/**
|
|
114
149
|
* Read-only accessors this plugin exposes to other plugins via `ctx.shared`.
|
|
115
150
|
* Pattern: this plugin computes/owns some derived value from state; others
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { MergedConfig, RuntimeContext } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Authenticated, request-local input. Deliberately exposes no model or tools.
|
|
5
|
+
*
|
|
6
|
+
* `config` is not the merged env: it carries the plugin's own `configSchema`
|
|
7
|
+
* keys and the core settings without credentials (no LLM provider key, no
|
|
8
|
+
* Matrix password or recovery phrase, no Cloudflare API token).
|
|
9
|
+
*
|
|
10
|
+
* The host only asks for admission on direct-room and Portal turns, never on
|
|
11
|
+
* a group-room turn (a direct read is posted into the room, where every
|
|
12
|
+
* member would see one user's authorized data) or a scheduled task run.
|
|
13
|
+
* `roomKind` is still passed so a handler can refuse anything it would not
|
|
14
|
+
* show to the whole room.
|
|
15
|
+
*/
|
|
16
|
+
export interface RequestAdmissionContext {
|
|
17
|
+
readonly config: MergedConfig;
|
|
18
|
+
readonly user: RuntimeContext['user'];
|
|
19
|
+
readonly session: RuntimeContext['session'] & {
|
|
20
|
+
/** Matrix turns: the room the turn arrived in is a direct or a group room. */
|
|
21
|
+
readonly roomKind?: 'direct' | 'group';
|
|
22
|
+
/** Matrix turns: the user's message event this turn answers. */
|
|
23
|
+
readonly eventId?: string;
|
|
24
|
+
/** Matrix turns: the thread root when the user replied inside a thread. */
|
|
25
|
+
readonly threadId?: string;
|
|
26
|
+
};
|
|
27
|
+
readonly message: string;
|
|
28
|
+
readonly metadata?: Record<string, unknown>;
|
|
29
|
+
/** Aborted when the turn is cancelled or the handler's time limit passes. */
|
|
30
|
+
readonly signal: AbortSignal;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type RequestAdmissionResult =
|
|
34
|
+
| { kind: 'pass' }
|
|
35
|
+
| { kind: 'handled'; text: string; title: string };
|
|
36
|
+
|
|
37
|
+
/** Persisted by the host, never accepted from a client. */
|
|
38
|
+
export type RequestDisposition =
|
|
39
|
+
| { kind: 'admitting' }
|
|
40
|
+
| { kind: 'agent' }
|
|
41
|
+
| { kind: 'direct-read'; text: string; title: string; messageId: string };
|
|
@@ -17,11 +17,20 @@ export interface ToolHelperOptions {
|
|
|
17
17
|
* `manifest.visibility` setting.
|
|
18
18
|
*/
|
|
19
19
|
visibility?: PluginTool['visibility'];
|
|
20
|
+
/**
|
|
21
|
+
* Privilege plane. Defaults to `orchestration`; `admin` marks a tool the
|
|
22
|
+
* user must explicitly delegate (`adminToolCapability`) before the model
|
|
23
|
+
* may see or run it — authority, credential or similar lifecycle
|
|
24
|
+
* operations. See `PluginTool.plane`.
|
|
25
|
+
*/
|
|
26
|
+
plane?: PluginTool['plane'];
|
|
20
27
|
/**
|
|
21
28
|
* `'read'` for a tool with no external effect (safe to run again when a
|
|
22
29
|
* turn resumes after a reset); omitted or `'write'` otherwise.
|
|
23
30
|
*/
|
|
24
31
|
effect?: PluginTool['effect'];
|
|
32
|
+
/** Same arguments again is a new action (a UI step); see `PluginTool.repeatable`. */
|
|
33
|
+
repeatable?: PluginTool['repeatable'];
|
|
25
34
|
/**
|
|
26
35
|
* Billing gate marker, kept for source compatibility with the Node
|
|
27
36
|
* runtime's plugin contract. The Workers runtime has no commerce lane, so
|
|
@@ -54,7 +63,16 @@ export function tool(
|
|
|
54
63
|
if (!options || typeof options !== 'object') {
|
|
55
64
|
throw new TypeError('tool(handler, options): `options` is required.');
|
|
56
65
|
}
|
|
57
|
-
const {
|
|
66
|
+
const {
|
|
67
|
+
name,
|
|
68
|
+
description,
|
|
69
|
+
schema,
|
|
70
|
+
visibility,
|
|
71
|
+
plane,
|
|
72
|
+
billing,
|
|
73
|
+
effect,
|
|
74
|
+
repeatable,
|
|
75
|
+
} = options;
|
|
58
76
|
if (!name || typeof name !== 'string') {
|
|
59
77
|
throw new TypeError(
|
|
60
78
|
'tool(handler, options): `options.name` must be a non-empty string.',
|
|
@@ -80,11 +98,17 @@ export function tool(
|
|
|
80
98
|
if (visibility !== undefined) {
|
|
81
99
|
pluginTool.visibility = visibility;
|
|
82
100
|
}
|
|
101
|
+
if (plane !== undefined) {
|
|
102
|
+
pluginTool.plane = plane;
|
|
103
|
+
}
|
|
83
104
|
if (billing !== undefined) {
|
|
84
105
|
pluginTool.billing = billing;
|
|
85
106
|
}
|
|
86
107
|
if (effect !== undefined) {
|
|
87
108
|
pluginTool.effect = effect;
|
|
88
109
|
}
|
|
110
|
+
if (repeatable !== undefined) {
|
|
111
|
+
pluginTool.repeatable = repeatable;
|
|
112
|
+
}
|
|
89
113
|
return pluginTool;
|
|
90
114
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { PluginTool, RuntimeContext, ToolPlane } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The ability every admin-tool capability names. Namespaced because a UCAN
|
|
5
|
+
* ability must be `*` or `<ns>/<name>` (`@ixo/ucan` refuses to issue a bare
|
|
6
|
+
* `invoke`); a grant of `admin-tool/*` or `*` covers it too.
|
|
7
|
+
*/
|
|
8
|
+
export const ADMIN_TOOL_ACTION = 'admin-tool/invoke';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Root of the admin-tool resources. One admin tool is
|
|
12
|
+
* `ixo:qiforge:admin-tool/<pluginName>/<toolName>`; under the runtime's
|
|
13
|
+
* resource rule (a grant covers itself and every `/` child, `*` covers
|
|
14
|
+
* everything) a grant on `ixo:qiforge:admin-tool/<pluginName>` covers all of
|
|
15
|
+
* that plugin's admin tools and one on this root covers every admin tool.
|
|
16
|
+
*/
|
|
17
|
+
export const ADMIN_TOOL_RESOURCE = 'ixo:qiforge:admin-tool';
|
|
18
|
+
|
|
19
|
+
type ToolPlaneDescriptor = Pick<PluginTool, 'name' | 'plane'>;
|
|
20
|
+
|
|
21
|
+
/** A tool's plane; undeclared is `orchestration`. */
|
|
22
|
+
export function toolPlaneOf(tool: Pick<PluginTool, 'plane'>): ToolPlane {
|
|
23
|
+
return tool.plane ?? 'orchestration';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function segment(kind: string, value: string): string {
|
|
27
|
+
if (value.length === 0 || value.includes('/')) {
|
|
28
|
+
// A `/` would make one tool's resource the parent of another's (plugin
|
|
29
|
+
// `a` tool `b/c` vs plugin `a/b` tool `c`), so the grant rule could no
|
|
30
|
+
// longer tell them apart.
|
|
31
|
+
throw new TypeError(
|
|
32
|
+
`admin tool ${kind} must be a non-empty name without "/" (got "${value}")`,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** `ixo:qiforge:admin-tool/<pluginName>/<toolName>`. */
|
|
39
|
+
export function adminToolResource(
|
|
40
|
+
pluginName: string,
|
|
41
|
+
toolName: string,
|
|
42
|
+
): string {
|
|
43
|
+
return `${ADMIN_TOOL_RESOURCE}/${segment('plugin name', pluginName)}/${segment('tool name', toolName)}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The capability the user's delegation must grant for this admin tool. */
|
|
47
|
+
export function adminToolCapability(
|
|
48
|
+
pluginName: string,
|
|
49
|
+
toolName: string,
|
|
50
|
+
): { resource: string; action: string } {
|
|
51
|
+
return {
|
|
52
|
+
resource: adminToolResource(pluginName, toolName),
|
|
53
|
+
action: ADMIN_TOOL_ACTION,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The capability `tool` requires of the turn's delegation, or `null` for an
|
|
59
|
+
* orchestration tool. This is the tool-level counterpart of a manifest's
|
|
60
|
+
* `requires`; every check (binding, discovery, the call itself) reads it.
|
|
61
|
+
*/
|
|
62
|
+
export function toolPlaneRequirement(
|
|
63
|
+
pluginName: string,
|
|
64
|
+
tool: ToolPlaneDescriptor,
|
|
65
|
+
): { resource: string; action: string } | null {
|
|
66
|
+
return toolPlaneOf(tool) === 'admin'
|
|
67
|
+
? adminToolCapability(pluginName, tool.name)
|
|
68
|
+
: null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Whether the delegation behind `ctx` reaches `tool`. */
|
|
72
|
+
export function canAccessToolPlane(
|
|
73
|
+
ctx: Pick<RuntimeContext, 'ucan'>,
|
|
74
|
+
pluginName: string,
|
|
75
|
+
tool: ToolPlaneDescriptor,
|
|
76
|
+
): boolean {
|
|
77
|
+
const required = toolPlaneRequirement(pluginName, tool);
|
|
78
|
+
return (
|
|
79
|
+
required === null ||
|
|
80
|
+
ctx.ucan.hasCapability(required.resource, required.action)
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Throws (`ctx.ucan.requireCapability`) unless the delegation behind `ctx` reaches `tool`. */
|
|
85
|
+
export function requireToolPlane(
|
|
86
|
+
ctx: Pick<RuntimeContext, 'ucan'>,
|
|
87
|
+
pluginName: string,
|
|
88
|
+
tool: ToolPlaneDescriptor,
|
|
89
|
+
): void {
|
|
90
|
+
const required = toolPlaneRequirement(pluginName, tool);
|
|
91
|
+
if (required) ctx.ucan.requireCapability(required.resource, required.action);
|
|
92
|
+
}
|
package/src/plugin-api/types.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import type { TaskExecutionProfile } from '../core/execution-profile';
|
|
2
|
+
import type {
|
|
3
|
+
DecisionDefinition,
|
|
4
|
+
DecisionEvaluateOptions,
|
|
5
|
+
DecisionEvaluation,
|
|
6
|
+
} from '@ixo/common/ai/decisions';
|
|
1
7
|
import type { z } from 'zod';
|
|
2
8
|
import type { BaseMessage } from '@langchain/core/messages';
|
|
3
9
|
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
4
10
|
import type { UserPreferences } from '../core/state';
|
|
5
11
|
import type { AttachmentViewSurface } from '../attachments/view';
|
|
12
|
+
import type { DeliveryConfig } from '../delivery/profile';
|
|
6
13
|
|
|
7
14
|
/**
|
|
8
15
|
* Route shape returned by `OraclePlugin.getAuthExcludedRoutes()`. Paths are
|
|
@@ -55,6 +62,13 @@ export interface UcanDelegation {
|
|
|
55
62
|
readonly issuer?: string;
|
|
56
63
|
readonly audience?: string;
|
|
57
64
|
readonly capabilities?: ReadonlyArray<{ resource: string; action: string }>;
|
|
65
|
+
/**
|
|
66
|
+
* When the delegation stops granting anything (Unix seconds; the earliest
|
|
67
|
+
* expiry across its proof chain). Capability checks compare it with the
|
|
68
|
+
* clock at every check, so a delegation that lapses mid-turn grants
|
|
69
|
+
* nothing from then on.
|
|
70
|
+
*/
|
|
71
|
+
readonly expiration?: number;
|
|
58
72
|
}
|
|
59
73
|
|
|
60
74
|
/** Per-room secret index. */
|
|
@@ -360,6 +374,16 @@ export interface PluginManifest {
|
|
|
360
374
|
|
|
361
375
|
/** Stability hint surfaced to the agent (`experimental` → warning footnote). */
|
|
362
376
|
stability?: 'stable' | 'beta' | 'experimental';
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* UCAN capabilities the user's delegation to this oracle must grant before
|
|
380
|
+
* the plugin may be used by that user (`ctx.ucan.hasCapability` semantics:
|
|
381
|
+
* the action may be `*`). While one is missing, `load_capability` refuses
|
|
382
|
+
* the plugin and names what is missing, `list_capabilities` marks it
|
|
383
|
+
* unavailable, and its tools are neither shown to nor run by the model —
|
|
384
|
+
* whatever its visibility. Omitted: no requirement.
|
|
385
|
+
*/
|
|
386
|
+
requires?: ReadonlyArray<{ resource: string; action: string }>;
|
|
363
387
|
}
|
|
364
388
|
|
|
365
389
|
export interface ManifestExample {
|
|
@@ -424,6 +448,13 @@ export interface OracleConfig {
|
|
|
424
448
|
description?: string;
|
|
425
449
|
/** Optional prompt customization (opening, communicationStyle, capabilities). */
|
|
426
450
|
prompt?: OraclePromptConfig;
|
|
451
|
+
/**
|
|
452
|
+
* Chat delivery (WhatsApp through IXO Channels, Matrix rooms): replies
|
|
453
|
+
* arrive as short messages with long content moved to artefacts. Matrix
|
|
454
|
+
* rooms use it only with `matrixChat: true` (or `MATRIX_CHAT_DELIVERY=true`,
|
|
455
|
+
* which wins when set); otherwise a room reply stays one message.
|
|
456
|
+
*/
|
|
457
|
+
delivery?: DeliveryConfig;
|
|
427
458
|
}
|
|
428
459
|
|
|
429
460
|
/**
|
|
@@ -476,6 +507,11 @@ export interface MatrixPostOpts {
|
|
|
476
507
|
txnId?: string;
|
|
477
508
|
}
|
|
478
509
|
|
|
510
|
+
/** `ctx.session.surface`: the delivery surface of the turn. */
|
|
511
|
+
export type SessionSurface =
|
|
512
|
+
| { kind: 'stream' }
|
|
513
|
+
| { kind: 'chat'; surface: string; label: string };
|
|
514
|
+
|
|
479
515
|
export interface RuntimeContext<TConfig = MergedConfig> {
|
|
480
516
|
/** Authenticated user identity (validated by core auth middleware). */
|
|
481
517
|
user: {
|
|
@@ -491,10 +527,16 @@ export interface RuntimeContext<TConfig = MergedConfig> {
|
|
|
491
527
|
session: {
|
|
492
528
|
/** = `thread_id`; thread root `eventId`. */
|
|
493
529
|
id: string;
|
|
494
|
-
client: 'portal' | 'matrix' | 'slack';
|
|
530
|
+
client: 'portal' | 'matrix' | 'slack' | 'channel';
|
|
495
531
|
wsId?: string;
|
|
496
532
|
requestId: string;
|
|
497
533
|
roomId?: string;
|
|
534
|
+
/**
|
|
535
|
+
* Where the reply lands. `stream` is the Portal; `chat` is a chat app
|
|
536
|
+
* (WhatsApp through IXO Channels, a Matrix room) where the reply arrives
|
|
537
|
+
* as short messages. Tools can keep their output compact on `chat`.
|
|
538
|
+
*/
|
|
539
|
+
surface?: SessionSurface;
|
|
498
540
|
};
|
|
499
541
|
|
|
500
542
|
/** Read-only view over the graph state's history. */
|
|
@@ -520,6 +562,12 @@ export interface RuntimeContext<TConfig = MergedConfig> {
|
|
|
520
562
|
secrets: {
|
|
521
563
|
getIndex: () => Promise<SecretIndex>;
|
|
522
564
|
getValues: (keys: string[]) => Promise<Record<string, string>>;
|
|
565
|
+
/**
|
|
566
|
+
* Values of every secret `getIndex` lists, read with one lookup of the
|
|
567
|
+
* room's secret index — use it instead of `getIndex` followed by
|
|
568
|
+
* `getValues` of every key. `{}` without a room.
|
|
569
|
+
*/
|
|
570
|
+
getAll: () => Promise<Record<string, string>>;
|
|
523
571
|
};
|
|
524
572
|
|
|
525
573
|
/**
|
|
@@ -671,6 +719,23 @@ export interface RuntimeContext<TConfig = MergedConfig> {
|
|
|
671
719
|
>;
|
|
672
720
|
};
|
|
673
721
|
|
|
722
|
+
/**
|
|
723
|
+
* Bounded semantic decisions. A decision only returns structured judgment;
|
|
724
|
+
* policy, authority checks, and side effects remain outside this primitive.
|
|
725
|
+
*/
|
|
726
|
+
decisions: {
|
|
727
|
+
evaluate<TSchema extends z.ZodType>(
|
|
728
|
+
definition: DecisionDefinition<TSchema>,
|
|
729
|
+
input: z.input<TSchema>,
|
|
730
|
+
options?: DecisionEvaluateOptions,
|
|
731
|
+
): Promise<DecisionEvaluation>;
|
|
732
|
+
evaluateByName(
|
|
733
|
+
name: string,
|
|
734
|
+
input: unknown,
|
|
735
|
+
options?: DecisionEvaluateOptions,
|
|
736
|
+
): Promise<DecisionEvaluation>;
|
|
737
|
+
};
|
|
738
|
+
|
|
674
739
|
/** LLM provider. */
|
|
675
740
|
llm: {
|
|
676
741
|
get: (role: ModelRole, params?: ChatOpenAIFields) => BaseChatModel;
|
|
@@ -706,6 +771,15 @@ export interface RuntimeContext<TConfig = MergedConfig> {
|
|
|
706
771
|
*/
|
|
707
772
|
preferences?: UserPreferencesSurface;
|
|
708
773
|
|
|
774
|
+
/**
|
|
775
|
+
* Host key-value rows in the user's OWN database, for plugin state that
|
|
776
|
+
* must outlive the in-memory plugin instance (on Workers the user's object
|
|
777
|
+
* is evicted when idle and restored from the owner copy; rows written here
|
|
778
|
+
* travel with that copy). Present when the host persists per-user state
|
|
779
|
+
* (the Workers runtime does); absent elsewhere.
|
|
780
|
+
*/
|
|
781
|
+
kv?: UserKvSurface;
|
|
782
|
+
|
|
709
783
|
/**
|
|
710
784
|
* Host bridge to the user's browser over the realtime (socket.io) channel:
|
|
711
785
|
* browser tools declared by the client (`state.browserTools`) and AG-UI
|
|
@@ -777,6 +851,7 @@ export type OracleTaskSchedule =
|
|
|
777
851
|
|
|
778
852
|
/** Stored task record (persisted in the user's own database → owner file). */
|
|
779
853
|
export interface OracleTaskRecord {
|
|
854
|
+
executionProfile?: TaskExecutionProfile;
|
|
780
855
|
id: string;
|
|
781
856
|
title: string;
|
|
782
857
|
/** Markdown intent body — what the agent should do each run. */
|
|
@@ -799,6 +874,8 @@ export interface OracleTaskRecord {
|
|
|
799
874
|
}
|
|
800
875
|
|
|
801
876
|
export interface OracleTaskInput {
|
|
877
|
+
/** Host-only closed execution profile; never exposed by model task tools. */
|
|
878
|
+
executionProfile?: TaskExecutionProfile;
|
|
802
879
|
title: string;
|
|
803
880
|
intent: string;
|
|
804
881
|
schedule: OracleTaskSchedule;
|
|
@@ -812,11 +889,14 @@ export interface OracleTaskInput {
|
|
|
812
889
|
}
|
|
813
890
|
|
|
814
891
|
/**
|
|
815
|
-
* Bridge to the user's browser over the realtime channel.
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
819
|
-
*
|
|
892
|
+
* Bridge to the user's browser over the realtime channel. Each call is one
|
|
893
|
+
* invocation with its own id, sent (`browser_tool_call` / `action_call`) to
|
|
894
|
+
* ONE authenticated socket of `sessionId`; only that socket's answer settles
|
|
895
|
+
* it. It resolves with the browser's answer and rejects on the browser's
|
|
896
|
+
* `error`, an AG-UI `success: false`, or when no socket could take it. When
|
|
897
|
+
* the answer cannot arrive — the deadline passed or the socket went — it
|
|
898
|
+
* resolves with `FRONTEND_OUTCOME_UNKNOWN` (`@ixo/common/ai/frontend-bridge`):
|
|
899
|
+
* the browser may have performed the action, and it is never sent again.
|
|
820
900
|
*/
|
|
821
901
|
export interface FrontendCallSurface {
|
|
822
902
|
callBrowserTool(params: FrontendCallParams): Promise<unknown>;
|
|
@@ -827,11 +907,20 @@ export interface FrontendCallSurface {
|
|
|
827
907
|
|
|
828
908
|
export interface FrontendCallParams {
|
|
829
909
|
sessionId: string;
|
|
910
|
+
/** The caller's id; the invocation id the browser sees is `<toolCallId>:<uuid>`. */
|
|
830
911
|
toolCallId: string;
|
|
831
912
|
toolName: string;
|
|
832
913
|
args: Record<string, unknown>;
|
|
833
914
|
/** Default 15 s (browser tools) / 10 s (AG-UI actions), as on Node. */
|
|
834
915
|
timeoutMs?: number;
|
|
916
|
+
/** Receives the invocation id once the call is registered (for diagnostics). */
|
|
917
|
+
onInvocation?: (invocationId: string) => void;
|
|
918
|
+
/**
|
|
919
|
+
* The turn's abort signal (`ctx.abortSignal`). Aborted before the call is
|
|
920
|
+
* sent, it rejects as not sent; after, it resolves with
|
|
921
|
+
* `FRONTEND_OUTCOME_UNKNOWN` at once — the browser may already have run it.
|
|
922
|
+
*/
|
|
923
|
+
signal?: AbortSignal;
|
|
835
924
|
}
|
|
836
925
|
|
|
837
926
|
/**
|
|
@@ -861,6 +950,8 @@ export interface OracleTasksSurface {
|
|
|
861
950
|
): Promise<{ resolved: boolean }>;
|
|
862
951
|
}
|
|
863
952
|
|
|
953
|
+
export type ToolPlane = 'orchestration' | 'admin';
|
|
954
|
+
|
|
864
955
|
export interface PluginTool {
|
|
865
956
|
name: string;
|
|
866
957
|
description: string;
|
|
@@ -868,6 +959,15 @@ export interface PluginTool {
|
|
|
868
959
|
handler: (args: unknown, ctx: RuntimeContext) => Promise<unknown>;
|
|
869
960
|
/** Override visibility — by default inherits from the plugin's `manifest.visibility`. */
|
|
870
961
|
visibility?: 'always' | 'on-demand' | 'silent';
|
|
962
|
+
/**
|
|
963
|
+
* Privilege plane. `orchestration` is the default. An `admin` tool exists
|
|
964
|
+
* for a turn only when the user's delegation to the oracle grants
|
|
965
|
+
* `adminToolCapability(pluginName, name)`: otherwise it is never bound or
|
|
966
|
+
* listed, and the capability is checked again right before the handler.
|
|
967
|
+
* That grant is the user's consent, not operator authority — a user can
|
|
968
|
+
* issue it for themselves.
|
|
969
|
+
*/
|
|
970
|
+
plane?: ToolPlane;
|
|
871
971
|
/**
|
|
872
972
|
* Whether calling the tool changes anything outside the conversation.
|
|
873
973
|
* `'read'` tools may be executed again when a turn is resumed after a
|
|
@@ -876,6 +976,14 @@ export interface PluginTool {
|
|
|
876
976
|
* outcome is unknown. See `core/middlewares/tool-marks.ts`.
|
|
877
977
|
*/
|
|
878
978
|
effect?: 'read' | 'write';
|
|
979
|
+
/**
|
|
980
|
+
* `true` when calling the tool again with the same arguments is a new,
|
|
981
|
+
* intended action rather than a repeat — a step in the user's browser
|
|
982
|
+
* such as scrolling or paging. Within one turn the repetition guard lets
|
|
983
|
+
* such a tool run up to its read limit (5 identical calls) instead of once;
|
|
984
|
+
* `effect` still governs retries, write claims and resume.
|
|
985
|
+
*/
|
|
986
|
+
repeatable?: boolean;
|
|
879
987
|
/**
|
|
880
988
|
* Billing gate. `'contracted'` marks a tool that performs paid contracted
|
|
881
989
|
* work: the runtime binds it only while the turn runs inside an active work
|
|
@@ -924,3 +1032,83 @@ export interface UserPreferencesSurface {
|
|
|
924
1032
|
partial: Partial<UserPreferences>,
|
|
925
1033
|
): Promise<UserPreferences>;
|
|
926
1034
|
}
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* Bounds applied by a write to {@link UserKvSurface}. Both are optional; an
|
|
1038
|
+
* entry written without `idleTtlMs` never expires, and a write without
|
|
1039
|
+
* `maxEntries` evicts nothing. They come on top of the store's hard caps
|
|
1040
|
+
* (see {@link UserKvSurface}), which no option lifts.
|
|
1041
|
+
*/
|
|
1042
|
+
export interface UserKvWriteOptions {
|
|
1043
|
+
/**
|
|
1044
|
+
* Idle lifetime: the entry expires once this long passes without a read or
|
|
1045
|
+
* a write of it. Every hit slides the deadline.
|
|
1046
|
+
*/
|
|
1047
|
+
idleTtlMs?: number;
|
|
1048
|
+
/**
|
|
1049
|
+
* After the write, drop the namespace's expired entries, then the least
|
|
1050
|
+
* recently used ones until at most this many remain. At most
|
|
1051
|
+
* `USER_KV_MAX_ENTRIES_PER_NAMESPACE` (10,000); a larger value is rejected
|
|
1052
|
+
* with a `RangeError`, not clamped.
|
|
1053
|
+
*/
|
|
1054
|
+
maxEntries?: number;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Key-value rows in the user's own database, grouped by namespace (a plugin
|
|
1059
|
+
* uses its own name as the prefix, e.g. `pod-creator/blueprints`). Namespaces
|
|
1060
|
+
* are a naming convention, not isolation: every plugin of the oracle sees the
|
|
1061
|
+
* same surface and can read or write any namespace. Plugins are trusted code
|
|
1062
|
+
* the operator chose to load; do not rely on namespaces to keep a plugin out
|
|
1063
|
+
* of another's rows. Values are
|
|
1064
|
+
* JSON: what goes in is serialised, what comes out is the parsed copy, so a
|
|
1065
|
+
* caller never shares an object with the store. Reads and writes mark an
|
|
1066
|
+
* entry most recently used and slide its idle deadline (LRU + idle TTL, the
|
|
1067
|
+
* semantics of an in-memory bounded map, but durable).
|
|
1068
|
+
*
|
|
1069
|
+
* The rows share the user's file with their checkpoints, sessions and
|
|
1070
|
+
* transcript, so the store enforces hard caps no plugin can opt out of:
|
|
1071
|
+
*
|
|
1072
|
+
* - one value: `USER_KV_MAX_VALUE_BYTES` (256 KiB) of UTF-8 JSON;
|
|
1073
|
+
* - one namespace: `USER_KV_MAX_ENTRIES_PER_NAMESPACE` (10,000) entries;
|
|
1074
|
+
* - all namespaces together: `USER_KV_MAX_TOTAL_ENTRIES` (50,000) entries
|
|
1075
|
+
* and `USER_KV_MAX_TOTAL_BYTES` (32 MiB), counting the UTF-8 bytes of
|
|
1076
|
+
* namespace, key and value JSON of every row.
|
|
1077
|
+
*
|
|
1078
|
+
* A `set` / `update` that would break one rejects with `UserKvLimitError`
|
|
1079
|
+
* (`limit`, `max`, `actual`, `namespace`): nothing is written and nothing
|
|
1080
|
+
* is evicted to make room — the previous value, if any, stays. Expired
|
|
1081
|
+
* entries of every namespace are swept before a write is refused, and
|
|
1082
|
+
* replacing an entry counts only the difference in size. Keep plugin state
|
|
1083
|
+
* bounded with `idleTtlMs` / `maxEntries` rather than relying on the caps.
|
|
1084
|
+
*/
|
|
1085
|
+
export interface UserKvSurface {
|
|
1086
|
+
/** The stored value, or `undefined` when absent or expired. */
|
|
1087
|
+
get(namespace: string, key: string): Promise<unknown>;
|
|
1088
|
+
/**
|
|
1089
|
+
* Store a JSON-serialisable value. Rejects with `UserKvLimitError` when
|
|
1090
|
+
* the write would break a hard cap.
|
|
1091
|
+
*/
|
|
1092
|
+
set(
|
|
1093
|
+
namespace: string,
|
|
1094
|
+
key: string,
|
|
1095
|
+
value: unknown,
|
|
1096
|
+
options?: UserKvWriteOptions,
|
|
1097
|
+
): Promise<void>;
|
|
1098
|
+
/**
|
|
1099
|
+
* Atomic read-modify-write: `fn` receives the current value (`undefined`
|
|
1100
|
+
* when absent or expired) and returns the new one; returning `undefined`
|
|
1101
|
+
* deletes the entry. No other write to the store interleaves. `fn` must be
|
|
1102
|
+
* synchronous and free of side effects — the host may run it again when a
|
|
1103
|
+
* storage read has to be retried. Resolves with the value written; rejects
|
|
1104
|
+
* with `UserKvLimitError` (the entry left as it was) when the new value
|
|
1105
|
+
* would break a hard cap. Deleting is never refused.
|
|
1106
|
+
*/
|
|
1107
|
+
update(
|
|
1108
|
+
namespace: string,
|
|
1109
|
+
key: string,
|
|
1110
|
+
fn: (current: unknown) => unknown,
|
|
1111
|
+
options?: UserKvWriteOptions,
|
|
1112
|
+
): Promise<unknown>;
|
|
1113
|
+
delete(namespace: string, key: string): Promise<void>;
|
|
1114
|
+
}
|