@ixo/oracle-runtime-workers 0.20.1 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ixo/oracle-runtime-workers",
3
- "version": "0.20.1",
3
+ "version": "0.21.1",
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,8 +58,8 @@
58
58
  "wa-sqlite": "1.0.0",
59
59
  "yjs": "13.6.32",
60
60
  "zod": "^4.4.3",
61
- "@ixo/ixo-transaction": "0.1.0",
62
61
  "@ixo/common": "1.7.0",
62
+ "@ixo/ixo-transaction": "0.1.0",
63
63
  "@ixo/ucan": "2.2.1"
64
64
  },
65
65
  "devDependencies": {
@@ -3198,17 +3198,28 @@ export function createUserOracleDO(opts: UserOracleDOOptions) {
3198
3198
  client: TurnRequest['client'];
3199
3199
  roomKind: TurnRequest['roomKind'];
3200
3200
  }): UserContextSettle | null {
3201
- // Task runs never get the user's memory (see `scheduleHistoryIndexing`).
3202
- if (!input.roomId || input.sessionId.startsWith(TASK_SESSION_PREFIX))
3201
+ // A first contact that fetches nothing still prints the one
3202
+ // first-contact line (see the settle step below), with its reason, so
3203
+ // a warn-level reading of the logs accounts for every first turn.
3204
+ const skipped = (reason: string): null => {
3205
+ if (!hasUserContext(input.prior)) {
3206
+ console.warn(
3207
+ `[user-context] first contact room=${input.roomId ?? '-'} session=${input.sessionId} outcome=skipped reason=${reason} waited=0ms`,
3208
+ );
3209
+ }
3203
3210
  return null;
3211
+ };
3212
+ // Task runs never get the user's memory (see `scheduleHistoryIndexing`).
3213
+ if (input.sessionId.startsWith(TASK_SESSION_PREFIX)) return null;
3214
+ if (!input.roomId) return skipped('no-room');
3204
3215
  const settings = this.userContextSettings();
3216
+ if (!settings) return skipped('disabled');
3205
3217
  const ambient = this.ambient;
3206
- if (!settings || !ambient) return null;
3218
+ if (!ambient) return skipped('not-booted');
3207
3219
  // A group room's reply is posted to every member: one user's memory
3208
3220
  // must not be (as direct reads are not, see `admissionApplies`).
3209
3221
  if (input.client === 'matrix' && input.roomKind === 'group') {
3210
- console.log('[user-context] skipped: group room');
3211
- return null;
3222
+ return skipped('group-room');
3212
3223
  }
3213
3224
  // Without a memory grant the gather could only fail at the mint: skip
3214
3225
  // it before any request (the engine's did.json included).
@@ -3219,10 +3230,7 @@ export function createUserOracleDO(opts: UserOracleDOOptions) {
3219
3230
  MEMORY_CAPABILITY.action,
3220
3231
  )
3221
3232
  ) {
3222
- console.log(
3223
- `[user-context] skipped: the delegation grants no ${MEMORY_CAPABILITY.resource} ${MEMORY_CAPABILITY.action}`,
3224
- );
3225
- return null;
3233
+ return skipped('no-memory-grant');
3226
3234
  }
3227
3235
  const fetcher = this.userContextFetcherFor(settings);
3228
3236
  const params: UserContextFetchParams = {
@@ -3265,8 +3273,12 @@ export function createUserOracleDO(opts: UserOracleDOOptions) {
3265
3273
  // One line per first contact, at warn so it stands out when logs
3266
3274
  // are read at warn and above: what the turn was given and how
3267
3275
  // long it waited for it.
3276
+ const reason =
3277
+ outcome?.kind === 'skipped' || outcome?.kind === 'failed'
3278
+ ? ` reason=${outcome.reason}`
3279
+ : '';
3268
3280
  console.warn(
3269
- `[user-context] first contact room=${input.roomId} session=${input.sessionId} outcome=${outcome?.kind ?? 'aborted'} waited=${Date.now() - waitedFrom}ms`,
3281
+ `[user-context] first contact room=${input.roomId} session=${input.sessionId} outcome=${outcome?.kind ?? 'aborted'}${reason} waited=${Date.now() - waitedFrom}ms`,
3270
3282
  );
3271
3283
  return outcome?.kind === 'cached' || outcome?.kind === 'fresh'
3272
3284
  ? withEverySlot(outcome.context)
@@ -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 clear — the user must
27
- * always be able to ask for a full memory wipe, so the destructive `clear`
28
- * stays in the default set. Forks that need org-owner knowledge writes (or
29
- * want to drop `clear`) pass an explicit list via plugin options.
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 `add_oracle_knowledge` for org-owner mode).
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 explicit list to expose
58
- * `add_oracle_knowledge`, `delete_edge`, etc.
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
  }