clawcompany 0.2.0 → 0.4.0
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/index.js +510 -123
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,89 +9,6 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
// src/utils.ts
|
|
13
|
-
import { join } from "path";
|
|
14
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
15
|
-
function banner() {
|
|
16
|
-
console.log("");
|
|
17
|
-
console.log(" \u{1F99E} ClawCompany v0.2.0");
|
|
18
|
-
console.log(" Build for OPC. Every human being is a chairman.");
|
|
19
|
-
console.log("");
|
|
20
|
-
}
|
|
21
|
-
function getConfigDir() {
|
|
22
|
-
const dir = join(process.env.HOME ?? "~", ".clawcompany");
|
|
23
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
24
|
-
return dir;
|
|
25
|
-
}
|
|
26
|
-
function getConfigPath() {
|
|
27
|
-
return join(getConfigDir(), "config.json");
|
|
28
|
-
}
|
|
29
|
-
function configExists() {
|
|
30
|
-
return existsSync(getConfigPath());
|
|
31
|
-
}
|
|
32
|
-
function readConfig() {
|
|
33
|
-
if (!configExists()) return null;
|
|
34
|
-
try {
|
|
35
|
-
return JSON.parse(readFileSync(getConfigPath(), "utf-8"));
|
|
36
|
-
} catch {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function writeConfig(config) {
|
|
41
|
-
writeFileSync(getConfigPath(), JSON.stringify(config, null, 2));
|
|
42
|
-
}
|
|
43
|
-
async function apiGet(path, port = 3200) {
|
|
44
|
-
const res = await fetch(`http://localhost:${port}${path}`);
|
|
45
|
-
if (!res.ok) throw new Error(`API error: ${res.status}`);
|
|
46
|
-
return res.json();
|
|
47
|
-
}
|
|
48
|
-
async function apiPost(path, body, port = 3200) {
|
|
49
|
-
const res = await fetch(`http://localhost:${port}${path}`, {
|
|
50
|
-
method: "POST",
|
|
51
|
-
headers: { "Content-Type": "application/json" },
|
|
52
|
-
body: JSON.stringify(body)
|
|
53
|
-
});
|
|
54
|
-
if (!res.ok) {
|
|
55
|
-
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
56
|
-
throw new Error(err.error ?? `API error: ${res.status}`);
|
|
57
|
-
}
|
|
58
|
-
return res.json();
|
|
59
|
-
}
|
|
60
|
-
async function validateClawApiKey(key) {
|
|
61
|
-
try {
|
|
62
|
-
const res = await fetch("https://clawapi.org/api/v1/chat/completions", {
|
|
63
|
-
method: "POST",
|
|
64
|
-
headers: {
|
|
65
|
-
"Authorization": `Bearer ${key}`,
|
|
66
|
-
"Content-Type": "application/json"
|
|
67
|
-
},
|
|
68
|
-
body: JSON.stringify({
|
|
69
|
-
model: "gpt-oss-20b",
|
|
70
|
-
messages: [{ role: "user", content: "hi" }],
|
|
71
|
-
max_tokens: 5
|
|
72
|
-
})
|
|
73
|
-
});
|
|
74
|
-
if (res.status === 401) return { valid: false, error: "Invalid key. Check your key at clawapi.org" };
|
|
75
|
-
if (!res.ok) return { valid: false, error: `ClawAPI returned ${res.status}. Try again later.` };
|
|
76
|
-
return { valid: true };
|
|
77
|
-
} catch (err) {
|
|
78
|
-
return { valid: false, error: `Cannot reach ClawAPI: ${err.message}. Check your internet connection.` };
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
async function isServerRunning(port = 3200) {
|
|
82
|
-
try {
|
|
83
|
-
const res = await fetch(`http://localhost:${port}/api/health`);
|
|
84
|
-
return res.ok;
|
|
85
|
-
} catch {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
var init_utils = __esm({
|
|
90
|
-
"src/utils.ts"() {
|
|
91
|
-
"use strict";
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
|
|
95
12
|
// ../packages/shared/src/types.ts
|
|
96
13
|
var init_types = __esm({
|
|
97
14
|
"../packages/shared/src/types.ts"() {
|
|
@@ -205,7 +122,7 @@ COST AWARENESS:
|
|
|
205
122
|
budgetTier: "earn",
|
|
206
123
|
budgetMonthly: null,
|
|
207
124
|
maxTokensPerTask: null,
|
|
208
|
-
tools: ["http", "filesystem"],
|
|
125
|
+
tools: ["http", "filesystem", "web_fetch", "web_search"],
|
|
209
126
|
skills: [],
|
|
210
127
|
isBuiltin: true,
|
|
211
128
|
isActive: true,
|
|
@@ -276,7 +193,7 @@ Own marketing strategy, content creation, brand voice, growth initiatives. Write
|
|
|
276
193
|
budgetTier: "earn",
|
|
277
194
|
budgetMonthly: null,
|
|
278
195
|
maxTokensPerTask: null,
|
|
279
|
-
tools: ["http", "filesystem"],
|
|
196
|
+
tools: ["http", "filesystem", "web_fetch", "web_search"],
|
|
280
197
|
skills: [],
|
|
281
198
|
isBuiltin: true,
|
|
282
199
|
isActive: true,
|
|
@@ -300,7 +217,7 @@ Conduct deep research \u2014 gather information, evaluate sources, analyze compe
|
|
|
300
217
|
budgetTier: "earn",
|
|
301
218
|
budgetMonthly: null,
|
|
302
219
|
maxTokensPerTask: null,
|
|
303
|
-
tools: ["http", "filesystem"],
|
|
220
|
+
tools: ["http", "filesystem", "web_fetch", "web_search"],
|
|
304
221
|
skills: [],
|
|
305
222
|
isBuiltin: true,
|
|
306
223
|
isActive: true,
|
|
@@ -315,7 +232,7 @@ Conduct deep research \u2014 gather information, evaluate sources, analyze compe
|
|
|
315
232
|
systemPrompt: `You are an Analyst. You report to the CFO or CEO.
|
|
316
233
|
|
|
317
234
|
Analyze data, detect patterns, calculate metrics, build models. Show calculations step by step. Present findings in tables. State assumptions. Quantify confidence levels.`,
|
|
318
|
-
model: "
|
|
235
|
+
model: "gpt-5-mini",
|
|
319
236
|
provider: "clawapi",
|
|
320
237
|
reportsTo: "cfo",
|
|
321
238
|
canDelegateTo: ["worker"],
|
|
@@ -323,7 +240,7 @@ Analyze data, detect patterns, calculate metrics, build models. Show calculation
|
|
|
323
240
|
budgetTier: "save",
|
|
324
241
|
budgetMonthly: null,
|
|
325
242
|
maxTokensPerTask: null,
|
|
326
|
-
tools: ["http", "filesystem", "code_interpreter"],
|
|
243
|
+
tools: ["http", "filesystem", "code_interpreter", "web_fetch", "web_search"],
|
|
327
244
|
skills: [],
|
|
328
245
|
isBuiltin: true,
|
|
329
246
|
isActive: true,
|
|
@@ -391,7 +308,7 @@ Prepare briefings, format reports, summarize documents, organize information. Ma
|
|
|
391
308
|
budgetTier: "save",
|
|
392
309
|
budgetMonthly: null,
|
|
393
310
|
maxTokensPerTask: null,
|
|
394
|
-
tools: ["filesystem", "http"],
|
|
311
|
+
tools: ["filesystem", "http", "web_fetch", "web_search"],
|
|
395
312
|
skills: [],
|
|
396
313
|
isBuiltin: true,
|
|
397
314
|
isActive: true,
|
|
@@ -856,6 +773,153 @@ var init_market = __esm({
|
|
|
856
773
|
}
|
|
857
774
|
});
|
|
858
775
|
|
|
776
|
+
// ../packages/shared/src/memory.ts
|
|
777
|
+
function createEmptyMemory() {
|
|
778
|
+
return {
|
|
779
|
+
version: 1,
|
|
780
|
+
chairman: {
|
|
781
|
+
domains: [],
|
|
782
|
+
commonMissions: [],
|
|
783
|
+
preferences: []
|
|
784
|
+
},
|
|
785
|
+
company: {
|
|
786
|
+
missionCount: 0,
|
|
787
|
+
learnings: [],
|
|
788
|
+
domainKnowledge: [],
|
|
789
|
+
goodPatterns: [],
|
|
790
|
+
recentMissions: []
|
|
791
|
+
},
|
|
792
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
function buildMemoryContext(memory) {
|
|
796
|
+
const parts = [];
|
|
797
|
+
const ch = memory.chairman;
|
|
798
|
+
if (ch.language) parts.push(`Chairman language: ${ch.language}`);
|
|
799
|
+
if (ch.outputStyle) parts.push(`Output style: ${ch.outputStyle}`);
|
|
800
|
+
if (ch.domains.length > 0) parts.push(`Focus areas: ${ch.domains.slice(0, 5).join(", ")}`);
|
|
801
|
+
if (ch.preferences.length > 0) parts.push(`Preferences: ${ch.preferences.slice(0, 5).join("; ")}`);
|
|
802
|
+
const co = memory.company;
|
|
803
|
+
if (co.missionCount > 0) parts.push(`Missions completed: ${co.missionCount}`);
|
|
804
|
+
if (co.learnings.length > 0) parts.push(`Key learnings: ${co.learnings.slice(-5).join("; ")}`);
|
|
805
|
+
if (co.domainKnowledge.length > 0) parts.push(`Domain knowledge: ${co.domainKnowledge.slice(-5).join("; ")}`);
|
|
806
|
+
if (co.recentMissions.length > 0) {
|
|
807
|
+
const recent = co.recentMissions.slice(-3).map((m) => m.goal).join("; ");
|
|
808
|
+
parts.push(`Recent missions: ${recent}`);
|
|
809
|
+
}
|
|
810
|
+
if (parts.length === 0) return "";
|
|
811
|
+
return `
|
|
812
|
+
|
|
813
|
+
## Company Memory
|
|
814
|
+
${parts.join("\n")}`;
|
|
815
|
+
}
|
|
816
|
+
function updateMemoryFromMission(memory, mission, chairmanMessage) {
|
|
817
|
+
const updated = structuredClone(memory);
|
|
818
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
819
|
+
updated.updatedAt = now;
|
|
820
|
+
if (chairmanMessage || mission.goal) {
|
|
821
|
+
const text = chairmanMessage ?? mission.goal;
|
|
822
|
+
const hasChinese = /[\u4e00-\u9fff]/.test(text);
|
|
823
|
+
const hasJapanese = /[\u3040-\u309f\u30a0-\u30ff]/.test(text);
|
|
824
|
+
if (hasChinese) updated.chairman.language = "zh";
|
|
825
|
+
else if (hasJapanese) updated.chairman.language = "ja";
|
|
826
|
+
else if (!updated.chairman.language) updated.chairman.language = "en";
|
|
827
|
+
}
|
|
828
|
+
const domainKeywords = extractDomains(mission.goal);
|
|
829
|
+
for (const d of domainKeywords) {
|
|
830
|
+
if (!updated.chairman.domains.includes(d)) {
|
|
831
|
+
updated.chairman.domains.push(d);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
if (updated.chairman.domains.length > 10) {
|
|
835
|
+
updated.chairman.domains = updated.chairman.domains.slice(-10);
|
|
836
|
+
}
|
|
837
|
+
const missionType = classifyMission(mission.goal);
|
|
838
|
+
if (missionType && !updated.chairman.commonMissions.includes(missionType)) {
|
|
839
|
+
updated.chairman.commonMissions.push(missionType);
|
|
840
|
+
}
|
|
841
|
+
if (updated.chairman.commonMissions.length > 8) {
|
|
842
|
+
updated.chairman.commonMissions = updated.chairman.commonMissions.slice(-8);
|
|
843
|
+
}
|
|
844
|
+
updated.company.missionCount++;
|
|
845
|
+
const rolesUsed = [...new Set(mission.workStreams.map((ws) => ws.assignedTo))];
|
|
846
|
+
updated.company.recentMissions.push({
|
|
847
|
+
goal: mission.goal.slice(0, 100),
|
|
848
|
+
date: now.split("T")[0],
|
|
849
|
+
cost: mission.cost,
|
|
850
|
+
duration: mission.duration,
|
|
851
|
+
workStreamCount: mission.workStreams.length,
|
|
852
|
+
rolesUsed,
|
|
853
|
+
success: mission.workStreams.every((ws) => ws.status === "completed")
|
|
854
|
+
});
|
|
855
|
+
if (updated.company.recentMissions.length > 10) {
|
|
856
|
+
updated.company.recentMissions = updated.company.recentMissions.slice(-10);
|
|
857
|
+
}
|
|
858
|
+
return updated;
|
|
859
|
+
}
|
|
860
|
+
function extractDomains(text) {
|
|
861
|
+
const domains = [];
|
|
862
|
+
const lower = text.toLowerCase();
|
|
863
|
+
const domainMap = {
|
|
864
|
+
bitcoin: "crypto",
|
|
865
|
+
btc: "crypto",
|
|
866
|
+
ethereum: "crypto",
|
|
867
|
+
eth: "crypto",
|
|
868
|
+
"\u6BD4\u7279\u5E01": "crypto",
|
|
869
|
+
"\u4EE5\u592A\u574A": "crypto",
|
|
870
|
+
"\u52A0\u5BC6": "crypto",
|
|
871
|
+
defi: "crypto",
|
|
872
|
+
crypto: "crypto",
|
|
873
|
+
trading: "finance",
|
|
874
|
+
investment: "finance",
|
|
875
|
+
revenue: "finance",
|
|
876
|
+
stock: "finance",
|
|
877
|
+
market: "finance",
|
|
878
|
+
ai: "ai/ml",
|
|
879
|
+
"machine learning": "ai/ml",
|
|
880
|
+
llm: "ai/ml",
|
|
881
|
+
agent: "ai/ml",
|
|
882
|
+
"\u4EBA\u5DE5\u667A\u80FD": "ai/ml",
|
|
883
|
+
marketing: "marketing",
|
|
884
|
+
seo: "marketing",
|
|
885
|
+
content: "marketing",
|
|
886
|
+
brand: "marketing",
|
|
887
|
+
"\u8425\u9500": "marketing",
|
|
888
|
+
code: "engineering",
|
|
889
|
+
api: "engineering",
|
|
890
|
+
software: "engineering",
|
|
891
|
+
deploy: "engineering",
|
|
892
|
+
legal: "legal",
|
|
893
|
+
contract: "legal",
|
|
894
|
+
compliance: "legal",
|
|
895
|
+
ecommerce: "ecommerce",
|
|
896
|
+
product: "ecommerce",
|
|
897
|
+
shopify: "ecommerce"
|
|
898
|
+
};
|
|
899
|
+
for (const [keyword, domain] of Object.entries(domainMap)) {
|
|
900
|
+
if (lower.includes(keyword) && !domains.includes(domain)) {
|
|
901
|
+
domains.push(domain);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return domains;
|
|
905
|
+
}
|
|
906
|
+
function classifyMission(goal) {
|
|
907
|
+
const lower = goal.toLowerCase();
|
|
908
|
+
if (lower.includes("analyz") || lower.includes("\u5206\u6790")) return "analysis";
|
|
909
|
+
if (lower.includes("research") || lower.includes("\u7814\u7A76") || lower.includes("\u8C03\u7814")) return "research";
|
|
910
|
+
if (lower.includes("write") || lower.includes("draft") || lower.includes("\u5199")) return "writing";
|
|
911
|
+
if (lower.includes("compare") || lower.includes("\u5BF9\u6BD4") || lower.includes("\u6BD4\u8F83")) return "comparison";
|
|
912
|
+
if (lower.includes("build") || lower.includes("create") || lower.includes("\u5F00\u53D1")) return "building";
|
|
913
|
+
if (lower.includes("plan") || lower.includes("strategy") || lower.includes("\u7B56\u7565")) return "strategy";
|
|
914
|
+
if (lower.includes("price") || lower.includes("cost") || lower.includes("\u4EF7\u683C")) return "pricing";
|
|
915
|
+
return null;
|
|
916
|
+
}
|
|
917
|
+
var init_memory = __esm({
|
|
918
|
+
"../packages/shared/src/memory.ts"() {
|
|
919
|
+
"use strict";
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
|
|
859
923
|
// ../packages/shared/src/index.ts
|
|
860
924
|
var init_src = __esm({
|
|
861
925
|
"../packages/shared/src/index.ts"() {
|
|
@@ -864,6 +928,106 @@ var init_src = __esm({
|
|
|
864
928
|
init_defaults();
|
|
865
929
|
init_api_paths();
|
|
866
930
|
init_market();
|
|
931
|
+
init_memory();
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
// src/utils.ts
|
|
936
|
+
import { join } from "path";
|
|
937
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
938
|
+
function banner() {
|
|
939
|
+
console.log("");
|
|
940
|
+
console.log(" \u{1F99E} ClawCompany v0.1.0");
|
|
941
|
+
console.log(" Build for OPC. Every human being is a chairman.");
|
|
942
|
+
console.log("");
|
|
943
|
+
}
|
|
944
|
+
function getConfigDir() {
|
|
945
|
+
const dir = join(process.env.HOME ?? "~", ".clawcompany");
|
|
946
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
947
|
+
return dir;
|
|
948
|
+
}
|
|
949
|
+
function getConfigPath() {
|
|
950
|
+
return join(getConfigDir(), "config.json");
|
|
951
|
+
}
|
|
952
|
+
function configExists() {
|
|
953
|
+
return existsSync(getConfigPath());
|
|
954
|
+
}
|
|
955
|
+
function readConfig() {
|
|
956
|
+
if (!configExists()) return null;
|
|
957
|
+
try {
|
|
958
|
+
return JSON.parse(readFileSync(getConfigPath(), "utf-8"));
|
|
959
|
+
} catch {
|
|
960
|
+
return null;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
function writeConfig(config) {
|
|
964
|
+
writeFileSync(getConfigPath(), JSON.stringify(config, null, 2));
|
|
965
|
+
}
|
|
966
|
+
function getMemoryPath() {
|
|
967
|
+
return join(getConfigDir(), "memory.json");
|
|
968
|
+
}
|
|
969
|
+
function readMemory() {
|
|
970
|
+
try {
|
|
971
|
+
if (existsSync(getMemoryPath())) {
|
|
972
|
+
return JSON.parse(readFileSync(getMemoryPath(), "utf-8"));
|
|
973
|
+
}
|
|
974
|
+
} catch {
|
|
975
|
+
}
|
|
976
|
+
return createEmptyMemory();
|
|
977
|
+
}
|
|
978
|
+
function writeMemory(memory) {
|
|
979
|
+
writeFileSync(getMemoryPath(), JSON.stringify(memory, null, 2));
|
|
980
|
+
}
|
|
981
|
+
async function apiGet(path, port = 3200) {
|
|
982
|
+
const res = await fetch(`http://localhost:${port}${path}`);
|
|
983
|
+
if (!res.ok) throw new Error(`API error: ${res.status}`);
|
|
984
|
+
return res.json();
|
|
985
|
+
}
|
|
986
|
+
async function apiPost(path, body, port = 3200) {
|
|
987
|
+
const res = await fetch(`http://localhost:${port}${path}`, {
|
|
988
|
+
method: "POST",
|
|
989
|
+
headers: { "Content-Type": "application/json" },
|
|
990
|
+
body: JSON.stringify(body)
|
|
991
|
+
});
|
|
992
|
+
if (!res.ok) {
|
|
993
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
994
|
+
throw new Error(err.error ?? `API error: ${res.status}`);
|
|
995
|
+
}
|
|
996
|
+
return res.json();
|
|
997
|
+
}
|
|
998
|
+
async function validateClawApiKey(key) {
|
|
999
|
+
try {
|
|
1000
|
+
const res = await fetch("https://clawapi.org/api/v1/chat/completions", {
|
|
1001
|
+
method: "POST",
|
|
1002
|
+
headers: {
|
|
1003
|
+
"Authorization": `Bearer ${key}`,
|
|
1004
|
+
"Content-Type": "application/json"
|
|
1005
|
+
},
|
|
1006
|
+
body: JSON.stringify({
|
|
1007
|
+
model: "gpt-oss-20b",
|
|
1008
|
+
messages: [{ role: "user", content: "hi" }],
|
|
1009
|
+
max_tokens: 5
|
|
1010
|
+
})
|
|
1011
|
+
});
|
|
1012
|
+
if (res.status === 401) return { valid: false, error: "Invalid key. Check your key at clawapi.org" };
|
|
1013
|
+
if (!res.ok) return { valid: false, error: `ClawAPI returned ${res.status}. Try again later.` };
|
|
1014
|
+
return { valid: true };
|
|
1015
|
+
} catch (err) {
|
|
1016
|
+
return { valid: false, error: `Cannot reach ClawAPI: ${err.message}. Check your internet connection.` };
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
async function isServerRunning(port = 3200) {
|
|
1020
|
+
try {
|
|
1021
|
+
const res = await fetch(`http://localhost:${port}/api/health`);
|
|
1022
|
+
return res.ok;
|
|
1023
|
+
} catch {
|
|
1024
|
+
return false;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
var init_utils = __esm({
|
|
1028
|
+
"src/utils.ts"() {
|
|
1029
|
+
"use strict";
|
|
1030
|
+
init_src();
|
|
867
1031
|
}
|
|
868
1032
|
});
|
|
869
1033
|
|
|
@@ -1248,8 +1412,7 @@ var OpenAICompatibleProvider = class _OpenAICompatibleProvider {
|
|
|
1248
1412
|
// reasoning model timeout → fast model
|
|
1249
1413
|
"gpt-5.4": "claude-sonnet-4-6",
|
|
1250
1414
|
// GPT timeout → Sonnet
|
|
1251
|
-
"claude-opus-4-6": "claude-sonnet-4-6"
|
|
1252
|
-
"claude-sonnet-4-6": "gemini-3.1-flash-lite"
|
|
1415
|
+
"claude-opus-4-6": "claude-sonnet-4-6"
|
|
1253
1416
|
// Opus timeout → Sonnet
|
|
1254
1417
|
};
|
|
1255
1418
|
async chat(params) {
|
|
@@ -1270,11 +1433,14 @@ var OpenAICompatibleProvider = class _OpenAICompatibleProvider {
|
|
|
1270
1433
|
const url = `${this.baseUrl}/chat/completions`;
|
|
1271
1434
|
const body = {
|
|
1272
1435
|
model: params.model,
|
|
1273
|
-
messages: params.messages,
|
|
1436
|
+
messages: this.toApiMessages(params.messages),
|
|
1274
1437
|
temperature: params.temperature ?? 0.7,
|
|
1275
1438
|
max_tokens: params.maxTokens ?? 4096,
|
|
1276
|
-
stream:
|
|
1439
|
+
stream: true
|
|
1277
1440
|
};
|
|
1441
|
+
if (this.isReasoningModel(params.model)) {
|
|
1442
|
+
delete body.temperature;
|
|
1443
|
+
}
|
|
1278
1444
|
if (params.tools?.length) {
|
|
1279
1445
|
body.tools = params.tools;
|
|
1280
1446
|
}
|
|
@@ -1294,25 +1460,88 @@ var OpenAICompatibleProvider = class _OpenAICompatibleProvider {
|
|
|
1294
1460
|
this.id
|
|
1295
1461
|
);
|
|
1296
1462
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1463
|
+
let content = "";
|
|
1464
|
+
let model = params.model;
|
|
1465
|
+
let finishReason = "stop";
|
|
1466
|
+
let promptTokens = 0;
|
|
1467
|
+
let completionTokens = 0;
|
|
1468
|
+
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
1469
|
+
const reader = response.body.getReader();
|
|
1470
|
+
const decoder = new TextDecoder();
|
|
1471
|
+
let buffer = "";
|
|
1472
|
+
while (true) {
|
|
1473
|
+
const { done, value } = await reader.read();
|
|
1474
|
+
if (done) break;
|
|
1475
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1476
|
+
const lines = buffer.split("\n");
|
|
1477
|
+
buffer = lines.pop() ?? "";
|
|
1478
|
+
for (const line of lines) {
|
|
1479
|
+
if (!line.startsWith("data: ") || line === "data: [DONE]") continue;
|
|
1480
|
+
try {
|
|
1481
|
+
const chunk = JSON.parse(line.slice(6));
|
|
1482
|
+
const delta = chunk.choices?.[0]?.delta;
|
|
1483
|
+
if (delta?.content) content += delta.content;
|
|
1484
|
+
if (chunk.model) model = chunk.model;
|
|
1485
|
+
const fr = chunk.choices?.[0]?.finish_reason;
|
|
1486
|
+
if (fr) finishReason = fr;
|
|
1487
|
+
if (delta?.tool_calls) {
|
|
1488
|
+
for (const tc of delta.tool_calls) {
|
|
1489
|
+
const idx = tc.index ?? 0;
|
|
1490
|
+
if (!toolCallBuffers.has(idx)) {
|
|
1491
|
+
toolCallBuffers.set(idx, { id: tc.id ?? `call_${idx}`, name: "", args: "" });
|
|
1492
|
+
}
|
|
1493
|
+
const buf = toolCallBuffers.get(idx);
|
|
1494
|
+
if (tc.id) buf.id = tc.id;
|
|
1495
|
+
if (tc.function?.name) buf.name = tc.function.name;
|
|
1496
|
+
if (tc.function?.arguments) buf.args += tc.function.arguments;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
if (chunk.usage) {
|
|
1500
|
+
promptTokens = chunk.usage.prompt_tokens ?? 0;
|
|
1501
|
+
completionTokens = chunk.usage.completion_tokens ?? 0;
|
|
1502
|
+
}
|
|
1503
|
+
} catch {
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
const toolCalls = [];
|
|
1508
|
+
for (const [, buf] of [...toolCallBuffers.entries()].sort((a, b) => a[0] - b[0])) {
|
|
1509
|
+
toolCalls.push({ id: buf.id, type: "function", function: { name: buf.name, arguments: buf.args } });
|
|
1510
|
+
}
|
|
1299
1511
|
return {
|
|
1300
|
-
content
|
|
1301
|
-
model
|
|
1512
|
+
content,
|
|
1513
|
+
model,
|
|
1302
1514
|
provider: this.id,
|
|
1303
1515
|
usage: {
|
|
1304
|
-
inputTokens:
|
|
1305
|
-
outputTokens:
|
|
1306
|
-
cost: calculateCost(
|
|
1307
|
-
params.model,
|
|
1308
|
-
data.usage?.prompt_tokens ?? 0,
|
|
1309
|
-
data.usage?.completion_tokens ?? 0
|
|
1310
|
-
)
|
|
1516
|
+
inputTokens: promptTokens,
|
|
1517
|
+
outputTokens: completionTokens,
|
|
1518
|
+
cost: calculateCost(params.model, promptTokens, completionTokens)
|
|
1311
1519
|
},
|
|
1312
|
-
toolCalls:
|
|
1313
|
-
finishReason
|
|
1520
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
1521
|
+
finishReason
|
|
1314
1522
|
};
|
|
1315
1523
|
}
|
|
1524
|
+
/** Convert internal message format to OpenAI API format */
|
|
1525
|
+
toApiMessages(messages) {
|
|
1526
|
+
return messages.map((msg) => {
|
|
1527
|
+
const out = {
|
|
1528
|
+
role: msg.role,
|
|
1529
|
+
content: msg.content
|
|
1530
|
+
};
|
|
1531
|
+
if (msg.toolCalls) {
|
|
1532
|
+
out.tool_calls = msg.toolCalls;
|
|
1533
|
+
if (!out.content) out.content = null;
|
|
1534
|
+
}
|
|
1535
|
+
if (msg.role === "tool" && msg.toolCallId) {
|
|
1536
|
+
out.tool_call_id = msg.toolCallId;
|
|
1537
|
+
}
|
|
1538
|
+
if (msg.name) out.name = msg.name;
|
|
1539
|
+
return out;
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
isReasoningModel(model) {
|
|
1543
|
+
return /^(o1|o3|gpt-5-mini)/.test(model);
|
|
1544
|
+
}
|
|
1316
1545
|
async listModels() {
|
|
1317
1546
|
if (Array.isArray(this.config.models)) {
|
|
1318
1547
|
return this.config.models;
|
|
@@ -1588,6 +1817,10 @@ var ToolExecutor = class {
|
|
|
1588
1817
|
return this.execHttp(args);
|
|
1589
1818
|
case "code_interpreter":
|
|
1590
1819
|
return this.execCode(args);
|
|
1820
|
+
case "web_fetch":
|
|
1821
|
+
return this.execWebFetch(args);
|
|
1822
|
+
case "web_search":
|
|
1823
|
+
return this.execWebSearch(args);
|
|
1591
1824
|
default:
|
|
1592
1825
|
return `Unknown tool: ${toolName}`;
|
|
1593
1826
|
}
|
|
@@ -1648,6 +1881,88 @@ ${text.slice(0, 5e3)}`;
|
|
|
1648
1881
|
}
|
|
1649
1882
|
return `Unsupported language: ${language}`;
|
|
1650
1883
|
}
|
|
1884
|
+
async execWebFetch(args) {
|
|
1885
|
+
const { url, maxLength } = args;
|
|
1886
|
+
const limit = maxLength ?? 8e3;
|
|
1887
|
+
try {
|
|
1888
|
+
const response = await fetch(url, {
|
|
1889
|
+
headers: {
|
|
1890
|
+
"User-Agent": "ClawCompany/1.0 (AI Agent)",
|
|
1891
|
+
"Accept": "text/html,application/xhtml+xml,text/plain,application/json"
|
|
1892
|
+
},
|
|
1893
|
+
redirect: "follow",
|
|
1894
|
+
signal: AbortSignal.timeout(15e3)
|
|
1895
|
+
});
|
|
1896
|
+
if (!response.ok) {
|
|
1897
|
+
return `Error: HTTP ${response.status} ${response.statusText}`;
|
|
1898
|
+
}
|
|
1899
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1900
|
+
const raw = await response.text();
|
|
1901
|
+
if (contentType.includes("application/json")) {
|
|
1902
|
+
return raw.slice(0, limit);
|
|
1903
|
+
}
|
|
1904
|
+
if (contentType.includes("text/html")) {
|
|
1905
|
+
const text = raw.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<nav[^>]*>[\s\S]*?<\/nav>/gi, "").replace(/<footer[^>]*>[\s\S]*?<\/footer>/gi, "").replace(/<header[^>]*>[\s\S]*?<\/header>/gi, "").replace(/<[^>]+>/g, " ").replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/\s+/g, " ").trim();
|
|
1906
|
+
return text.slice(0, limit);
|
|
1907
|
+
}
|
|
1908
|
+
return raw.slice(0, limit);
|
|
1909
|
+
} catch (err) {
|
|
1910
|
+
if (err.name === "TimeoutError") return "Error: Request timed out (15s)";
|
|
1911
|
+
return `Error: ${err.message}`;
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
async execWebSearch(args) {
|
|
1915
|
+
const { query, maxResults } = args;
|
|
1916
|
+
const limit = Math.min(maxResults ?? 5, 10);
|
|
1917
|
+
try {
|
|
1918
|
+
const encoded = encodeURIComponent(query);
|
|
1919
|
+
const response = await fetch(`https://html.duckduckgo.com/html/?q=${encoded}`, {
|
|
1920
|
+
headers: {
|
|
1921
|
+
"User-Agent": "ClawCompany/1.0 (AI Agent)"
|
|
1922
|
+
},
|
|
1923
|
+
signal: AbortSignal.timeout(1e4)
|
|
1924
|
+
});
|
|
1925
|
+
if (!response.ok) {
|
|
1926
|
+
return `Error: Search failed with HTTP ${response.status}`;
|
|
1927
|
+
}
|
|
1928
|
+
const html = await response.text();
|
|
1929
|
+
const results = [];
|
|
1930
|
+
const resultBlocks = html.split('class="result__body"');
|
|
1931
|
+
for (let i = 1; i < resultBlocks.length && results.length < limit; i++) {
|
|
1932
|
+
const block = resultBlocks[i];
|
|
1933
|
+
const titleMatch = block.match(/class="result__a"[^>]*>([^<]+)</);
|
|
1934
|
+
const title = titleMatch?.[1]?.trim() ?? "";
|
|
1935
|
+
const urlMatch = block.match(/href="\/\/duckduckgo\.com\/l\/\?[^"]*uddg=([^&"]+)/);
|
|
1936
|
+
const url = urlMatch?.[1] ? decodeURIComponent(urlMatch[1]) : "";
|
|
1937
|
+
const snippetMatch = block.match(/class="result__snippet"[^>]*>([\s\S]*?)<\/a>/);
|
|
1938
|
+
const snippet = snippetMatch?.[1]?.replace(/<[^>]+>/g, "")?.replace(/\s+/g, " ")?.trim() ?? "";
|
|
1939
|
+
if (title && url) {
|
|
1940
|
+
results.push({ title, url, snippet });
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
if (results.length === 0) {
|
|
1944
|
+
return `No results found for "${query}"`;
|
|
1945
|
+
}
|
|
1946
|
+
let output = `Search results for "${query}":
|
|
1947
|
+
|
|
1948
|
+
`;
|
|
1949
|
+
for (let i = 0; i < results.length; i++) {
|
|
1950
|
+
output += `${i + 1}. ${results[i].title}
|
|
1951
|
+
`;
|
|
1952
|
+
output += ` URL: ${results[i].url}
|
|
1953
|
+
`;
|
|
1954
|
+
if (results[i].snippet) {
|
|
1955
|
+
output += ` ${results[i].snippet}
|
|
1956
|
+
`;
|
|
1957
|
+
}
|
|
1958
|
+
output += "\n";
|
|
1959
|
+
}
|
|
1960
|
+
return output;
|
|
1961
|
+
} catch (err) {
|
|
1962
|
+
if (err.name === "TimeoutError") return "Error: Search timed out (10s)";
|
|
1963
|
+
return `Error: ${err.message}`;
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1651
1966
|
};
|
|
1652
1967
|
|
|
1653
1968
|
// ../packages/tools/src/index.ts
|
|
@@ -1714,6 +2029,36 @@ var BUILTIN_TOOLS = {
|
|
|
1714
2029
|
required: ["language", "code"]
|
|
1715
2030
|
}
|
|
1716
2031
|
}
|
|
2032
|
+
},
|
|
2033
|
+
web_fetch: {
|
|
2034
|
+
type: "function",
|
|
2035
|
+
function: {
|
|
2036
|
+
name: "web_fetch",
|
|
2037
|
+
description: "Fetch a web page and extract its text content. Use this to read articles, documentation, blog posts, or any public web page. Returns cleaned text without HTML tags.",
|
|
2038
|
+
parameters: {
|
|
2039
|
+
type: "object",
|
|
2040
|
+
properties: {
|
|
2041
|
+
url: { type: "string", description: "URL of the web page to fetch" },
|
|
2042
|
+
maxLength: { type: "number", description: "Max characters to return (default: 8000)" }
|
|
2043
|
+
},
|
|
2044
|
+
required: ["url"]
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
},
|
|
2048
|
+
web_search: {
|
|
2049
|
+
type: "function",
|
|
2050
|
+
function: {
|
|
2051
|
+
name: "web_search",
|
|
2052
|
+
description: "Search the web for current information. Returns a list of results with titles, URLs, and snippets. Use this to find up-to-date facts, news, prices, or research topics.",
|
|
2053
|
+
parameters: {
|
|
2054
|
+
type: "object",
|
|
2055
|
+
properties: {
|
|
2056
|
+
query: { type: "string", description: "Search query" },
|
|
2057
|
+
maxResults: { type: "number", description: "Max results to return (default: 5, max: 10)" }
|
|
2058
|
+
},
|
|
2059
|
+
required: ["query"]
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
1717
2062
|
}
|
|
1718
2063
|
};
|
|
1719
2064
|
function getToolsForRole(toolNames) {
|
|
@@ -1739,7 +2084,7 @@ var AgentExecutor = class {
|
|
|
1739
2084
|
content: this.buildTaskPrompt(task)
|
|
1740
2085
|
}
|
|
1741
2086
|
];
|
|
1742
|
-
const MAX_TURNS =
|
|
2087
|
+
const MAX_TURNS = 15;
|
|
1743
2088
|
for (let turn = 0; turn < MAX_TURNS; turn++) {
|
|
1744
2089
|
const response = await this.router.chatAsRole(
|
|
1745
2090
|
role2.id,
|
|
@@ -1814,6 +2159,11 @@ var TaskOrchestrator = class {
|
|
|
1814
2159
|
this.executor = new AgentExecutor(router, new ToolExecutor());
|
|
1815
2160
|
}
|
|
1816
2161
|
executor;
|
|
2162
|
+
memoryContext = "";
|
|
2163
|
+
/** Set company memory context to inject into all agent prompts */
|
|
2164
|
+
setMemoryContext(ctx) {
|
|
2165
|
+
this.memoryContext = ctx;
|
|
2166
|
+
}
|
|
1817
2167
|
/**
|
|
1818
2168
|
* Phase 2: CEO decomposes mission into work streams.
|
|
1819
2169
|
* Human (Chairman) gives the mission → CEO breaks it down.
|
|
@@ -1832,7 +2182,8 @@ var TaskOrchestrator = class {
|
|
|
1832
2182
|
Priority: ${mission.priority}
|
|
1833
2183
|
${mission.deadline ? `Deadline: ${mission.deadline}` : ""}
|
|
1834
2184
|
${mission.budgetLimit ? `Budget limit: $${mission.budgetLimit}` : ""}
|
|
1835
|
-
|
|
2185
|
+
${this.memoryContext ? `${this.memoryContext}
|
|
2186
|
+
` : ""}
|
|
1836
2187
|
Your team:
|
|
1837
2188
|
${roleList}
|
|
1838
2189
|
|
|
@@ -1951,24 +2302,41 @@ ${truncated}
|
|
|
1951
2302
|
`;
|
|
1952
2303
|
}
|
|
1953
2304
|
}
|
|
1954
|
-
const
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
2305
|
+
const role2 = this.router.getRole(ws.assignTo);
|
|
2306
|
+
if (!role2) throw new Error(`Role "${ws.assignTo}" not found`);
|
|
2307
|
+
const result = await this.executor.execute(role2, {
|
|
2308
|
+
id: ws.id,
|
|
2309
|
+
companyId: "default",
|
|
2310
|
+
missionId: ws.missionId,
|
|
2311
|
+
workStreamId: ws.id,
|
|
2312
|
+
title: ws.title,
|
|
2313
|
+
description: `${ws.description}
|
|
1960
2314
|
|
|
1961
|
-
Complexity: ${ws.estimatedComplexity}${context}
|
|
2315
|
+
Complexity: ${ws.estimatedComplexity}${context}${this.memoryContext ? `
|
|
2316
|
+
${this.memoryContext}` : ""}
|
|
1962
2317
|
|
|
1963
|
-
Today's date is ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
|
|
1964
|
-
|
|
1965
|
-
|
|
2318
|
+
Today's date is ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.`,
|
|
2319
|
+
assignedTo: ws.assignTo,
|
|
2320
|
+
createdBy: "ceo",
|
|
2321
|
+
reportTo: "ceo",
|
|
2322
|
+
status: "in_progress",
|
|
2323
|
+
priority: 1,
|
|
2324
|
+
tokensIn: 0,
|
|
2325
|
+
tokensOut: 0,
|
|
2326
|
+
cost: 0,
|
|
2327
|
+
modelUsed: role2.model,
|
|
2328
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2329
|
+
});
|
|
2330
|
+
if (result.toolCallCount > 0) {
|
|
2331
|
+
console.log(` \u{1F527} ${result.toolCallCount} tool calls executed`);
|
|
2332
|
+
}
|
|
1966
2333
|
return {
|
|
1967
|
-
content:
|
|
1968
|
-
cost:
|
|
1969
|
-
tokensIn:
|
|
1970
|
-
tokensOut:
|
|
1971
|
-
model:
|
|
2334
|
+
content: result.output,
|
|
2335
|
+
cost: result.cost,
|
|
2336
|
+
tokensIn: result.tokensIn,
|
|
2337
|
+
tokensOut: result.tokensOut,
|
|
2338
|
+
model: result.modelUsed,
|
|
2339
|
+
toolCallCount: result.toolCallCount
|
|
1972
2340
|
};
|
|
1973
2341
|
}
|
|
1974
2342
|
topologicalSort(workStreams) {
|
|
@@ -2033,6 +2401,12 @@ async function runInProcess(goal, userConfig) {
|
|
|
2033
2401
|
await registry.loadFromConfig(clawConfig.providers);
|
|
2034
2402
|
const router = new ModelRouter(registry, clawConfig);
|
|
2035
2403
|
const orchestrator = new TaskOrchestrator(router);
|
|
2404
|
+
const memory = readMemory();
|
|
2405
|
+
const memoryCtx = buildMemoryContext(memory);
|
|
2406
|
+
if (memoryCtx) {
|
|
2407
|
+
orchestrator.setMemoryContext(memoryCtx);
|
|
2408
|
+
console.log(" \u{1F9E0} Company memory loaded\n");
|
|
2409
|
+
}
|
|
2036
2410
|
console.log(" Phase 2: CEO decomposing...");
|
|
2037
2411
|
const mission = {
|
|
2038
2412
|
id: `mission-${Date.now()}`,
|
|
@@ -2050,6 +2424,19 @@ async function runInProcess(goal, userConfig) {
|
|
|
2050
2424
|
console.log(" Phase 3-5: Executing...");
|
|
2051
2425
|
const report = await orchestrator.executeMission(mission, workStreams);
|
|
2052
2426
|
console.log(" Phase 6: Delivering to Chairman\n");
|
|
2427
|
+
const updatedMemory = updateMemoryFromMission(memory, {
|
|
2428
|
+
goal,
|
|
2429
|
+
cost: report.totalCost,
|
|
2430
|
+
duration: report.totalTimeSeconds,
|
|
2431
|
+
workStreams: report.workStreams.map((ws) => ({
|
|
2432
|
+
title: ws.title,
|
|
2433
|
+
assignedTo: ws.assignedTo,
|
|
2434
|
+
status: ws.status,
|
|
2435
|
+
output: ws.output
|
|
2436
|
+
}))
|
|
2437
|
+
}, goal);
|
|
2438
|
+
writeMemory(updatedMemory);
|
|
2439
|
+
console.log(" \u{1F9E0} Memory updated\n");
|
|
2053
2440
|
const result = {
|
|
2054
2441
|
status: "completed",
|
|
2055
2442
|
mission: report.mission,
|
package/package.json
CHANGED