@holoscript/holoscript-agent 2.0.7 → 2.1.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/dist/runner.js CHANGED
@@ -2,6 +2,8 @@
2
2
  import { embedAcrossFleet, cosineSimilarity } from "@holoscript/llm-provider";
3
3
 
4
4
  // src/holomesh-client.ts
5
+ import { readFile, appendFile, mkdir } from "fs/promises";
6
+ import { dirname } from "path";
5
7
  function pickClaimableTask(tasks, brainCapabilityTags) {
6
8
  const wanted = new Set(brainCapabilityTags.map((t) => t.toLowerCase()));
7
9
  const open = tasks.filter((t) => t.status === "open" && !t.claimedBy);
@@ -73,8 +75,8 @@ function buildCaelRecord(input) {
73
75
  }
74
76
 
75
77
  // src/tools.ts
76
- import { readFile, writeFile, readdir, mkdir, stat } from "fs/promises";
77
- import { resolve, dirname, delimiter, isAbsolute, sep } from "path";
78
+ import { readFile as readFile2, writeFile, readdir, mkdir as mkdir2, stat } from "fs/promises";
79
+ import { resolve, dirname as dirname2, delimiter, isAbsolute, sep } from "path";
78
80
  import { spawn } from "child_process";
79
81
  import { createHash as createHash2 } from "crypto";
80
82
  var FLEET_READ_ROOTS = [
@@ -365,7 +367,7 @@ async function runTool(use, opts = {}) {
365
367
  const path = use.input.path;
366
368
  const denied = checkReadAllowed(path);
367
369
  if (denied) return errResult(use.id, denied);
368
- const text = await readFile(path, "utf8");
370
+ const text = await readFile2(path, "utf8");
369
371
  const truncated = text.length > 2e5 ? text.slice(0, 2e5) + `
370
372
  \u2026[truncated, full file is ${text.length} bytes]` : text;
371
373
  return okResult(use.id, truncated);
@@ -383,7 +385,7 @@ async function runTool(use, opts = {}) {
383
385
  const content = use.input.content;
384
386
  const denied = checkWriteAllowed(path);
385
387
  if (denied) return errResult(use.id, denied);
386
- await mkdir(dirname(path), { recursive: true });
388
+ await mkdir2(dirname2(path), { recursive: true });
387
389
  await writeFile(path, content, "utf8");
388
390
  const s = await stat(path);
389
391
  return okResult(use.id, `wrote ${s.size} bytes to ${path}`);
@@ -498,7 +500,7 @@ ${truncated}`);
498
500
  const outPath = resolve(ALLOWED_WRITE_ROOTS[0], `hardware-receipt-${ts}.json`);
499
501
  const denied = checkWriteAllowed(outPath);
500
502
  if (denied) return errResult(use.id, `Cannot write receipt: ${denied}`);
501
- await mkdir(dirname(outPath), { recursive: true });
503
+ await mkdir2(dirname2(outPath), { recursive: true });
502
504
  await writeFile(outPath, JSON.stringify(sealed, null, 2), "utf8");
503
505
  return okResult(
504
506
  use.id,
@@ -511,7 +513,7 @@ ${truncated}`);
511
513
  const newStr = use.input.new;
512
514
  const denied = checkWriteAllowed(path);
513
515
  if (denied) return errResult(use.id, denied);
514
- const text = await readFile(path, "utf8");
516
+ const text = await readFile2(path, "utf8");
515
517
  const count = text.split(oldStr).length - 1;
516
518
  if (count === 0) return errResult(use.id, `str_replace: "old" string not found in ${path} \u2014 0 occurrences`);
517
519
  if (count > 1) return errResult(use.id, `str_replace: "old" string is ambiguous in ${path} \u2014 ${count} occurrences; add more surrounding context`);
@@ -946,6 +948,37 @@ var AgentRunner = class {
946
948
  finalText = resp.content;
947
949
  break;
948
950
  }
951
+ if (productiveCallCount === 0 && toolsCalled.size > 0 && iters < MAX_TOOL_ITERS) {
952
+ iters++;
953
+ messages.push({
954
+ role: "user",
955
+ content: "You gathered data but did not write the task deliverable. Call write_file NOW with the exact output path from the task description. Embed all data you gathered into the write_file content field. Do NOT output text \u2014 your only valid response is a write_file tool call."
956
+ });
957
+ const reResp = await provider.complete(
958
+ { messages, maxTokens: 8192, temperature: 0.4, tools: activeTools },
959
+ identity.llmModel
960
+ );
961
+ aggUsage = {
962
+ promptTokens: aggUsage.promptTokens + reResp.usage.promptTokens,
963
+ completionTokens: aggUsage.completionTokens + reResp.usage.completionTokens,
964
+ totalTokens: aggUsage.totalTokens + reResp.usage.totalTokens
965
+ };
966
+ if (reResp.finishReason === "tool_use" && reResp.toolUses && reResp.toolUses.length > 0) {
967
+ log({ ev: "reprompt-tool-call", taskId: target.id, iter: iters, tools: reResp.toolUses.map((t) => t.name) });
968
+ const reProd = summarizeToolProductivity(reResp.toolUses);
969
+ for (const n of reProd.names) toolsCalled.add(n);
970
+ productiveCallCount += reProd.productiveCount;
971
+ messages.push({ role: "assistant", content: reResp.assistantBlocks ?? [] });
972
+ const reResults = await Promise.all(
973
+ reResp.toolUses.map(
974
+ (u) => runTool(u, { signReceipt: this.opts.signReceipt, addTask: (tasks2) => mesh.addTasks(tasks2) })
975
+ )
976
+ );
977
+ messages.push({ role: "user", content: reResults });
978
+ }
979
+ finalText = reResp.content;
980
+ lastResponse = reResp;
981
+ }
949
982
  const durationMs = Date.now() - start;
950
983
  if (productiveCallCount === 0) {
951
984
  log({