@ixo/oracle-runtime-workers 0.20.0 → 0.21.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ixo/oracle-runtime-workers",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "QiForge oracle runtime for Cloudflare Workers — Durable Object per user (SQLite in WASM over DO storage), Matrix E2EE gateway Durable Object, Hono HTTP/SSE shell.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
"wa-sqlite": "1.0.0",
|
|
59
59
|
"yjs": "13.6.32",
|
|
60
60
|
"zod": "^4.4.3",
|
|
61
|
-
"@ixo/
|
|
61
|
+
"@ixo/ucan": "2.2.1",
|
|
62
62
|
"@ixo/ixo-transaction": "0.1.0",
|
|
63
|
-
"@ixo/
|
|
63
|
+
"@ixo/common": "1.7.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@cloudflare/vitest-pool-workers": "^0.22.0",
|
package/src/do/user-oracle-do.ts
CHANGED
|
@@ -3253,6 +3253,7 @@ export function createUserOracleDO(opts: UserOracleDOOptions) {
|
|
|
3253
3253
|
keepGathering();
|
|
3254
3254
|
return async (onSlow, signal) => {
|
|
3255
3255
|
if (signal.aborted) return undefined;
|
|
3256
|
+
const waitedFrom = Date.now();
|
|
3256
3257
|
const timer = setTimeout(onSlow, USER_CONTEXT_PROGRESS_GRACE_MS);
|
|
3257
3258
|
let onAbort: (() => void) | undefined;
|
|
3258
3259
|
const aborted = new Promise<undefined>((resolve) => {
|
|
@@ -3261,6 +3262,12 @@ export function createUserOracleDO(opts: UserOracleDOOptions) {
|
|
|
3261
3262
|
});
|
|
3262
3263
|
try {
|
|
3263
3264
|
const outcome = await Promise.race([pending, aborted]);
|
|
3265
|
+
// One line per first contact, at warn so it stands out when logs
|
|
3266
|
+
// are read at warn and above: what the turn was given and how
|
|
3267
|
+
// long it waited for it.
|
|
3268
|
+
console.warn(
|
|
3269
|
+
`[user-context] first contact room=${input.roomId} session=${input.sessionId} outcome=${outcome?.kind ?? 'aborted'} waited=${Date.now() - waitedFrom}ms`,
|
|
3270
|
+
);
|
|
3264
3271
|
return outcome?.kind === 'cached' || outcome?.kind === 'fresh'
|
|
3265
3272
|
? withEverySlot(outcome.context)
|
|
3266
3273
|
: undefined;
|
|
@@ -557,8 +557,18 @@ type GatherResult = Extract<
|
|
|
557
557
|
|
|
558
558
|
interface InFlightGather {
|
|
559
559
|
promise: Promise<GatherResult>;
|
|
560
|
+
/** `now()` when the gather started; a gather older than its request timeout plus grace is treated as lost. */
|
|
561
|
+
startedAt: number;
|
|
560
562
|
}
|
|
561
563
|
|
|
564
|
+
/**
|
|
565
|
+
* Grace past `requestTimeoutMs` before an unsettled gather is given up on.
|
|
566
|
+
* A gather settles within its request timeout; one that has not after this
|
|
567
|
+
* long never will (its request context is gone), and a room must not keep
|
|
568
|
+
* joining it.
|
|
569
|
+
*/
|
|
570
|
+
const STALE_GATHER_GRACE_MS = 5_000;
|
|
571
|
+
|
|
562
572
|
function describe(err: unknown): string {
|
|
563
573
|
return err instanceof Error ? err.message : String(err);
|
|
564
574
|
}
|
|
@@ -769,7 +779,18 @@ export class UserContextFetcher {
|
|
|
769
779
|
}
|
|
770
780
|
|
|
771
781
|
const existing = this.inFlight.get(roomId);
|
|
772
|
-
if (existing)
|
|
782
|
+
if (existing) {
|
|
783
|
+
const ageMs = this.now() - existing.startedAt;
|
|
784
|
+
if (ageMs <= this.requestTimeoutMs + STALE_GATHER_GRACE_MS) {
|
|
785
|
+
return existing;
|
|
786
|
+
}
|
|
787
|
+
// Lost: never settled within its own timeout. Detach it (a late
|
|
788
|
+
// settle must not repopulate the room) and gather again.
|
|
789
|
+
logger.warn(
|
|
790
|
+
`[user-context] gather for room=${roomId} unsettled after ${ageMs}ms; starting a new one`,
|
|
791
|
+
);
|
|
792
|
+
this.inFlight.delete(roomId);
|
|
793
|
+
}
|
|
773
794
|
|
|
774
795
|
if (this.recentlyFailed(roomId)) {
|
|
775
796
|
logger.log(
|
|
@@ -785,6 +806,7 @@ export class UserContextFetcher {
|
|
|
785
806
|
}
|
|
786
807
|
|
|
787
808
|
const entry: InFlightGather = {
|
|
809
|
+
startedAt: this.now(),
|
|
788
810
|
promise: this.gather(engineUrl, roomId).then(
|
|
789
811
|
(result) => this.settle(roomId, entry, result),
|
|
790
812
|
(err: unknown) =>
|
|
@@ -23,14 +23,21 @@ export const MEMORY_DELETE_EDGE_MCP_NAME = 'memory-engine__delete_edge';
|
|
|
23
23
|
export const MEMORY_CLEAR_MCP_NAME = 'memory-engine__clear';
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Default selection: search, add, delete-episode, and
|
|
27
|
-
* always be able to ask for a full memory wipe, so the
|
|
28
|
-
* stays in the default set.
|
|
29
|
-
*
|
|
26
|
+
* Default selection: search, add, add-oracle-knowledge, delete-episode, and
|
|
27
|
+
* clear. The user must always be able to ask for a full memory wipe, so the
|
|
28
|
+
* destructive `clear` stays in the default set. `add_oracle_knowledge` is in
|
|
29
|
+
* the set so the controllers and owners of any oracle can grow its shared
|
|
30
|
+
* knowledge from chat without a per-oracle code change: the Memory Engine
|
|
31
|
+
* itself checks on chain that the caller controls or owns an entity linked to
|
|
32
|
+
* the oracle and refuses everyone else, so listing the tool for every user
|
|
33
|
+
* costs one tool description and grants nothing. Forks that want a different
|
|
34
|
+
* surface (drop `clear`, add `delete_edge`) pass an explicit list via plugin
|
|
35
|
+
* options.
|
|
30
36
|
*/
|
|
31
37
|
export const DEFAULT_MEMORY_TOOLS = [
|
|
32
38
|
MEMORY_SEARCH_MCP_NAME,
|
|
33
39
|
MEMORY_ADD_MCP_NAME,
|
|
40
|
+
MEMORY_ADD_ORACLE_KNOWLEDGE_MCP_NAME,
|
|
34
41
|
MEMORY_DELETE_EPISODE_MCP_NAME,
|
|
35
42
|
MEMORY_CLEAR_MCP_NAME,
|
|
36
43
|
] as const;
|
|
@@ -450,7 +457,7 @@ function adaptMcpTool(mcpTool: UpstreamMcpTool): PluginTool {
|
|
|
450
457
|
/**
|
|
451
458
|
* Fetch the upstream Memory Engine MCP tools for this request and return them
|
|
452
459
|
* as `PluginTool[]`. Filtered by `selectedTools` so forks can scope the
|
|
453
|
-
* surface (e.g. drop `clear`, add `
|
|
460
|
+
* surface (e.g. drop `clear`, add `delete_edge`).
|
|
454
461
|
*
|
|
455
462
|
* Returns `[]` when the factory cannot mint auth — the agent then sees no
|
|
456
463
|
* memory tools rather than getting a half-built request to upstream.
|
|
@@ -32,12 +32,14 @@ const manifest: PluginManifest = {
|
|
|
32
32
|
'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.',
|
|
33
33
|
'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.',
|
|
34
34
|
'The user references something they told you before, or something you made before.',
|
|
35
|
+
'A controller or owner of this oracle asks you to store something every user of the oracle should know (a policy, a procedure, reference material): tell them it will be shared with every user of the oracle (or, for the private space, with its controllers and owners only), get their confirmation, then store it as oracle knowledge rather than as a memory about them.',
|
|
35
36
|
],
|
|
36
37
|
whenNotToUse: [
|
|
37
38
|
'Ephemeral conversation-only state (use the current message thread).',
|
|
38
39
|
'Behavioral preferences about how to respond (call the user-preferences tool instead).',
|
|
39
40
|
'Public web facts that are not specific to this user (use a web-search capability).',
|
|
40
41
|
'Anything the user asked you to forget or framed as temporary.',
|
|
42
|
+
'Oracle knowledge for something about one user: the shared knowledge is only for what every user of this oracle should know.',
|
|
41
43
|
],
|
|
42
44
|
tags: ['memory', 'recall', 'artifacts', 'personalization'],
|
|
43
45
|
category: 'memory',
|
|
@@ -54,8 +56,8 @@ export interface MemoryPluginOptions {
|
|
|
54
56
|
mcpFactory?: (memoryMcpUrl: string) => MemoryMcpFactory;
|
|
55
57
|
/**
|
|
56
58
|
* Filter the upstream tool surface. Defaults to {@link DEFAULT_MEMORY_TOOLS}
|
|
57
|
-
* (search + add + delete-episode + clear). Pass an
|
|
58
|
-
*
|
|
59
|
+
* (search + add + add-oracle-knowledge + delete-episode + clear). Pass an
|
|
60
|
+
* explicit list to drop one of them or to expose `delete_edge`.
|
|
59
61
|
*/
|
|
60
62
|
selectedTools?: readonly string[];
|
|
61
63
|
}
|