@openviking/openclaw-plugin 2026.5.8 → 2026.5.21

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/dist/client.js CHANGED
@@ -245,6 +245,36 @@ export class OpenVikingClient {
245
245
  async read(uri, agentId) {
246
246
  return this.request(`/api/v1/content/read?uri=${encodeURIComponent(uri)}`, {}, agentId);
247
247
  }
248
+ async readToolResult(sessionId, toolResultId, options, agentId) {
249
+ const params = new URLSearchParams();
250
+ if (options?.offset !== undefined)
251
+ params.set("offset", String(options.offset));
252
+ if (options?.limit !== undefined)
253
+ params.set("limit", String(options.limit));
254
+ if (options?.includeMetadata !== undefined) {
255
+ params.set("include_metadata", String(options.includeMetadata));
256
+ }
257
+ const query = params.toString();
258
+ return this.request(`/api/v1/sessions/${encodeURIComponent(sessionId)}/tool-results/${encodeURIComponent(toolResultId)}${query ? `?${query}` : ""}`, {}, agentId);
259
+ }
260
+ async searchToolResult(sessionId, toolResultId, queryText, options, agentId) {
261
+ const params = new URLSearchParams({ q: queryText });
262
+ if (options?.limit !== undefined)
263
+ params.set("limit", String(options.limit));
264
+ if (options?.contextChars !== undefined) {
265
+ params.set("context_chars", String(options.contextChars));
266
+ }
267
+ return this.request(`/api/v1/sessions/${encodeURIComponent(sessionId)}/tool-results/${encodeURIComponent(toolResultId)}/search?${params.toString()}`, {}, agentId);
268
+ }
269
+ async listToolResults(sessionId, options, agentId) {
270
+ const params = new URLSearchParams();
271
+ if (options?.toolName)
272
+ params.set("tool_name", options.toolName);
273
+ if (options?.limit !== undefined)
274
+ params.set("limit", String(options.limit));
275
+ const query = params.toString();
276
+ return this.request(`/api/v1/sessions/${encodeURIComponent(sessionId)}/tool-results${query ? `?${query}` : ""}`, {}, agentId);
277
+ }
248
278
  async uploadTempFile(filePath, agentId) {
249
279
  const fileBytes = await readFile(filePath);
250
280
  const form = new FormData();
@@ -29,9 +29,6 @@ function allocateContextBudget(totalBudget, instructionTokens = 0) {
29
29
  const sessionContext = Math.max(usableBudget - archiveMemory, 0);
30
30
  return { archiveMemory, sessionContext, reserved };
31
31
  }
32
- function estimateTokens(messages) {
33
- return Math.max(1, messages.length * 80);
34
- }
35
32
  function roughEstimate(messages) {
36
33
  return Math.ceil(JSON.stringify(messages).length / 4);
37
34
  }
@@ -265,6 +262,10 @@ export function convertToAgentMessages(msg) {
265
262
  const toolName = typeof p.tool_name === "string" ? p.tool_name : undefined;
266
263
  const status = typeof p.tool_status === "string" ? p.tool_status : "unknown";
267
264
  const output = typeof p.tool_output === "string" ? p.tool_output : "";
265
+ const ref = typeof p.tool_output_ref === "string" ? p.tool_output_ref : "";
266
+ const originalChars = typeof p.tool_output_original_chars === "number"
267
+ ? p.tool_output_original_chars
268
+ : undefined;
268
269
  if (toolId) {
269
270
  // Structured path: emit canonical toolCall + toolResult pair (works for any role)
270
271
  toolCallBlocks.push({
@@ -273,9 +274,15 @@ export function convertToAgentMessages(msg) {
273
274
  name: toolName ?? "unknown",
274
275
  arguments: p.tool_input ?? {},
275
276
  });
276
- const resultText = (status === "completed" || status === "error")
277
+ let resultText = (status === "completed" || status === "error")
277
278
  ? (output || "(no output)")
278
279
  : "(interrupted — tool did not complete)";
280
+ if (ref && !resultText.includes(ref)) {
281
+ const suffix = originalChars !== undefined
282
+ ? `\n[tool-result-ref] ${ref} original_chars=${originalChars}`
283
+ : `\n[tool-result-ref] ${ref}`;
284
+ resultText += suffix;
285
+ }
279
286
  const resultPayload = {
280
287
  role: "toolResult",
281
288
  toolCallId: toolId,
@@ -330,6 +337,32 @@ export function convertToAgentMessages(msg) {
330
337
  }
331
338
  return result;
332
339
  }
340
+ function isToolOnlyMessage(msg) {
341
+ return msg.role === "user" && msg.parts.length > 0 && msg.parts.every((part) => part.type === "tool");
342
+ }
343
+ function coalesceConsecutiveToolMessages(messages) {
344
+ const result = [];
345
+ let pendingTools;
346
+ const flush = () => {
347
+ if (pendingTools) {
348
+ result.push(pendingTools);
349
+ pendingTools = undefined;
350
+ }
351
+ };
352
+ for (const msg of messages) {
353
+ if (isToolOnlyMessage(msg)) {
354
+ if (!pendingTools) {
355
+ pendingTools = { role: "user", parts: [] };
356
+ }
357
+ pendingTools.parts.push(...msg.parts);
358
+ continue;
359
+ }
360
+ flush();
361
+ result.push(msg);
362
+ }
363
+ flush();
364
+ return result;
365
+ }
333
366
  function normalizeAssistantContent(messages) {
334
367
  for (let i = 0; i < messages.length; i++) {
335
368
  const msg = messages[i];
@@ -965,7 +998,8 @@ export function createMemoryOpenVikingContextEngine(params) {
965
998
  afterTurnParams.prePromptMessageCount >= 0
966
999
  ? afterTurnParams.prePromptMessageCount
967
1000
  : 0;
968
- const { messages: extractedMessages, newCount } = extractNewTurnMessages(messages, start);
1001
+ const { messages: extractedMessagesRaw, newCount } = extractNewTurnMessages(messages, start);
1002
+ const extractedMessages = coalesceConsecutiveToolMessages(extractedMessagesRaw);
969
1003
  if (extractedMessages.length === 0) {
970
1004
  diag("afterTurn_skip", OVSessionId, {
971
1005
  reason: "no_new_turn_messages",
@@ -1055,9 +1089,7 @@ export function createMemoryOpenVikingContextEngine(params) {
1055
1089
  if (commitResult.task_id && cfg.logFindRequests) {
1056
1090
  logger.info(`openviking: Phase2 memory extraction runs asynchronously on the server (task_id=${commitResult.task_id}). ` +
1057
1091
  "memories_extracted appears only after that task completes — not in this immediate response.");
1058
- if (cfg.logFindRequests) {
1059
- void pollPhase2ExtractionOutcome(getClient, commitResult.task_id, agentId, logger, OVSessionId);
1060
- }
1092
+ void pollPhase2ExtractionOutcome(getClient, commitResult.task_id, agentId, logger, OVSessionId);
1061
1093
  }
1062
1094
  }
1063
1095
  catch (err) {