@remnic/plugin-openclaw 1.0.6 → 1.0.8

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.
@@ -1,65 +1,10 @@
1
+ import {
2
+ extractJsonCandidates
3
+ } from "./chunk-3A5ELHTT.js";
1
4
  import {
2
5
  log
3
6
  } from "./chunk-UFU5GGGA.js";
4
7
 
5
- // ../remnic-core/src/json-extract.ts
6
- function stripCodeFences(text) {
7
- return text.replace(/```(?:json)?\s*([\s\S]*?)```/gi, (_m, inner) => String(inner).trim());
8
- }
9
- function extractJsonCandidates(text) {
10
- const trimmed = text.trim();
11
- const cleaned = stripCodeFences(trimmed);
12
- const candidates = [];
13
- if (cleaned.length > 0) candidates.push(cleaned);
14
- candidates.push(...scanBalancedJsonBlocks(cleaned));
15
- const objMatch = cleaned.match(/\{[\s\S]*\}/);
16
- if (objMatch) candidates.push(objMatch[0]);
17
- const seen = /* @__PURE__ */ new Set();
18
- return candidates.map((c) => c.trim()).filter((c) => c.length > 0).filter((c) => {
19
- if (seen.has(c)) return false;
20
- seen.add(c);
21
- return true;
22
- });
23
- }
24
- function scanBalancedJsonBlocks(text) {
25
- const out = [];
26
- const opens = /* @__PURE__ */ new Set(["{", "["]);
27
- const closes = { "{": "}", "[": "]" };
28
- for (let i = 0; i < text.length; i++) {
29
- const start = text[i];
30
- if (!opens.has(start)) continue;
31
- const expectedClose = closes[start];
32
- let depth = 0;
33
- let inString = false;
34
- let escape = false;
35
- for (let j = i; j < text.length; j++) {
36
- const ch = text[j];
37
- if (inString) {
38
- if (escape) {
39
- escape = false;
40
- } else if (ch === "\\") {
41
- escape = true;
42
- } else if (ch === '"') {
43
- inString = false;
44
- }
45
- continue;
46
- }
47
- if (ch === '"') {
48
- inString = true;
49
- continue;
50
- }
51
- if (ch === start) depth++;
52
- if (ch === expectedClose) depth--;
53
- if (depth === 0) {
54
- out.push(text.slice(i, j + 1).trim());
55
- i = j;
56
- break;
57
- }
58
- }
59
- }
60
- return out;
61
- }
62
-
63
8
  // ../remnic-core/src/openai-chat-compat.ts
64
9
  function normalizedModel(model) {
65
10
  return model.trim().toLowerCase();
@@ -183,13 +128,25 @@ async function getGatewayResolver() {
183
128
  async function findRuntimeModules() {
184
129
  const { readdirSync } = await import("fs");
185
130
  const { createRequire } = await import("module");
131
+ const { execFileSync } = await import("child_process");
186
132
  const candidates = [];
187
133
  const distDirs = [];
134
+ const pushDistDirs = (entryPath) => {
135
+ const resolvedEntryDir = path.dirname(entryPath);
136
+ const packageRoot = path.basename(resolvedEntryDir) === "dist" ? path.resolve(resolvedEntryDir, "..") : resolvedEntryDir;
137
+ const candidateDistDirs = [
138
+ path.join(packageRoot, "dist"),
139
+ path.join(packageRoot, "..", "dist")
140
+ ];
141
+ for (const candidate of candidateDistDirs) {
142
+ const resolved = path.resolve(candidate);
143
+ if (!distDirs.includes(resolved)) distDirs.push(resolved);
144
+ }
145
+ };
188
146
  try {
189
147
  const req = createRequire(import.meta.url);
190
148
  const openclawMain = req.resolve("openclaw");
191
- const openclawDist = path.join(path.dirname(openclawMain), "..", "dist");
192
- if (openclawDist) distDirs.push(path.resolve(openclawDist));
149
+ pushDistDirs(openclawMain);
193
150
  } catch {
194
151
  }
195
152
  try {
@@ -198,12 +155,22 @@ async function findRuntimeModules() {
198
155
  if (mainScript) {
199
156
  const realScript = realpathSync(mainScript);
200
157
  if (realScript.includes("openclaw")) {
201
- const distDir = path.dirname(realScript);
202
- if (!distDirs.includes(distDir)) distDirs.push(distDir);
158
+ pushDistDirs(realScript);
203
159
  }
204
160
  }
205
161
  } catch {
206
162
  }
163
+ try {
164
+ const openclawBin = execFileSync("which", ["openclaw"], {
165
+ encoding: "utf8",
166
+ stdio: ["ignore", "pipe", "ignore"]
167
+ }).trim();
168
+ if (openclawBin) {
169
+ const { realpathSync } = await import("fs");
170
+ pushDistDirs(realpathSync(openclawBin));
171
+ }
172
+ } catch {
173
+ }
207
174
  for (const dir of distDirs) {
208
175
  try {
209
176
  const files = readdirSync(dir);
@@ -218,7 +185,10 @@ async function findRuntimeModules() {
218
185
  return candidates;
219
186
  }
220
187
  async function resolveProviderApiKey(providerId, apiKeyValue, gatewayConfig, agentDir) {
221
- const cacheKey = `provider:${providerId}`;
188
+ const resolvedAgentDir = path.resolve(
189
+ agentDir ?? path.join(os2.homedir(), ".openclaw", "agents", "main", "agent")
190
+ );
191
+ const cacheKey = `provider:${providerId}:agentDir:${resolvedAgentDir}`;
222
192
  if (resolvedCache.has(cacheKey)) {
223
193
  return resolvedCache.get(cacheKey);
224
194
  }
@@ -234,7 +204,6 @@ async function resolveProviderApiKey(providerId, apiKeyValue, gatewayConfig, age
234
204
  const resolver = await getGatewayResolver();
235
205
  if (resolver) {
236
206
  try {
237
- const resolvedAgentDir = agentDir ?? path.join(os2.homedir(), ".openclaw", "agents", "main", "agent");
238
207
  const auth = await resolver({ provider: providerId, cfg: gatewayConfig, agentDir: resolvedAgentDir });
239
208
  if (auth?.apiKey) {
240
209
  resolved = auth.apiKey;
@@ -310,8 +279,10 @@ function loadModelsJsonProviders() {
310
279
  // ../remnic-core/src/fallback-llm.ts
311
280
  var FallbackLlmClient = class {
312
281
  gatewayConfig;
313
- constructor(gatewayConfig) {
282
+ runtimeContext;
283
+ constructor(gatewayConfig, runtimeContext = {}) {
314
284
  this.gatewayConfig = gatewayConfig;
285
+ this.runtimeContext = runtimeContext;
315
286
  }
316
287
  /**
317
288
  * Check if fallback is available (gateway config has at least one model).
@@ -513,6 +484,14 @@ var FallbackLlmClient = class {
513
484
  if (model.providerConfig.api === "anthropic-messages") {
514
485
  return await this.callAnthropic(effectiveConfig, model.modelId, messages, options);
515
486
  }
487
+ if (model.providerConfig.api === "openai-responses" || model.providerConfig.api === "openai-codex-responses" || model.providerConfig.api === "azure-openai-responses") {
488
+ return await this.callOpenAIResponses(
489
+ effectiveConfig,
490
+ model.modelId,
491
+ messages,
492
+ options
493
+ );
494
+ }
516
495
  return await this.callOpenAI(
517
496
  effectiveConfig,
518
497
  model.modelId,
@@ -537,7 +516,8 @@ var FallbackLlmClient = class {
537
516
  api: model.providerConfig.api,
538
517
  baseUrl: model.providerConfig.baseUrl
539
518
  },
540
- cfg: this.gatewayConfig
519
+ cfg: this.gatewayConfig,
520
+ workspaceDir: this.runtimeContext.workspaceDir
541
521
  });
542
522
  if (result?.apiKey || result?.baseUrl) {
543
523
  log.debug(
@@ -557,7 +537,12 @@ var FallbackLlmClient = class {
557
537
  * secret refs, etc.). Used as fallback when gateway runtime auth isn't available.
558
538
  */
559
539
  async resolveFallbackApiKey(model) {
560
- return resolveProviderApiKey(model.providerId, model.providerConfig.apiKey, this.gatewayConfig);
540
+ return resolveProviderApiKey(
541
+ model.providerId,
542
+ model.providerConfig.apiKey,
543
+ this.gatewayConfig,
544
+ this.runtimeContext.agentDir
545
+ );
561
546
  }
562
547
  /**
563
548
  * Call OpenAI-compatible API.
@@ -605,11 +590,65 @@ var FallbackLlmClient = class {
605
590
  } : void 0
606
591
  };
607
592
  }
593
+ /**
594
+ * Call an OpenAI-compatible Responses API.
595
+ */
596
+ async callOpenAIResponses(config, modelId, messages, options) {
597
+ const base = config.baseUrl.replace(/\/$/, "");
598
+ const url = base.endsWith("/v1") ? `${base}/responses` : `${base}/v1/responses`;
599
+ const headers = {
600
+ "Content-Type": "application/json",
601
+ ...config.headers
602
+ };
603
+ if (config.apiKey && typeof config.apiKey === "string" && config.authHeader !== false) {
604
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
605
+ }
606
+ const instructions = messages.filter((message) => message.role === "system").map((message) => message.content).join("\n\n").trim();
607
+ const input = messages.filter((message) => message.role !== "system").map((message) => ({
608
+ role: message.role,
609
+ content: [{
610
+ type: message.role === "assistant" ? "output_text" : "input_text",
611
+ text: message.content
612
+ }]
613
+ }));
614
+ const body = {
615
+ model: modelId,
616
+ input,
617
+ max_output_tokens: Math.max(0, Math.floor(options.maxTokens ?? 4096)),
618
+ temperature: options.temperature ?? 0.3
619
+ };
620
+ if (instructions.length > 0) {
621
+ body.instructions = instructions;
622
+ }
623
+ const response = await fetch(url, {
624
+ method: "POST",
625
+ headers,
626
+ body: JSON.stringify(body)
627
+ });
628
+ if (!response.ok) {
629
+ const error = await response.text();
630
+ throw new Error(`OpenAI Responses API error: ${response.status} ${error}`);
631
+ }
632
+ const data = await response.json();
633
+ const outputText = extractResponsesOutputText(data);
634
+ if (!outputText) {
635
+ throw new Error("Empty response from OpenAI Responses API");
636
+ }
637
+ return {
638
+ content: outputText,
639
+ usage: data.usage ? {
640
+ inputTokens: data.usage.input_tokens,
641
+ outputTokens: data.usage.output_tokens,
642
+ totalTokens: data.usage.total_tokens
643
+ } : void 0
644
+ };
645
+ }
608
646
  /**
609
647
  * Call Anthropic Messages API.
610
648
  */
611
649
  async callAnthropic(config, modelId, messages, options) {
612
- const url = `${config.baseUrl.replace(/\/$/, "")}/messages`;
650
+ const base = config.baseUrl.replace(/\/$/, "");
651
+ const url = base.endsWith("/v1") ? `${base}/messages` : `${base}/v1/messages`;
613
652
  const headers = {
614
653
  "Content-Type": "application/json",
615
654
  "anthropic-version": "2023-06-01",
@@ -657,12 +696,29 @@ var FallbackLlmClient = class {
657
696
  };
658
697
  }
659
698
  };
699
+ function extractResponsesOutputText(data) {
700
+ if (typeof data.output_text === "string" && data.output_text.trim().length > 0) {
701
+ return data.output_text;
702
+ }
703
+ const chunks = [];
704
+ for (const item of data.output ?? []) {
705
+ if (typeof item.text === "string" && item.text.trim().length > 0) {
706
+ chunks.push(item.text);
707
+ }
708
+ for (const part of item.content ?? []) {
709
+ if ((part.type === "output_text" || part.type === "text") && typeof part.text === "string" && part.text.trim().length > 0) {
710
+ chunks.push(part.text);
711
+ }
712
+ }
713
+ }
714
+ const joined = chunks.join("\n").trim();
715
+ return joined.length > 0 ? joined : null;
716
+ }
660
717
 
661
718
  export {
662
719
  readEnvVar,
663
720
  resolveHomeDir,
664
721
  mergeEnv,
665
- extractJsonCandidates,
666
722
  shouldAssumeOpenAiChatCompletions,
667
723
  buildChatCompletionTokenLimit,
668
724
  FallbackLlmClient
@@ -3,7 +3,7 @@ import {
3
3
  parseContinuityImprovementLoops,
4
4
  parseContinuityIncident,
5
5
  sanitizeMemoryContent
6
- } from "./chunk-KPMXWORS.js";
6
+ } from "./chunk-JJSNPSCD.js";
7
7
  import {
8
8
  log
9
9
  } from "./chunk-UFU5GGGA.js";
@@ -4881,7 +4881,7 @@ var CompoundingEngine = class {
4881
4881
  let promotionCandidates = this.config.compoundingSemanticEnabled ? this.derivePromotionCandidates(outcomeSummary, mistakes.registry, rubrics) : [];
4882
4882
  if (this.config.cmcConsolidationEnabled) {
4883
4883
  try {
4884
- const { deriveCausalPromotionCandidates, materializeAfterCausalConsolidation } = await import("./causal-consolidation-EBLROS42.js");
4884
+ const { deriveCausalPromotionCandidates, materializeAfterCausalConsolidation } = await import("./causal-consolidation-33R5JTPX.js");
4885
4885
  const causalCandidates = await deriveCausalPromotionCandidates({
4886
4886
  memoryDir: this.config.memoryDir,
4887
4887
  causalTrajectoryStoreDir: this.config.causalTrajectoryStoreDir,
@@ -4913,7 +4913,7 @@ var CompoundingEngine = class {
4913
4913
  }
4914
4914
  if (this.config.calibrationEnabled) {
4915
4915
  try {
4916
- const { runCalibrationConsolidation } = await import("./calibration-3JHF25QT.js");
4916
+ const { runCalibrationConsolidation } = await import("./calibration-BAC7KNKR.js");
4917
4917
  const calRules = await runCalibrationConsolidation({
4918
4918
  memoryDir: this.config.memoryDir,
4919
4919
  gatewayConfig: this.config.gatewayConfig,