hyperclaw 4.0.0 → 4.0.2
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 +53 -18
- package/dist/a2ui-protocol-CT_jDEU9.js +75 -0
- package/dist/agents-routing-683Q2JGp.js +129 -0
- package/dist/agents-routing-BpZBswBH.js +4 -0
- package/dist/api-keys-guide-Bzig1R5W.js +149 -0
- package/dist/api-keys-guide-Dq5Obbp4.js +149 -0
- package/dist/audit-BYxPlnTQ.js +248 -0
- package/dist/bounty-tools-C6LyzxM-.js +211 -0
- package/dist/browser-tools-CQBSbIuO.js +5 -0
- package/dist/browser-tools-YQmwRLLM.js +179 -0
- package/dist/claw-tasks-BRLUvFRD.js +80 -0
- package/dist/connector-3HnyH8fn.js +167 -0
- package/dist/connector-6PMZo5Ky.js +189 -0
- package/dist/connector-B6eoF3DD.js +181 -0
- package/dist/connector-B9tLG8UZ.js +196 -0
- package/dist/connector-BOlqjXWP.js +182 -0
- package/dist/connector-BP8zsbP8.js +189 -0
- package/dist/connector-BPoSevxp.js +286 -0
- package/dist/connector-BRHj773i.js +163 -0
- package/dist/connector-BToxU-jV.js +267 -0
- package/dist/connector-BliDVsJQ.js +239 -0
- package/dist/connector-Bv6s9oP7.js +88 -0
- package/dist/connector-By5wWGTR.js +343 -0
- package/dist/connector-C1BaFFgN.js +213 -0
- package/dist/connector-CRRWY5Wv.js +167 -0
- package/dist/connector-CXPQVGyI.js +85 -0
- package/dist/connector-Cdk1CXKi.js +194 -0
- package/dist/connector-CwlgFgjx.js +181 -0
- package/dist/connector-DFchk6l7.js +178 -0
- package/dist/connector-DKw7tRAy.js +192 -0
- package/dist/connector-DRv1ahC_.js +343 -0
- package/dist/connector-DU63KW94.js +165 -0
- package/dist/connector-Dbvb1Cj9.js +280 -0
- package/dist/connector-DcZdQcgR.js +173 -0
- package/dist/connector-DxKL8VvZ.js +182 -0
- package/dist/connector-T_YdZtzv.js +162 -0
- package/dist/connector-i4gOS9xL.js +154 -0
- package/dist/connector-rHXE1ZD2.js +167 -0
- package/dist/connector-wdUXChwa.js +172 -0
- package/dist/cost-tracker-pVE15Yq4.js +103 -0
- package/dist/credentials-store-BvnMPJwi.js +4 -0
- package/dist/credentials-store-sb-TRLwR.js +77 -0
- package/dist/cron-tasks-BvDFNyiE.js +82 -0
- package/dist/delivery-B-SJqXLn.js +95 -0
- package/dist/delivery-D5Z98EVq.js +95 -0
- package/dist/delivery-DCOXhXEO.js +5 -0
- package/dist/delivery-VgFeuu2J.js +5 -0
- package/dist/destructive-gate-m-dWqUFg.js +101 -0
- package/dist/developer-keys-JaJK3T27.js +127 -0
- package/dist/developer-keys-kyqmtWK3.js +8 -0
- package/dist/doctor-3oi89QIc.js +175 -0
- package/dist/doctor-Cf1XSfp9.js +4 -0
- package/dist/engine-B4eMiTgl.js +7 -0
- package/dist/engine-B8M7dYul.js +7 -0
- package/dist/engine-BhT-1M9W.js +256 -0
- package/dist/engine-D49jnSd_.js +256 -0
- package/dist/env-resolve-DWOQ45jG.js +9 -0
- package/dist/env-resolve-szSWl0UF.js +94 -0
- package/dist/extraction-tools-D3qDFBJ1.js +91 -0
- package/dist/extraction-tools-DLr_AEwq.js +5 -0
- package/dist/form_data-B_hIUrxU.js +8657 -0
- package/dist/gmail-watch-setup-Czt8rXaX.js +40 -0
- package/dist/heartbeat-engine-CRqfPcFM.js +83 -0
- package/dist/hub-DTsqe5Bt.js +6 -0
- package/dist/hub-FrPTA33j.js +515 -0
- package/dist/hyperclawbot-D9KCtc4P.js +480 -0
- package/dist/hyperclawbot-DfMGowZC.js +480 -0
- package/dist/hyperclawbot-Dw27pJo4.js +480 -0
- package/dist/inference-CTWJeX9Q.js +922 -0
- package/dist/inference-ix607p7k.js +6 -0
- package/dist/knowledge-graph-DqA-Fztl.js +131 -0
- package/dist/loader-CISCqBto.js +400 -0
- package/dist/loader-CYMQ8VOS.js +4 -0
- package/dist/logger-8tEtAd3y.js +83 -0
- package/dist/manager-CPjeRe-6.js +4 -0
- package/dist/manager-Cwzj7w5R.js +105 -0
- package/dist/manager-DLmZI-9R.js +6 -0
- package/dist/manager-DSGhn5i3.js +117 -0
- package/dist/manager-DgyF52mg.js +218 -0
- package/dist/manager-Dm8nrMFx.js +40 -0
- package/dist/mcp-B_9Ber63.js +139 -0
- package/dist/mcp-loader-DSM5UiFG.js +94 -0
- package/dist/mcp-loader-j5ZLLw5O.js +94 -0
- package/dist/memory-BI1kPkAN.js +4 -0
- package/dist/memory-BVFGkxxK.js +270 -0
- package/dist/memory-auto-Bc7euou4.js +306 -0
- package/dist/memory-auto-DPfbkMVt.js +5 -0
- package/dist/memory-integration-DZExqWr4.js +91 -0
- package/dist/moltbook-B6ZeGN5_.js +81 -0
- package/dist/node-pwL6O_KX.js +222 -0
- package/dist/nodes-registry-CsPm_-CJ.js +52 -0
- package/dist/oauth-flow-CpWlgvNB.js +150 -0
- package/dist/oauth-provider-BZb6qOw5.js +110 -0
- package/dist/observability-B43YvNQV.js +89 -0
- package/dist/onboard-3q20ZyHj.js +9 -0
- package/dist/onboard-Bd_wsYdi.js +4086 -0
- package/dist/onboard-CAN7x3me.js +3026 -0
- package/dist/onboard-DnegOHMh.js +3026 -0
- package/dist/onboard-RYtDlYBw.js +9 -0
- package/dist/onboard-aTwlQs-4.js +9 -0
- package/dist/orchestrator-BSp2M5EU.js +189 -0
- package/dist/orchestrator-C7ko5tWa.js +6 -0
- package/dist/orchestrator-DfPkIx2Z.js +6 -0
- package/dist/orchestrator-NJQsmiBE.js +189 -0
- package/dist/pairing-DU0_J28n.js +87 -0
- package/dist/pairing-DWllbSbO.js +4 -0
- package/dist/pc-access-Ly-uA8mn.js +8 -0
- package/dist/pc-access-NxBvTrRj.js +819 -0
- package/dist/pending-approval-DIHvwwWS.js +22 -0
- package/dist/puppeteer-2o3QOwAy.js +2 -2
- package/dist/puppeteer-BYTMp3BI.js +2 -2
- package/dist/puppeteer-DQ45qwWk.js +2 -2
- package/dist/reminders-store-D79qdfN0.js +58 -0
- package/dist/renderer-pqlDRKbH.js +225 -0
- package/dist/rules-BooT_qFP.js +103 -0
- package/dist/run-main.js +366 -1109
- package/dist/runner-Bu--_RXw.js +810 -0
- package/dist/runner-D1rjuMTJ.js +810 -0
- package/dist/sdk/index.js +2 -2
- package/dist/sdk/index.mjs +2 -2
- package/dist/security-C-5URby1.js +73 -0
- package/dist/security-_xve79aq.js +4 -0
- package/dist/server-0kgyELx4.js +1047 -0
- package/dist/server-BIuTobTC.js +4 -0
- package/dist/server-BRlCEjyT.js +1047 -0
- package/dist/server-CCI1hv45.js +1047 -0
- package/dist/server-DU9POoWc.js +4 -0
- package/dist/server-RBqwE_GN.js +4 -0
- package/dist/session-store-CujxByI6.js +113 -0
- package/dist/session-store-qpJUg2M1.js +5 -0
- package/dist/sessions-tools-CB2qbwIk.js +5 -0
- package/dist/sessions-tools-DHMaTZIs.js +95 -0
- package/dist/skill-loader-BkceKkIg.js +7 -0
- package/dist/skill-loader-DhgIwK4J.js +159 -0
- package/dist/skill-runtime--LqxWrp5.js +102 -0
- package/dist/skill-runtime-C5l0Tgt-.js +5 -0
- package/dist/skill-runtime-DsXK_HYG.js +102 -0
- package/dist/skill-runtime-IVTiqrMR.js +5 -0
- package/dist/src-BEVLgaF1.js +63 -0
- package/dist/src-Bgu_OxTQ.js +458 -0
- package/dist/src-Bq-oKt7Z.js +458 -0
- package/dist/src-DWCUhnD4.js +20 -0
- package/dist/src-cfRTjFef.js +63 -0
- package/dist/sub-agent-tools-BD9DF8_g.js +39 -0
- package/dist/sub-agent-tools-V7b3T9_s.js +39 -0
- package/dist/tool-policy-DNvNRnve.js +189 -0
- package/dist/tts-elevenlabs-BUOGKL-k.js +61 -0
- package/dist/update-check-BD4qH7Am.js +81 -0
- package/dist/vision-DRq-f-Dj.js +121 -0
- package/dist/vision-tools-CFZEpQKm.js +5 -0
- package/dist/vision-tools-CQnBI9aa.js +51 -0
- package/dist/voice-transcription-CbQBToY0.js +138 -0
- package/dist/voice-transcription-CgWq54hn.js +138 -0
- package/dist/website-watch-tools-Bk_TnwuE.js +5 -0
- package/dist/website-watch-tools-DraMPxdl.js +139 -0
- package/package.json +1 -1
|
@@ -0,0 +1,922 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-jS-bbMI5.js');
|
|
2
|
+
const fs_extra = require_chunk.__toESM(require("fs-extra"));
|
|
3
|
+
const path = require_chunk.__toESM(require("path"));
|
|
4
|
+
const os = require_chunk.__toESM(require("os"));
|
|
5
|
+
const http = require_chunk.__toESM(require("http"));
|
|
6
|
+
const https = require_chunk.__toESM(require("https"));
|
|
7
|
+
|
|
8
|
+
//#region packages/core/src/agent/inference.ts
|
|
9
|
+
function streamRequest(hostname, reqPath, headers, body, onChunk, onDone, onError, opts) {
|
|
10
|
+
const payload = JSON.stringify(body);
|
|
11
|
+
const useHttps = opts?.useHttps ?? (hostname !== "localhost" && !hostname.startsWith("127."));
|
|
12
|
+
const port = opts?.port ?? (useHttps ? 443 : 11434);
|
|
13
|
+
const mod = useHttps ? https.default : http.default;
|
|
14
|
+
const req = mod.request({
|
|
15
|
+
hostname,
|
|
16
|
+
port,
|
|
17
|
+
path: reqPath,
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: {
|
|
20
|
+
...headers,
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
"Content-Length": Buffer.byteLength(payload)
|
|
23
|
+
}
|
|
24
|
+
}, (res) => {
|
|
25
|
+
let buf = "";
|
|
26
|
+
res.on("data", (chunk) => {
|
|
27
|
+
buf += chunk.toString();
|
|
28
|
+
const lines = buf.split("\n");
|
|
29
|
+
buf = lines.pop() || "";
|
|
30
|
+
for (const line of lines) if (line.trim()) onChunk(line);
|
|
31
|
+
});
|
|
32
|
+
res.on("end", () => {
|
|
33
|
+
if (buf.trim()) onChunk(buf);
|
|
34
|
+
onDone();
|
|
35
|
+
});
|
|
36
|
+
res.on("error", onError);
|
|
37
|
+
});
|
|
38
|
+
req.on("error", onError);
|
|
39
|
+
req.write(payload);
|
|
40
|
+
req.end();
|
|
41
|
+
}
|
|
42
|
+
function emitMarkdownBlocks(text, onBlock) {
|
|
43
|
+
const codeRe = /```(\w*)\n([\s\S]*?)```/g;
|
|
44
|
+
let last = 0;
|
|
45
|
+
let m;
|
|
46
|
+
while ((m = codeRe.exec(text)) !== null) {
|
|
47
|
+
if (m.index > last) onBlock("markdown", text.slice(last, m.index));
|
|
48
|
+
onBlock("code", m[2], m[1] || void 0);
|
|
49
|
+
last = m.index + m[0].length;
|
|
50
|
+
}
|
|
51
|
+
if (last < text.length) onBlock("markdown", text.slice(last));
|
|
52
|
+
}
|
|
53
|
+
function parseSSEChunk(line) {
|
|
54
|
+
if (!line.startsWith("data: ")) return null;
|
|
55
|
+
const data = line.slice(6).trim();
|
|
56
|
+
if (data === "[DONE]") return null;
|
|
57
|
+
try {
|
|
58
|
+
return JSON.parse(data);
|
|
59
|
+
} catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function getBuiltinTools() {
|
|
64
|
+
return [
|
|
65
|
+
{
|
|
66
|
+
name: "get_current_time",
|
|
67
|
+
description: "Get the current date and time",
|
|
68
|
+
input_schema: {
|
|
69
|
+
type: "object",
|
|
70
|
+
properties: { timezone: {
|
|
71
|
+
type: "string",
|
|
72
|
+
description: "Timezone name, e.g. Europe/Athens"
|
|
73
|
+
} }
|
|
74
|
+
},
|
|
75
|
+
handler: async (input) => {
|
|
76
|
+
const tz = input.timezone || "UTC";
|
|
77
|
+
try {
|
|
78
|
+
return (/* @__PURE__ */ new Date()).toLocaleString("en-US", {
|
|
79
|
+
timeZone: tz,
|
|
80
|
+
dateStyle: "full",
|
|
81
|
+
timeStyle: "long"
|
|
82
|
+
});
|
|
83
|
+
} catch {
|
|
84
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "read_memory",
|
|
90
|
+
description: "Read content from workspace memory files in ~/.hyperclaw/. Use MEMORY.md, AGENTS.md, SOUL.md, USER.md, or any custom .md (e.g. EPIXEIRISI.md).",
|
|
91
|
+
input_schema: {
|
|
92
|
+
type: "object",
|
|
93
|
+
properties: { file: {
|
|
94
|
+
type: "string",
|
|
95
|
+
description: "Filename, e.g. MEMORY.md, AGENTS.md, SOUL.md, EPIXEIRISI.md. Must end in .md and stay in workspace."
|
|
96
|
+
} },
|
|
97
|
+
required: ["file"]
|
|
98
|
+
},
|
|
99
|
+
handler: async (input) => {
|
|
100
|
+
const name = String(input.file || "").trim();
|
|
101
|
+
if (!name.endsWith(".md") || /[\\/]/.test(name)) return `Invalid filename: must be a .md file in workspace (e.g. MEMORY.md, EPIXEIRISI.md).`;
|
|
102
|
+
const fpath = path.default.join(HC_DIR, path.default.basename(name));
|
|
103
|
+
if (path.default.resolve(fpath).indexOf(path.default.resolve(HC_DIR)) !== 0) return `Invalid path.`;
|
|
104
|
+
if (await fs_extra.default.pathExists(fpath)) return fs_extra.default.readFile(fpath, "utf8");
|
|
105
|
+
return `${name} not found. Create it with create_memory_file.`;
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: "write_memory",
|
|
110
|
+
description: "Append a fact or note to MEMORY.md. Also adds to knowledge graph for cross-session context.",
|
|
111
|
+
input_schema: {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: {
|
|
114
|
+
content: {
|
|
115
|
+
type: "string",
|
|
116
|
+
description: "Text to append to MEMORY.md"
|
|
117
|
+
},
|
|
118
|
+
tags: {
|
|
119
|
+
type: "string",
|
|
120
|
+
description: "Optional comma-separated tags for knowledge graph"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
required: ["content"]
|
|
124
|
+
},
|
|
125
|
+
handler: async (input) => {
|
|
126
|
+
const content = input.content;
|
|
127
|
+
const fpath = path.default.join(HC_DIR, "MEMORY.md");
|
|
128
|
+
const entry = `\n- ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}: ${content}\n`;
|
|
129
|
+
await fs_extra.default.appendFile(fpath, entry);
|
|
130
|
+
const { addFact } = await Promise.resolve().then(() => require("./knowledge-graph-DqA-Fztl.js"));
|
|
131
|
+
const tags = input.tags?.split(",").map((t) => t.trim()).filter(Boolean);
|
|
132
|
+
await addFact(content, tags).catch(() => {});
|
|
133
|
+
return `Appended to MEMORY.md + knowledge graph: ${content.slice(0, 80)}${content.length > 80 ? "..." : ""}`;
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "create_memory_file",
|
|
138
|
+
description: "Create or append to a custom .md file in ~/.hyperclaw/. Use when the user asks for a dedicated file (e.g. EPIXEIRISI.md for business context). File is loaded into context on every session.",
|
|
139
|
+
input_schema: {
|
|
140
|
+
type: "object",
|
|
141
|
+
properties: {
|
|
142
|
+
filename: {
|
|
143
|
+
type: "string",
|
|
144
|
+
description: "Filename must end in .md, e.g. EPIXEIRISI.md, PROJECTS.md"
|
|
145
|
+
},
|
|
146
|
+
content: {
|
|
147
|
+
type: "string",
|
|
148
|
+
description: "Initial content or content to append"
|
|
149
|
+
},
|
|
150
|
+
append: {
|
|
151
|
+
type: "string",
|
|
152
|
+
description: "\"true\" to append, omit to create/overwrite"
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
required: ["filename", "content"]
|
|
156
|
+
},
|
|
157
|
+
handler: async (input) => {
|
|
158
|
+
const name = String(input.filename || "").trim();
|
|
159
|
+
if (!/^[a-zA-Z0-9_-]+\.md$/.test(name)) return "Invalid filename: use only letters, numbers, underscore, hyphen, and .md extension (e.g. EPIXEIRISI.md).";
|
|
160
|
+
const content = String(input.content || "").trim();
|
|
161
|
+
if (!content) return "Content is required.";
|
|
162
|
+
await fs_extra.default.ensureDir(HC_DIR);
|
|
163
|
+
const fpath = path.default.join(HC_DIR, name);
|
|
164
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
165
|
+
if (input.append === "true" && await fs_extra.default.pathExists(fpath)) {
|
|
166
|
+
const entry = `\n- ${today}: ${content}\n`;
|
|
167
|
+
await fs_extra.default.appendFile(fpath, entry);
|
|
168
|
+
return `Appended to ${name}: ${content.slice(0, 80)}${content.length > 80 ? "..." : ""}`;
|
|
169
|
+
}
|
|
170
|
+
const header = `# ${name.replace(".md", "")}\n> Created: ${today}\n\n`;
|
|
171
|
+
await fs_extra.default.writeFile(fpath, header + content + "\n", "utf8");
|
|
172
|
+
return `Created ${name}. It will be loaded into context on every session.`;
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "memory_graph_add",
|
|
177
|
+
description: "Add a structured fact to the knowledge graph. Use for preferences, projects, key facts that should persist across sessions.",
|
|
178
|
+
input_schema: {
|
|
179
|
+
type: "object",
|
|
180
|
+
properties: {
|
|
181
|
+
type: {
|
|
182
|
+
type: "string",
|
|
183
|
+
description: "fact | preference | project",
|
|
184
|
+
enum: [
|
|
185
|
+
"fact",
|
|
186
|
+
"preference",
|
|
187
|
+
"project"
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
content: {
|
|
191
|
+
type: "string",
|
|
192
|
+
description: "The fact, preference (e.g. \"coffee: strong\"), or project name"
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
required: ["type", "content"]
|
|
196
|
+
},
|
|
197
|
+
handler: async (input) => {
|
|
198
|
+
const { addFact, addPreference, addProject } = await Promise.resolve().then(() => require("./knowledge-graph-DqA-Fztl.js"));
|
|
199
|
+
const t = input.type.toLowerCase();
|
|
200
|
+
const c = input.content.trim();
|
|
201
|
+
if (t === "preference") {
|
|
202
|
+
const [topic, value] = c.includes(":") ? c.split(":").map((s) => s.trim()) : [c, ""];
|
|
203
|
+
const id$1 = await addPreference(topic, value || "yes");
|
|
204
|
+
return `Added preference: ${topic}${value ? ` = ${value}` : ""}`;
|
|
205
|
+
}
|
|
206
|
+
if (t === "project") {
|
|
207
|
+
const id$1 = await addProject(c);
|
|
208
|
+
return `Added project: ${c}`;
|
|
209
|
+
}
|
|
210
|
+
const id = await addFact(c);
|
|
211
|
+
return `Added fact to knowledge graph: ${c.slice(0, 100)}`;
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: "memory_graph_query",
|
|
216
|
+
description: "Query the knowledge graph for relevant context. Returns facts, preferences, projects.",
|
|
217
|
+
input_schema: {
|
|
218
|
+
type: "object",
|
|
219
|
+
properties: {
|
|
220
|
+
types: {
|
|
221
|
+
type: "string",
|
|
222
|
+
description: "Optional: fact,preference,project"
|
|
223
|
+
},
|
|
224
|
+
tags: {
|
|
225
|
+
type: "string",
|
|
226
|
+
description: "Optional comma-separated tags to filter"
|
|
227
|
+
},
|
|
228
|
+
limit: {
|
|
229
|
+
type: "string",
|
|
230
|
+
description: "Max items (default 20)"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
handler: async (input) => {
|
|
235
|
+
const { queryMemory } = await Promise.resolve().then(() => require("./knowledge-graph-DqA-Fztl.js"));
|
|
236
|
+
const types = input.types?.split(",").map((t) => t.trim()).filter(Boolean);
|
|
237
|
+
const tags = input.tags?.split(",").map((t) => t.trim()).filter(Boolean);
|
|
238
|
+
const limit = parseInt(input.limit || "20");
|
|
239
|
+
const result = await queryMemory({
|
|
240
|
+
types,
|
|
241
|
+
tags,
|
|
242
|
+
limit
|
|
243
|
+
});
|
|
244
|
+
return result || "No matching entries in knowledge graph.";
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: "node_command",
|
|
249
|
+
description: "Send a device command to a paired mobile node (iOS/Android Connect tab). Use when the user asks to take a photo, get location, read contacts, etc. on their phone. First call with no params to list connected nodes.",
|
|
250
|
+
input_schema: {
|
|
251
|
+
type: "object",
|
|
252
|
+
properties: {
|
|
253
|
+
nodeId: {
|
|
254
|
+
type: "string",
|
|
255
|
+
description: "Node ID from node_command list (e.g. \"iPhone-1\")"
|
|
256
|
+
},
|
|
257
|
+
command: {
|
|
258
|
+
type: "string",
|
|
259
|
+
description: "camera_capture | screen_record | location | contacts_list | calendar_events | photos_recent | sms_send | notify | motion",
|
|
260
|
+
enum: [
|
|
261
|
+
"camera_capture",
|
|
262
|
+
"screen_record",
|
|
263
|
+
"location",
|
|
264
|
+
"contacts_list",
|
|
265
|
+
"calendar_events",
|
|
266
|
+
"photos_recent",
|
|
267
|
+
"sms_send",
|
|
268
|
+
"notify",
|
|
269
|
+
"motion"
|
|
270
|
+
]
|
|
271
|
+
},
|
|
272
|
+
params: {
|
|
273
|
+
type: "string",
|
|
274
|
+
description: "Optional JSON params, e.g. {\"message\":\"Hello\"} for notify"
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
handler: async (input) => {
|
|
279
|
+
const { NodeRegistry } = await Promise.resolve().then(() => require("./nodes-registry-CsPm_-CJ.js"));
|
|
280
|
+
const nodes = NodeRegistry.getNodes();
|
|
281
|
+
if (!input.nodeId) {
|
|
282
|
+
if (nodes.length === 0) return "No mobile nodes connected. Pair the iOS/Android app via WebSocket to the gateway.";
|
|
283
|
+
return nodes.map((n) => `${n.nodeId} (${n.platform}): ${Object.keys(n.capabilities).filter((k) => Boolean(n.capabilities[k])).join(", ")}`).join("\n");
|
|
284
|
+
}
|
|
285
|
+
const node = NodeRegistry.getNode(String(input.nodeId ?? ""));
|
|
286
|
+
if (!node) return `Node ${input.nodeId} not found.`;
|
|
287
|
+
const cmd = input.command;
|
|
288
|
+
if (!cmd) return "command is required.";
|
|
289
|
+
const cmdId = `cmd-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
290
|
+
let params = {};
|
|
291
|
+
try {
|
|
292
|
+
if (input.params) params = JSON.parse(input.params);
|
|
293
|
+
} catch {}
|
|
294
|
+
const result = await node.send({
|
|
295
|
+
id: cmdId,
|
|
296
|
+
type: cmd,
|
|
297
|
+
params
|
|
298
|
+
});
|
|
299
|
+
if (!result.ok) return result.error || "Command failed";
|
|
300
|
+
return typeof result.data === "string" ? result.data : JSON.stringify(result.data);
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: "run_command",
|
|
305
|
+
description: "Run a safe shell command (read-only: ls, cat, echo, date, whoami, pwd)",
|
|
306
|
+
input_schema: {
|
|
307
|
+
type: "object",
|
|
308
|
+
properties: { command: {
|
|
309
|
+
type: "string",
|
|
310
|
+
description: "Shell command to run (read-only commands only)"
|
|
311
|
+
} },
|
|
312
|
+
required: ["command"]
|
|
313
|
+
},
|
|
314
|
+
handler: async (input) => {
|
|
315
|
+
const cmd = input.command.trim();
|
|
316
|
+
const safePattern = /^(ls|cat|echo|date|whoami|pwd|uname|hostname|df|free|uptime)(\s|$)/;
|
|
317
|
+
if (!safePattern.test(cmd)) return `Blocked: only read-only commands allowed. Got: ${cmd}`;
|
|
318
|
+
const { exec } = await import("child_process");
|
|
319
|
+
const { promisify } = await import("util");
|
|
320
|
+
const execAsync = promisify(exec);
|
|
321
|
+
const { stdout, stderr } = await execAsync(cmd, { timeout: 5e3 });
|
|
322
|
+
return (stdout + stderr).trim().slice(0, 2e3);
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
name: "add_reminder",
|
|
327
|
+
description: "Add a reminder. Use for \"remind me to X in Y\" requests.",
|
|
328
|
+
input_schema: {
|
|
329
|
+
type: "object",
|
|
330
|
+
properties: {
|
|
331
|
+
message: {
|
|
332
|
+
type: "string",
|
|
333
|
+
description: "Reminder text"
|
|
334
|
+
},
|
|
335
|
+
dueAt: {
|
|
336
|
+
type: "string",
|
|
337
|
+
description: "Optional: ISO 8601 or natural like \"in 2 hours\", \"tomorrow 9am\""
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
required: ["message"]
|
|
341
|
+
},
|
|
342
|
+
handler: async (input) => {
|
|
343
|
+
const { addReminder } = await Promise.resolve().then(() => require("./reminders-store-D79qdfN0.js"));
|
|
344
|
+
const r = await addReminder(input.message, input.dueAt);
|
|
345
|
+
return `Reminder added (id: ${r.id}): ${r.message}${r.dueAt ? ` due ${r.dueAt}` : ""}`;
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
name: "list_reminders",
|
|
350
|
+
description: "List pending reminders.",
|
|
351
|
+
input_schema: {
|
|
352
|
+
type: "object",
|
|
353
|
+
properties: { includeCompleted: {
|
|
354
|
+
type: "string",
|
|
355
|
+
description: "\"true\" to include completed"
|
|
356
|
+
} },
|
|
357
|
+
required: []
|
|
358
|
+
},
|
|
359
|
+
handler: async (input) => {
|
|
360
|
+
const { listReminders } = await Promise.resolve().then(() => require("./reminders-store-D79qdfN0.js"));
|
|
361
|
+
const items = await listReminders(input.includeCompleted === "true");
|
|
362
|
+
if (items.length === 0) return "No reminders.";
|
|
363
|
+
return items.map((r) => `[${r.id}] ${r.message}${r.dueAt ? ` (due ${r.dueAt})` : ""} ${r.completed ? "(done)" : ""}`).join("\n");
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
name: "complete_reminder",
|
|
368
|
+
description: "Mark a reminder as done.",
|
|
369
|
+
input_schema: {
|
|
370
|
+
type: "object",
|
|
371
|
+
properties: { id: {
|
|
372
|
+
type: "string",
|
|
373
|
+
description: "Reminder ID from list_reminders"
|
|
374
|
+
} },
|
|
375
|
+
required: ["id"]
|
|
376
|
+
},
|
|
377
|
+
handler: async (input) => {
|
|
378
|
+
const { completeReminder } = await Promise.resolve().then(() => require("./reminders-store-D79qdfN0.js"));
|
|
379
|
+
const ok = await completeReminder(input.id);
|
|
380
|
+
return ok ? `Reminder ${input.id} completed.` : `Reminder ${input.id} not found.`;
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
name: "canvas_add",
|
|
385
|
+
description: "Add a component to the HyperClaw canvas (AI-driven UI). Use for charts, tables, forms, markdown, image, or script (in-browser JS execution). For type \"script\", pass data as JSON with key \"script\" containing the JavaScript to run in a sandboxed iframe.",
|
|
386
|
+
input_schema: {
|
|
387
|
+
type: "object",
|
|
388
|
+
properties: {
|
|
389
|
+
type: {
|
|
390
|
+
type: "string",
|
|
391
|
+
description: "Component type",
|
|
392
|
+
enum: [
|
|
393
|
+
"chart",
|
|
394
|
+
"table",
|
|
395
|
+
"form",
|
|
396
|
+
"markdown",
|
|
397
|
+
"image",
|
|
398
|
+
"custom",
|
|
399
|
+
"script"
|
|
400
|
+
]
|
|
401
|
+
},
|
|
402
|
+
title: {
|
|
403
|
+
type: "string",
|
|
404
|
+
description: "Component title"
|
|
405
|
+
},
|
|
406
|
+
data: {
|
|
407
|
+
type: "string",
|
|
408
|
+
description: "Optional JSON. For type \"script\" use {\"script\": \"document.body.innerHTML = \\\"Hello\\\";\"}"
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
required: ["type", "title"]
|
|
412
|
+
},
|
|
413
|
+
handler: async (input) => {
|
|
414
|
+
const { CanvasRenderer } = await Promise.resolve().then(() => require("./renderer-pqlDRKbH.js"));
|
|
415
|
+
const renderer = new CanvasRenderer();
|
|
416
|
+
let data;
|
|
417
|
+
try {
|
|
418
|
+
data = input.data ? JSON.parse(input.data) : void 0;
|
|
419
|
+
} catch {}
|
|
420
|
+
const c = await renderer.addComponent(input.type, input.title, data);
|
|
421
|
+
return `Canvas component added: ${c.type}/${c.title} (id: ${c.id}). View at http://localhost:18789/canvas`;
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
name: "http_get",
|
|
426
|
+
description: "Make an HTTP GET request to a URL and return the response",
|
|
427
|
+
input_schema: {
|
|
428
|
+
type: "object",
|
|
429
|
+
properties: {
|
|
430
|
+
url: {
|
|
431
|
+
type: "string",
|
|
432
|
+
description: "URL to fetch"
|
|
433
|
+
},
|
|
434
|
+
headers: {
|
|
435
|
+
type: "string",
|
|
436
|
+
description: "Optional JSON headers object"
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
required: ["url"]
|
|
440
|
+
},
|
|
441
|
+
handler: async (input) => {
|
|
442
|
+
const url = input.url;
|
|
443
|
+
if (!url.startsWith("http://") && !url.startsWith("https://")) return "Error: URL must start with http:// or https://";
|
|
444
|
+
return new Promise((resolve) => {
|
|
445
|
+
const mod = url.startsWith("https://") ? https.default : require("http");
|
|
446
|
+
let extra = {};
|
|
447
|
+
try {
|
|
448
|
+
if (input.headers) extra = JSON.parse(input.headers);
|
|
449
|
+
} catch {}
|
|
450
|
+
const req = mod.get(url, {
|
|
451
|
+
headers: extra,
|
|
452
|
+
timeout: 1e4
|
|
453
|
+
}, (res) => {
|
|
454
|
+
let data = "";
|
|
455
|
+
res.on("data", (c) => data += c);
|
|
456
|
+
res.on("end", () => resolve(data.slice(0, 3e3)));
|
|
457
|
+
});
|
|
458
|
+
req.on("error", (e) => resolve(`Error: ${e.message}`));
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
name: "moltbook_feed",
|
|
464
|
+
description: "Get the latest posts from Moltbook (social feed for agents). Set MOLTBOOK_API_URL to enable.",
|
|
465
|
+
input_schema: {
|
|
466
|
+
type: "object",
|
|
467
|
+
properties: { limit: {
|
|
468
|
+
type: "string",
|
|
469
|
+
description: "Max posts (default 10)"
|
|
470
|
+
} },
|
|
471
|
+
required: []
|
|
472
|
+
},
|
|
473
|
+
handler: async (input) => {
|
|
474
|
+
const { getFeed } = await Promise.resolve().then(() => require("./moltbook-B6ZeGN5_.js"));
|
|
475
|
+
const posts = await getFeed(parseInt(input.limit || "10", 10));
|
|
476
|
+
if (posts.length === 0) return "Moltbook feed empty or MOLTBOOK_API_URL not set.";
|
|
477
|
+
return posts.map((p) => `[${p.agentId}] ${p.content.slice(0, 200)}`).join("\n---\n");
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
name: "moltbook_post",
|
|
482
|
+
description: "Publish a post to Moltbook. Requires MOLTBOOK_API_URL and agent auth.",
|
|
483
|
+
input_schema: {
|
|
484
|
+
type: "object",
|
|
485
|
+
properties: { content: {
|
|
486
|
+
type: "string",
|
|
487
|
+
description: "Post content"
|
|
488
|
+
} },
|
|
489
|
+
required: ["content"]
|
|
490
|
+
},
|
|
491
|
+
handler: async (input) => {
|
|
492
|
+
const { publishPost } = await Promise.resolve().then(() => require("./moltbook-B6ZeGN5_.js"));
|
|
493
|
+
const post = await publishPost(input.content);
|
|
494
|
+
return post ? `Published: ${post.id}` : "Moltbook not configured or publish failed. Set MOLTBOOK_API_URL.";
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
name: "claw_tasks_list",
|
|
499
|
+
description: "List open bounties from ClawTasks (bounty marketplace). Set CLAW_TASKS_API_URL to enable.",
|
|
500
|
+
input_schema: {
|
|
501
|
+
type: "object",
|
|
502
|
+
properties: { limit: {
|
|
503
|
+
type: "string",
|
|
504
|
+
description: "Max bounties (default 10)"
|
|
505
|
+
} },
|
|
506
|
+
required: []
|
|
507
|
+
},
|
|
508
|
+
handler: async (input) => {
|
|
509
|
+
const { listBounties } = await Promise.resolve().then(() => require("./claw-tasks-BRLUvFRD.js"));
|
|
510
|
+
const bounties = await listBounties(parseInt(input.limit || "10", 10), "open");
|
|
511
|
+
if (bounties.length === 0) return "No open bounties or CLAW_TASKS_API_URL not set.";
|
|
512
|
+
return bounties.map((b) => `[${b.id}] ${b.title}${b.reward ? ` — ${b.reward}` : ""}`).join("\n");
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
name: "claw_tasks_claim",
|
|
517
|
+
description: "Claim a ClawTasks bounty by ID. Requires CLAW_TASKS_API_URL and agent token.",
|
|
518
|
+
input_schema: {
|
|
519
|
+
type: "object",
|
|
520
|
+
properties: { bountyId: {
|
|
521
|
+
type: "string",
|
|
522
|
+
description: "Bounty ID from claw_tasks_list"
|
|
523
|
+
} },
|
|
524
|
+
required: ["bountyId"]
|
|
525
|
+
},
|
|
526
|
+
handler: async (input) => {
|
|
527
|
+
const { claimBounty } = await Promise.resolve().then(() => require("./claw-tasks-BRLUvFRD.js"));
|
|
528
|
+
const b = await claimBounty(input.bountyId);
|
|
529
|
+
return b ? `Claimed: ${b.title}` : "Claim failed or ClawTasks not configured.";
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
name: "create_skill",
|
|
534
|
+
description: "Create or overwrite a custom skill (self-writing skills). The skill will be loaded on next message. Use when the user asks to \"add skill X\" or \"create a skill that does Y\".",
|
|
535
|
+
input_schema: {
|
|
536
|
+
type: "object",
|
|
537
|
+
properties: {
|
|
538
|
+
skillId: {
|
|
539
|
+
type: "string",
|
|
540
|
+
description: "Unique slug, e.g. \"remind-weekly\" or \"format-dates\""
|
|
541
|
+
},
|
|
542
|
+
name: {
|
|
543
|
+
type: "string",
|
|
544
|
+
description: "Human-readable name"
|
|
545
|
+
},
|
|
546
|
+
description: {
|
|
547
|
+
type: "string",
|
|
548
|
+
description: "Short description of when to use"
|
|
549
|
+
},
|
|
550
|
+
content: {
|
|
551
|
+
type: "string",
|
|
552
|
+
description: "Full SKILL.md body: instructions, when to use, steps. Use markdown."
|
|
553
|
+
}
|
|
554
|
+
},
|
|
555
|
+
required: ["skillId", "content"]
|
|
556
|
+
},
|
|
557
|
+
handler: async (input) => {
|
|
558
|
+
const { writeSkill } = await Promise.resolve().then(() => require("./skill-loader-BkceKkIg.js"));
|
|
559
|
+
const { path: p, id } = await writeSkill(input.skillId, {
|
|
560
|
+
name: input.name,
|
|
561
|
+
description: input.description,
|
|
562
|
+
content: input.content
|
|
563
|
+
});
|
|
564
|
+
return `Skill created: ${id} at ${p}. It will be loaded on the next turn.`;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
];
|
|
568
|
+
}
|
|
569
|
+
var HC_DIR, InferenceEngine;
|
|
570
|
+
var init_inference = require_chunk.__esm({ "packages/core/src/agent/inference.ts"() {
|
|
571
|
+
HC_DIR = path.default.join(os.default.homedir(), ".hyperclaw");
|
|
572
|
+
InferenceEngine = class {
|
|
573
|
+
opts;
|
|
574
|
+
constructor(opts) {
|
|
575
|
+
this.opts = opts;
|
|
576
|
+
}
|
|
577
|
+
async run(messages) {
|
|
578
|
+
const result = {
|
|
579
|
+
text: "",
|
|
580
|
+
thinking: void 0,
|
|
581
|
+
toolCalls: [],
|
|
582
|
+
usage: {
|
|
583
|
+
input: 0,
|
|
584
|
+
output: 0
|
|
585
|
+
},
|
|
586
|
+
stopReason: "end_turn"
|
|
587
|
+
};
|
|
588
|
+
const history = [...messages];
|
|
589
|
+
const maxRounds = this.opts.maxToolRounds ?? 10;
|
|
590
|
+
let rounds = 0;
|
|
591
|
+
while (rounds < maxRounds) {
|
|
592
|
+
rounds++;
|
|
593
|
+
const response = await this.callAPI(history, result);
|
|
594
|
+
const toolUses = response.content?.filter((b) => b.type === "tool_use") || [];
|
|
595
|
+
if (toolUses.length === 0 || !this.opts.tools?.length) {
|
|
596
|
+
const textBlocks = (response.content || []).filter((b) => b.type === "text");
|
|
597
|
+
result.text = textBlocks.map((b) => b.text).join("");
|
|
598
|
+
result.stopReason = response.stop_reason || "end_turn";
|
|
599
|
+
if (response.usage) result.usage = {
|
|
600
|
+
input: response.usage.input_tokens || 0,
|
|
601
|
+
output: response.usage.output_tokens || 0,
|
|
602
|
+
cacheRead: response.usage.cache_read_input_tokens
|
|
603
|
+
};
|
|
604
|
+
break;
|
|
605
|
+
}
|
|
606
|
+
history.push({
|
|
607
|
+
role: "assistant",
|
|
608
|
+
content: response.content
|
|
609
|
+
});
|
|
610
|
+
const toolResults = [];
|
|
611
|
+
for (const toolUse of toolUses) {
|
|
612
|
+
const tool = this.opts.tools?.find((t) => t.name === toolUse.name);
|
|
613
|
+
this.opts.onToolCall?.(toolUse.name, toolUse.input);
|
|
614
|
+
let toolResult = "";
|
|
615
|
+
if (tool) try {
|
|
616
|
+
toolResult = await tool.handler(toolUse.input);
|
|
617
|
+
} catch (err) {
|
|
618
|
+
toolResult = `Error: ${err.message}`;
|
|
619
|
+
}
|
|
620
|
+
else toolResult = `Error: Tool "${toolUse.name}" not found`;
|
|
621
|
+
this.opts.onToolResult?.(toolUse.name, toolResult);
|
|
622
|
+
result.toolCalls.push({
|
|
623
|
+
name: toolUse.name,
|
|
624
|
+
input: toolUse.input,
|
|
625
|
+
result: toolResult
|
|
626
|
+
});
|
|
627
|
+
toolResults.push({
|
|
628
|
+
type: "tool_result",
|
|
629
|
+
tool_use_id: toolUse.id,
|
|
630
|
+
content: toolResult
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
history.push({
|
|
634
|
+
role: "user",
|
|
635
|
+
content: toolResults
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
return result;
|
|
639
|
+
}
|
|
640
|
+
callAPI(messages, result) {
|
|
641
|
+
const { provider } = this.opts;
|
|
642
|
+
if (provider === "anthropic") return this.callAnthropic(messages, result);
|
|
643
|
+
if (provider === "custom" && this.opts.baseUrl) return this.callCustom(messages, result);
|
|
644
|
+
return this.callOpenRouter(messages, result);
|
|
645
|
+
}
|
|
646
|
+
callAnthropic(messages, result) {
|
|
647
|
+
return new Promise((resolve, reject) => {
|
|
648
|
+
const body = {
|
|
649
|
+
model: this.opts.model,
|
|
650
|
+
max_tokens: this.opts.maxTokens || 4096,
|
|
651
|
+
messages,
|
|
652
|
+
stream: true
|
|
653
|
+
};
|
|
654
|
+
if (this.opts.system) body.system = this.opts.system;
|
|
655
|
+
if (this.opts.thinking) body.thinking = {
|
|
656
|
+
type: "enabled",
|
|
657
|
+
budget_tokens: this.opts.thinking.budget_tokens
|
|
658
|
+
};
|
|
659
|
+
if (this.opts.tools?.length) {
|
|
660
|
+
body.tools = this.opts.tools.map((t) => ({
|
|
661
|
+
name: t.name,
|
|
662
|
+
description: t.description,
|
|
663
|
+
input_schema: t.input_schema
|
|
664
|
+
}));
|
|
665
|
+
body.tool_choice = { type: "auto" };
|
|
666
|
+
}
|
|
667
|
+
const responseContent = [];
|
|
668
|
+
let currentBlock = null;
|
|
669
|
+
let inputJson = "";
|
|
670
|
+
let stopReason = "end_turn";
|
|
671
|
+
let usage = {
|
|
672
|
+
input_tokens: 0,
|
|
673
|
+
output_tokens: 0
|
|
674
|
+
};
|
|
675
|
+
streamRequest("api.anthropic.com", "/v1/messages", {
|
|
676
|
+
"Authorization": `Bearer ${this.opts.apiKey}`,
|
|
677
|
+
"anthropic-version": "2023-06-01",
|
|
678
|
+
"anthropic-beta": "interleaved-thinking-2025-05-14"
|
|
679
|
+
}, body, (line) => {
|
|
680
|
+
const event = parseSSEChunk(line);
|
|
681
|
+
if (!event) return;
|
|
682
|
+
switch (event.type) {
|
|
683
|
+
case "content_block_start":
|
|
684
|
+
currentBlock = { ...event.content_block };
|
|
685
|
+
inputJson = "";
|
|
686
|
+
break;
|
|
687
|
+
case "content_block_delta":
|
|
688
|
+
if (!currentBlock) break;
|
|
689
|
+
if (event.delta?.type === "text_delta") {
|
|
690
|
+
currentBlock.text = (currentBlock.text || "") + event.delta.text;
|
|
691
|
+
this.opts.onToken?.(event.delta.text);
|
|
692
|
+
if (currentBlock.type !== "thinking") result.text += event.delta.text;
|
|
693
|
+
}
|
|
694
|
+
if (event.delta?.type === "thinking_delta") {
|
|
695
|
+
currentBlock.thinking = (currentBlock.thinking || "") + event.delta.thinking;
|
|
696
|
+
this.opts.onThinking?.(event.delta.thinking);
|
|
697
|
+
}
|
|
698
|
+
if (event.delta?.type === "input_json_delta") inputJson += event.delta.partial_json;
|
|
699
|
+
break;
|
|
700
|
+
case "content_block_stop":
|
|
701
|
+
if (currentBlock) {
|
|
702
|
+
if (currentBlock.type === "tool_use" && inputJson) try {
|
|
703
|
+
currentBlock.input = JSON.parse(inputJson);
|
|
704
|
+
} catch {}
|
|
705
|
+
if (currentBlock.type === "text" && currentBlock.text && this.opts.onBlock) emitMarkdownBlocks(currentBlock.text, (type, content, lang) => this.opts.onBlock(type, content, lang));
|
|
706
|
+
responseContent.push(currentBlock);
|
|
707
|
+
currentBlock = null;
|
|
708
|
+
}
|
|
709
|
+
break;
|
|
710
|
+
case "message_delta":
|
|
711
|
+
if (event.delta?.stop_reason) stopReason = event.delta.stop_reason;
|
|
712
|
+
if (event.usage) usage.output_tokens = event.usage.output_tokens || 0;
|
|
713
|
+
break;
|
|
714
|
+
case "message_start":
|
|
715
|
+
if (event.message?.usage) usage = event.message.usage;
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
}, () => resolve({
|
|
719
|
+
content: responseContent,
|
|
720
|
+
stop_reason: stopReason,
|
|
721
|
+
usage
|
|
722
|
+
}), reject);
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
callOpenRouter(messages, _result) {
|
|
726
|
+
return new Promise((resolve, reject) => {
|
|
727
|
+
const oaiMessages = messages.map((m) => {
|
|
728
|
+
if (m.role === "user" && Array.isArray(m.content)) {
|
|
729
|
+
const toolResults = m.content.filter((b) => b.type === "tool_result");
|
|
730
|
+
if (toolResults.length > 0) return toolResults.map((b) => ({
|
|
731
|
+
role: "tool",
|
|
732
|
+
tool_call_id: b.tool_use_id,
|
|
733
|
+
content: b.content
|
|
734
|
+
}));
|
|
735
|
+
}
|
|
736
|
+
if (m.role === "assistant" && Array.isArray(m.content)) {
|
|
737
|
+
const textBlocks = m.content.filter((b) => b.type === "text");
|
|
738
|
+
const toolUseBlocks = m.content.filter((b) => b.type === "tool_use");
|
|
739
|
+
const msg = {
|
|
740
|
+
role: "assistant",
|
|
741
|
+
content: textBlocks.map((b) => b.text).join("") || null
|
|
742
|
+
};
|
|
743
|
+
if (toolUseBlocks.length > 0) msg.tool_calls = toolUseBlocks.map((b) => ({
|
|
744
|
+
id: b.id,
|
|
745
|
+
type: "function",
|
|
746
|
+
function: {
|
|
747
|
+
name: b.name,
|
|
748
|
+
arguments: JSON.stringify(b.input)
|
|
749
|
+
}
|
|
750
|
+
}));
|
|
751
|
+
return msg;
|
|
752
|
+
}
|
|
753
|
+
return {
|
|
754
|
+
role: m.role === "tool" ? "tool" : m.role,
|
|
755
|
+
content: typeof m.content === "string" ? m.content : m.content.filter((b) => b.type === "text").map((b) => b.text).join("")
|
|
756
|
+
};
|
|
757
|
+
}).flat();
|
|
758
|
+
const body = {
|
|
759
|
+
model: this.opts.model,
|
|
760
|
+
max_tokens: this.opts.maxTokens || 4096,
|
|
761
|
+
messages: this.opts.system ? [{
|
|
762
|
+
role: "system",
|
|
763
|
+
content: this.opts.system
|
|
764
|
+
}, ...oaiMessages] : oaiMessages,
|
|
765
|
+
stream: true
|
|
766
|
+
};
|
|
767
|
+
if (this.opts.tools?.length) {
|
|
768
|
+
body.tools = this.opts.tools.map((t) => ({
|
|
769
|
+
type: "function",
|
|
770
|
+
function: {
|
|
771
|
+
name: t.name,
|
|
772
|
+
description: t.description,
|
|
773
|
+
parameters: t.input_schema
|
|
774
|
+
}
|
|
775
|
+
}));
|
|
776
|
+
body.tool_choice = "auto";
|
|
777
|
+
}
|
|
778
|
+
let fullText = "";
|
|
779
|
+
let stopReason = "stop";
|
|
780
|
+
const toolCallsAcc = {};
|
|
781
|
+
streamRequest("openrouter.ai", "/api/v1/chat/completions", {
|
|
782
|
+
"Authorization": `Bearer ${this.opts.apiKey}`,
|
|
783
|
+
"HTTP-Referer": "https://hyperclaw.ai",
|
|
784
|
+
"X-Title": "HyperClaw"
|
|
785
|
+
}, body, (line) => {
|
|
786
|
+
const event = parseSSEChunk(line);
|
|
787
|
+
if (!event?.choices?.[0]) return;
|
|
788
|
+
const choice = event.choices[0];
|
|
789
|
+
const delta = choice.delta;
|
|
790
|
+
if (delta?.content) {
|
|
791
|
+
fullText += delta.content;
|
|
792
|
+
this.opts.onToken?.(delta.content);
|
|
793
|
+
}
|
|
794
|
+
if (delta?.tool_calls) for (const tc of delta.tool_calls) {
|
|
795
|
+
const idx = tc.index ?? 0;
|
|
796
|
+
if (!toolCallsAcc[idx]) toolCallsAcc[idx] = {
|
|
797
|
+
id: tc.id || `call_${idx}`,
|
|
798
|
+
name: "",
|
|
799
|
+
arguments: ""
|
|
800
|
+
};
|
|
801
|
+
if (tc.id) toolCallsAcc[idx].id = tc.id;
|
|
802
|
+
if (tc.function?.name) toolCallsAcc[idx].name += tc.function.name;
|
|
803
|
+
if (tc.function?.arguments) toolCallsAcc[idx].arguments += tc.function.arguments;
|
|
804
|
+
}
|
|
805
|
+
if (choice.finish_reason) stopReason = choice.finish_reason;
|
|
806
|
+
}, () => {
|
|
807
|
+
const responseContent = [];
|
|
808
|
+
if (fullText) responseContent.push({
|
|
809
|
+
type: "text",
|
|
810
|
+
text: fullText
|
|
811
|
+
});
|
|
812
|
+
for (const tc of Object.values(toolCallsAcc)) {
|
|
813
|
+
let input = {};
|
|
814
|
+
try {
|
|
815
|
+
input = JSON.parse(tc.arguments || "{}");
|
|
816
|
+
} catch {}
|
|
817
|
+
this.opts.onToolCall?.(tc.name, input);
|
|
818
|
+
responseContent.push({
|
|
819
|
+
type: "tool_use",
|
|
820
|
+
id: tc.id,
|
|
821
|
+
name: tc.name,
|
|
822
|
+
input
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
const mappedStop = stopReason === "tool_calls" ? "tool_use" : stopReason;
|
|
826
|
+
resolve({
|
|
827
|
+
content: responseContent,
|
|
828
|
+
stop_reason: mappedStop,
|
|
829
|
+
usage: {}
|
|
830
|
+
});
|
|
831
|
+
}, reject);
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
callCustom(messages, _result) {
|
|
835
|
+
const baseUrl = (this.opts.baseUrl || "").trim().replace(/\/$/, "");
|
|
836
|
+
if (!baseUrl) return Promise.reject(new Error("Custom provider requires baseUrl"));
|
|
837
|
+
let hostname;
|
|
838
|
+
let reqPath;
|
|
839
|
+
let port;
|
|
840
|
+
let useHttps;
|
|
841
|
+
try {
|
|
842
|
+
const u = new URL(baseUrl.startsWith("http") ? baseUrl : "https://" + baseUrl);
|
|
843
|
+
hostname = u.hostname;
|
|
844
|
+
reqPath = (u.pathname || "/").replace(/\/$/, "") + "/chat/completions";
|
|
845
|
+
if (!reqPath.startsWith("/")) reqPath = "/" + reqPath;
|
|
846
|
+
useHttps = u.protocol === "https:";
|
|
847
|
+
port = u.port ? parseInt(u.port, 10) : useHttps ? 443 : 80;
|
|
848
|
+
} catch {
|
|
849
|
+
return Promise.reject(new Error("Invalid custom baseUrl"));
|
|
850
|
+
}
|
|
851
|
+
return new Promise((resolve, reject) => {
|
|
852
|
+
const oaiMessages = messages.map((m) => ({
|
|
853
|
+
role: m.role === "tool" ? "tool" : m.role,
|
|
854
|
+
content: typeof m.content === "string" ? m.content : m.content.filter((b) => b.type === "text").map((b) => b.text).join("")
|
|
855
|
+
}));
|
|
856
|
+
const body = {
|
|
857
|
+
model: this.opts.model,
|
|
858
|
+
max_tokens: this.opts.maxTokens || 4096,
|
|
859
|
+
messages: this.opts.system ? [{
|
|
860
|
+
role: "system",
|
|
861
|
+
content: this.opts.system
|
|
862
|
+
}, ...oaiMessages] : oaiMessages,
|
|
863
|
+
stream: true
|
|
864
|
+
};
|
|
865
|
+
if (this.opts.tools?.length) body.tools = this.opts.tools.map((t) => ({
|
|
866
|
+
type: "function",
|
|
867
|
+
function: {
|
|
868
|
+
name: t.name,
|
|
869
|
+
description: t.description,
|
|
870
|
+
parameters: t.input_schema
|
|
871
|
+
}
|
|
872
|
+
}));
|
|
873
|
+
let fullText = "";
|
|
874
|
+
let stopReason = "stop";
|
|
875
|
+
streamRequest(hostname, reqPath, {
|
|
876
|
+
"Authorization": `Bearer ${this.opts.apiKey}`,
|
|
877
|
+
"HTTP-Referer": "https://hyperclaw.ai",
|
|
878
|
+
"X-Title": "HyperClaw"
|
|
879
|
+
}, body, (line) => {
|
|
880
|
+
const event = parseSSEChunk(line);
|
|
881
|
+
if (!event?.choices?.[0]) return;
|
|
882
|
+
const delta = event.choices[0].delta;
|
|
883
|
+
if (delta?.content) {
|
|
884
|
+
fullText += delta.content;
|
|
885
|
+
this.opts.onToken?.(delta.content);
|
|
886
|
+
}
|
|
887
|
+
if (event.choices[0].finish_reason) stopReason = event.choices[0].finish_reason;
|
|
888
|
+
}, () => resolve({
|
|
889
|
+
content: [{
|
|
890
|
+
type: "text",
|
|
891
|
+
text: fullText
|
|
892
|
+
}],
|
|
893
|
+
stop_reason: stopReason,
|
|
894
|
+
usage: {}
|
|
895
|
+
}), reject, {
|
|
896
|
+
port,
|
|
897
|
+
useHttps
|
|
898
|
+
});
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
} });
|
|
903
|
+
|
|
904
|
+
//#endregion
|
|
905
|
+
Object.defineProperty(exports, 'InferenceEngine', {
|
|
906
|
+
enumerable: true,
|
|
907
|
+
get: function () {
|
|
908
|
+
return InferenceEngine;
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
Object.defineProperty(exports, 'getBuiltinTools', {
|
|
912
|
+
enumerable: true,
|
|
913
|
+
get: function () {
|
|
914
|
+
return getBuiltinTools;
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
Object.defineProperty(exports, 'init_inference', {
|
|
918
|
+
enumerable: true,
|
|
919
|
+
get: function () {
|
|
920
|
+
return init_inference;
|
|
921
|
+
}
|
|
922
|
+
});
|