@ixo/oracle-runtime-workers 0.22.0 → 0.24.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 +15 -13
- package/package.json +10 -4
- package/src/action-proposals/policy.ts +54 -0
- package/src/action-proposals/reconcile.ts +87 -0
- package/src/action-proposals/store.ts +863 -0
- package/src/action-proposals/topic-budget.ts +84 -0
- package/src/action-proposals/topic-chain.ts +272 -0
- package/src/action-proposals/topic-effects.ts +44 -0
- package/src/action-proposals/topic-errors.ts +79 -0
- package/src/action-proposals/topic-history.ts +267 -0
- package/src/action-proposals/topic-matrix.ts +292 -0
- package/src/action-proposals/topic-prepare.ts +299 -0
- package/src/action-proposals/topic-store.ts +999 -0
- package/src/action-proposals/topic-verify.ts +279 -0
- package/src/action-proposals/verify.ts +223 -0
- package/src/channels/auth.ts +6 -1
- package/src/channels/contract.ts +4 -0
- package/src/channels/turns.ts +1 -0
- package/src/core/env.ts +93 -6
- package/src/core/main-agent-types.ts +8 -0
- package/src/core/main-agent.ts +2 -0
- package/src/core/runtime-context.ts +12 -0
- package/src/delivery/plan.ts +43 -2
- package/src/delivery/schema.ts +25 -1
- package/src/delivery/types.ts +13 -2
- package/src/do/ambient.ts +6 -0
- package/src/do/contracts.ts +39 -0
- package/src/do/user-oracle-do.ts +1275 -8
- package/src/hub-actions/client.ts +163 -0
- package/src/hub-actions/request.ts +110 -0
- package/src/hub-actions/store.ts +485 -0
- package/src/matrix/gateway-do.ts +176 -0
- package/src/matrix/reply-parts.ts +8 -2
- package/src/memory/session-history-indexer.ts +30 -3
- package/src/memory/user-context-fetcher.ts +36 -12
- package/src/plugin-api/types.ts +54 -0
- package/src/plugins/action-proposals/action-proposals.plugin.ts +486 -0
- package/src/plugins/action-proposals/evidence.ts +67 -0
- package/src/plugins/hub-actions/hub-actions.plugin.ts +244 -0
- package/src/plugins/index.ts +6 -0
- package/src/plugins/memory/index.ts +4 -0
- package/src/plugins/memory/memory-entity.ts +49 -0
- package/src/plugins/memory/memory-tools.ts +7 -4
- package/src/plugins/memory/memory-ucan.ts +10 -1
- package/src/plugins/memory/memory.plugin.ts +22 -7
- package/src/shell/app.ts +195 -1
|
@@ -189,6 +189,8 @@ export interface AmbientServices {
|
|
|
189
189
|
* `DecisionProviderUnavailableError`.
|
|
190
190
|
*/
|
|
191
191
|
decisions?: DecisionEvaluator;
|
|
192
|
+
actionProposals?: RuntimeContext['actionProposals'];
|
|
193
|
+
hubActions?: RuntimeContext['hubActions'];
|
|
192
194
|
/** Host task scheduler for the current user, when the host provides one. */
|
|
193
195
|
tasks?: import('../plugin-api/types').OracleTasksSurface;
|
|
194
196
|
/** Host user-preferences store for the current user, when provided. */
|
|
@@ -323,6 +325,12 @@ export interface RuntimeSessionContext {
|
|
|
323
325
|
client: 'portal' | 'matrix' | 'slack' | 'channel';
|
|
324
326
|
wsId?: string;
|
|
325
327
|
requestId: string;
|
|
328
|
+
runId?: string;
|
|
329
|
+
channel?: {
|
|
330
|
+
provider: string;
|
|
331
|
+
bindingId: string;
|
|
332
|
+
bindingRevision: number;
|
|
333
|
+
};
|
|
326
334
|
roomId?: string;
|
|
327
335
|
surface?: SessionSurface;
|
|
328
336
|
}
|
|
@@ -528,6 +536,10 @@ export function buildRuntimeContext<TConfig = MergedConfig>(
|
|
|
528
536
|
logger: ambient.logger,
|
|
529
537
|
abortSignal,
|
|
530
538
|
...(ambient.tasks ? { tasks: ambient.tasks } : {}),
|
|
539
|
+
...(ambient.actionProposals
|
|
540
|
+
? { actionProposals: ambient.actionProposals }
|
|
541
|
+
: {}),
|
|
542
|
+
...(ambient.hubActions ? { hubActions: ambient.hubActions } : {}),
|
|
531
543
|
...(ambient.preferences ? { preferences: ambient.preferences } : {}),
|
|
532
544
|
...(ambient.kv ? { kv: ambient.kv } : {}),
|
|
533
545
|
...(ambient.frontend ? { frontend: ambient.frontend } : {}),
|
package/src/delivery/plan.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ActionReferenceSchema } from '@ixo/ixo-transaction/action-proposals';
|
|
2
|
+
import { parseReference } from '@ixo/action-protocol';
|
|
1
3
|
/**
|
|
2
4
|
* A finished run → its Reply Plan. Built once, when the run finishes, from
|
|
3
5
|
* the turn's own messages (the model's checkpointed history is never
|
|
@@ -160,11 +162,42 @@ export function draftReplyPlan(input: {
|
|
|
160
162
|
);
|
|
161
163
|
else parts.push({ kind: 'spill', key: `step-${i}`, spill: shape.spill });
|
|
162
164
|
}
|
|
163
|
-
for (const call of step.toolCalls)
|
|
165
|
+
for (const call of step.toolCalls) {
|
|
166
|
+
if (call.name === 'request_hub_action') {
|
|
167
|
+
try {
|
|
168
|
+
const result = JSON.parse(input.toolResults.get(call.id) ?? 'null');
|
|
169
|
+
if (result?.status === 'prepared') {
|
|
170
|
+
const actionReference = parseReference(result.actionReference);
|
|
171
|
+
if (
|
|
172
|
+
typeof result.summary === 'string' &&
|
|
173
|
+
result.summary === actionReference.title
|
|
174
|
+
)
|
|
175
|
+
parts.push({
|
|
176
|
+
kind: 'hub-action',
|
|
177
|
+
actionReference,
|
|
178
|
+
summary: result.summary,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
} catch {
|
|
182
|
+
// Only a parsed tool result becomes a structured Hub reference.
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (call.name === 'prepare_action') {
|
|
186
|
+
try {
|
|
187
|
+
const result = JSON.parse(input.toolResults.get(call.id) ?? 'null');
|
|
188
|
+
if (result?.status === 'prepared') {
|
|
189
|
+
const ref = ActionReferenceSchema.safeParse(result.action);
|
|
190
|
+
if (ref.success) parts.push({ kind: 'action', action: ref.data });
|
|
191
|
+
}
|
|
192
|
+
} catch {
|
|
193
|
+
/* A malformed result is not an action reference. */
|
|
194
|
+
}
|
|
195
|
+
}
|
|
164
196
|
if (call.name === CREATE_ARTIFACT_TOOL)
|
|
165
197
|
parts.push(
|
|
166
198
|
...createArtifactParts(call.args, input.toolResults.get(call.id)),
|
|
167
199
|
);
|
|
200
|
+
}
|
|
168
201
|
});
|
|
169
202
|
return parts;
|
|
170
203
|
}
|
|
@@ -221,7 +254,15 @@ function capParts(parts: PlanPart[], limits: ChatLimits): ReplyContent[] {
|
|
|
221
254
|
(part): ReplyContent =>
|
|
222
255
|
part.kind === 'text'
|
|
223
256
|
? { kind: 'text', text: part.text }
|
|
224
|
-
:
|
|
257
|
+
: part.kind === 'artifact'
|
|
258
|
+
? { kind: 'artifact', artifact: part.artifact }
|
|
259
|
+
: part.kind === 'action'
|
|
260
|
+
? { kind: 'action', action: part.action }
|
|
261
|
+
: {
|
|
262
|
+
kind: 'hub-action',
|
|
263
|
+
actionReference: part.actionReference,
|
|
264
|
+
summary: part.summary,
|
|
265
|
+
},
|
|
225
266
|
);
|
|
226
267
|
}
|
|
227
268
|
|
package/src/delivery/schema.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ActionReferenceSchema } from '@ixo/ixo-transaction/action-proposals';
|
|
2
|
+
import { parseReference, type ActionReferenceV1 } from '@ixo/action-protocol';
|
|
1
3
|
import { z } from 'zod';
|
|
2
4
|
import type { ReplyContent, ReplyPlan } from './types';
|
|
3
5
|
|
|
@@ -19,6 +21,24 @@ export const ReplyPlanSchema = z.object({
|
|
|
19
21
|
kind: z.literal('text'),
|
|
20
22
|
text: z.string(),
|
|
21
23
|
}),
|
|
24
|
+
z.object({
|
|
25
|
+
partId: z.string(),
|
|
26
|
+
kind: z.literal('action'),
|
|
27
|
+
action: ActionReferenceSchema,
|
|
28
|
+
}),
|
|
29
|
+
z.object({
|
|
30
|
+
partId: z.string(),
|
|
31
|
+
kind: z.literal('hub-action'),
|
|
32
|
+
actionReference: z.custom<ActionReferenceV1>((value) => {
|
|
33
|
+
try {
|
|
34
|
+
parseReference(value);
|
|
35
|
+
return true;
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}),
|
|
40
|
+
summary: z.string().min(1).max(80),
|
|
41
|
+
}),
|
|
22
42
|
z.object({
|
|
23
43
|
partId: z.string(),
|
|
24
44
|
kind: z.literal('artifact'),
|
|
@@ -55,7 +75,11 @@ export function planText(plan: { parts: readonly ReplyContent[] }): string {
|
|
|
55
75
|
.map((part) =>
|
|
56
76
|
part.kind === 'text'
|
|
57
77
|
? part.text
|
|
58
|
-
:
|
|
78
|
+
: part.kind === 'action'
|
|
79
|
+
? `[${linkLabel(part.action.title)}](${part.action.url})`
|
|
80
|
+
: part.kind === 'hub-action'
|
|
81
|
+
? `[${linkLabel(part.summary)}](${part.actionReference.url})`
|
|
82
|
+
: `[${linkLabel(part.artifact.title)}](${part.artifact.url})`,
|
|
59
83
|
)
|
|
60
84
|
.join('\n\n');
|
|
61
85
|
}
|
package/src/delivery/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ActionReference } from '@ixo/ixo-transaction/action-proposals';
|
|
2
|
+
import type { ActionReferenceV1 } from '@ixo/action-protocol';
|
|
1
3
|
/**
|
|
2
4
|
* Chat delivery: how a finished turn reaches a chat surface (an IXO Channels
|
|
3
5
|
* provider such as WhatsApp, or a Matrix room) as a few short messages and
|
|
@@ -70,12 +72,21 @@ export interface ArtifactRef {
|
|
|
70
72
|
*/
|
|
71
73
|
export type ReplyPart =
|
|
72
74
|
| { partId: string; kind: 'text'; text: string }
|
|
73
|
-
| { partId: string; kind: 'artifact'; artifact: ArtifactRef }
|
|
75
|
+
| { partId: string; kind: 'artifact'; artifact: ArtifactRef }
|
|
76
|
+
| { partId: string; kind: 'action'; action: ActionReference }
|
|
77
|
+
| {
|
|
78
|
+
partId: string;
|
|
79
|
+
kind: 'hub-action';
|
|
80
|
+
actionReference: ActionReferenceV1;
|
|
81
|
+
summary: string;
|
|
82
|
+
};
|
|
74
83
|
|
|
75
84
|
/** A part before it is numbered: what a plan is assembled from. */
|
|
76
85
|
export type ReplyContent =
|
|
77
86
|
| { kind: 'text'; text: string }
|
|
78
|
-
| { kind: 'artifact'; artifact: ArtifactRef }
|
|
87
|
+
| { kind: 'artifact'; artifact: ArtifactRef }
|
|
88
|
+
| { kind: 'action'; action: ActionReference }
|
|
89
|
+
| { kind: 'hub-action'; actionReference: ActionReferenceV1; summary: string };
|
|
79
90
|
|
|
80
91
|
/** What a chat surface delivers for one finished run, in delivery order. */
|
|
81
92
|
export interface ReplyPlan {
|
package/src/do/ambient.ts
CHANGED
|
@@ -267,6 +267,8 @@ export function createUcanAdapter(
|
|
|
267
267
|
|
|
268
268
|
export interface CreateAmbientInput {
|
|
269
269
|
/** Host task scheduler surface for this user, when tasks are enabled. */
|
|
270
|
+
actionProposals?: AmbientServices['actionProposals'];
|
|
271
|
+
hubActions?: AmbientServices['hubActions'];
|
|
270
272
|
tasks?: import('../plugin-api/types').OracleTasksSurface;
|
|
271
273
|
preferences?: import('../plugin-api/types').UserPreferencesSurface;
|
|
272
274
|
/** `ctx.kv` over the user's working copy (`SqliteUserKv`). */
|
|
@@ -302,6 +304,10 @@ export function createAmbientServices(
|
|
|
302
304
|
): AmbientServices {
|
|
303
305
|
return {
|
|
304
306
|
...(input.tasks ? { tasks: input.tasks } : {}),
|
|
307
|
+
...(input.actionProposals
|
|
308
|
+
? { actionProposals: input.actionProposals }
|
|
309
|
+
: {}),
|
|
310
|
+
...(input.hubActions ? { hubActions: input.hubActions } : {}),
|
|
305
311
|
...(input.preferences ? { preferences: input.preferences } : {}),
|
|
306
312
|
...(input.kv ? { kv: input.kv } : {}),
|
|
307
313
|
...(input.frontend ? { frontend: input.frontend } : {}),
|
package/src/do/contracts.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BeginTopicStep,
|
|
3
|
+
TopicReceiptReferences,
|
|
4
|
+
} from '@ixo/ixo-transaction/topic-proposals';
|
|
5
|
+
import type { ProposalCommand } from '../action-proposals/store';
|
|
6
|
+
import type { ActionOutcomeV1 } from '@ixo/action-protocol';
|
|
1
7
|
import type {
|
|
2
8
|
TopicDeliverableCommand,
|
|
3
9
|
TopicDeliverableResult,
|
|
@@ -50,6 +56,12 @@ import type { DomainContextProvenance } from '../core/domain-context';
|
|
|
50
56
|
/** Bindings every oracle Worker must declare (see the example `wrangler.jsonc`). */
|
|
51
57
|
export interface OracleWorkerEnv {
|
|
52
58
|
TOPIC_DELIVERABLES_ENABLED?: string;
|
|
59
|
+
ACTION_PROPOSALS_RPC_TESTNET?: string;
|
|
60
|
+
ACTION_PROPOSALS_RPC_DEVNET?: string;
|
|
61
|
+
ACTION_PROPOSALS_RPC_MAINNET?: string;
|
|
62
|
+
ACTION_PROPOSALS_ENABLED?: string;
|
|
63
|
+
ACTION_TOPIC_PROPOSALS_ENABLED?: string;
|
|
64
|
+
ACTION_PROPOSALS_PORTAL_ORIGIN?: string;
|
|
53
65
|
USER_ORACLE: DurableObjectNamespace<UserOracleObject>;
|
|
54
66
|
MATRIX_GATEWAY: DurableObjectNamespace<MatrixGatewayObject>;
|
|
55
67
|
|
|
@@ -72,6 +84,8 @@ export interface OracleWorkerEnv {
|
|
|
72
84
|
AUTH_HUB?: Fetcher;
|
|
73
85
|
AUTH_HUB_URL?: string;
|
|
74
86
|
AUTH_HUB_CHANNEL_SERVICE_KEY?: string;
|
|
87
|
+
HUB_ACTIONS_ENABLED?: string;
|
|
88
|
+
AUTH_HUB_ACTION_OUTCOME_KEY?: string;
|
|
75
89
|
|
|
76
90
|
// --- matrix -------------------------------------------------------------
|
|
77
91
|
MATRIX_BASE_URL: string;
|
|
@@ -371,6 +385,7 @@ export interface TurnRequest {
|
|
|
371
385
|
/** A provider id (`/^[a-z][a-z0-9_-]{0,31}$/`), e.g. `whatsapp`. */
|
|
372
386
|
provider: string;
|
|
373
387
|
bindingId: string;
|
|
388
|
+
bindingRevision?: number;
|
|
374
389
|
remoteMessageRef: string;
|
|
375
390
|
};
|
|
376
391
|
executionProfile?: TaskExecutionProfile;
|
|
@@ -721,6 +736,7 @@ export interface StorageStatus {
|
|
|
721
736
|
* piped straight to the client.
|
|
722
737
|
*/
|
|
723
738
|
export interface UserOracleObject extends Rpc.DurableObjectBranded {
|
|
739
|
+
recordHubActionOutcome(outcome: ActionOutcomeV1): Promise<void>;
|
|
724
740
|
topicDeliverable(
|
|
725
741
|
identity: TurnIdentity,
|
|
726
742
|
operationId: string,
|
|
@@ -759,6 +775,18 @@ export interface UserOracleObject extends Rpc.DurableObjectBranded {
|
|
|
759
775
|
opts?: { limit?: number; offset?: number },
|
|
760
776
|
): Promise<{ sessions: SessionSummary[]; total: number }>;
|
|
761
777
|
deleteSession(identity: TurnIdentity, sessionId: string): Promise<boolean>;
|
|
778
|
+
actionProposal(
|
|
779
|
+
identity: TurnIdentity,
|
|
780
|
+
id: string,
|
|
781
|
+
command?:
|
|
782
|
+
| ProposalCommand
|
|
783
|
+
| { kind: 'topic-reconcile'; input: TopicReceiptReferences },
|
|
784
|
+
): Promise<JsonString | null>;
|
|
785
|
+
beginTopicStep(
|
|
786
|
+
identity: TurnIdentity,
|
|
787
|
+
id: string,
|
|
788
|
+
input: BeginTopicStep,
|
|
789
|
+
): Promise<JsonString | null>;
|
|
762
790
|
/** `GET /artifacts/:id` — the owner's canonical copy, or null. */
|
|
763
791
|
artifact(
|
|
764
792
|
identity: TurnIdentity,
|
|
@@ -1066,6 +1094,17 @@ export interface MatrixGatewayObject extends Rpc.DurableObjectBranded {
|
|
|
1066
1094
|
): Promise<string>;
|
|
1067
1095
|
/** Full room state as a JSON-encoded array of `{ type, state_key, content, sender, event_id }`. */
|
|
1068
1096
|
getRoomState(roomId: string): Promise<JsonString>;
|
|
1097
|
+
getTopicRoomState(roomId: string): Promise<JsonString>;
|
|
1098
|
+
getTopicEvent(
|
|
1099
|
+
roomId: string,
|
|
1100
|
+
eventId: string,
|
|
1101
|
+
opts?: { deadlineAt?: number },
|
|
1102
|
+
): Promise<JsonString | null>;
|
|
1103
|
+
getTopicHistory(
|
|
1104
|
+
roomId: string,
|
|
1105
|
+
root: string,
|
|
1106
|
+
opts?: { deadlineAt?: number; sender?: string },
|
|
1107
|
+
): Promise<JsonString>;
|
|
1069
1108
|
/** One timeline event (decrypted when E2EE) as JSON `{ event_id, type, content, sender, origin_server_ts }`, or null. */
|
|
1070
1109
|
getEvent(roomId: string, eventId: string): Promise<JsonString | null>;
|
|
1071
1110
|
/**
|