@holoscript/holoscript-agent 2.0.0 → 2.0.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/bin/holoscript-agent.cjs +16 -0
- package/dist/brain.js +18 -4
- package/dist/brain.js.map +1 -1
- package/dist/cost-guard.d.ts +17 -2
- package/dist/cost-guard.js +29 -3
- package/dist/cost-guard.js.map +1 -1
- package/dist/holomesh-client.d.ts +50 -1
- package/dist/holomesh-client.js +45 -0
- package/dist/holomesh-client.js.map +1 -1
- package/dist/identity.js +5 -1
- package/dist/identity.js.map +1 -1
- package/dist/index.js +489 -70
- package/dist/index.js.map +1 -1
- package/dist/runner.d.ts +57 -0
- package/dist/runner.js +86 -15
- package/dist/runner.js.map +1 -1
- package/dist/supervisor-config.js +12 -5
- package/dist/supervisor-config.js.map +1 -1
- package/dist/supervisor.js +350 -29
- package/dist/supervisor.js.map +1 -1
- package/dist/types.d.ts +30 -1
- package/package.json +7 -5
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { existsSync } = require('node:fs');
|
|
3
|
+
const { join } = require('node:path');
|
|
4
|
+
const { pathToFileURL } = require('node:url');
|
|
5
|
+
|
|
6
|
+
const target = join(__dirname, '..', 'dist', 'index.js');
|
|
7
|
+
|
|
8
|
+
if (!existsSync(target)) {
|
|
9
|
+
console.error('[holoscript-agent] build output is missing. Run `pnpm --filter @holoscript/holoscript-agent run build` first.');
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
import(pathToFileURL(target).href).catch((error) => {
|
|
14
|
+
console.error(error);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
});
|
package/dist/brain.js
CHANGED
|
@@ -2,15 +2,29 @@
|
|
|
2
2
|
import { readFile } from "fs/promises";
|
|
3
3
|
async function loadBrain(brainPath, scopeTier = "warm") {
|
|
4
4
|
const systemPrompt = await readFile(brainPath, "utf8");
|
|
5
|
-
const { domain, capabilityTags } = extractIdentity(systemPrompt);
|
|
6
|
-
return {
|
|
5
|
+
const { domain, capabilityTags, requires, prefers, avoids } = extractIdentity(systemPrompt);
|
|
6
|
+
return {
|
|
7
|
+
brainPath,
|
|
8
|
+
systemPrompt,
|
|
9
|
+
capabilityTags,
|
|
10
|
+
domain,
|
|
11
|
+
scopeTier,
|
|
12
|
+
requires,
|
|
13
|
+
prefers,
|
|
14
|
+
avoids
|
|
15
|
+
};
|
|
7
16
|
}
|
|
8
17
|
function extractIdentity(brain) {
|
|
9
18
|
const identityBlock = sliceNamedBlock(brain, "identity");
|
|
10
|
-
if (!identityBlock)
|
|
19
|
+
if (!identityBlock) {
|
|
20
|
+
return { domain: "unknown", capabilityTags: [], requires: [], prefers: [], avoids: [] };
|
|
21
|
+
}
|
|
11
22
|
const domain = scalarField(identityBlock, "domain") ?? "unknown";
|
|
12
23
|
const capabilityTags = listField(identityBlock, "capability_tags") ?? [];
|
|
13
|
-
|
|
24
|
+
const requires = listField(identityBlock, "requires") ?? [];
|
|
25
|
+
const prefers = listField(identityBlock, "prefers") ?? [];
|
|
26
|
+
const avoids = listField(identityBlock, "avoids") ?? [];
|
|
27
|
+
return { domain, capabilityTags, requires, prefers, avoids };
|
|
14
28
|
}
|
|
15
29
|
function sliceNamedBlock(src, name) {
|
|
16
30
|
const re = new RegExp(`\\b${name}\\s*:?\\s*\\{`, "g");
|
package/dist/brain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/brain.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { RuntimeBrainConfig } from './types.js';\n\nexport async function loadBrain(\n brainPath: string,\n scopeTier: 'cold' | 'warm' | 'hot' = 'warm'\n): Promise<RuntimeBrainConfig> {\n const systemPrompt = await readFile(brainPath, 'utf8');\n const { domain, capabilityTags } = extractIdentity(systemPrompt);\n return {
|
|
1
|
+
{"version":3,"sources":["../src/brain.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { RuntimeBrainConfig } from './types.js';\n\nexport async function loadBrain(\n brainPath: string,\n scopeTier: 'cold' | 'warm' | 'hot' = 'warm'\n): Promise<RuntimeBrainConfig> {\n const systemPrompt = await readFile(brainPath, 'utf8');\n const { domain, capabilityTags, requires, prefers, avoids } = extractIdentity(systemPrompt);\n return {\n brainPath,\n systemPrompt,\n capabilityTags,\n domain,\n scopeTier,\n requires,\n prefers,\n avoids,\n };\n}\n\nfunction extractIdentity(brain: string): {\n domain: string;\n capabilityTags: string[];\n requires: string[];\n prefers: string[];\n avoids: string[];\n} {\n const identityBlock = sliceNamedBlock(brain, 'identity');\n if (!identityBlock) {\n // No identity block — open routing (backward-compatible default).\n // Brains without explicit requires/prefers/avoids match any provider.\n return { domain: 'unknown', capabilityTags: [], requires: [], prefers: [], avoids: [] };\n }\n const domain = scalarField(identityBlock, 'domain') ?? 'unknown';\n const capabilityTags = listField(identityBlock, 'capability_tags') ?? [];\n // Universal+segregated routing fields (founder ruling 2026-05-06): brains\n // declare capability requirements as data; router matches against the\n // provider's `capabilities` manifest at session start. Empty (omitted) =\n // open routing — preserves today's behavior for unmigrated brains.\n const requires = listField(identityBlock, 'requires') ?? [];\n const prefers = listField(identityBlock, 'prefers') ?? [];\n const avoids = listField(identityBlock, 'avoids') ?? [];\n return { domain, capabilityTags, requires, prefers, avoids };\n}\n\nfunction sliceNamedBlock(src: string, name: string): string | undefined {\n // Accept both `identity {` and `identity: {` — brain compositions in\n // .ai-ecosystem use both forms (lean-theorist + antigravity-hot use the\n // colon variant; security-auditor + others use the bare form). Without\n // both-form tolerance the colon-form brains parse to empty\n // capability_tags, breaking task scoring entirely (silent claim-blackhole\n // observed 2026-04-25 on W01 H200 lean-theorist).\n const re = new RegExp(`\\\\b${name}\\\\s*:?\\\\s*\\\\{`, 'g');\n const match = re.exec(src);\n if (!match) return undefined;\n const headerEnd = match.index + match[0].length; // position just past the `{`\n let depth = 1;\n for (let i = headerEnd; i < src.length; i++) {\n const ch = src[i];\n if (ch === '{') depth++;\n else if (ch === '}') {\n depth--;\n if (depth === 0) return src.slice(headerEnd, i);\n }\n }\n return undefined;\n}\n\nfunction scalarField(block: string, key: string): string | undefined {\n const idx = block.indexOf(`${key}:`);\n if (idx < 0) return undefined;\n const after = block.slice(idx + key.length + 1).trimStart();\n if (after.startsWith('\"')) {\n const end = after.indexOf('\"', 1);\n if (end > 0) return after.slice(1, end);\n }\n const eol = after.indexOf('\\n');\n return after.slice(0, eol < 0 ? undefined : eol).trim();\n}\n\nfunction listField(block: string, key: string): string[] | undefined {\n const idx = block.indexOf(`${key}:`);\n if (idx < 0) return undefined;\n const after = block.slice(idx + key.length + 1).trimStart();\n if (!after.startsWith('[')) return undefined;\n let depth = 0;\n let end = -1;\n for (let i = 0; i < after.length; i++) {\n if (after[i] === '[') depth++;\n else if (after[i] === ']') {\n depth--;\n if (depth === 0) {\n end = i;\n break;\n }\n }\n }\n if (end < 0) return undefined;\n const inner = after.slice(1, end);\n return inner\n .split(',')\n .map((s) => s.trim().replace(/^[\"']|[\"']$/g, ''))\n .filter((s) => s.length > 0);\n}\n"],"mappings":";AAAA,SAAS,gBAAgB;AAGzB,eAAsB,UACpB,WACA,YAAqC,QACR;AAC7B,QAAM,eAAe,MAAM,SAAS,WAAW,MAAM;AACrD,QAAM,EAAE,QAAQ,gBAAgB,UAAU,SAAS,OAAO,IAAI,gBAAgB,YAAY;AAC1F,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,OAMvB;AACA,QAAM,gBAAgB,gBAAgB,OAAO,UAAU;AACvD,MAAI,CAAC,eAAe;AAGlB,WAAO,EAAE,QAAQ,WAAW,gBAAgB,CAAC,GAAG,UAAU,CAAC,GAAG,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE;AAAA,EACxF;AACA,QAAM,SAAS,YAAY,eAAe,QAAQ,KAAK;AACvD,QAAM,iBAAiB,UAAU,eAAe,iBAAiB,KAAK,CAAC;AAKvE,QAAM,WAAW,UAAU,eAAe,UAAU,KAAK,CAAC;AAC1D,QAAM,UAAU,UAAU,eAAe,SAAS,KAAK,CAAC;AACxD,QAAM,SAAS,UAAU,eAAe,QAAQ,KAAK,CAAC;AACtD,SAAO,EAAE,QAAQ,gBAAgB,UAAU,SAAS,OAAO;AAC7D;AAEA,SAAS,gBAAgB,KAAa,MAAkC;AAOtE,QAAM,KAAK,IAAI,OAAO,MAAM,IAAI,iBAAiB,GAAG;AACpD,QAAM,QAAQ,GAAG,KAAK,GAAG;AACzB,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,YAAY,MAAM,QAAQ,MAAM,CAAC,EAAE;AACzC,MAAI,QAAQ;AACZ,WAAS,IAAI,WAAW,IAAI,IAAI,QAAQ,KAAK;AAC3C,UAAM,KAAK,IAAI,CAAC;AAChB,QAAI,OAAO,IAAK;AAAA,aACP,OAAO,KAAK;AACnB;AACA,UAAI,UAAU,EAAG,QAAO,IAAI,MAAM,WAAW,CAAC;AAAA,IAChD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,YAAY,OAAe,KAAiC;AACnE,QAAM,MAAM,MAAM,QAAQ,GAAG,GAAG,GAAG;AACnC,MAAI,MAAM,EAAG,QAAO;AACpB,QAAM,QAAQ,MAAM,MAAM,MAAM,IAAI,SAAS,CAAC,EAAE,UAAU;AAC1D,MAAI,MAAM,WAAW,GAAG,GAAG;AACzB,UAAM,MAAM,MAAM,QAAQ,KAAK,CAAC;AAChC,QAAI,MAAM,EAAG,QAAO,MAAM,MAAM,GAAG,GAAG;AAAA,EACxC;AACA,QAAM,MAAM,MAAM,QAAQ,IAAI;AAC9B,SAAO,MAAM,MAAM,GAAG,MAAM,IAAI,SAAY,GAAG,EAAE,KAAK;AACxD;AAEA,SAAS,UAAU,OAAe,KAAmC;AACnE,QAAM,MAAM,MAAM,QAAQ,GAAG,GAAG,GAAG;AACnC,MAAI,MAAM,EAAG,QAAO;AACpB,QAAM,QAAQ,MAAM,MAAM,MAAM,IAAI,SAAS,CAAC,EAAE,UAAU;AAC1D,MAAI,CAAC,MAAM,WAAW,GAAG,EAAG,QAAO;AACnC,MAAI,QAAQ;AACZ,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,QAAI,MAAM,CAAC,MAAM,IAAK;AAAA,aACb,MAAM,CAAC,MAAM,KAAK;AACzB;AACA,UAAI,UAAU,GAAG;AACf,cAAM;AACN;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,EAAG,QAAO;AACpB,QAAM,QAAQ,MAAM,MAAM,GAAG,GAAG;AAChC,SAAO,MACJ,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,gBAAgB,EAAE,CAAC,EAC/C,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC/B;","names":[]}
|
package/dist/cost-guard.d.ts
CHANGED
|
@@ -16,6 +16,16 @@ declare function defaultAnthropicPricer(model: string, usage: TokenUsage): numbe
|
|
|
16
16
|
* so usage analytics work, but cost-guard never trips on token spend.
|
|
17
17
|
*/
|
|
18
18
|
declare function defaultLocalLlmPricer(_model: string, _usage: TokenUsage): number;
|
|
19
|
+
declare const XAI_PRICING_USD_PER_MTOK: Record<string, {
|
|
20
|
+
input: number;
|
|
21
|
+
output: number;
|
|
22
|
+
}>;
|
|
23
|
+
declare function defaultXAIPricer(model: string, usage: TokenUsage): number;
|
|
24
|
+
declare const OPENROUTER_PRICING_USD_PER_MTOK: Record<string, {
|
|
25
|
+
input: number;
|
|
26
|
+
output: number;
|
|
27
|
+
}>;
|
|
28
|
+
declare function defaultOpenRouterPricer(model: string, usage: TokenUsage): number;
|
|
19
29
|
/**
|
|
20
30
|
* Provider-aware default pricer dispatch. Picks the right pricer by
|
|
21
31
|
* provider so the holoscript-agent runtime works for both Anthropic
|
|
@@ -26,8 +36,13 @@ declare function defaultLocalLlmPricer(_model: string, _usage: TokenUsage): numb
|
|
|
26
36
|
* "No pricing configured for model 'Qwen/Qwen2.5-0.5B-Instruct'" because
|
|
27
37
|
* defaultAnthropicPricer was wired in for ALL providers regardless of
|
|
28
38
|
* which LLM the agent uses.
|
|
39
|
+
*
|
|
40
|
+
* Known gap (separate task): non-Anthropic non-local providers (openai,
|
|
41
|
+
* gemini) still fall through to defaultAnthropicPricer here. xai +
|
|
42
|
+
* openrouter were added 2026-05-06 with explicit dispatch + empty
|
|
43
|
+
* pricing dicts (Lane A — see docs/LLM_CAPABILITIES.md).
|
|
29
44
|
*/
|
|
30
|
-
declare function defaultPricerForProvider(provider: 'anthropic' | 'local-llm' | 'openai' | string): ModelPricer;
|
|
45
|
+
declare function defaultPricerForProvider(provider: 'anthropic' | 'local-llm' | 'openai' | 'xai' | 'openrouter' | string): ModelPricer;
|
|
31
46
|
declare class CostGuard {
|
|
32
47
|
private state;
|
|
33
48
|
private readonly statePath;
|
|
@@ -51,4 +66,4 @@ declare class CostGuard {
|
|
|
51
66
|
private persist;
|
|
52
67
|
}
|
|
53
68
|
|
|
54
|
-
export { ANTHROPIC_PRICING_USD_PER_MTOK, CostGuard, defaultAnthropicPricer, defaultLocalLlmPricer, defaultPricerForProvider };
|
|
69
|
+
export { ANTHROPIC_PRICING_USD_PER_MTOK, CostGuard, OPENROUTER_PRICING_USD_PER_MTOK, XAI_PRICING_USD_PER_MTOK, defaultAnthropicPricer, defaultLocalLlmPricer, defaultOpenRouterPricer, defaultPricerForProvider, defaultXAIPricer };
|
package/dist/cost-guard.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
3
3
|
import { dirname } from "path";
|
|
4
4
|
var ANTHROPIC_PRICING_USD_PER_MTOK = {
|
|
5
|
-
"claude-opus-4-7": { input:
|
|
6
|
-
"claude-opus-4-6": { input:
|
|
5
|
+
"claude-opus-4-7": { input: 5, output: 25 },
|
|
6
|
+
"claude-opus-4-6": { input: 5, output: 25 },
|
|
7
7
|
"claude-sonnet-4-6": { input: 3, output: 15 },
|
|
8
8
|
"claude-haiku-4-5-20251001": { input: 1, output: 5 },
|
|
9
9
|
"claude-haiku-4-5": { input: 1, output: 5 }
|
|
@@ -20,8 +20,30 @@ function defaultAnthropicPricer(model, usage) {
|
|
|
20
20
|
function defaultLocalLlmPricer(_model, _usage) {
|
|
21
21
|
return 0;
|
|
22
22
|
}
|
|
23
|
+
var XAI_PRICING_USD_PER_MTOK = {};
|
|
24
|
+
function defaultXAIPricer(model, usage) {
|
|
25
|
+
const price = XAI_PRICING_USD_PER_MTOK[model];
|
|
26
|
+
if (!price) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`No xAI pricing configured for model "${model}" \u2014 populate XAI_PRICING_USD_PER_MTOK (see /research task_1778109552044_qed8 in docs/LLM_CAPABILITIES.md) or pass a custom pricer`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return (usage.promptTokens * price.input + usage.completionTokens * price.output) / 1e6;
|
|
32
|
+
}
|
|
33
|
+
var OPENROUTER_PRICING_USD_PER_MTOK = {};
|
|
34
|
+
function defaultOpenRouterPricer(model, usage) {
|
|
35
|
+
const price = OPENROUTER_PRICING_USD_PER_MTOK[model];
|
|
36
|
+
if (!price) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`No OpenRouter pricing configured for model "${model}" \u2014 populate OPENROUTER_PRICING_USD_PER_MTOK or pass a custom pricer`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return (usage.promptTokens * price.input + usage.completionTokens * price.output) / 1e6;
|
|
42
|
+
}
|
|
23
43
|
function defaultPricerForProvider(provider) {
|
|
24
44
|
if (provider === "local-llm" || provider === "mock") return defaultLocalLlmPricer;
|
|
45
|
+
if (provider === "xai") return defaultXAIPricer;
|
|
46
|
+
if (provider === "openrouter") return defaultOpenRouterPricer;
|
|
25
47
|
return defaultAnthropicPricer;
|
|
26
48
|
}
|
|
27
49
|
var CostGuard = class {
|
|
@@ -85,8 +107,12 @@ function todayUtc() {
|
|
|
85
107
|
export {
|
|
86
108
|
ANTHROPIC_PRICING_USD_PER_MTOK,
|
|
87
109
|
CostGuard,
|
|
110
|
+
OPENROUTER_PRICING_USD_PER_MTOK,
|
|
111
|
+
XAI_PRICING_USD_PER_MTOK,
|
|
88
112
|
defaultAnthropicPricer,
|
|
89
113
|
defaultLocalLlmPricer,
|
|
90
|
-
|
|
114
|
+
defaultOpenRouterPricer,
|
|
115
|
+
defaultPricerForProvider,
|
|
116
|
+
defaultXAIPricer
|
|
91
117
|
};
|
|
92
118
|
//# sourceMappingURL=cost-guard.js.map
|
package/dist/cost-guard.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cost-guard.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { TokenUsage } from '@holoscript/llm-provider';\nimport type { CostState, ModelPricer } from './types.js';\n\nexport const ANTHROPIC_PRICING_USD_PER_MTOK: Record<string, { input: number; output: number }> = {\n 'claude-opus-4-7': { input:
|
|
1
|
+
{"version":3,"sources":["../src/cost-guard.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { TokenUsage } from '@holoscript/llm-provider';\nimport type { CostState, ModelPricer } from './types.js';\n\nexport const ANTHROPIC_PRICING_USD_PER_MTOK: Record<string, { input: number; output: number }> = {\n 'claude-opus-4-7': { input: 5, output: 25 },\n 'claude-opus-4-6': { input: 5, output: 25 },\n 'claude-sonnet-4-6': { input: 3, output: 15 },\n 'claude-haiku-4-5-20251001': { input: 1, output: 5 },\n 'claude-haiku-4-5': { input: 1, output: 5 },\n};\n\nexport function defaultAnthropicPricer(model: string, usage: TokenUsage): number {\n const price = ANTHROPIC_PRICING_USD_PER_MTOK[model];\n if (!price) {\n throw new Error(\n `No pricing configured for model \"${model}\" — add to ANTHROPIC_PRICING_USD_PER_MTOK or pass a custom pricer`\n );\n }\n return (usage.promptTokens * price.input + usage.completionTokens * price.output) / 1_000_000;\n}\n\n/**\n * Pricer for local-llm providers (vLLM-on-GPU). The compute cost is the\n * Vast.ai (or other GPU) hourly rental, NOT per-token. From the agent's\n * perspective each LLM call has $0 marginal cost — the budget guard for\n * local-llm should track tick count or wall-clock time, not tokens.\n *\n * Returns 0 unconditionally. Token counts are still recorded in CostState\n * so usage analytics work, but cost-guard never trips on token spend.\n */\nexport function defaultLocalLlmPricer(_model: string, _usage: TokenUsage): number {\n return 0;\n}\n\n// xAI / Grok pricing — populated by /research task task_1778109552044_qed8.\n// Empty until verified pricing lands. defaultXAIPricer throws on missing\n// model with a helpful pointer (matches defaultAnthropicPricer behavior).\n// Never paste training-era pricing here — F.014 / W.GOLD.341.\nexport const XAI_PRICING_USD_PER_MTOK: Record<string, { input: number; output: number }> = {};\n\nexport function defaultXAIPricer(model: string, usage: TokenUsage): number {\n const price = XAI_PRICING_USD_PER_MTOK[model];\n if (!price) {\n throw new Error(\n `No xAI pricing configured for model \"${model}\" — populate XAI_PRICING_USD_PER_MTOK ` +\n `(see /research task_1778109552044_qed8 in docs/LLM_CAPABILITIES.md) or pass a custom pricer`\n );\n }\n return (usage.promptTokens * price.input + usage.completionTokens * price.output) / 1_000_000;\n}\n\n// OpenRouter pricing is per-model and varies by upstream — populated lazily.\n// Empty until verified pricing lands.\nexport const OPENROUTER_PRICING_USD_PER_MTOK: Record<string, { input: number; output: number }> =\n {};\n\nexport function defaultOpenRouterPricer(model: string, usage: TokenUsage): number {\n const price = OPENROUTER_PRICING_USD_PER_MTOK[model];\n if (!price) {\n throw new Error(\n `No OpenRouter pricing configured for model \"${model}\" — populate OPENROUTER_PRICING_USD_PER_MTOK ` +\n `or pass a custom pricer`\n );\n }\n return (usage.promptTokens * price.input + usage.completionTokens * price.output) / 1_000_000;\n}\n\n/**\n * Provider-aware default pricer dispatch. Picks the right pricer by\n * provider so the holoscript-agent runtime works for both Anthropic\n * (per-token billing) and local-llm (compute already paid via GPU\n * rental) without a custom pricer at every call site.\n *\n * Refs: 2026-04-26 mw02 boot loop — local-llm workers tick-erroring with\n * \"No pricing configured for model 'Qwen/Qwen2.5-0.5B-Instruct'\" because\n * defaultAnthropicPricer was wired in for ALL providers regardless of\n * which LLM the agent uses.\n *\n * Known gap (separate task): non-Anthropic non-local providers (openai,\n * gemini) still fall through to defaultAnthropicPricer here. xai +\n * openrouter were added 2026-05-06 with explicit dispatch + empty\n * pricing dicts (Lane A — see docs/LLM_CAPABILITIES.md).\n */\nexport function defaultPricerForProvider(\n provider: 'anthropic' | 'local-llm' | 'openai' | 'xai' | 'openrouter' | string\n): ModelPricer {\n if (provider === 'local-llm' || provider === 'mock') return defaultLocalLlmPricer;\n if (provider === 'xai') return defaultXAIPricer;\n if (provider === 'openrouter') return defaultOpenRouterPricer;\n return defaultAnthropicPricer;\n}\n\nexport class CostGuard {\n private state: CostState;\n private readonly statePath: string;\n private readonly dailyBudgetUsd: number;\n private readonly pricer: ModelPricer;\n\n constructor(opts: { statePath: string; dailyBudgetUsd: number; pricer?: ModelPricer }) {\n this.statePath = opts.statePath;\n this.dailyBudgetUsd = opts.dailyBudgetUsd;\n this.pricer = opts.pricer ?? defaultAnthropicPricer;\n this.state = this.loadOrInit();\n }\n\n recordUsage(\n model: string,\n usage: TokenUsage\n ): { costUsd: number; spentUsd: number; remainingUsd: number } {\n this.rolloverIfNewDay();\n const costUsd = this.pricer(model, usage);\n this.state.spentUsd += costUsd;\n this.state.promptTokens += usage.promptTokens;\n this.state.completionTokens += usage.completionTokens;\n this.state.callCount += 1;\n this.persist();\n return {\n costUsd,\n spentUsd: this.state.spentUsd,\n remainingUsd: Math.max(0, this.dailyBudgetUsd - this.state.spentUsd),\n };\n }\n\n isOverBudget(): boolean {\n if (this.dailyBudgetUsd === 0) return false;\n this.rolloverIfNewDay();\n return this.state.spentUsd >= this.dailyBudgetUsd;\n }\n\n getRemainingUsd(): number {\n if (this.dailyBudgetUsd === 0) return Number.POSITIVE_INFINITY;\n this.rolloverIfNewDay();\n return Math.max(0, this.dailyBudgetUsd - this.state.spentUsd);\n }\n\n getState(): Readonly<CostState> {\n this.rolloverIfNewDay();\n return { ...this.state };\n }\n\n private rolloverIfNewDay(): void {\n const today = todayUtc();\n if (this.state.date !== today) {\n this.state = { date: today, spentUsd: 0, promptTokens: 0, completionTokens: 0, callCount: 0 };\n this.persist();\n }\n }\n\n private loadOrInit(): CostState {\n if (existsSync(this.statePath)) {\n const raw = readFileSync(this.statePath, 'utf8');\n const parsed = JSON.parse(raw) as CostState;\n if (parsed.date === todayUtc()) return parsed;\n }\n return { date: todayUtc(), spentUsd: 0, promptTokens: 0, completionTokens: 0, callCount: 0 };\n }\n\n private persist(): void {\n mkdirSync(dirname(this.statePath), { recursive: true });\n writeFileSync(this.statePath, JSON.stringify(this.state, null, 2), 'utf8');\n }\n}\n\nfunction todayUtc(): string {\n return new Date().toISOString().slice(0, 10);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -12,6 +12,19 @@ interface CaelAuditRecord {
|
|
|
12
12
|
trial?: number;
|
|
13
13
|
attack_class?: string;
|
|
14
14
|
defense_state?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Trust-epoch tag for downstream consumers (Paper 25 gate clock,
|
|
17
|
+
* fleet-health drift detector, retroactive corpus filters). Set to
|
|
18
|
+
* `'post-w107'` for any record built after the 2026-04-26 W.107
|
|
19
|
+
* artifact-grounding gate landed (HoloScript commit 4aab897ad). Records
|
|
20
|
+
* without this field — i.e. anything in the audit store before the gate
|
|
21
|
+
* was deployed — are implicitly `'pre-w107-untrusted'`. The mesh-worker-02
|
|
22
|
+
* 27.5h hallucination class (fabricated "100 scenes validated" CAEL
|
|
23
|
+
* records with no actual artifact) all live in the implicit-untrusted
|
|
24
|
+
* cohort. Consumers should filter by `trust_epoch === 'post-w107'`
|
|
25
|
+
* before treating CAEL records as evidence of real work.
|
|
26
|
+
*/
|
|
27
|
+
trust_epoch?: 'post-w107';
|
|
15
28
|
}
|
|
16
29
|
|
|
17
30
|
interface HolomeshClientOptions {
|
|
@@ -20,6 +33,14 @@ interface HolomeshClientOptions {
|
|
|
20
33
|
teamId: string;
|
|
21
34
|
fetchImpl?: typeof fetch;
|
|
22
35
|
}
|
|
36
|
+
interface TeamMessage {
|
|
37
|
+
id: string;
|
|
38
|
+
fromAgentId: string;
|
|
39
|
+
fromAgentName: string;
|
|
40
|
+
content: string;
|
|
41
|
+
messageType: string;
|
|
42
|
+
createdAt: string;
|
|
43
|
+
}
|
|
23
44
|
declare class HolomeshClient {
|
|
24
45
|
private readonly apiBase;
|
|
25
46
|
private readonly bearer;
|
|
@@ -48,6 +69,34 @@ declare class HolomeshClient {
|
|
|
48
69
|
surface: string;
|
|
49
70
|
wallet?: string;
|
|
50
71
|
}>;
|
|
72
|
+
/** Read recent team messages. */
|
|
73
|
+
getTeamMessages(limit?: number): Promise<TeamMessage[]>;
|
|
74
|
+
/** Post a message to the team feed. */
|
|
75
|
+
sendTeamMessage(content: string, messageType?: string): Promise<void>;
|
|
76
|
+
/** Switch team mode. Requires owner or founder role. */
|
|
77
|
+
setTeamMode(mode: string, reason?: string): Promise<{
|
|
78
|
+
mode: string;
|
|
79
|
+
unchanged?: boolean;
|
|
80
|
+
}>;
|
|
81
|
+
/** Update room preferences. Requires config:write permission. */
|
|
82
|
+
patchRoomPrefs(prefs: {
|
|
83
|
+
communicationStyle?: string;
|
|
84
|
+
objective?: string;
|
|
85
|
+
}): Promise<{
|
|
86
|
+
communicationStyle: string;
|
|
87
|
+
objective: string;
|
|
88
|
+
}>;
|
|
89
|
+
/** Update a board task. */
|
|
90
|
+
updateTask(taskId: string, updates: {
|
|
91
|
+
title?: string;
|
|
92
|
+
description?: string;
|
|
93
|
+
priority?: number;
|
|
94
|
+
tags?: string[];
|
|
95
|
+
}): Promise<unknown>;
|
|
96
|
+
/** Delete a board task. */
|
|
97
|
+
deleteTask(taskId: string): Promise<unknown>;
|
|
98
|
+
/** Delegate a board task to another agent. */
|
|
99
|
+
delegateTask(taskId: string, toAgentId: string): Promise<unknown>;
|
|
51
100
|
private req;
|
|
52
101
|
}
|
|
53
102
|
/**
|
|
@@ -60,4 +109,4 @@ declare class HolomeshClient {
|
|
|
60
109
|
declare function deriveSurface(seatName: string | undefined): string;
|
|
61
110
|
declare function pickClaimableTask(tasks: BoardTask[], brainCapabilityTags: string[]): BoardTask | undefined;
|
|
62
111
|
|
|
63
|
-
export { HolomeshClient, type HolomeshClientOptions, deriveSurface, pickClaimableTask };
|
|
112
|
+
export { HolomeshClient, type HolomeshClientOptions, type TeamMessage, deriveSurface, pickClaimableTask };
|
package/dist/holomesh-client.js
CHANGED
|
@@ -61,6 +61,51 @@ var HolomeshClient = class {
|
|
|
61
61
|
wallet: raw.wallet
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
+
// ── Team Message Surface (E4 delegated-authority protocol) ───────────────────
|
|
65
|
+
/** Read recent team messages. */
|
|
66
|
+
async getTeamMessages(limit = 20) {
|
|
67
|
+
const data = await this.req(
|
|
68
|
+
"GET",
|
|
69
|
+
`/team/${this.teamId}/messages?limit=${limit}`
|
|
70
|
+
);
|
|
71
|
+
return data.messages ?? [];
|
|
72
|
+
}
|
|
73
|
+
/** Post a message to the team feed. */
|
|
74
|
+
async sendTeamMessage(content, messageType = "text") {
|
|
75
|
+
await this.req("POST", `/team/${this.teamId}/message`, {
|
|
76
|
+
content,
|
|
77
|
+
type: messageType
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// ── Owner-op API wrappers (E4) ─────────────────────────────────────────────
|
|
81
|
+
/** Switch team mode. Requires owner or founder role. */
|
|
82
|
+
async setTeamMode(mode, reason) {
|
|
83
|
+
return this.req("POST", `/team/${this.teamId}/mode`, { mode, reason });
|
|
84
|
+
}
|
|
85
|
+
/** Update room preferences. Requires config:write permission. */
|
|
86
|
+
async patchRoomPrefs(prefs) {
|
|
87
|
+
return this.req("PATCH", `/team/${this.teamId}/room`, prefs);
|
|
88
|
+
}
|
|
89
|
+
/** Update a board task. */
|
|
90
|
+
async updateTask(taskId, updates) {
|
|
91
|
+
return this.req("PATCH", `/team/${this.teamId}/board/${taskId}`, {
|
|
92
|
+
action: "update",
|
|
93
|
+
...updates
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/** Delete a board task. */
|
|
97
|
+
async deleteTask(taskId) {
|
|
98
|
+
return this.req("PATCH", `/team/${this.teamId}/board/${taskId}`, {
|
|
99
|
+
action: "delete"
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/** Delegate a board task to another agent. */
|
|
103
|
+
async delegateTask(taskId, toAgentId) {
|
|
104
|
+
return this.req("PATCH", `/team/${this.teamId}/board/${taskId}`, {
|
|
105
|
+
action: "delegate",
|
|
106
|
+
toAgentId
|
|
107
|
+
});
|
|
108
|
+
}
|
|
64
109
|
async req(method, path, body) {
|
|
65
110
|
const url = `${this.apiBase}${path}`;
|
|
66
111
|
const res = await this.fetchImpl(url, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/holomesh-client.ts"],"sourcesContent":["import type { BoardTask } from './types.js';\nimport type { CaelAuditRecord } from './cael-builder.js';\n\nexport interface HolomeshClientOptions {\n apiBase: string;\n bearer: string;\n teamId: string;\n fetchImpl?: typeof fetch;\n}\n\nexport class HolomeshClient {\n private readonly apiBase: string;\n private readonly bearer: string;\n private readonly teamId: string;\n private readonly fetchImpl: typeof fetch;\n\n constructor(opts: HolomeshClientOptions) {\n this.apiBase = opts.apiBase.replace(/\\/$/, '');\n this.bearer = opts.bearer;\n this.teamId = opts.teamId;\n this.fetchImpl = opts.fetchImpl ?? fetch;\n }\n\n async heartbeat(payload: { agentName: string; surface: string }): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/presence`, payload);\n }\n\n async getOpenTasks(): Promise<BoardTask[]> {\n const data = await this.req<{ tasks?: BoardTask[]; open?: BoardTask[] }>(\n 'GET',\n `/team/${this.teamId}/board`\n );\n return data.tasks ?? data.open ?? [];\n }\n\n async claim(taskId: string): Promise<BoardTask> {\n return this.req<BoardTask>('PATCH', `/team/${this.teamId}/board/${taskId}`, { action: 'claim' });\n }\n\n async joinTeam(): Promise<{ success: boolean; role?: string; members?: number }> {\n return this.req<{ success: boolean; role?: string; members?: number }>(\n 'POST',\n `/team/${this.teamId}/join`,\n {}\n );\n }\n\n async sendMessageOnTask(taskId: string, body: string): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/message`, {\n to: 'team',\n subject: `task:${taskId}`,\n content: body,\n });\n }\n\n async markDone(taskId: string, summary: string, commitHash?: string): Promise<void> {\n await this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, {\n action: 'done',\n summary,\n commitHash,\n });\n }\n\n // POST CAEL audit records for this agent. Server validator at\n // packages/mcp-server/src/holomesh/routes/core-routes.ts:472-533 requires\n // bearer == handle owner OR founder; the per-surface x402 bearer is the\n // handle owner so this resolves correctly. Records that fail shape\n // validation (layer_hashes != 7 elements, missing tick_iso/operation/\n // fnv1a_chain) are silently dropped server-side, not rejected as a batch.\n async postAuditRecords(handle: string, records: CaelAuditRecord[]): Promise<{ appended: number; rejected: number }> {\n return this.req<{ appended: number; rejected: number }>(\n 'POST',\n `/agent/${encodeURIComponent(handle)}/audit`,\n { records }\n );\n }\n\n async whoAmI(): Promise<{ agentId: string; surface: string; wallet?: string }> {\n // GET /api/holomesh/me returns { agentId, name, wallet, isFounder, teamId, teams, permissions }\n // (see packages/mcp-server/src/holomesh/routes/core-routes.ts §/me handler).\n // It does NOT return a `surface` field — derive it from the seat name on the\n // client side. Seat naming convention (set by the provisioning admin path):\n // claudecode-claude-x402 → claude-code\n // cursor-claude-x402 → claude-cursor\n // gemini-antigravity → gemini-antigravity\n // copilot-vscode → copilot-vscode\n // Founder → unknown (shared key, no surface attribution)\n const raw = await this.req<{\n agentId: string;\n name?: string;\n wallet?: string;\n }>('GET', '/me');\n return {\n agentId: raw.agentId,\n surface: deriveSurface(raw.name),\n wallet: raw.wallet,\n };\n }\n\n private async req<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.apiBase}${path}`;\n // HoloMesh REST auth: server (packages/mcp-server/src/holomesh/auth-utils.ts\n // resolveRequestingAgent) accepts EITHER `Authorization: Bearer <token>`\n // (HTTP-standard, used here) OR `x-mcp-api-key: <token>` (orchestrator\n // convention). Both resolve through the same key-registry / agent-store /\n // env-fallback chain. Bearer is preferred for new code (W.087 vertex B,\n // task_1777073616424_klls).\n const res = await this.fetchImpl(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.bearer}`,\n 'content-type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n throw new Error(`HoloMesh ${method} ${path} ${res.status}: ${txt.slice(0, 300)}`);\n }\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n}\n\n/**\n * Derive a surface tag from a seat name returned by /me. Mirrors the surface\n * detection in scripts/probe-surface-bearers.mjs and hooks/lib/holomesh-env.mjs\n * so a single agent's surface attribution is consistent across read and write\n * paths. Returns 'unknown' when the seat name doesn't encode a surface\n * (e.g. shared-key resolution to \"Founder\").\n */\nexport function deriveSurface(seatName: string | undefined): string {\n if (!seatName) return 'unknown';\n const n = seatName.toLowerCase();\n if (n.startsWith('claudecode')) return 'claude-code';\n if (n.startsWith('cursor')) return 'claude-cursor';\n if (n.startsWith('claudedesktop')) return 'claude-desktop';\n if (n.startsWith('vscode-claude') || n.startsWith('claude-vscode')) return 'claude-vscode';\n if (n.startsWith('gemini')) return 'gemini-antigravity';\n if (n.startsWith('copilot')) return 'copilot-vscode';\n return 'unknown';\n}\n\nexport function pickClaimableTask(\n tasks: BoardTask[],\n brainCapabilityTags: string[]\n): BoardTask | undefined {\n const wanted = new Set(brainCapabilityTags.map((t) => t.toLowerCase()));\n const open = tasks.filter((t) => t.status === 'open' && !t.claimedBy);\n const scored = open\n .map((t) => ({ task: t, score: scoreTask(t, wanted) }))\n .filter((s) => s.score > 0)\n .sort((a, b) => b.score - a.score || priority(a.task) - priority(b.task));\n return scored[0]?.task;\n}\n\nfunction scoreTask(task: BoardTask, wanted: Set<string>): number {\n const tags = (task.tags ?? []).map((t) => t.toLowerCase());\n const text = `${task.title} ${task.description ?? ''}`.toLowerCase();\n let score = 0;\n for (const tag of tags) if (wanted.has(tag)) score += 2;\n for (const w of wanted) if (text.includes(w)) score += 1;\n return score;\n}\n\nfunction priority(t: BoardTask): number {\n if (typeof t.priority === 'number') return t.priority;\n const map: Record<string, number> = { critical: 1, high: 2, medium: 4, low: 6 };\n return map[String(t.priority).toLowerCase()] ?? 5;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/holomesh-client.ts"],"sourcesContent":["import type { BoardTask } from './types.js';\nimport type { CaelAuditRecord } from './cael-builder.js';\n\nexport interface HolomeshClientOptions {\n apiBase: string;\n bearer: string;\n teamId: string;\n fetchImpl?: typeof fetch;\n}\n\nexport interface TeamMessage {\n id: string;\n fromAgentId: string;\n fromAgentName: string;\n content: string;\n messageType: string;\n createdAt: string;\n}\n\nexport class HolomeshClient {\n private readonly apiBase: string;\n private readonly bearer: string;\n private readonly teamId: string;\n private readonly fetchImpl: typeof fetch;\n\n constructor(opts: HolomeshClientOptions) {\n this.apiBase = opts.apiBase.replace(/\\/$/, '');\n this.bearer = opts.bearer;\n this.teamId = opts.teamId;\n this.fetchImpl = opts.fetchImpl ?? fetch;\n }\n\n async heartbeat(payload: { agentName: string; surface: string }): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/presence`, payload);\n }\n\n async getOpenTasks(): Promise<BoardTask[]> {\n const data = await this.req<{ tasks?: BoardTask[]; open?: BoardTask[] }>(\n 'GET',\n `/team/${this.teamId}/board`\n );\n return data.tasks ?? data.open ?? [];\n }\n\n async claim(taskId: string): Promise<BoardTask> {\n return this.req<BoardTask>('PATCH', `/team/${this.teamId}/board/${taskId}`, { action: 'claim' });\n }\n\n async joinTeam(): Promise<{ success: boolean; role?: string; members?: number }> {\n return this.req<{ success: boolean; role?: string; members?: number }>(\n 'POST',\n `/team/${this.teamId}/join`,\n {}\n );\n }\n\n async sendMessageOnTask(taskId: string, body: string): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/message`, {\n to: 'team',\n subject: `task:${taskId}`,\n content: body,\n });\n }\n\n async markDone(taskId: string, summary: string, commitHash?: string): Promise<void> {\n await this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, {\n action: 'done',\n summary,\n commitHash,\n });\n }\n\n // POST CAEL audit records for this agent. Server validator at\n // packages/mcp-server/src/holomesh/routes/core-routes.ts:472-533 requires\n // bearer == handle owner OR founder; the per-surface x402 bearer is the\n // handle owner so this resolves correctly. Records that fail shape\n // validation (layer_hashes != 7 elements, missing tick_iso/operation/\n // fnv1a_chain) are silently dropped server-side, not rejected as a batch.\n async postAuditRecords(handle: string, records: CaelAuditRecord[]): Promise<{ appended: number; rejected: number }> {\n return this.req<{ appended: number; rejected: number }>(\n 'POST',\n `/agent/${encodeURIComponent(handle)}/audit`,\n { records }\n );\n }\n\n async whoAmI(): Promise<{ agentId: string; surface: string; wallet?: string }> {\n // GET /api/holomesh/me returns { agentId, name, wallet, isFounder, teamId, teams, permissions }\n // (see packages/mcp-server/src/holomesh/routes/core-routes.ts §/me handler).\n // It does NOT return a `surface` field — derive it from the seat name on the\n // client side. Seat naming convention (set by the provisioning admin path):\n // claudecode-claude-x402 → claude-code\n // cursor-claude-x402 → claude-cursor\n // gemini-antigravity → gemini-antigravity\n // copilot-vscode → copilot-vscode\n // Founder → unknown (shared key, no surface attribution)\n const raw = await this.req<{\n agentId: string;\n name?: string;\n wallet?: string;\n }>('GET', '/me');\n return {\n agentId: raw.agentId,\n surface: deriveSurface(raw.name),\n wallet: raw.wallet,\n };\n }\n\n // ── Team Message Surface (E4 delegated-authority protocol) ───────────────────\n\n /** Read recent team messages. */\n async getTeamMessages(limit = 20): Promise<TeamMessage[]> {\n const data = await this.req<{ messages?: TeamMessage[]; success?: boolean }>(\n 'GET',\n `/team/${this.teamId}/messages?limit=${limit}`\n );\n return data.messages ?? [];\n }\n\n /** Post a message to the team feed. */\n async sendTeamMessage(content: string, messageType = 'text'): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/message`, {\n content,\n type: messageType,\n });\n }\n\n // ── Owner-op API wrappers (E4) ─────────────────────────────────────────────\n\n /** Switch team mode. Requires owner or founder role. */\n async setTeamMode(mode: string, reason?: string): Promise<{ mode: string; unchanged?: boolean }> {\n return this.req('POST', `/team/${this.teamId}/mode`, { mode, reason });\n }\n\n /** Update room preferences. Requires config:write permission. */\n async patchRoomPrefs(prefs: { communicationStyle?: string; objective?: string }): Promise<{\n communicationStyle: string;\n objective: string;\n }> {\n return this.req('PATCH', `/team/${this.teamId}/room`, prefs);\n }\n\n /** Update a board task. */\n async updateTask(\n taskId: string,\n updates: {\n title?: string;\n description?: string;\n priority?: number;\n tags?: string[];\n }\n ): Promise<unknown> {\n return this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, {\n action: 'update',\n ...updates,\n });\n }\n\n /** Delete a board task. */\n async deleteTask(taskId: string): Promise<unknown> {\n return this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, {\n action: 'delete',\n });\n }\n\n /** Delegate a board task to another agent. */\n async delegateTask(taskId: string, toAgentId: string): Promise<unknown> {\n return this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, {\n action: 'delegate',\n toAgentId,\n });\n }\n\n private async req<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.apiBase}${path}`;\n // HoloMesh REST auth: server (packages/mcp-server/src/holomesh/auth-utils.ts\n // resolveRequestingAgent) accepts EITHER `Authorization: Bearer <token>`\n // (HTTP-standard, used here) OR `x-mcp-api-key: <token>` (orchestrator\n // convention). Both resolve through the same key-registry / agent-store /\n // env-fallback chain. Bearer is preferred for new code (W.087 vertex B,\n // task_1777073616424_klls).\n const res = await this.fetchImpl(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.bearer}`,\n 'content-type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n throw new Error(`HoloMesh ${method} ${path} ${res.status}: ${txt.slice(0, 300)}`);\n }\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n}\n\n/**\n * Derive a surface tag from a seat name returned by /me. Mirrors the surface\n * detection in scripts/probe-surface-bearers.mjs and hooks/lib/holomesh-env.mjs\n * so a single agent's surface attribution is consistent across read and write\n * paths. Returns 'unknown' when the seat name doesn't encode a surface\n * (e.g. shared-key resolution to \"Founder\").\n */\nexport function deriveSurface(seatName: string | undefined): string {\n if (!seatName) return 'unknown';\n const n = seatName.toLowerCase();\n if (n.startsWith('claudecode')) return 'claude-code';\n if (n.startsWith('cursor')) return 'claude-cursor';\n if (n.startsWith('claudedesktop')) return 'claude-desktop';\n if (n.startsWith('vscode-claude') || n.startsWith('claude-vscode')) return 'claude-vscode';\n if (n.startsWith('gemini')) return 'gemini-antigravity';\n if (n.startsWith('copilot')) return 'copilot-vscode';\n return 'unknown';\n}\n\nexport function pickClaimableTask(\n tasks: BoardTask[],\n brainCapabilityTags: string[]\n): BoardTask | undefined {\n const wanted = new Set(brainCapabilityTags.map((t) => t.toLowerCase()));\n const open = tasks.filter((t) => t.status === 'open' && !t.claimedBy);\n const scored = open\n .map((t) => ({ task: t, score: scoreTask(t, wanted) }))\n .filter((s) => s.score > 0)\n .sort((a, b) => b.score - a.score || priority(a.task) - priority(b.task));\n return scored[0]?.task;\n}\n\nfunction scoreTask(task: BoardTask, wanted: Set<string>): number {\n const tags = (task.tags ?? []).map((t) => t.toLowerCase());\n const text = `${task.title} ${task.description ?? ''}`.toLowerCase();\n let score = 0;\n for (const tag of tags) if (wanted.has(tag)) score += 2;\n for (const w of wanted) if (text.includes(w)) score += 1;\n return score;\n}\n\nfunction priority(t: BoardTask): number {\n if (typeof t.priority === 'number') return t.priority;\n const map: Record<string, number> = { critical: 1, high: 2, medium: 4, low: 6 };\n return map[String(t.priority).toLowerCase()] ?? 5;\n}\n"],"mappings":"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","names":[]}
|
package/dist/identity.js
CHANGED
|
@@ -3,6 +3,8 @@ var VALID_PROVIDERS = /* @__PURE__ */ new Set([
|
|
|
3
3
|
"anthropic",
|
|
4
4
|
"openai",
|
|
5
5
|
"gemini",
|
|
6
|
+
"xai",
|
|
7
|
+
"openrouter",
|
|
6
8
|
"mock",
|
|
7
9
|
"bitnet",
|
|
8
10
|
"local-llm"
|
|
@@ -23,7 +25,9 @@ function loadIdentity(env = process.env) {
|
|
|
23
25
|
const budgetRaw = env.HOLOSCRIPT_AGENT_BUDGET_USD_DAY ?? "5";
|
|
24
26
|
const budget = Number(budgetRaw);
|
|
25
27
|
if (!Number.isFinite(budget) || budget < 0) {
|
|
26
|
-
throw new Error(
|
|
28
|
+
throw new Error(
|
|
29
|
+
`HOLOSCRIPT_AGENT_BUDGET_USD_DAY must be >= 0 (0 = unlimited), got ${budgetRaw}`
|
|
30
|
+
);
|
|
27
31
|
}
|
|
28
32
|
return {
|
|
29
33
|
handle,
|
package/dist/identity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/identity.ts"],"sourcesContent":["import type { LLMProviderName } from '@holoscript/llm-provider';\nimport type { AgentIdentity } from './types.js';\n\nconst VALID_PROVIDERS: ReadonlySet<LLMProviderName> = new Set([\n 'anthropic',\n 'openai',\n 'gemini',\n 'mock',\n 'bitnet',\n 'local-llm',\n]);\n\nexport function loadIdentity(env: NodeJS.ProcessEnv = process.env): AgentIdentity {\n const handle = required(env, 'HOLOSCRIPT_AGENT_HANDLE');\n const provider = required(env, 'HOLOSCRIPT_AGENT_PROVIDER');\n if (!VALID_PROVIDERS.has(provider as LLMProviderName)) {\n throw new Error(\n `HOLOSCRIPT_AGENT_PROVIDER=${provider} not in [${[...VALID_PROVIDERS].join(', ')}]`\n );\n }\n const x402Bearer = required(env, 'HOLOSCRIPT_AGENT_X402_BEARER');\n const wallet = required(env, 'HOLOSCRIPT_AGENT_WALLET');\n if (!/^0x[0-9a-fA-F]{40}$/.test(wallet)) {\n throw new Error(`HOLOSCRIPT_AGENT_WALLET is not a 0x-prefixed 40-hex address: ${wallet}`);\n }\n const budgetRaw = env.HOLOSCRIPT_AGENT_BUDGET_USD_DAY ?? '5';\n const budget = Number(budgetRaw);\n if (!Number.isFinite(budget) || budget < 0) {\n throw new Error(`HOLOSCRIPT_AGENT_BUDGET_USD_DAY must be >= 0 (0 = unlimited), got ${budgetRaw}
|
|
1
|
+
{"version":3,"sources":["../src/identity.ts"],"sourcesContent":["import type { LLMProviderName } from '@holoscript/llm-provider';\nimport type { AgentIdentity } from './types.js';\n\nconst VALID_PROVIDERS: ReadonlySet<LLMProviderName> = new Set([\n 'anthropic',\n 'openai',\n 'gemini',\n 'xai',\n 'openrouter',\n 'mock',\n 'bitnet',\n 'local-llm',\n]);\n\nexport function loadIdentity(env: NodeJS.ProcessEnv = process.env): AgentIdentity {\n const handle = required(env, 'HOLOSCRIPT_AGENT_HANDLE');\n const provider = required(env, 'HOLOSCRIPT_AGENT_PROVIDER');\n if (!VALID_PROVIDERS.has(provider as LLMProviderName)) {\n throw new Error(\n `HOLOSCRIPT_AGENT_PROVIDER=${provider} not in [${[...VALID_PROVIDERS].join(', ')}]`\n );\n }\n const x402Bearer = required(env, 'HOLOSCRIPT_AGENT_X402_BEARER');\n const wallet = required(env, 'HOLOSCRIPT_AGENT_WALLET');\n if (!/^0x[0-9a-fA-F]{40}$/.test(wallet)) {\n throw new Error(`HOLOSCRIPT_AGENT_WALLET is not a 0x-prefixed 40-hex address: ${wallet}`);\n }\n const budgetRaw = env.HOLOSCRIPT_AGENT_BUDGET_USD_DAY ?? '5';\n const budget = Number(budgetRaw);\n if (!Number.isFinite(budget) || budget < 0) {\n throw new Error(\n `HOLOSCRIPT_AGENT_BUDGET_USD_DAY must be >= 0 (0 = unlimited), got ${budgetRaw}`\n );\n }\n\n return {\n handle,\n surface: env.HOLOSCRIPT_AGENT_SURFACE ?? handle,\n wallet,\n x402Bearer,\n llmProvider: provider as LLMProviderName,\n llmModel: required(env, 'HOLOSCRIPT_AGENT_MODEL'),\n brainPath: required(env, 'HOLOSCRIPT_AGENT_BRAIN'),\n budgetUsdPerDay: budget,\n teamId: required(env, 'HOLOMESH_TEAM_ID'),\n meshApiBase: env.HOLOMESH_API_BASE ?? 'https://mcp.holoscript.net/api/holomesh',\n };\n}\n\nfunction required(env: NodeJS.ProcessEnv, key: string): string {\n const v = env[key];\n if (!v || v.trim().length === 0) {\n throw new Error(`Missing required env var: ${key}`);\n }\n return v.trim();\n}\n\nexport function identityForLog(id: AgentIdentity): Record<string, string | number> {\n return {\n handle: id.handle,\n surface: id.surface,\n wallet: `${id.wallet.slice(0, 6)}…${id.wallet.slice(-4)}`,\n bearer: `${id.x402Bearer.slice(0, 6)}…`,\n provider: id.llmProvider,\n model: id.llmModel,\n brain: id.brainPath,\n budgetUsdPerDay: id.budgetUsdPerDay,\n };\n}\n"],"mappings":";AAGA,IAAM,kBAAgD,oBAAI,IAAI;AAAA,EAC5D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,aAAa,MAAyB,QAAQ,KAAoB;AAChF,QAAM,SAAS,SAAS,KAAK,yBAAyB;AACtD,QAAM,WAAW,SAAS,KAAK,2BAA2B;AAC1D,MAAI,CAAC,gBAAgB,IAAI,QAA2B,GAAG;AACrD,UAAM,IAAI;AAAA,MACR,6BAA6B,QAAQ,YAAY,CAAC,GAAG,eAAe,EAAE,KAAK,IAAI,CAAC;AAAA,IAClF;AAAA,EACF;AACA,QAAM,aAAa,SAAS,KAAK,8BAA8B;AAC/D,QAAM,SAAS,SAAS,KAAK,yBAAyB;AACtD,MAAI,CAAC,sBAAsB,KAAK,MAAM,GAAG;AACvC,UAAM,IAAI,MAAM,gEAAgE,MAAM,EAAE;AAAA,EAC1F;AACA,QAAM,YAAY,IAAI,mCAAmC;AACzD,QAAM,SAAS,OAAO,SAAS;AAC/B,MAAI,CAAC,OAAO,SAAS,MAAM,KAAK,SAAS,GAAG;AAC1C,UAAM,IAAI;AAAA,MACR,qEAAqE,SAAS;AAAA,IAChF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,SAAS,IAAI,4BAA4B;AAAA,IACzC;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,UAAU,SAAS,KAAK,wBAAwB;AAAA,IAChD,WAAW,SAAS,KAAK,wBAAwB;AAAA,IACjD,iBAAiB;AAAA,IACjB,QAAQ,SAAS,KAAK,kBAAkB;AAAA,IACxC,aAAa,IAAI,qBAAqB;AAAA,EACxC;AACF;AAEA,SAAS,SAAS,KAAwB,KAAqB;AAC7D,QAAM,IAAI,IAAI,GAAG;AACjB,MAAI,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,GAAG;AAC/B,UAAM,IAAI,MAAM,6BAA6B,GAAG,EAAE;AAAA,EACpD;AACA,SAAO,EAAE,KAAK;AAChB;AAEO,SAAS,eAAe,IAAoD;AACjF,SAAO;AAAA,IACL,QAAQ,GAAG;AAAA,IACX,SAAS,GAAG;AAAA,IACZ,QAAQ,GAAG,GAAG,OAAO,MAAM,GAAG,CAAC,CAAC,SAAI,GAAG,OAAO,MAAM,EAAE,CAAC;AAAA,IACvD,QAAQ,GAAG,GAAG,WAAW,MAAM,GAAG,CAAC,CAAC;AAAA,IACpC,UAAU,GAAG;AAAA,IACb,OAAO,GAAG;AAAA,IACV,OAAO,GAAG;AAAA,IACV,iBAAiB,GAAG;AAAA,EACtB;AACF;","names":[]}
|