heyio 4.0.3 → 4.0.4
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/daemon/cli.js +672 -174
- package/dist/daemon/index.js +622 -164
- package/dist/web/assets/{index-Bkx7szi0.js → index-YRIn8uJ2.js} +76 -76
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
package/dist/daemon/cli.js
CHANGED
|
@@ -75,18 +75,15 @@ var init_api = __esm({
|
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
// packages/shared/dist/constants.js
|
|
78
|
-
var APP_NAME, APP_VERSION, API_PORT, API_HOST, DEFAULT_MODEL,
|
|
78
|
+
var APP_NAME, APP_VERSION, API_PORT, API_HOST, DEFAULT_MODEL, SESSION_RESET_THRESHOLD, SCHEDULER_INTERVAL_MS, QA_MAX_REVISIONS, MANDATORY_ROLES, EVENT_NAMES;
|
|
79
79
|
var init_constants = __esm({
|
|
80
80
|
"packages/shared/dist/constants.js"() {
|
|
81
81
|
"use strict";
|
|
82
82
|
APP_NAME = "io";
|
|
83
|
-
APP_VERSION = "4.0.
|
|
83
|
+
APP_VERSION = "4.0.4";
|
|
84
84
|
API_PORT = 7777;
|
|
85
85
|
API_HOST = "0.0.0.0";
|
|
86
|
-
DEFAULT_MODEL = "gpt-
|
|
87
|
-
FAST_MODEL = "gpt-4.1-mini";
|
|
88
|
-
STANDARD_MODEL = "claude-sonnet-4.6";
|
|
89
|
-
PREMIUM_MODEL = "claude-sonnet-4.6";
|
|
86
|
+
DEFAULT_MODEL = "gpt-4o";
|
|
90
87
|
SESSION_RESET_THRESHOLD = 50;
|
|
91
88
|
SCHEDULER_INTERVAL_MS = 6e4;
|
|
92
89
|
QA_MAX_REVISIONS = 3;
|
|
@@ -2067,6 +2064,27 @@ var init_db = __esm({
|
|
|
2067
2064
|
"CREATE INDEX IF NOT EXISTS idx_activity_objective_id ON activity(objective_id)",
|
|
2068
2065
|
"CREATE INDEX IF NOT EXISTS idx_agent_history_agent_id_created_at ON agent_history(agent_id, created_at)"
|
|
2069
2066
|
]
|
|
2067
|
+
},
|
|
2068
|
+
{
|
|
2069
|
+
version: 2,
|
|
2070
|
+
name: "add-model-pricing-and-dual-costs",
|
|
2071
|
+
statements: [
|
|
2072
|
+
`CREATE TABLE IF NOT EXISTS model_pricing (
|
|
2073
|
+
id TEXT PRIMARY KEY,
|
|
2074
|
+
display_name TEXT NOT NULL,
|
|
2075
|
+
premium_multiplier REAL,
|
|
2076
|
+
token_input_multiplier REAL,
|
|
2077
|
+
token_output_multiplier REAL,
|
|
2078
|
+
cached_input_multiplier REAL,
|
|
2079
|
+
tier TEXT NOT NULL,
|
|
2080
|
+
available INTEGER NOT NULL DEFAULT 1,
|
|
2081
|
+
updated_at TEXT NOT NULL
|
|
2082
|
+
)`,
|
|
2083
|
+
"CREATE INDEX IF NOT EXISTS idx_model_pricing_tier ON model_pricing(tier)",
|
|
2084
|
+
"CREATE INDEX IF NOT EXISTS idx_model_pricing_available ON model_pricing(available)",
|
|
2085
|
+
"ALTER TABLE token_usage ADD COLUMN premium_request_cost REAL",
|
|
2086
|
+
"ALTER TABLE token_usage ADD COLUMN token_unit_cost REAL"
|
|
2087
|
+
]
|
|
2070
2088
|
}
|
|
2071
2089
|
];
|
|
2072
2090
|
client = null;
|
|
@@ -11817,8 +11835,8 @@ async function recordUsage(data, db) {
|
|
|
11817
11835
|
createdAt: data.createdAt ?? nowIso()
|
|
11818
11836
|
};
|
|
11819
11837
|
await database.execute({
|
|
11820
|
-
sql: `INSERT INTO token_usage (id, squad_id, agent_id, model, input_tokens, output_tokens, cost, created_at)
|
|
11821
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
11838
|
+
sql: `INSERT INTO token_usage (id, squad_id, agent_id, model, input_tokens, output_tokens, cost, premium_request_cost, token_unit_cost, created_at)
|
|
11839
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
11822
11840
|
args: [
|
|
11823
11841
|
usage.id,
|
|
11824
11842
|
usage.squadId,
|
|
@@ -11827,6 +11845,8 @@ async function recordUsage(data, db) {
|
|
|
11827
11845
|
usage.inputTokens,
|
|
11828
11846
|
usage.outputTokens,
|
|
11829
11847
|
usage.cost,
|
|
11848
|
+
data.premiumRequestCost ?? null,
|
|
11849
|
+
data.tokenUnitCost ?? null,
|
|
11830
11850
|
usage.createdAt
|
|
11831
11851
|
]
|
|
11832
11852
|
});
|
|
@@ -51543,6 +51563,9 @@ function readEnvOverrides() {
|
|
|
51543
51563
|
if (process.env.IO_SESSION_RESET_THRESHOLD !== void 0) {
|
|
51544
51564
|
overrides.sessionResetThreshold = process.env.IO_SESSION_RESET_THRESHOLD;
|
|
51545
51565
|
}
|
|
51566
|
+
if (process.env.IO_PRICING_REFRESH_HOURS !== void 0) {
|
|
51567
|
+
overrides.pricingRefreshHours = process.env.IO_PRICING_REFRESH_HOURS;
|
|
51568
|
+
}
|
|
51546
51569
|
return overrides;
|
|
51547
51570
|
}
|
|
51548
51571
|
function loadConfig() {
|
|
@@ -51569,7 +51592,8 @@ var init_config = __esm({
|
|
|
51569
51592
|
telegramUserId: external_exports.string().trim().min(1).nullable().default(null),
|
|
51570
51593
|
supabaseUrl: external_exports.string().trim().min(1).nullable().default(null),
|
|
51571
51594
|
supabaseAnonKey: external_exports.string().trim().min(1).nullable().default(null),
|
|
51572
|
-
sessionResetThreshold: external_exports.coerce.number().int().positive().default(SESSION_RESET_THRESHOLD)
|
|
51595
|
+
sessionResetThreshold: external_exports.coerce.number().int().positive().default(SESSION_RESET_THRESHOLD),
|
|
51596
|
+
pricingRefreshHours: external_exports.coerce.number().positive().default(24)
|
|
51573
51597
|
});
|
|
51574
51598
|
}
|
|
51575
51599
|
});
|
|
@@ -51650,7 +51674,8 @@ var init_settings = __esm({
|
|
|
51650
51674
|
"telegramUserId",
|
|
51651
51675
|
"supabaseUrl",
|
|
51652
51676
|
"supabaseAnonKey",
|
|
51653
|
-
"sessionResetThreshold"
|
|
51677
|
+
"sessionResetThreshold",
|
|
51678
|
+
"pricingRefreshHours"
|
|
51654
51679
|
];
|
|
51655
51680
|
router5.get("/api/settings", async (_req, res) => {
|
|
51656
51681
|
try {
|
|
@@ -51795,7 +51820,78 @@ function chooseEntryFileName(url2, contentType) {
|
|
|
51795
51820
|
function isMissingFileError2(error51) {
|
|
51796
51821
|
return !!error51 && typeof error51 === "object" && "code" in error51 && error51.code === "ENOENT";
|
|
51797
51822
|
}
|
|
51798
|
-
|
|
51823
|
+
async function discoverSkillsSh(query) {
|
|
51824
|
+
if (!query) return [];
|
|
51825
|
+
const endpoint = `https://skills.sh/api/search?q=${encodeURIComponent(query)}&limit=50`;
|
|
51826
|
+
const response = await fetch(endpoint, { signal: AbortSignal.timeout(1e4) });
|
|
51827
|
+
if (!response.ok) {
|
|
51828
|
+
throw new Error(`skills.sh returned ${response.status}`);
|
|
51829
|
+
}
|
|
51830
|
+
const data = await response.json();
|
|
51831
|
+
const installedSkills = await readInstalledSkills();
|
|
51832
|
+
const installedIds = new Set(installedSkills.map((s) => s.id));
|
|
51833
|
+
return (data.skills ?? []).map((entry) => {
|
|
51834
|
+
const skillUrl = entry.source ? `https://raw.githubusercontent.com/${entry.source}/main/skills/${entry.skillId}/SKILL.md` : "";
|
|
51835
|
+
return {
|
|
51836
|
+
name: entry.name || entry.skillId,
|
|
51837
|
+
title: entry.name || entry.skillId,
|
|
51838
|
+
description: `${entry.source ?? ""}`,
|
|
51839
|
+
url: skillUrl,
|
|
51840
|
+
source: "skillssh",
|
|
51841
|
+
installed: installedIds.has(`skillssh:${normalizeSlug(entry.skillId || entry.name)}`),
|
|
51842
|
+
registrySource: entry.source ?? void 0,
|
|
51843
|
+
skillId: entry.skillId ?? void 0,
|
|
51844
|
+
installs: entry.installs ?? 0
|
|
51845
|
+
};
|
|
51846
|
+
});
|
|
51847
|
+
}
|
|
51848
|
+
async function discoverAwesomeCopilot(query) {
|
|
51849
|
+
const now = Date.now();
|
|
51850
|
+
if (!awesomeCopilotCache || now - awesomeCopilotCache.fetchedAt > AWESOME_COPILOT_CACHE_TTL) {
|
|
51851
|
+
awesomeCopilotCache = { skills: await fetchAwesomeCopilotList(), fetchedAt: now };
|
|
51852
|
+
}
|
|
51853
|
+
const skills = awesomeCopilotCache.skills;
|
|
51854
|
+
if (!query) return skills;
|
|
51855
|
+
const needle = query.toLowerCase();
|
|
51856
|
+
return skills.filter(
|
|
51857
|
+
(s) => s.name.toLowerCase().includes(needle) || s.title.toLowerCase().includes(needle) || s.description.toLowerCase().includes(needle)
|
|
51858
|
+
);
|
|
51859
|
+
}
|
|
51860
|
+
async function fetchAwesomeCopilotList() {
|
|
51861
|
+
const treeUrl = "https://api.github.com/repos/github/awesome-copilot/git/trees/main?recursive=1";
|
|
51862
|
+
const headers = {
|
|
51863
|
+
Accept: "application/vnd.github.v3+json",
|
|
51864
|
+
"User-Agent": "io-daemon"
|
|
51865
|
+
};
|
|
51866
|
+
if (process.env.GITHUB_TOKEN) {
|
|
51867
|
+
headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
|
51868
|
+
}
|
|
51869
|
+
const response = await fetch(treeUrl, { headers, signal: AbortSignal.timeout(15e3) });
|
|
51870
|
+
if (!response.ok) {
|
|
51871
|
+
throw new Error(`GitHub API returned ${response.status}`);
|
|
51872
|
+
}
|
|
51873
|
+
const data = await response.json();
|
|
51874
|
+
const installedSkills = await readInstalledSkills();
|
|
51875
|
+
const installedIds = new Set(installedSkills.map((s) => s.id));
|
|
51876
|
+
const skillEntries = (data.tree ?? []).filter(
|
|
51877
|
+
(entry) => entry.type === "blob" && entry.path.startsWith("skills/") && entry.path.endsWith("/SKILL.md")
|
|
51878
|
+
);
|
|
51879
|
+
return skillEntries.map((entry) => {
|
|
51880
|
+
const parts = entry.path.split("/");
|
|
51881
|
+
const skillName = parts[1] ?? "unknown";
|
|
51882
|
+
const slug = normalizeSlug(skillName);
|
|
51883
|
+
const rawUrl = `https://raw.githubusercontent.com/github/awesome-copilot/main/${entry.path}`;
|
|
51884
|
+
return {
|
|
51885
|
+
name: skillName,
|
|
51886
|
+
title: skillName.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
51887
|
+
description: "From github/awesome-copilot",
|
|
51888
|
+
url: rawUrl,
|
|
51889
|
+
source: "awesome-copilot",
|
|
51890
|
+
installed: installedIds.has(`awesome-copilot:${slug}`)
|
|
51891
|
+
};
|
|
51892
|
+
});
|
|
51893
|
+
}
|
|
51894
|
+
var import_express6, router6, awesomeCopilotCache, AWESOME_COPILOT_CACHE_TTL;
|
|
51799
51895
|
var init_skills = __esm({
|
|
51800
51896
|
"packages/daemon/src/api/routes/skills.ts"() {
|
|
51801
51897
|
"use strict";
|
|
@@ -51844,9 +51940,28 @@ var init_skills = __esm({
|
|
|
51844
51940
|
});
|
|
51845
51941
|
}
|
|
51846
51942
|
});
|
|
51847
|
-
router6.get("/api/skills/discover", async (
|
|
51848
|
-
|
|
51943
|
+
router6.get("/api/skills/discover", async (req, res) => {
|
|
51944
|
+
try {
|
|
51945
|
+
const source = typeof req.query.source === "string" ? req.query.source : "";
|
|
51946
|
+
const query = typeof req.query.q === "string" ? req.query.q.trim() : "";
|
|
51947
|
+
if (source === "skillssh") {
|
|
51948
|
+
const skills = await discoverSkillsSh(query);
|
|
51949
|
+
res.status(200).json(skills);
|
|
51950
|
+
} else if (source === "awesome-copilot") {
|
|
51951
|
+
const skills = await discoverAwesomeCopilot(query);
|
|
51952
|
+
res.status(200).json(skills);
|
|
51953
|
+
} else {
|
|
51954
|
+
res.status(400).json({ error: `Unknown source: ${source}` });
|
|
51955
|
+
}
|
|
51956
|
+
} catch (error51) {
|
|
51957
|
+
res.status(500).json({
|
|
51958
|
+
error: "Failed to discover skills",
|
|
51959
|
+
details: error51 instanceof Error ? error51.message : "Unknown error"
|
|
51960
|
+
});
|
|
51961
|
+
}
|
|
51849
51962
|
});
|
|
51963
|
+
awesomeCopilotCache = null;
|
|
51964
|
+
AWESOME_COPILOT_CACHE_TTL = 60 * 60 * 1e3;
|
|
51850
51965
|
}
|
|
51851
51966
|
});
|
|
51852
51967
|
|
|
@@ -66900,6 +67015,493 @@ var init_logger = __esm({
|
|
|
66900
67015
|
}
|
|
66901
67016
|
});
|
|
66902
67017
|
|
|
67018
|
+
// packages/daemon/src/models/catalog.ts
|
|
67019
|
+
import { execFileSync } from "node:child_process";
|
|
67020
|
+
function resolveGitHubToken() {
|
|
67021
|
+
const envToken = process.env.GITHUB_TOKEN?.trim();
|
|
67022
|
+
if (envToken && envToken.length > 0) {
|
|
67023
|
+
return envToken;
|
|
67024
|
+
}
|
|
67025
|
+
try {
|
|
67026
|
+
const token = execFileSync("gh", ["auth", "token"], {
|
|
67027
|
+
encoding: "utf8",
|
|
67028
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
67029
|
+
}).trim();
|
|
67030
|
+
return token.length > 0 ? token : void 0;
|
|
67031
|
+
} catch {
|
|
67032
|
+
return void 0;
|
|
67033
|
+
}
|
|
67034
|
+
}
|
|
67035
|
+
async function fetchModelCatalog() {
|
|
67036
|
+
const token = resolveGitHubToken();
|
|
67037
|
+
if (!token) {
|
|
67038
|
+
throw new Error("No GitHub token available for model catalog fetch");
|
|
67039
|
+
}
|
|
67040
|
+
const response = await fetch(CATALOG_URL, {
|
|
67041
|
+
headers: {
|
|
67042
|
+
Accept: "application/json",
|
|
67043
|
+
Authorization: `Bearer ${token}`,
|
|
67044
|
+
"X-GitHub-Api-Version": "2024-12-01"
|
|
67045
|
+
}
|
|
67046
|
+
});
|
|
67047
|
+
if (!response.ok) {
|
|
67048
|
+
throw new Error(`Model catalog fetch failed: ${response.status} ${response.statusText}`);
|
|
67049
|
+
}
|
|
67050
|
+
const data = await response.json();
|
|
67051
|
+
if (!Array.isArray(data)) {
|
|
67052
|
+
throw new Error("Model catalog response is not an array");
|
|
67053
|
+
}
|
|
67054
|
+
const models = [];
|
|
67055
|
+
for (const entry of data) {
|
|
67056
|
+
const id = entry.id ?? entry.name;
|
|
67057
|
+
const displayName = entry.friendly_name ?? entry.name ?? id;
|
|
67058
|
+
if (id && typeof id === "string") {
|
|
67059
|
+
models.push({ id, displayName: displayName ?? id });
|
|
67060
|
+
}
|
|
67061
|
+
}
|
|
67062
|
+
return models;
|
|
67063
|
+
}
|
|
67064
|
+
var CATALOG_URL;
|
|
67065
|
+
var init_catalog = __esm({
|
|
67066
|
+
"packages/daemon/src/models/catalog.ts"() {
|
|
67067
|
+
"use strict";
|
|
67068
|
+
CATALOG_URL = "https://models.github.ai/catalog/models";
|
|
67069
|
+
}
|
|
67070
|
+
});
|
|
67071
|
+
|
|
67072
|
+
// packages/daemon/src/models/pricing-scraper.ts
|
|
67073
|
+
async function scrapeTokenUnitPricing() {
|
|
67074
|
+
const html = await fetchPage(TOKEN_UNIT_COSTS_URL);
|
|
67075
|
+
return parseTokenUnitTable(html);
|
|
67076
|
+
}
|
|
67077
|
+
async function scrapePremiumRequestPricing() {
|
|
67078
|
+
const html = await fetchPage(PREMIUM_MULTIPLIERS_URL);
|
|
67079
|
+
return parsePremiumMultiplierTable(html);
|
|
67080
|
+
}
|
|
67081
|
+
async function fetchPage(url2) {
|
|
67082
|
+
const response = await fetch(url2, {
|
|
67083
|
+
headers: {
|
|
67084
|
+
Accept: "text/html",
|
|
67085
|
+
"User-Agent": "IO-Daemon/4.0 (pricing-refresh)"
|
|
67086
|
+
},
|
|
67087
|
+
redirect: "follow"
|
|
67088
|
+
});
|
|
67089
|
+
if (!response.ok) {
|
|
67090
|
+
throw new Error(`Failed to fetch ${url2}: ${response.status} ${response.statusText}`);
|
|
67091
|
+
}
|
|
67092
|
+
return response.text();
|
|
67093
|
+
}
|
|
67094
|
+
function parseTokenUnitTable(html) {
|
|
67095
|
+
const results = [];
|
|
67096
|
+
const tableRowPattern = /<tr[^>]*>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]*)<\/td>\s*<td[^>]*>([^<]+)<\/td>/gi;
|
|
67097
|
+
for (const match of html.matchAll(tableRowPattern)) {
|
|
67098
|
+
const modelName = cleanCellText(match[1]);
|
|
67099
|
+
const inputMultiplier = Number.parseFloat(match[2]);
|
|
67100
|
+
const cachedInput = match[3].trim().toLowerCase();
|
|
67101
|
+
const outputMultiplier = Number.parseFloat(match[4]);
|
|
67102
|
+
if (modelName && !Number.isNaN(inputMultiplier) && !Number.isNaN(outputMultiplier)) {
|
|
67103
|
+
results.push({
|
|
67104
|
+
modelName,
|
|
67105
|
+
inputMultiplier,
|
|
67106
|
+
cachedInputMultiplier: cachedInput === "n/a" || cachedInput === "" ? null : Number.parseFloat(cachedInput) || null,
|
|
67107
|
+
outputMultiplier
|
|
67108
|
+
});
|
|
67109
|
+
}
|
|
67110
|
+
}
|
|
67111
|
+
return results;
|
|
67112
|
+
}
|
|
67113
|
+
function parsePremiumMultiplierTable(html) {
|
|
67114
|
+
const results = [];
|
|
67115
|
+
const tableRowPattern = /<tr[^>]*>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]+)<\/td>\s*<\/tr>/gi;
|
|
67116
|
+
for (const match of html.matchAll(tableRowPattern)) {
|
|
67117
|
+
const modelName = cleanCellText(match[1]);
|
|
67118
|
+
const multiplier = Number.parseFloat(match[2]);
|
|
67119
|
+
if (modelName && !Number.isNaN(multiplier) && multiplier > 0) {
|
|
67120
|
+
results.push({ modelName, multiplier });
|
|
67121
|
+
}
|
|
67122
|
+
}
|
|
67123
|
+
return results;
|
|
67124
|
+
}
|
|
67125
|
+
function cleanCellText(text) {
|
|
67126
|
+
return text.replace(/<[^>]*>/g, "").replace(/&[^;]+;/g, " ").trim();
|
|
67127
|
+
}
|
|
67128
|
+
var TOKEN_UNIT_COSTS_URL, PREMIUM_MULTIPLIERS_URL;
|
|
67129
|
+
var init_pricing_scraper = __esm({
|
|
67130
|
+
"packages/daemon/src/models/pricing-scraper.ts"() {
|
|
67131
|
+
"use strict";
|
|
67132
|
+
TOKEN_UNIT_COSTS_URL = "https://docs.github.com/en/billing/reference/costs-for-github-models";
|
|
67133
|
+
PREMIUM_MULTIPLIERS_URL = "https://docs.github.com/en/copilot/reference/copilot-billing/request-based-billing-legacy/model-multipliers-for-annual-plans";
|
|
67134
|
+
}
|
|
67135
|
+
});
|
|
67136
|
+
|
|
67137
|
+
// packages/daemon/src/models/seed.ts
|
|
67138
|
+
var SEED_MODELS;
|
|
67139
|
+
var init_seed = __esm({
|
|
67140
|
+
"packages/daemon/src/models/seed.ts"() {
|
|
67141
|
+
"use strict";
|
|
67142
|
+
SEED_MODELS = [
|
|
67143
|
+
{
|
|
67144
|
+
id: "gpt-4o-mini",
|
|
67145
|
+
displayName: "OpenAI GPT-4o mini",
|
|
67146
|
+
premiumMultiplier: 0.33,
|
|
67147
|
+
tokenInputMultiplier: 0.015,
|
|
67148
|
+
tokenOutputMultiplier: 0.06,
|
|
67149
|
+
cachedInputMultiplier: 75e-4,
|
|
67150
|
+
tier: "trivial",
|
|
67151
|
+
available: true
|
|
67152
|
+
},
|
|
67153
|
+
{
|
|
67154
|
+
id: "gpt-4o",
|
|
67155
|
+
displayName: "OpenAI GPT-4o",
|
|
67156
|
+
premiumMultiplier: 0.33,
|
|
67157
|
+
tokenInputMultiplier: 0.25,
|
|
67158
|
+
tokenOutputMultiplier: 1,
|
|
67159
|
+
cachedInputMultiplier: 0.125,
|
|
67160
|
+
tier: "trivial",
|
|
67161
|
+
available: true
|
|
67162
|
+
},
|
|
67163
|
+
{
|
|
67164
|
+
id: "gpt-5-mini",
|
|
67165
|
+
displayName: "GPT-5 mini",
|
|
67166
|
+
premiumMultiplier: 0.33,
|
|
67167
|
+
tokenInputMultiplier: null,
|
|
67168
|
+
tokenOutputMultiplier: null,
|
|
67169
|
+
cachedInputMultiplier: null,
|
|
67170
|
+
tier: "trivial",
|
|
67171
|
+
available: true
|
|
67172
|
+
},
|
|
67173
|
+
{
|
|
67174
|
+
id: "claude-sonnet-4",
|
|
67175
|
+
displayName: "Claude Sonnet 4",
|
|
67176
|
+
premiumMultiplier: 6,
|
|
67177
|
+
tokenInputMultiplier: 0.6,
|
|
67178
|
+
tokenOutputMultiplier: 2.4,
|
|
67179
|
+
cachedInputMultiplier: null,
|
|
67180
|
+
tier: "premium",
|
|
67181
|
+
available: true
|
|
67182
|
+
},
|
|
67183
|
+
{
|
|
67184
|
+
id: "claude-haiku-4.5",
|
|
67185
|
+
displayName: "Claude Haiku 4.5",
|
|
67186
|
+
premiumMultiplier: 0.33,
|
|
67187
|
+
tokenInputMultiplier: null,
|
|
67188
|
+
tokenOutputMultiplier: null,
|
|
67189
|
+
cachedInputMultiplier: null,
|
|
67190
|
+
tier: "trivial",
|
|
67191
|
+
available: true
|
|
67192
|
+
},
|
|
67193
|
+
{
|
|
67194
|
+
id: "gemini-2.5-pro",
|
|
67195
|
+
displayName: "Gemini 2.5 Pro",
|
|
67196
|
+
premiumMultiplier: 1,
|
|
67197
|
+
tokenInputMultiplier: null,
|
|
67198
|
+
tokenOutputMultiplier: null,
|
|
67199
|
+
cachedInputMultiplier: null,
|
|
67200
|
+
tier: "fast",
|
|
67201
|
+
available: true
|
|
67202
|
+
},
|
|
67203
|
+
{
|
|
67204
|
+
id: "gpt-5.1",
|
|
67205
|
+
displayName: "GPT-5.1",
|
|
67206
|
+
premiumMultiplier: 3,
|
|
67207
|
+
tokenInputMultiplier: null,
|
|
67208
|
+
tokenOutputMultiplier: null,
|
|
67209
|
+
cachedInputMultiplier: null,
|
|
67210
|
+
tier: "standard",
|
|
67211
|
+
available: true
|
|
67212
|
+
},
|
|
67213
|
+
{
|
|
67214
|
+
id: "gpt-5.2",
|
|
67215
|
+
displayName: "GPT-5.2",
|
|
67216
|
+
premiumMultiplier: 3,
|
|
67217
|
+
tokenInputMultiplier: null,
|
|
67218
|
+
tokenOutputMultiplier: null,
|
|
67219
|
+
cachedInputMultiplier: null,
|
|
67220
|
+
tier: "standard",
|
|
67221
|
+
available: true
|
|
67222
|
+
},
|
|
67223
|
+
{
|
|
67224
|
+
id: "gpt-5.4",
|
|
67225
|
+
displayName: "GPT-5.4",
|
|
67226
|
+
premiumMultiplier: 6,
|
|
67227
|
+
tokenInputMultiplier: null,
|
|
67228
|
+
tokenOutputMultiplier: null,
|
|
67229
|
+
cachedInputMultiplier: null,
|
|
67230
|
+
tier: "premium",
|
|
67231
|
+
available: true
|
|
67232
|
+
},
|
|
67233
|
+
{
|
|
67234
|
+
id: "claude-opus-4.5",
|
|
67235
|
+
displayName: "Claude Opus 4.5",
|
|
67236
|
+
premiumMultiplier: 15,
|
|
67237
|
+
tokenInputMultiplier: null,
|
|
67238
|
+
tokenOutputMultiplier: null,
|
|
67239
|
+
cachedInputMultiplier: null,
|
|
67240
|
+
tier: "premium",
|
|
67241
|
+
available: true
|
|
67242
|
+
},
|
|
67243
|
+
{
|
|
67244
|
+
id: "claude-opus-4.6",
|
|
67245
|
+
displayName: "Claude Opus 4.6",
|
|
67246
|
+
premiumMultiplier: 27,
|
|
67247
|
+
tokenInputMultiplier: null,
|
|
67248
|
+
tokenOutputMultiplier: null,
|
|
67249
|
+
cachedInputMultiplier: null,
|
|
67250
|
+
tier: "ultra",
|
|
67251
|
+
available: true
|
|
67252
|
+
},
|
|
67253
|
+
{
|
|
67254
|
+
id: "claude-opus-4.7",
|
|
67255
|
+
displayName: "Claude Opus 4.7",
|
|
67256
|
+
premiumMultiplier: 27,
|
|
67257
|
+
tokenInputMultiplier: null,
|
|
67258
|
+
tokenOutputMultiplier: null,
|
|
67259
|
+
cachedInputMultiplier: null,
|
|
67260
|
+
tier: "ultra",
|
|
67261
|
+
available: true
|
|
67262
|
+
},
|
|
67263
|
+
{
|
|
67264
|
+
id: "gpt-5.5",
|
|
67265
|
+
displayName: "GPT-5.5",
|
|
67266
|
+
premiumMultiplier: 57,
|
|
67267
|
+
tokenInputMultiplier: null,
|
|
67268
|
+
tokenOutputMultiplier: null,
|
|
67269
|
+
cachedInputMultiplier: null,
|
|
67270
|
+
tier: "ultra",
|
|
67271
|
+
available: true
|
|
67272
|
+
}
|
|
67273
|
+
];
|
|
67274
|
+
}
|
|
67275
|
+
});
|
|
67276
|
+
|
|
67277
|
+
// packages/daemon/src/models/types.ts
|
|
67278
|
+
function computeTierFromMultiplier(premiumMultiplier) {
|
|
67279
|
+
if (premiumMultiplier === null) {
|
|
67280
|
+
return "standard";
|
|
67281
|
+
}
|
|
67282
|
+
for (const [tier, range] of Object.entries(TIER_RANGES)) {
|
|
67283
|
+
if (premiumMultiplier >= range.min && premiumMultiplier <= range.max) {
|
|
67284
|
+
return tier;
|
|
67285
|
+
}
|
|
67286
|
+
}
|
|
67287
|
+
return "ultra";
|
|
67288
|
+
}
|
|
67289
|
+
var TIER_RANGES, TOKEN_UNIT_PRICE;
|
|
67290
|
+
var init_types = __esm({
|
|
67291
|
+
"packages/daemon/src/models/types.ts"() {
|
|
67292
|
+
"use strict";
|
|
67293
|
+
TIER_RANGES = {
|
|
67294
|
+
trivial: { min: 0, max: 0.33 },
|
|
67295
|
+
fast: { min: 0.34, max: 1 },
|
|
67296
|
+
standard: { min: 1.1, max: 5 },
|
|
67297
|
+
premium: { min: 5.1, max: 15 },
|
|
67298
|
+
ultra: { min: 15.1, max: Number.POSITIVE_INFINITY }
|
|
67299
|
+
};
|
|
67300
|
+
TOKEN_UNIT_PRICE = 1e-5;
|
|
67301
|
+
}
|
|
67302
|
+
});
|
|
67303
|
+
|
|
67304
|
+
// packages/daemon/src/models/registry.ts
|
|
67305
|
+
function normalizeModelName(name) {
|
|
67306
|
+
return name.toLowerCase().replace(/^openai\s+/i, "").replace(/\s+/g, "-").replace(/[^a-z0-9.\-]/g, "").trim();
|
|
67307
|
+
}
|
|
67308
|
+
async function fetchCatalogIntoMap(modelMap, result, logger) {
|
|
67309
|
+
try {
|
|
67310
|
+
const catalogModels = await fetchModelCatalog();
|
|
67311
|
+
result.catalogFetched = true;
|
|
67312
|
+
for (const m of catalogModels) {
|
|
67313
|
+
const key = normalizeModelName(m.id);
|
|
67314
|
+
modelMap.set(key, { id: m.id, displayName: m.displayName, available: true });
|
|
67315
|
+
}
|
|
67316
|
+
} catch (error51) {
|
|
67317
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
67318
|
+
result.errors.push(`Catalog fetch failed: ${msg}`);
|
|
67319
|
+
logger?.warn(`Model catalog fetch failed: ${msg}`);
|
|
67320
|
+
}
|
|
67321
|
+
}
|
|
67322
|
+
async function scrapeTokenPricingIntoMap(modelMap, result, logger) {
|
|
67323
|
+
try {
|
|
67324
|
+
const tokenPricing = await scrapeTokenUnitPricing();
|
|
67325
|
+
result.tokenPricingScraped = true;
|
|
67326
|
+
for (const tp of tokenPricing) {
|
|
67327
|
+
const key = normalizeModelName(tp.modelName);
|
|
67328
|
+
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
67329
|
+
if (existing) {
|
|
67330
|
+
existing.tokenInputMultiplier = tp.inputMultiplier;
|
|
67331
|
+
existing.tokenOutputMultiplier = tp.outputMultiplier;
|
|
67332
|
+
existing.cachedInputMultiplier = tp.cachedInputMultiplier;
|
|
67333
|
+
} else {
|
|
67334
|
+
modelMap.set(key, {
|
|
67335
|
+
id: key,
|
|
67336
|
+
displayName: tp.modelName,
|
|
67337
|
+
tokenInputMultiplier: tp.inputMultiplier,
|
|
67338
|
+
tokenOutputMultiplier: tp.outputMultiplier,
|
|
67339
|
+
cachedInputMultiplier: tp.cachedInputMultiplier,
|
|
67340
|
+
available: true
|
|
67341
|
+
});
|
|
67342
|
+
}
|
|
67343
|
+
}
|
|
67344
|
+
} catch (error51) {
|
|
67345
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
67346
|
+
result.errors.push(`Token pricing scrape failed: ${msg}`);
|
|
67347
|
+
logger?.warn(`Token pricing scrape failed: ${msg}`);
|
|
67348
|
+
}
|
|
67349
|
+
}
|
|
67350
|
+
async function scrapePremiumPricingIntoMap(modelMap, result, logger) {
|
|
67351
|
+
try {
|
|
67352
|
+
const premiumPricing = await scrapePremiumRequestPricing();
|
|
67353
|
+
result.premiumPricingScraped = true;
|
|
67354
|
+
for (const pp of premiumPricing) {
|
|
67355
|
+
const key = normalizeModelName(pp.modelName);
|
|
67356
|
+
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
67357
|
+
if (existing) {
|
|
67358
|
+
existing.premiumMultiplier = pp.multiplier;
|
|
67359
|
+
} else {
|
|
67360
|
+
modelMap.set(key, {
|
|
67361
|
+
id: key,
|
|
67362
|
+
displayName: pp.modelName,
|
|
67363
|
+
premiumMultiplier: pp.multiplier,
|
|
67364
|
+
available: true
|
|
67365
|
+
});
|
|
67366
|
+
}
|
|
67367
|
+
}
|
|
67368
|
+
} catch (error51) {
|
|
67369
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
67370
|
+
result.errors.push(`Premium pricing scrape failed: ${msg}`);
|
|
67371
|
+
logger?.warn(`Premium pricing scrape failed: ${msg}`);
|
|
67372
|
+
}
|
|
67373
|
+
}
|
|
67374
|
+
async function refreshModelPricing(logger) {
|
|
67375
|
+
const result = {
|
|
67376
|
+
modelsUpdated: 0,
|
|
67377
|
+
catalogFetched: false,
|
|
67378
|
+
tokenPricingScraped: false,
|
|
67379
|
+
premiumPricingScraped: false,
|
|
67380
|
+
errors: []
|
|
67381
|
+
};
|
|
67382
|
+
const modelMap = /* @__PURE__ */ new Map();
|
|
67383
|
+
await fetchCatalogIntoMap(modelMap, result, logger);
|
|
67384
|
+
await scrapeTokenPricingIntoMap(modelMap, result, logger);
|
|
67385
|
+
await scrapePremiumPricingIntoMap(modelMap, result, logger);
|
|
67386
|
+
if (!result.catalogFetched && !result.tokenPricingScraped && !result.premiumPricingScraped) {
|
|
67387
|
+
logger?.warn("All pricing sources failed, using seed data");
|
|
67388
|
+
await seedFromFallback();
|
|
67389
|
+
result.modelsUpdated = SEED_MODELS.length;
|
|
67390
|
+
return result;
|
|
67391
|
+
}
|
|
67392
|
+
const db = await getDatabase();
|
|
67393
|
+
const now = nowIso();
|
|
67394
|
+
for (const model of modelMap.values()) {
|
|
67395
|
+
const tier = computeTierFromMultiplier(model.premiumMultiplier ?? null);
|
|
67396
|
+
await upsertModel(db, {
|
|
67397
|
+
id: model.id,
|
|
67398
|
+
displayName: model.displayName,
|
|
67399
|
+
premiumMultiplier: model.premiumMultiplier ?? null,
|
|
67400
|
+
tokenInputMultiplier: model.tokenInputMultiplier ?? null,
|
|
67401
|
+
tokenOutputMultiplier: model.tokenOutputMultiplier ?? null,
|
|
67402
|
+
cachedInputMultiplier: model.cachedInputMultiplier ?? null,
|
|
67403
|
+
tier,
|
|
67404
|
+
available: model.available ?? true,
|
|
67405
|
+
updatedAt: now
|
|
67406
|
+
});
|
|
67407
|
+
result.modelsUpdated++;
|
|
67408
|
+
}
|
|
67409
|
+
return result;
|
|
67410
|
+
}
|
|
67411
|
+
async function seedFromFallback() {
|
|
67412
|
+
const db = await getDatabase();
|
|
67413
|
+
const now = nowIso();
|
|
67414
|
+
for (const model of SEED_MODELS) {
|
|
67415
|
+
await upsertModel(db, { ...model, updatedAt: now });
|
|
67416
|
+
}
|
|
67417
|
+
}
|
|
67418
|
+
async function getModelPricing(modelId) {
|
|
67419
|
+
const db = await getDatabase();
|
|
67420
|
+
const result = await db.execute({
|
|
67421
|
+
sql: "SELECT * FROM model_pricing WHERE id = ?",
|
|
67422
|
+
args: [modelId]
|
|
67423
|
+
});
|
|
67424
|
+
if (result.rows.length === 0) {
|
|
67425
|
+
return null;
|
|
67426
|
+
}
|
|
67427
|
+
return rowToModelPricing(result.rows[0]);
|
|
67428
|
+
}
|
|
67429
|
+
function calculateTokenUnitCost(inputTokens, outputTokens, inputMultiplier, outputMultiplier) {
|
|
67430
|
+
if (inputMultiplier === null || outputMultiplier === null) {
|
|
67431
|
+
return 0;
|
|
67432
|
+
}
|
|
67433
|
+
const tokenUnits = inputTokens * inputMultiplier + outputTokens * outputMultiplier;
|
|
67434
|
+
return tokenUnits * TOKEN_UNIT_PRICE;
|
|
67435
|
+
}
|
|
67436
|
+
async function upsertModel(db, model) {
|
|
67437
|
+
await db.execute({
|
|
67438
|
+
sql: `INSERT INTO model_pricing (id, display_name, premium_multiplier, token_input_multiplier, token_output_multiplier, cached_input_multiplier, tier, available, updated_at)
|
|
67439
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
67440
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
67441
|
+
display_name = excluded.display_name,
|
|
67442
|
+
premium_multiplier = COALESCE(excluded.premium_multiplier, model_pricing.premium_multiplier),
|
|
67443
|
+
token_input_multiplier = COALESCE(excluded.token_input_multiplier, model_pricing.token_input_multiplier),
|
|
67444
|
+
token_output_multiplier = COALESCE(excluded.token_output_multiplier, model_pricing.token_output_multiplier),
|
|
67445
|
+
cached_input_multiplier = COALESCE(excluded.cached_input_multiplier, model_pricing.cached_input_multiplier),
|
|
67446
|
+
tier = excluded.tier,
|
|
67447
|
+
available = excluded.available,
|
|
67448
|
+
updated_at = excluded.updated_at`,
|
|
67449
|
+
args: [
|
|
67450
|
+
model.id,
|
|
67451
|
+
model.displayName,
|
|
67452
|
+
model.premiumMultiplier,
|
|
67453
|
+
model.tokenInputMultiplier,
|
|
67454
|
+
model.tokenOutputMultiplier,
|
|
67455
|
+
model.cachedInputMultiplier,
|
|
67456
|
+
model.tier,
|
|
67457
|
+
model.available ? 1 : 0,
|
|
67458
|
+
model.updatedAt
|
|
67459
|
+
]
|
|
67460
|
+
});
|
|
67461
|
+
}
|
|
67462
|
+
function rowToModelPricing(row) {
|
|
67463
|
+
return {
|
|
67464
|
+
id: asString(row.id),
|
|
67465
|
+
displayName: asString(row.display_name),
|
|
67466
|
+
premiumMultiplier: asNullableNumber(row.premium_multiplier),
|
|
67467
|
+
tokenInputMultiplier: asNullableNumber(row.token_input_multiplier),
|
|
67468
|
+
tokenOutputMultiplier: asNullableNumber(row.token_output_multiplier),
|
|
67469
|
+
cachedInputMultiplier: asNullableNumber(row.cached_input_multiplier),
|
|
67470
|
+
tier: asString(row.tier),
|
|
67471
|
+
available: asNumber(row.available) === 1,
|
|
67472
|
+
updatedAt: asString(row.updated_at)
|
|
67473
|
+
};
|
|
67474
|
+
}
|
|
67475
|
+
function findClosestKey(map2, targetKey) {
|
|
67476
|
+
for (const [key, value] of map2) {
|
|
67477
|
+
if (key.includes(targetKey) || targetKey.includes(key)) {
|
|
67478
|
+
return value;
|
|
67479
|
+
}
|
|
67480
|
+
}
|
|
67481
|
+
return void 0;
|
|
67482
|
+
}
|
|
67483
|
+
var init_registry = __esm({
|
|
67484
|
+
"packages/daemon/src/models/registry.ts"() {
|
|
67485
|
+
"use strict";
|
|
67486
|
+
init_db();
|
|
67487
|
+
init_catalog();
|
|
67488
|
+
init_pricing_scraper();
|
|
67489
|
+
init_seed();
|
|
67490
|
+
init_types();
|
|
67491
|
+
}
|
|
67492
|
+
});
|
|
67493
|
+
|
|
67494
|
+
// packages/daemon/src/models/index.ts
|
|
67495
|
+
var init_models = __esm({
|
|
67496
|
+
"packages/daemon/src/models/index.ts"() {
|
|
67497
|
+
"use strict";
|
|
67498
|
+
init_catalog();
|
|
67499
|
+
init_registry();
|
|
67500
|
+
init_seed();
|
|
67501
|
+
init_types();
|
|
67502
|
+
}
|
|
67503
|
+
});
|
|
67504
|
+
|
|
66903
67505
|
// packages/daemon/src/orchestrator/system-prompt.ts
|
|
66904
67506
|
function formatSquadRoster(squads) {
|
|
66905
67507
|
if (squads.length === 0) {
|
|
@@ -67003,148 +67605,8 @@ var init_reset = __esm({
|
|
|
67003
67605
|
}
|
|
67004
67606
|
});
|
|
67005
67607
|
|
|
67006
|
-
// packages/daemon/src/copilot/router.ts
|
|
67007
|
-
function normalizeMessage(message2) {
|
|
67008
|
-
return message2.trim().toLowerCase();
|
|
67009
|
-
}
|
|
67010
|
-
function getWordCount(message2) {
|
|
67011
|
-
const normalized = message2.trim();
|
|
67012
|
-
if (normalized.length === 0) {
|
|
67013
|
-
return 0;
|
|
67014
|
-
}
|
|
67015
|
-
return normalized.split(/\s+/u).length;
|
|
67016
|
-
}
|
|
67017
|
-
function containsAny(message2, keywords) {
|
|
67018
|
-
return keywords.some((keyword) => message2.includes(keyword));
|
|
67019
|
-
}
|
|
67020
|
-
function startsWithSimpleQuestion(message2) {
|
|
67021
|
-
return SIMPLE_QUESTION_PREFIXES.some(
|
|
67022
|
-
(prefix) => message2 === prefix || message2.startsWith(`${prefix} `)
|
|
67023
|
-
);
|
|
67024
|
-
}
|
|
67025
|
-
function classifyMessage(message2) {
|
|
67026
|
-
const normalized = normalizeMessage(message2);
|
|
67027
|
-
const wordCount = getWordCount(normalized);
|
|
67028
|
-
if (normalized.length === 0) {
|
|
67029
|
-
return "fast";
|
|
67030
|
-
}
|
|
67031
|
-
if (containsAny(normalized, PREMIUM_KEYWORDS) || normalized.includes("```") || wordCount >= 80) {
|
|
67032
|
-
return "premium";
|
|
67033
|
-
}
|
|
67034
|
-
if (wordCount <= 20 && (containsAny(normalized, FAST_KEYWORDS) || startsWithSimpleQuestion(normalized) || /^(yes|no|sure|okay|ok|thanks)[!.?]*$/u.test(normalized))) {
|
|
67035
|
-
return "fast";
|
|
67036
|
-
}
|
|
67037
|
-
if (wordCount <= 8 && /^(what|when|where|who)\b/u.test(normalized)) {
|
|
67038
|
-
return "fast";
|
|
67039
|
-
}
|
|
67040
|
-
return "standard";
|
|
67041
|
-
}
|
|
67042
|
-
function getModelForTier(tier) {
|
|
67043
|
-
switch (tier) {
|
|
67044
|
-
case "fast":
|
|
67045
|
-
return FAST_MODEL;
|
|
67046
|
-
case "premium":
|
|
67047
|
-
return PREMIUM_MODEL;
|
|
67048
|
-
default:
|
|
67049
|
-
return STANDARD_MODEL;
|
|
67050
|
-
}
|
|
67051
|
-
}
|
|
67052
|
-
function routeMessage(message2) {
|
|
67053
|
-
const requestedTier = classifyMessage(message2);
|
|
67054
|
-
if (activeTier === null) {
|
|
67055
|
-
activeTier = requestedTier;
|
|
67056
|
-
messagesSinceLastSwitch = 0;
|
|
67057
|
-
return {
|
|
67058
|
-
requestedTier,
|
|
67059
|
-
effectiveTier: activeTier,
|
|
67060
|
-
model: getModelForTier(activeTier),
|
|
67061
|
-
switched: true,
|
|
67062
|
-
cooldownRemaining: MODEL_SWITCH_COOLDOWN_MESSAGES
|
|
67063
|
-
};
|
|
67064
|
-
}
|
|
67065
|
-
if (requestedTier !== activeTier && messagesSinceLastSwitch >= MODEL_SWITCH_COOLDOWN_MESSAGES) {
|
|
67066
|
-
activeTier = requestedTier;
|
|
67067
|
-
messagesSinceLastSwitch = 0;
|
|
67068
|
-
return {
|
|
67069
|
-
requestedTier,
|
|
67070
|
-
effectiveTier: activeTier,
|
|
67071
|
-
model: getModelForTier(activeTier),
|
|
67072
|
-
switched: true,
|
|
67073
|
-
cooldownRemaining: MODEL_SWITCH_COOLDOWN_MESSAGES
|
|
67074
|
-
};
|
|
67075
|
-
}
|
|
67076
|
-
messagesSinceLastSwitch += 1;
|
|
67077
|
-
return {
|
|
67078
|
-
requestedTier,
|
|
67079
|
-
effectiveTier: activeTier,
|
|
67080
|
-
model: getModelForTier(activeTier),
|
|
67081
|
-
switched: false,
|
|
67082
|
-
cooldownRemaining: Math.max(MODEL_SWITCH_COOLDOWN_MESSAGES - messagesSinceLastSwitch, 0)
|
|
67083
|
-
};
|
|
67084
|
-
}
|
|
67085
|
-
var FAST_KEYWORDS, PREMIUM_KEYWORDS, SIMPLE_QUESTION_PREFIXES, MODEL_SWITCH_COOLDOWN_MESSAGES, activeTier, messagesSinceLastSwitch;
|
|
67086
|
-
var init_router = __esm({
|
|
67087
|
-
"packages/daemon/src/copilot/router.ts"() {
|
|
67088
|
-
"use strict";
|
|
67089
|
-
init_dist();
|
|
67090
|
-
FAST_KEYWORDS = [
|
|
67091
|
-
"hi",
|
|
67092
|
-
"hello",
|
|
67093
|
-
"hey",
|
|
67094
|
-
"thanks",
|
|
67095
|
-
"thank you",
|
|
67096
|
-
"status",
|
|
67097
|
-
"list",
|
|
67098
|
-
"show",
|
|
67099
|
-
"ping",
|
|
67100
|
-
"uptime",
|
|
67101
|
-
"what time",
|
|
67102
|
-
"ok",
|
|
67103
|
-
"okay"
|
|
67104
|
-
];
|
|
67105
|
-
PREMIUM_KEYWORDS = [
|
|
67106
|
-
"architecture",
|
|
67107
|
-
"architect",
|
|
67108
|
-
"design",
|
|
67109
|
-
"tradeoff",
|
|
67110
|
-
"trade-off",
|
|
67111
|
-
"plan",
|
|
67112
|
-
"planning",
|
|
67113
|
-
"strategy",
|
|
67114
|
-
"roadmap",
|
|
67115
|
-
"migration",
|
|
67116
|
-
"refactor",
|
|
67117
|
-
"generate",
|
|
67118
|
-
"implement",
|
|
67119
|
-
"build",
|
|
67120
|
-
"codebase",
|
|
67121
|
-
"repository",
|
|
67122
|
-
"system prompt",
|
|
67123
|
-
"multi-step",
|
|
67124
|
-
"complex",
|
|
67125
|
-
"reason",
|
|
67126
|
-
"compare"
|
|
67127
|
-
];
|
|
67128
|
-
SIMPLE_QUESTION_PREFIXES = [
|
|
67129
|
-
"is",
|
|
67130
|
-
"are",
|
|
67131
|
-
"do",
|
|
67132
|
-
"does",
|
|
67133
|
-
"did",
|
|
67134
|
-
"can",
|
|
67135
|
-
"could",
|
|
67136
|
-
"should",
|
|
67137
|
-
"would",
|
|
67138
|
-
"will"
|
|
67139
|
-
];
|
|
67140
|
-
MODEL_SWITCH_COOLDOWN_MESSAGES = 3;
|
|
67141
|
-
activeTier = null;
|
|
67142
|
-
messagesSinceLastSwitch = MODEL_SWITCH_COOLDOWN_MESSAGES;
|
|
67143
|
-
}
|
|
67144
|
-
});
|
|
67145
|
-
|
|
67146
67608
|
// packages/daemon/src/copilot/client.ts
|
|
67147
|
-
import { execFileSync } from "node:child_process";
|
|
67609
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
67148
67610
|
import { mkdirSync as mkdirSync2 } from "node:fs";
|
|
67149
67611
|
import { join as join6 } from "node:path";
|
|
67150
67612
|
import { CopilotClient } from "@github/copilot-sdk";
|
|
@@ -67154,7 +67616,7 @@ function readTokenFromEnvironment() {
|
|
|
67154
67616
|
}
|
|
67155
67617
|
function readTokenFromGhCli() {
|
|
67156
67618
|
try {
|
|
67157
|
-
const token =
|
|
67619
|
+
const token = execFileSync2("gh", ["auth", "token"], {
|
|
67158
67620
|
encoding: "utf8",
|
|
67159
67621
|
stdio: ["ignore", "pipe", "pipe"]
|
|
67160
67622
|
}).trim();
|
|
@@ -67163,7 +67625,7 @@ function readTokenFromGhCli() {
|
|
|
67163
67625
|
return void 0;
|
|
67164
67626
|
}
|
|
67165
67627
|
}
|
|
67166
|
-
function
|
|
67628
|
+
function resolveGitHubToken2() {
|
|
67167
67629
|
return readTokenFromEnvironment() ?? readTokenFromGhCli();
|
|
67168
67630
|
}
|
|
67169
67631
|
function buildClientOptions(token) {
|
|
@@ -67199,7 +67661,7 @@ async function initCopilotClient() {
|
|
|
67199
67661
|
}
|
|
67200
67662
|
copilotClientInitPromise = (async () => {
|
|
67201
67663
|
try {
|
|
67202
|
-
const token =
|
|
67664
|
+
const token = resolveGitHubToken2();
|
|
67203
67665
|
if (token === void 0) {
|
|
67204
67666
|
throw new Error(
|
|
67205
67667
|
`Unable to find a GitHub token for Copilot SDK authentication. ${COPILOT_AUTH_ERROR_HINT}`
|
|
@@ -68115,13 +68577,24 @@ function mergeUsage(target, usage) {
|
|
|
68115
68577
|
}
|
|
68116
68578
|
async function persistUsage(member, usageEvents) {
|
|
68117
68579
|
for (const usage of usageEvents) {
|
|
68580
|
+
const model = usage.model;
|
|
68581
|
+
const pricing = await getModelPricing(model);
|
|
68582
|
+
const premiumRequestCost = pricing?.premiumMultiplier ?? 0;
|
|
68583
|
+
const tokenUnitCost = pricing ? calculateTokenUnitCost(
|
|
68584
|
+
usage.inputTokens ?? 0,
|
|
68585
|
+
usage.outputTokens ?? 0,
|
|
68586
|
+
pricing.tokenInputMultiplier,
|
|
68587
|
+
pricing.tokenOutputMultiplier
|
|
68588
|
+
) : 0;
|
|
68118
68589
|
await recordUsage({
|
|
68119
68590
|
squadId: member.squadId,
|
|
68120
68591
|
agentId: member.id,
|
|
68121
|
-
model
|
|
68592
|
+
model,
|
|
68122
68593
|
inputTokens: usage.inputTokens ?? 0,
|
|
68123
68594
|
outputTokens: usage.outputTokens ?? 0,
|
|
68124
|
-
cost:
|
|
68595
|
+
cost: 0,
|
|
68596
|
+
premiumRequestCost,
|
|
68597
|
+
tokenUnitCost
|
|
68125
68598
|
});
|
|
68126
68599
|
}
|
|
68127
68600
|
}
|
|
@@ -68339,7 +68812,7 @@ async function executeAgentTask(member, task, worktreePath, options2) {
|
|
|
68339
68812
|
client2 = new CopilotClient2({ workingDirectory: worktreePath });
|
|
68340
68813
|
await client2.start();
|
|
68341
68814
|
const session = await client2.createSession({
|
|
68342
|
-
model: member.model ??
|
|
68815
|
+
model: member.model ?? DEFAULT_MODEL,
|
|
68343
68816
|
workingDirectory: worktreePath,
|
|
68344
68817
|
tools,
|
|
68345
68818
|
availableTools: ["custom:*"],
|
|
@@ -68396,6 +68869,7 @@ var init_agent = __esm({
|
|
|
68396
68869
|
"packages/daemon/src/execution/agent.ts"() {
|
|
68397
68870
|
"use strict";
|
|
68398
68871
|
init_dist();
|
|
68872
|
+
init_registry();
|
|
68399
68873
|
init_store2();
|
|
68400
68874
|
init_history();
|
|
68401
68875
|
execAsync2 = promisify2(exec2);
|
|
@@ -68594,7 +69068,7 @@ Return strict JSON in this shape:
|
|
|
68594
69068
|
client2 = new CopilotClient3({ workingDirectory: repoPath });
|
|
68595
69069
|
await client2.start();
|
|
68596
69070
|
const session = await client2.createSession({
|
|
68597
|
-
model:
|
|
69071
|
+
model: DEFAULT_MODEL,
|
|
68598
69072
|
workingDirectory: repoPath,
|
|
68599
69073
|
onPermissionRequest: approveAll3,
|
|
68600
69074
|
systemMessage: {
|
|
@@ -68885,7 +69359,7 @@ Return strict JSON:
|
|
|
68885
69359
|
client2 = new CopilotClient4({ workingDirectory: worktreePath });
|
|
68886
69360
|
await client2.start();
|
|
68887
69361
|
const session = await client2.createSession({
|
|
68888
|
-
model: qaMember.model ??
|
|
69362
|
+
model: qaMember.model ?? DEFAULT_MODEL,
|
|
68889
69363
|
workingDirectory: worktreePath,
|
|
68890
69364
|
onPermissionRequest: approveAll4,
|
|
68891
69365
|
systemMessage: {
|
|
@@ -69017,7 +69491,7 @@ Return strict JSON:
|
|
|
69017
69491
|
client2 = new CopilotClient5();
|
|
69018
69492
|
await client2.start();
|
|
69019
69493
|
const session = await client2.createSession({
|
|
69020
|
-
model: teamLead.model ??
|
|
69494
|
+
model: teamLead.model ?? DEFAULT_MODEL,
|
|
69021
69495
|
onPermissionRequest: approveAll5,
|
|
69022
69496
|
systemMessage: {
|
|
69023
69497
|
content: `${TEAM_LEAD_PROMPT}
|
|
@@ -69507,12 +69981,9 @@ function buildMandatoryRoles() {
|
|
|
69507
69981
|
function modelForRole(role) {
|
|
69508
69982
|
const normalized = slugifyRole(role);
|
|
69509
69983
|
if (normalized === "team-lead") {
|
|
69510
|
-
return
|
|
69984
|
+
return DEFAULT_MODEL;
|
|
69511
69985
|
}
|
|
69512
|
-
|
|
69513
|
-
return STANDARD_MODEL;
|
|
69514
|
-
}
|
|
69515
|
-
return STANDARD_MODEL;
|
|
69986
|
+
return DEFAULT_MODEL;
|
|
69516
69987
|
}
|
|
69517
69988
|
function systemPromptForRole(role, repoContext) {
|
|
69518
69989
|
const normalized = slugifyRole(role);
|
|
@@ -69544,7 +70015,7 @@ ${ROLE_GENERATION_PROMPT}`;
|
|
|
69544
70015
|
client2 = new CopilotClient6();
|
|
69545
70016
|
await client2.start();
|
|
69546
70017
|
const session = await client2.createSession({
|
|
69547
|
-
model:
|
|
70018
|
+
model: DEFAULT_MODEL,
|
|
69548
70019
|
onPermissionRequest: approveAll6,
|
|
69549
70020
|
systemMessage: {
|
|
69550
70021
|
content: ROLE_GENERATION_PROMPT
|
|
@@ -69983,9 +70454,9 @@ var init_orchestrator = __esm({
|
|
|
69983
70454
|
"use strict";
|
|
69984
70455
|
init_dist();
|
|
69985
70456
|
init_reset();
|
|
69986
|
-
init_router();
|
|
69987
70457
|
init_session();
|
|
69988
70458
|
init_logger();
|
|
70459
|
+
init_registry();
|
|
69989
70460
|
init_skills2();
|
|
69990
70461
|
init_store2();
|
|
69991
70462
|
init_episodes();
|
|
@@ -70078,8 +70549,7 @@ var init_orchestrator = __esm({
|
|
|
70078
70549
|
skillsContext,
|
|
70079
70550
|
conversationSummary: [this.latestResetSummary, conversationSummary].filter(Boolean).join("\n\n")
|
|
70080
70551
|
});
|
|
70081
|
-
|
|
70082
|
-
await this.refreshSession(route.model, systemPrompt);
|
|
70552
|
+
await this.refreshSession(this.config.defaultModel, systemPrompt);
|
|
70083
70553
|
const sendResult = await sendMessage(
|
|
70084
70554
|
this.requireActiveSession(),
|
|
70085
70555
|
normalizedMessage,
|
|
@@ -70207,11 +70677,22 @@ var init_orchestrator = __esm({
|
|
|
70207
70677
|
if (usage.inputTokens === 0 && usage.outputTokens === 0) {
|
|
70208
70678
|
return;
|
|
70209
70679
|
}
|
|
70680
|
+
const model = usage.model || this.activeModel || this.config.defaultModel;
|
|
70681
|
+
const pricing = await getModelPricing(model);
|
|
70682
|
+
const premiumRequestCost = pricing?.premiumMultiplier ?? 0;
|
|
70683
|
+
const tokenUnitCost = pricing ? calculateTokenUnitCost(
|
|
70684
|
+
usage.inputTokens,
|
|
70685
|
+
usage.outputTokens,
|
|
70686
|
+
pricing.tokenInputMultiplier,
|
|
70687
|
+
pricing.tokenOutputMultiplier
|
|
70688
|
+
) : 0;
|
|
70210
70689
|
await recordUsage({
|
|
70211
|
-
model
|
|
70690
|
+
model,
|
|
70212
70691
|
inputTokens: usage.inputTokens,
|
|
70213
70692
|
outputTokens: usage.outputTokens,
|
|
70214
|
-
cost: 0
|
|
70693
|
+
cost: 0,
|
|
70694
|
+
premiumRequestCost,
|
|
70695
|
+
tokenUnitCost
|
|
70215
70696
|
});
|
|
70216
70697
|
}
|
|
70217
70698
|
};
|
|
@@ -83818,6 +84299,7 @@ function registerShutdownHandlers(logger, onShutdown) {
|
|
|
83818
84299
|
}
|
|
83819
84300
|
async function main() {
|
|
83820
84301
|
let logger;
|
|
84302
|
+
let pricingRefreshTimer = null;
|
|
83821
84303
|
try {
|
|
83822
84304
|
ensureDataDirectories();
|
|
83823
84305
|
const config2 = loadConfig();
|
|
@@ -83825,6 +84307,12 @@ async function main() {
|
|
|
83825
84307
|
logger.info(`IO Daemon v${APP_VERSION} starting...`);
|
|
83826
84308
|
await initDatabase();
|
|
83827
84309
|
logger.info("Database initialized");
|
|
84310
|
+
const pricingResult = await refreshModelPricing(logger);
|
|
84311
|
+
if (pricingResult.modelsUpdated === 0) {
|
|
84312
|
+
logger.warn("Model pricing refresh returned 0 models, seeding with fallback");
|
|
84313
|
+
await seedFromFallback();
|
|
84314
|
+
}
|
|
84315
|
+
logger.info({ modelsUpdated: pricingResult.modelsUpdated }, "Model pricing initialized");
|
|
83828
84316
|
await scanSkills();
|
|
83829
84317
|
logger.info("Skills scanned");
|
|
83830
84318
|
const orchestrator2 = createOrchestrator(config2, eventBus);
|
|
@@ -83833,12 +84321,21 @@ async function main() {
|
|
|
83833
84321
|
const scheduler = createScheduler(orchestrator2, eventBus);
|
|
83834
84322
|
scheduler.start();
|
|
83835
84323
|
logger.info("Scheduler started");
|
|
84324
|
+
const refreshIntervalMs = config2.pricingRefreshHours * 60 * 60 * 1e3;
|
|
84325
|
+
pricingRefreshTimer = setInterval(() => {
|
|
84326
|
+
void refreshModelPricing(logger).catch((err) => {
|
|
84327
|
+
logger?.warn({ err }, "Periodic model pricing refresh failed");
|
|
84328
|
+
});
|
|
84329
|
+
}, refreshIntervalMs);
|
|
83836
84330
|
setChatOrchestrator(orchestrator2);
|
|
83837
84331
|
const apiServer = createApiServer(config2);
|
|
83838
84332
|
const telegramBot = createTelegramBot(config2, orchestrator2);
|
|
83839
84333
|
telegramBot?.start();
|
|
83840
84334
|
createTelegramNotifier(telegramBot, config2, eventBus);
|
|
83841
84335
|
registerShutdownHandlers(logger, async () => {
|
|
84336
|
+
if (pricingRefreshTimer) {
|
|
84337
|
+
clearInterval(pricingRefreshTimer);
|
|
84338
|
+
}
|
|
83842
84339
|
scheduler.stop();
|
|
83843
84340
|
telegramBot?.stop();
|
|
83844
84341
|
apiServer.server.close();
|
|
@@ -83863,6 +84360,7 @@ var init_index = __esm({
|
|
|
83863
84360
|
init_data_dir();
|
|
83864
84361
|
init_event_bus();
|
|
83865
84362
|
init_logger();
|
|
84363
|
+
init_models();
|
|
83866
84364
|
init_orchestrator2();
|
|
83867
84365
|
init_scheduler();
|
|
83868
84366
|
init_skills2();
|