@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/holomesh-client.d.ts +9 -0
- package/dist/holomesh-client.js +28 -0
- package/dist/holomesh-client.js.map +1 -1
- package/dist/index.js +77 -15
- package/dist/index.js.map +1 -1
- package/dist/runner.js +39 -6
- package/dist/runner.js.map +1 -1
- package/dist/supervisor.js +73 -14
- package/dist/supervisor.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
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
|
|
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({
|