@remnic/plugin-openclaw 1.0.32 → 1.0.34

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 CHANGED
@@ -164,6 +164,13 @@ CI jobs that provision OpenClaw should use
164
164
  `npm run check:openclaw-sdk-surface:required` or pass
165
165
  `-- --require --package-root <path>` so a missing SDK fails instead of skipping.
166
166
 
167
+ Last compatibility sweep: May 7, 2026. The SDK surface check passed against
168
+ `openclaw@2026.5.3`, `openclaw@2026.5.3-1`, `openclaw@2026.5.4-beta.1`,
169
+ `openclaw@2026.5.4-beta.2`, `openclaw@2026.5.4-beta.3`,
170
+ `openclaw@2026.5.4`, `openclaw@2026.5.5`, and `openclaw@2026.5.6`.
171
+ Keep the peer range broad unless an upstream release removes a runtime surface
172
+ Remnic actively uses.
173
+
167
174
  Native memory registrars are tracked separately in
168
175
  [`docs/plugins/openclaw-native-memory-registrars.md`](../../docs/plugins/openclaw-native-memory-registrars.md).
169
176
  That spike explains why Remnic currently uses `registerMemoryCapability()` as
@@ -3,12 +3,12 @@ import {
3
3
  } from "./chunk-5LE4HTVL.js";
4
4
  import {
5
5
  FallbackLlmClient
6
- } from "./chunk-24MGN4E3.js";
6
+ } from "./chunk-7NUFIRM3.js";
7
7
  import "./chunk-3A5ELHTT.js";
8
8
  import {
9
9
  log
10
10
  } from "./chunk-UFU5GGGA.js";
11
- import "./chunk-I6B2W2IY.js";
11
+ import "./chunk-TDRJVMUP.js";
12
12
  import "./chunk-MLKGABMK.js";
13
13
 
14
14
  // ../remnic-core/src/calibration.ts
@@ -183,7 +183,9 @@ function buildCalibrationRecallSection(rules, query, maxChars = 1200) {
183
183
  }
184
184
  async function runCalibrationConsolidation(options) {
185
185
  try {
186
- const llm = new FallbackLlmClient(options.gatewayConfig);
186
+ const llm = new FallbackLlmClient(options.gatewayConfig, {
187
+ workspaceDir: options.workspaceDir
188
+ });
187
189
  if (!llm.isAvailable(options.gatewayAgentId)) {
188
190
  log.debug("[calibration] no LLM available \u2014 skipping consolidation");
189
191
  return [];
@@ -229,7 +231,8 @@ async function runCalibrationIfEnabled(options) {
229
231
  }
230
232
  return runCalibrationConsolidation({
231
233
  memoryDir: options.memoryDir,
232
- gatewayConfig: options.gatewayConfig
234
+ gatewayConfig: options.gatewayConfig,
235
+ workspaceDir: options.workspaceDir
233
236
  });
234
237
  }
235
238
  async function getCalibrationRulesForRecall(memoryDir) {
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  buildExtensionsBlockForConsolidation,
7
7
  runPostConsolidationMaterialize
8
- } from "./chunk-HI5HX3S7.js";
8
+ } from "./chunk-NDZNURDM.js";
9
9
  import "./chunk-WPINX4MF.js";
10
10
  import {
11
11
  isRecord
@@ -16,7 +16,7 @@ import {
16
16
  } from "./chunk-5LE4HTVL.js";
17
17
  import {
18
18
  FallbackLlmClient
19
- } from "./chunk-24MGN4E3.js";
19
+ } from "./chunk-7NUFIRM3.js";
20
20
  import "./chunk-3A5ELHTT.js";
21
21
  import "./chunk-ZXLYEVOP.js";
22
22
  import "./chunk-6OJAU466.js";
@@ -25,7 +25,7 @@ import {
25
25
  log
26
26
  } from "./chunk-UFU5GGGA.js";
27
27
  import "./chunk-YGGGUTG3.js";
28
- import "./chunk-I6B2W2IY.js";
28
+ import "./chunk-TDRJVMUP.js";
29
29
  import "./chunk-MLKGABMK.js";
30
30
 
31
31
  // ../remnic-core/src/causal-consolidation.ts
@@ -177,7 +177,9 @@ async function deriveCausalPromotionCandidates(options) {
177
177
  context += "\n\n" + extBlock;
178
178
  }
179
179
  }
180
- const llm = new FallbackLlmClient(options.gatewayConfig);
180
+ const llm = new FallbackLlmClient(options.gatewayConfig, {
181
+ workspaceDir: options.pluginConfig?.workspaceDir ?? options.workspaceDir
182
+ });
181
183
  if (!llm.isAvailable(options.gatewayAgentId)) {
182
184
  log.debug("[cmc] no LLM available for consolidation \u2014 skipping");
183
185
  return [];
@@ -198,7 +200,9 @@ async function synthesizeCausalPreferencesViaLlm(options) {
198
200
  const chainsDir = resolveChainsDir(options.memoryDir, options.causalTrajectoryStoreDir);
199
201
  const chainIndex = await readChainIndex(chainsDir);
200
202
  const context = formatCausalContext(trajectories, chainIndex);
201
- const llm = new FallbackLlmClient(options.gatewayConfig);
203
+ const llm = new FallbackLlmClient(options.gatewayConfig, {
204
+ workspaceDir: options.workspaceDir
205
+ });
202
206
  if (!llm.isAvailable(options.gatewayAgentId)) return null;
203
207
  const result = await consolidateWithLlm(context, llm, options.gatewayAgentId);
204
208
  if (result.preferences.length === 0 && result.rules.length === 0) return null;
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-UFU5GGGA.js";
12
12
  import {
13
13
  expandTildePath
14
- } from "./chunk-OEI7GLV2.js";
14
+ } from "./chunk-TDRJVMUP.js";
15
15
 
16
16
  // ../remnic-core/src/compounding/engine.ts
17
17
  import { createHash } from "crypto";
@@ -842,12 +842,13 @@ var CompoundingEngine = class {
842
842
  let promotionCandidates = this.config.compoundingSemanticEnabled ? this.derivePromotionCandidates(outcomeSummary, mistakes.registry, rubrics) : [];
843
843
  if (this.config.cmcConsolidationEnabled) {
844
844
  try {
845
- const { deriveCausalPromotionCandidates, materializeAfterCausalConsolidation } = await import("./causal-consolidation-3GTZFN2T.js");
845
+ const { deriveCausalPromotionCandidates, materializeAfterCausalConsolidation } = await import("./causal-consolidation-DSLFN64P.js");
846
846
  const causalCandidates = await deriveCausalPromotionCandidates({
847
847
  memoryDir: this.config.memoryDir,
848
848
  causalTrajectoryStoreDir: this.config.causalTrajectoryStoreDir,
849
849
  gatewayConfig: this.config.gatewayConfig,
850
850
  gatewayAgentId: this.config.modelSource === "gateway" ? this.config.gatewayAgentId || void 0 : void 0,
851
+ workspaceDir: this.config.workspaceDir,
851
852
  pluginConfig: this.config,
852
853
  config: {
853
854
  minRecurrence: this.config.cmcConsolidationMinRecurrence,
@@ -874,11 +875,12 @@ var CompoundingEngine = class {
874
875
  }
875
876
  if (this.config.calibrationEnabled) {
876
877
  try {
877
- const { runCalibrationConsolidation } = await import("./calibration-V6NBBNCD.js");
878
+ const { runCalibrationConsolidation } = await import("./calibration-JD4AU7FB.js");
878
879
  const calRules = await runCalibrationConsolidation({
879
880
  memoryDir: this.config.memoryDir,
880
881
  gatewayConfig: this.config.gatewayConfig,
881
- gatewayAgentId: this.config.modelSource === "gateway" ? this.config.gatewayAgentId || void 0 : void 0
882
+ gatewayAgentId: this.config.modelSource === "gateway" ? this.config.gatewayAgentId || void 0 : void 0,
883
+ workspaceDir: this.config.workspaceDir
882
884
  });
883
885
  log.debug(`[calibration] weekly synthesis produced ${calRules.length} calibration rule(s)`);
884
886
  } catch (error) {
@@ -5,8 +5,13 @@ import {
5
5
  log
6
6
  } from "./chunk-UFU5GGGA.js";
7
7
  import {
8
- readEnvVar
9
- } from "./chunk-I6B2W2IY.js";
8
+ expandTildePath,
9
+ readEnvVar,
10
+ resolveHomeDir
11
+ } from "./chunk-TDRJVMUP.js";
12
+
13
+ // ../remnic-core/src/fallback-llm.ts
14
+ import path2 from "path";
10
15
 
11
16
  // ../remnic-core/src/openai-chat-compat.ts
12
17
  function normalizedModel(model) {
@@ -269,6 +274,73 @@ function loadModelsJsonProviders() {
269
274
  return {};
270
275
  }
271
276
 
277
+ // ../remnic-core/src/codex-cli-fallback.ts
278
+ var VALID_CODEX_CLI_REASONING_EFFORTS = /* @__PURE__ */ new Set([
279
+ "low",
280
+ "medium",
281
+ "high",
282
+ "xhigh"
283
+ ]);
284
+ var processRunner;
285
+ async function callCodexCliFallback(config, modelId, messages, options = {}) {
286
+ if (!processRunner) {
287
+ throw new Error(
288
+ 'codex-cli fallback transport is not registered; install a runner with setCodexCliFallbackRunnerForProcess() before using api: "codex-cli"'
289
+ );
290
+ }
291
+ return await processRunner({
292
+ config: normalizeCodexCliFallbackConfig(config),
293
+ modelId: normalizeCodexCliModel(modelId),
294
+ messages,
295
+ options: normalizeCodexCliFallbackOptions(options)
296
+ });
297
+ }
298
+ function normalizeCodexCliFallbackConfig(config) {
299
+ return {
300
+ ...config,
301
+ ...config.executable !== void 0 ? { executable: normalizeOptionalString(config.executable, "codex-cli executable") } : {},
302
+ ...config.codexCliExecutable !== void 0 ? { codexCliExecutable: normalizeOptionalString(config.codexCliExecutable, "codex-cli executable") } : {},
303
+ ...config.reasoningEffort !== void 0 ? { reasoningEffort: normalizeCodexCliReasoningEffort(config.reasoningEffort) } : {},
304
+ ...config.codexCliReasoningEffort !== void 0 ? { codexCliReasoningEffort: normalizeCodexCliReasoningEffort(config.codexCliReasoningEffort) } : {},
305
+ ...config.retryOptions?.timeoutMs !== void 0 ? { retryOptions: { timeoutMs: normalizeCodexCliTimeoutMs(config.retryOptions.timeoutMs) } } : {}
306
+ };
307
+ }
308
+ function normalizeCodexCliFallbackOptions(options) {
309
+ return {
310
+ ...options.timeoutMs !== void 0 ? { timeoutMs: normalizeCodexCliTimeoutMs(options.timeoutMs) } : {}
311
+ };
312
+ }
313
+ function normalizeOptionalString(value, label) {
314
+ if (typeof value !== "string" || value.trim().length === 0) {
315
+ throw new Error(`${label} must be a non-empty string`);
316
+ }
317
+ return value.trim();
318
+ }
319
+ function normalizeCodexCliModel(value) {
320
+ const trimmed = value.trim();
321
+ if (trimmed.length === 0) {
322
+ throw new Error("codex-cli model must be a non-empty string");
323
+ }
324
+ return trimmed;
325
+ }
326
+ function normalizeCodexCliReasoningEffort(value) {
327
+ if (typeof value !== "string") {
328
+ throw new Error("codex-cli reasoningEffort must be one of low, medium, high, xhigh");
329
+ }
330
+ const normalized = value.trim().toLowerCase();
331
+ if (VALID_CODEX_CLI_REASONING_EFFORTS.has(normalized)) {
332
+ return normalized;
333
+ }
334
+ throw new Error("codex-cli reasoningEffort must be one of low, medium, high, xhigh");
335
+ }
336
+ function normalizeCodexCliTimeoutMs(value) {
337
+ const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim().length > 0 ? Number(value) : NaN;
338
+ if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0) {
339
+ throw new Error("codex-cli timeoutMs must be a positive integer");
340
+ }
341
+ return parsed;
342
+ }
343
+
272
344
  // ../remnic-core/src/fallback-llm.ts
273
345
  var PROVIDER_ALIASES = {
274
346
  "openai-codex": ["codex"],
@@ -291,7 +363,10 @@ var FallbackLlmClient = class {
291
363
  runtimeContext;
292
364
  constructor(gatewayConfig, runtimeContext = {}) {
293
365
  this.gatewayConfig = gatewayConfig;
294
- this.runtimeContext = runtimeContext;
366
+ this.runtimeContext = {
367
+ ...runtimeContext,
368
+ workspaceDir: normalizeRuntimePath(runtimeContext.workspaceDir) ?? readGatewayWorkspaceDir(gatewayConfig) ?? defaultOpenClawWorkspaceDir()
369
+ };
295
370
  }
296
371
  /**
297
372
  * Check if fallback is available (gateway config has at least one model).
@@ -522,9 +597,9 @@ var FallbackLlmClient = class {
522
597
  * simpler providers or when the runtime module isn't loaded.
523
598
  */
524
599
  async tryModel(model, messages, options) {
525
- const runtimeAuth = await this.resolveRuntimeAuth(model);
600
+ const runtimeAuth = model.providerConfig.api === "codex-cli" ? null : await this.resolveRuntimeAuth(model);
526
601
  const effectiveBaseUrl = runtimeAuth?.baseUrl ?? model.providerConfig.baseUrl;
527
- const resolvedCredential = runtimeAuth?.["api"+"Key"] ?? await this.resolveFallbackApiKey(model);
602
+ const resolvedCredential = runtimeAuth?.["api"+"Key"] ?? (model.providerConfig.api === "codex-cli" && model.providerConfig["api"+"Key"] === void 0 ? void 0 : await this.resolveFallbackApiKey(model));
528
603
  const rawKey = model.providerConfig["api"+"Key"];
529
604
  const needsResolution = rawKey === "secretref-managed" || typeof rawKey === "object" && rawKey !== null;
530
605
  if (needsResolution && !resolvedCredential) {
@@ -538,6 +613,17 @@ var FallbackLlmClient = class {
538
613
  if (model.providerConfig.api === "anthropic-messages") {
539
614
  return await this.callAnthropic(effectiveConfig, model.modelId, messages, options);
540
615
  }
616
+ if (model.providerConfig.api === "codex-cli") {
617
+ return await callCodexCliFallback(
618
+ effectiveConfig,
619
+ model.modelId,
620
+ messages,
621
+ { timeoutMs: options.timeoutMs }
622
+ );
623
+ }
624
+ if (model.providerConfig.api === "ollama-chat") {
625
+ return await this.callOllamaChat(effectiveConfig, model.modelId, messages, options);
626
+ }
541
627
  if (model.providerConfig.api === "openai-responses" || model.providerConfig.api === "openai-codex-responses" || model.providerConfig.api === "azure-openai-responses") {
542
628
  return await this.callOpenAIResponses(
543
629
  effectiveConfig,
@@ -646,6 +732,55 @@ var FallbackLlmClient = class {
646
732
  } : void 0
647
733
  };
648
734
  }
735
+ /**
736
+ * Call Ollama's native /api/chat transport. This lets benchmark-isolated
737
+ * gateway configs route Remnic's own internal LLM calls to Ollama Cloud
738
+ * without requiring an OpenAI-compatible shim.
739
+ */
740
+ async callOllamaChat(config, modelId, messages, options) {
741
+ const base = config.baseUrl.replace(/\/$/, "");
742
+ const url = base.endsWith("/api") ? `${base}/chat` : `${base}/api/chat`;
743
+ const headers = {
744
+ "Content-Type": "application/json",
745
+ ...config.headers
746
+ };
747
+ if (config["api"+"Key"] && typeof config["api"+"Key"] === "string" && config.authHeader !== false) {
748
+ headers.Authorization = `Bearer ${config["api"+"Key"]}`;
749
+ }
750
+ const response = await fetch(url, {
751
+ method: "POST",
752
+ headers,
753
+ body: JSON.stringify({
754
+ model: modelId,
755
+ messages,
756
+ stream: false,
757
+ ...config.disableThinking ? { think: false } : {},
758
+ options: {
759
+ temperature: options.temperature ?? 0.3,
760
+ num_predict: options.maxTokens ?? 4096
761
+ }
762
+ })
763
+ });
764
+ if (!response.ok) {
765
+ const error = await response.text();
766
+ throw new Error(`Ollama API error: ${response.status} ${error}`);
767
+ }
768
+ const data = await response.json();
769
+ const content = data.message?.content ?? data.response;
770
+ if (!content) {
771
+ throw new Error("Empty response from Ollama API");
772
+ }
773
+ const inputTokens = data.prompt_eval_count ?? 0;
774
+ const outputTokens = data.eval_count ?? 0;
775
+ return {
776
+ content,
777
+ usage: {
778
+ inputTokens,
779
+ outputTokens,
780
+ totalTokens: inputTokens + outputTokens
781
+ }
782
+ };
783
+ }
649
784
  /**
650
785
  * Call an OpenAI-compatible Responses API.
651
786
  */
@@ -754,6 +889,19 @@ var FallbackLlmClient = class {
754
889
  };
755
890
  }
756
891
  };
892
+ function normalizeRuntimePath(value) {
893
+ if (typeof value !== "string") return void 0;
894
+ const trimmed = value.trim();
895
+ return trimmed.length > 0 ? expandTildePath(trimmed) : void 0;
896
+ }
897
+ function readGatewayWorkspaceDir(gatewayConfig) {
898
+ if (!gatewayConfig || typeof gatewayConfig !== "object") return void 0;
899
+ const raw = gatewayConfig;
900
+ return normalizeRuntimePath(raw.workspaceDir) ?? normalizeRuntimePath(raw.workspacePath) ?? normalizeRuntimePath(raw.workspace);
901
+ }
902
+ function defaultOpenClawWorkspaceDir() {
903
+ return path2.join(resolveHomeDir(), ".openclaw", "workspace");
904
+ }
757
905
  function extractResponsesOutputText(data) {
758
906
  if (typeof data.output_text === "string" && data.output_text.trim().length > 0) {
759
907
  return data.output_text;
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  readEnvVar,
14
14
  resolveHomeDir
15
- } from "./chunk-I6B2W2IY.js";
15
+ } from "./chunk-TDRJVMUP.js";
16
16
 
17
17
  // ../remnic-core/src/connectors/codex-materialize-runner.ts
18
18
  import path2 from "path";
@@ -1,3 +1,6 @@
1
+ // ../remnic-core/src/utils/path.ts
2
+ import path from "path";
3
+
1
4
  // ../remnic-core/src/runtime/env.ts
2
5
  import os from "os";
3
6
  var REMNIC_ENGRAM_PREFIX_PAIRS = [
@@ -40,8 +43,18 @@ function mergeEnv(overrides) {
40
43
  return merged;
41
44
  }
42
45
 
46
+ // ../remnic-core/src/utils/path.ts
47
+ function expandTildePath(p) {
48
+ if (p === "~") return resolveHomeDir();
49
+ if (p.startsWith("~/") || p.startsWith("~\\")) {
50
+ return path.join(resolveHomeDir(), p.slice(2));
51
+ }
52
+ return p;
53
+ }
54
+
43
55
  export {
44
56
  readEnvVar,
45
57
  resolveHomeDir,
46
- mergeEnv
58
+ mergeEnv,
59
+ expandTildePath
47
60
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  expandTildePath
3
- } from "./chunk-OEI7GLV2.js";
3
+ } from "./chunk-TDRJVMUP.js";
4
4
 
5
5
  // ../remnic-core/src/connectors/live/state-store.ts
6
6
  import { promises as fs } from "fs";
@@ -1,15 +1,14 @@
1
1
  import {
2
2
  CompoundingEngine,
3
3
  defaultTierMigrationCycleBudget
4
- } from "./chunk-UVQXEQBQ.js";
4
+ } from "./chunk-7NMHI4IC.js";
5
5
  import "./chunk-EXDYWXMB.js";
6
6
  import "./chunk-ZXLYEVOP.js";
7
7
  import "./chunk-6OJAU466.js";
8
8
  import "./chunk-RKR6PTPA.js";
9
9
  import "./chunk-UFU5GGGA.js";
10
10
  import "./chunk-YGGGUTG3.js";
11
- import "./chunk-OEI7GLV2.js";
12
- import "./chunk-I6B2W2IY.js";
11
+ import "./chunk-TDRJVMUP.js";
13
12
  import "./chunk-MLKGABMK.js";
14
13
  export {
15
14
  CompoundingEngine,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  FallbackLlmClient
3
- } from "./chunk-24MGN4E3.js";
3
+ } from "./chunk-7NUFIRM3.js";
4
4
  import "./chunk-3A5ELHTT.js";
5
5
  import "./chunk-UFU5GGGA.js";
6
- import "./chunk-I6B2W2IY.js";
6
+ import "./chunk-TDRJVMUP.js";
7
7
  import "./chunk-MLKGABMK.js";
8
8
  export {
9
9
  FallbackLlmClient