heyio 4.0.2 → 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 +678 -174
- package/dist/daemon/index.js +628 -164
- package/dist/web/assets/{index-CbptHIYU.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
|
|
|
@@ -59905,6 +60020,12 @@ function createApiServer(config2) {
|
|
|
59905
60020
|
next();
|
|
59906
60021
|
});
|
|
59907
60022
|
app.use(import_express10.default.json({ limit: "1mb" }));
|
|
60023
|
+
app.get("/api/auth/config", (_req, res) => {
|
|
60024
|
+
res.json({
|
|
60025
|
+
supabaseUrl: config2.supabaseUrl ?? null,
|
|
60026
|
+
supabaseAnonKey: config2.supabaseAnonKey ?? null
|
|
60027
|
+
});
|
|
60028
|
+
});
|
|
59908
60029
|
app.use("/api", createAuthMiddleware(config2));
|
|
59909
60030
|
app.use(router2);
|
|
59910
60031
|
app.use(router7);
|
|
@@ -66894,6 +67015,493 @@ var init_logger = __esm({
|
|
|
66894
67015
|
}
|
|
66895
67016
|
});
|
|
66896
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
|
+
|
|
66897
67505
|
// packages/daemon/src/orchestrator/system-prompt.ts
|
|
66898
67506
|
function formatSquadRoster(squads) {
|
|
66899
67507
|
if (squads.length === 0) {
|
|
@@ -66997,148 +67605,8 @@ var init_reset = __esm({
|
|
|
66997
67605
|
}
|
|
66998
67606
|
});
|
|
66999
67607
|
|
|
67000
|
-
// packages/daemon/src/copilot/router.ts
|
|
67001
|
-
function normalizeMessage(message2) {
|
|
67002
|
-
return message2.trim().toLowerCase();
|
|
67003
|
-
}
|
|
67004
|
-
function getWordCount(message2) {
|
|
67005
|
-
const normalized = message2.trim();
|
|
67006
|
-
if (normalized.length === 0) {
|
|
67007
|
-
return 0;
|
|
67008
|
-
}
|
|
67009
|
-
return normalized.split(/\s+/u).length;
|
|
67010
|
-
}
|
|
67011
|
-
function containsAny(message2, keywords) {
|
|
67012
|
-
return keywords.some((keyword) => message2.includes(keyword));
|
|
67013
|
-
}
|
|
67014
|
-
function startsWithSimpleQuestion(message2) {
|
|
67015
|
-
return SIMPLE_QUESTION_PREFIXES.some(
|
|
67016
|
-
(prefix) => message2 === prefix || message2.startsWith(`${prefix} `)
|
|
67017
|
-
);
|
|
67018
|
-
}
|
|
67019
|
-
function classifyMessage(message2) {
|
|
67020
|
-
const normalized = normalizeMessage(message2);
|
|
67021
|
-
const wordCount = getWordCount(normalized);
|
|
67022
|
-
if (normalized.length === 0) {
|
|
67023
|
-
return "fast";
|
|
67024
|
-
}
|
|
67025
|
-
if (containsAny(normalized, PREMIUM_KEYWORDS) || normalized.includes("```") || wordCount >= 80) {
|
|
67026
|
-
return "premium";
|
|
67027
|
-
}
|
|
67028
|
-
if (wordCount <= 20 && (containsAny(normalized, FAST_KEYWORDS) || startsWithSimpleQuestion(normalized) || /^(yes|no|sure|okay|ok|thanks)[!.?]*$/u.test(normalized))) {
|
|
67029
|
-
return "fast";
|
|
67030
|
-
}
|
|
67031
|
-
if (wordCount <= 8 && /^(what|when|where|who)\b/u.test(normalized)) {
|
|
67032
|
-
return "fast";
|
|
67033
|
-
}
|
|
67034
|
-
return "standard";
|
|
67035
|
-
}
|
|
67036
|
-
function getModelForTier(tier) {
|
|
67037
|
-
switch (tier) {
|
|
67038
|
-
case "fast":
|
|
67039
|
-
return FAST_MODEL;
|
|
67040
|
-
case "premium":
|
|
67041
|
-
return PREMIUM_MODEL;
|
|
67042
|
-
default:
|
|
67043
|
-
return STANDARD_MODEL;
|
|
67044
|
-
}
|
|
67045
|
-
}
|
|
67046
|
-
function routeMessage(message2) {
|
|
67047
|
-
const requestedTier = classifyMessage(message2);
|
|
67048
|
-
if (activeTier === null) {
|
|
67049
|
-
activeTier = requestedTier;
|
|
67050
|
-
messagesSinceLastSwitch = 0;
|
|
67051
|
-
return {
|
|
67052
|
-
requestedTier,
|
|
67053
|
-
effectiveTier: activeTier,
|
|
67054
|
-
model: getModelForTier(activeTier),
|
|
67055
|
-
switched: true,
|
|
67056
|
-
cooldownRemaining: MODEL_SWITCH_COOLDOWN_MESSAGES
|
|
67057
|
-
};
|
|
67058
|
-
}
|
|
67059
|
-
if (requestedTier !== activeTier && messagesSinceLastSwitch >= MODEL_SWITCH_COOLDOWN_MESSAGES) {
|
|
67060
|
-
activeTier = requestedTier;
|
|
67061
|
-
messagesSinceLastSwitch = 0;
|
|
67062
|
-
return {
|
|
67063
|
-
requestedTier,
|
|
67064
|
-
effectiveTier: activeTier,
|
|
67065
|
-
model: getModelForTier(activeTier),
|
|
67066
|
-
switched: true,
|
|
67067
|
-
cooldownRemaining: MODEL_SWITCH_COOLDOWN_MESSAGES
|
|
67068
|
-
};
|
|
67069
|
-
}
|
|
67070
|
-
messagesSinceLastSwitch += 1;
|
|
67071
|
-
return {
|
|
67072
|
-
requestedTier,
|
|
67073
|
-
effectiveTier: activeTier,
|
|
67074
|
-
model: getModelForTier(activeTier),
|
|
67075
|
-
switched: false,
|
|
67076
|
-
cooldownRemaining: Math.max(MODEL_SWITCH_COOLDOWN_MESSAGES - messagesSinceLastSwitch, 0)
|
|
67077
|
-
};
|
|
67078
|
-
}
|
|
67079
|
-
var FAST_KEYWORDS, PREMIUM_KEYWORDS, SIMPLE_QUESTION_PREFIXES, MODEL_SWITCH_COOLDOWN_MESSAGES, activeTier, messagesSinceLastSwitch;
|
|
67080
|
-
var init_router = __esm({
|
|
67081
|
-
"packages/daemon/src/copilot/router.ts"() {
|
|
67082
|
-
"use strict";
|
|
67083
|
-
init_dist();
|
|
67084
|
-
FAST_KEYWORDS = [
|
|
67085
|
-
"hi",
|
|
67086
|
-
"hello",
|
|
67087
|
-
"hey",
|
|
67088
|
-
"thanks",
|
|
67089
|
-
"thank you",
|
|
67090
|
-
"status",
|
|
67091
|
-
"list",
|
|
67092
|
-
"show",
|
|
67093
|
-
"ping",
|
|
67094
|
-
"uptime",
|
|
67095
|
-
"what time",
|
|
67096
|
-
"ok",
|
|
67097
|
-
"okay"
|
|
67098
|
-
];
|
|
67099
|
-
PREMIUM_KEYWORDS = [
|
|
67100
|
-
"architecture",
|
|
67101
|
-
"architect",
|
|
67102
|
-
"design",
|
|
67103
|
-
"tradeoff",
|
|
67104
|
-
"trade-off",
|
|
67105
|
-
"plan",
|
|
67106
|
-
"planning",
|
|
67107
|
-
"strategy",
|
|
67108
|
-
"roadmap",
|
|
67109
|
-
"migration",
|
|
67110
|
-
"refactor",
|
|
67111
|
-
"generate",
|
|
67112
|
-
"implement",
|
|
67113
|
-
"build",
|
|
67114
|
-
"codebase",
|
|
67115
|
-
"repository",
|
|
67116
|
-
"system prompt",
|
|
67117
|
-
"multi-step",
|
|
67118
|
-
"complex",
|
|
67119
|
-
"reason",
|
|
67120
|
-
"compare"
|
|
67121
|
-
];
|
|
67122
|
-
SIMPLE_QUESTION_PREFIXES = [
|
|
67123
|
-
"is",
|
|
67124
|
-
"are",
|
|
67125
|
-
"do",
|
|
67126
|
-
"does",
|
|
67127
|
-
"did",
|
|
67128
|
-
"can",
|
|
67129
|
-
"could",
|
|
67130
|
-
"should",
|
|
67131
|
-
"would",
|
|
67132
|
-
"will"
|
|
67133
|
-
];
|
|
67134
|
-
MODEL_SWITCH_COOLDOWN_MESSAGES = 3;
|
|
67135
|
-
activeTier = null;
|
|
67136
|
-
messagesSinceLastSwitch = MODEL_SWITCH_COOLDOWN_MESSAGES;
|
|
67137
|
-
}
|
|
67138
|
-
});
|
|
67139
|
-
|
|
67140
67608
|
// packages/daemon/src/copilot/client.ts
|
|
67141
|
-
import { execFileSync } from "node:child_process";
|
|
67609
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
67142
67610
|
import { mkdirSync as mkdirSync2 } from "node:fs";
|
|
67143
67611
|
import { join as join6 } from "node:path";
|
|
67144
67612
|
import { CopilotClient } from "@github/copilot-sdk";
|
|
@@ -67148,7 +67616,7 @@ function readTokenFromEnvironment() {
|
|
|
67148
67616
|
}
|
|
67149
67617
|
function readTokenFromGhCli() {
|
|
67150
67618
|
try {
|
|
67151
|
-
const token =
|
|
67619
|
+
const token = execFileSync2("gh", ["auth", "token"], {
|
|
67152
67620
|
encoding: "utf8",
|
|
67153
67621
|
stdio: ["ignore", "pipe", "pipe"]
|
|
67154
67622
|
}).trim();
|
|
@@ -67157,7 +67625,7 @@ function readTokenFromGhCli() {
|
|
|
67157
67625
|
return void 0;
|
|
67158
67626
|
}
|
|
67159
67627
|
}
|
|
67160
|
-
function
|
|
67628
|
+
function resolveGitHubToken2() {
|
|
67161
67629
|
return readTokenFromEnvironment() ?? readTokenFromGhCli();
|
|
67162
67630
|
}
|
|
67163
67631
|
function buildClientOptions(token) {
|
|
@@ -67193,7 +67661,7 @@ async function initCopilotClient() {
|
|
|
67193
67661
|
}
|
|
67194
67662
|
copilotClientInitPromise = (async () => {
|
|
67195
67663
|
try {
|
|
67196
|
-
const token =
|
|
67664
|
+
const token = resolveGitHubToken2();
|
|
67197
67665
|
if (token === void 0) {
|
|
67198
67666
|
throw new Error(
|
|
67199
67667
|
`Unable to find a GitHub token for Copilot SDK authentication. ${COPILOT_AUTH_ERROR_HINT}`
|
|
@@ -68109,13 +68577,24 @@ function mergeUsage(target, usage) {
|
|
|
68109
68577
|
}
|
|
68110
68578
|
async function persistUsage(member, usageEvents) {
|
|
68111
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;
|
|
68112
68589
|
await recordUsage({
|
|
68113
68590
|
squadId: member.squadId,
|
|
68114
68591
|
agentId: member.id,
|
|
68115
|
-
model
|
|
68592
|
+
model,
|
|
68116
68593
|
inputTokens: usage.inputTokens ?? 0,
|
|
68117
68594
|
outputTokens: usage.outputTokens ?? 0,
|
|
68118
|
-
cost:
|
|
68595
|
+
cost: 0,
|
|
68596
|
+
premiumRequestCost,
|
|
68597
|
+
tokenUnitCost
|
|
68119
68598
|
});
|
|
68120
68599
|
}
|
|
68121
68600
|
}
|
|
@@ -68333,7 +68812,7 @@ async function executeAgentTask(member, task, worktreePath, options2) {
|
|
|
68333
68812
|
client2 = new CopilotClient2({ workingDirectory: worktreePath });
|
|
68334
68813
|
await client2.start();
|
|
68335
68814
|
const session = await client2.createSession({
|
|
68336
|
-
model: member.model ??
|
|
68815
|
+
model: member.model ?? DEFAULT_MODEL,
|
|
68337
68816
|
workingDirectory: worktreePath,
|
|
68338
68817
|
tools,
|
|
68339
68818
|
availableTools: ["custom:*"],
|
|
@@ -68390,6 +68869,7 @@ var init_agent = __esm({
|
|
|
68390
68869
|
"packages/daemon/src/execution/agent.ts"() {
|
|
68391
68870
|
"use strict";
|
|
68392
68871
|
init_dist();
|
|
68872
|
+
init_registry();
|
|
68393
68873
|
init_store2();
|
|
68394
68874
|
init_history();
|
|
68395
68875
|
execAsync2 = promisify2(exec2);
|
|
@@ -68588,7 +69068,7 @@ Return strict JSON in this shape:
|
|
|
68588
69068
|
client2 = new CopilotClient3({ workingDirectory: repoPath });
|
|
68589
69069
|
await client2.start();
|
|
68590
69070
|
const session = await client2.createSession({
|
|
68591
|
-
model:
|
|
69071
|
+
model: DEFAULT_MODEL,
|
|
68592
69072
|
workingDirectory: repoPath,
|
|
68593
69073
|
onPermissionRequest: approveAll3,
|
|
68594
69074
|
systemMessage: {
|
|
@@ -68879,7 +69359,7 @@ Return strict JSON:
|
|
|
68879
69359
|
client2 = new CopilotClient4({ workingDirectory: worktreePath });
|
|
68880
69360
|
await client2.start();
|
|
68881
69361
|
const session = await client2.createSession({
|
|
68882
|
-
model: qaMember.model ??
|
|
69362
|
+
model: qaMember.model ?? DEFAULT_MODEL,
|
|
68883
69363
|
workingDirectory: worktreePath,
|
|
68884
69364
|
onPermissionRequest: approveAll4,
|
|
68885
69365
|
systemMessage: {
|
|
@@ -69011,7 +69491,7 @@ Return strict JSON:
|
|
|
69011
69491
|
client2 = new CopilotClient5();
|
|
69012
69492
|
await client2.start();
|
|
69013
69493
|
const session = await client2.createSession({
|
|
69014
|
-
model: teamLead.model ??
|
|
69494
|
+
model: teamLead.model ?? DEFAULT_MODEL,
|
|
69015
69495
|
onPermissionRequest: approveAll5,
|
|
69016
69496
|
systemMessage: {
|
|
69017
69497
|
content: `${TEAM_LEAD_PROMPT}
|
|
@@ -69501,12 +69981,9 @@ function buildMandatoryRoles() {
|
|
|
69501
69981
|
function modelForRole(role) {
|
|
69502
69982
|
const normalized = slugifyRole(role);
|
|
69503
69983
|
if (normalized === "team-lead") {
|
|
69504
|
-
return
|
|
69984
|
+
return DEFAULT_MODEL;
|
|
69505
69985
|
}
|
|
69506
|
-
|
|
69507
|
-
return STANDARD_MODEL;
|
|
69508
|
-
}
|
|
69509
|
-
return STANDARD_MODEL;
|
|
69986
|
+
return DEFAULT_MODEL;
|
|
69510
69987
|
}
|
|
69511
69988
|
function systemPromptForRole(role, repoContext) {
|
|
69512
69989
|
const normalized = slugifyRole(role);
|
|
@@ -69538,7 +70015,7 @@ ${ROLE_GENERATION_PROMPT}`;
|
|
|
69538
70015
|
client2 = new CopilotClient6();
|
|
69539
70016
|
await client2.start();
|
|
69540
70017
|
const session = await client2.createSession({
|
|
69541
|
-
model:
|
|
70018
|
+
model: DEFAULT_MODEL,
|
|
69542
70019
|
onPermissionRequest: approveAll6,
|
|
69543
70020
|
systemMessage: {
|
|
69544
70021
|
content: ROLE_GENERATION_PROMPT
|
|
@@ -69977,9 +70454,9 @@ var init_orchestrator = __esm({
|
|
|
69977
70454
|
"use strict";
|
|
69978
70455
|
init_dist();
|
|
69979
70456
|
init_reset();
|
|
69980
|
-
init_router();
|
|
69981
70457
|
init_session();
|
|
69982
70458
|
init_logger();
|
|
70459
|
+
init_registry();
|
|
69983
70460
|
init_skills2();
|
|
69984
70461
|
init_store2();
|
|
69985
70462
|
init_episodes();
|
|
@@ -70072,8 +70549,7 @@ var init_orchestrator = __esm({
|
|
|
70072
70549
|
skillsContext,
|
|
70073
70550
|
conversationSummary: [this.latestResetSummary, conversationSummary].filter(Boolean).join("\n\n")
|
|
70074
70551
|
});
|
|
70075
|
-
|
|
70076
|
-
await this.refreshSession(route.model, systemPrompt);
|
|
70552
|
+
await this.refreshSession(this.config.defaultModel, systemPrompt);
|
|
70077
70553
|
const sendResult = await sendMessage(
|
|
70078
70554
|
this.requireActiveSession(),
|
|
70079
70555
|
normalizedMessage,
|
|
@@ -70201,11 +70677,22 @@ var init_orchestrator = __esm({
|
|
|
70201
70677
|
if (usage.inputTokens === 0 && usage.outputTokens === 0) {
|
|
70202
70678
|
return;
|
|
70203
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;
|
|
70204
70689
|
await recordUsage({
|
|
70205
|
-
model
|
|
70690
|
+
model,
|
|
70206
70691
|
inputTokens: usage.inputTokens,
|
|
70207
70692
|
outputTokens: usage.outputTokens,
|
|
70208
|
-
cost: 0
|
|
70693
|
+
cost: 0,
|
|
70694
|
+
premiumRequestCost,
|
|
70695
|
+
tokenUnitCost
|
|
70209
70696
|
});
|
|
70210
70697
|
}
|
|
70211
70698
|
};
|
|
@@ -83812,6 +84299,7 @@ function registerShutdownHandlers(logger, onShutdown) {
|
|
|
83812
84299
|
}
|
|
83813
84300
|
async function main() {
|
|
83814
84301
|
let logger;
|
|
84302
|
+
let pricingRefreshTimer = null;
|
|
83815
84303
|
try {
|
|
83816
84304
|
ensureDataDirectories();
|
|
83817
84305
|
const config2 = loadConfig();
|
|
@@ -83819,6 +84307,12 @@ async function main() {
|
|
|
83819
84307
|
logger.info(`IO Daemon v${APP_VERSION} starting...`);
|
|
83820
84308
|
await initDatabase();
|
|
83821
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");
|
|
83822
84316
|
await scanSkills();
|
|
83823
84317
|
logger.info("Skills scanned");
|
|
83824
84318
|
const orchestrator2 = createOrchestrator(config2, eventBus);
|
|
@@ -83827,12 +84321,21 @@ async function main() {
|
|
|
83827
84321
|
const scheduler = createScheduler(orchestrator2, eventBus);
|
|
83828
84322
|
scheduler.start();
|
|
83829
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);
|
|
83830
84330
|
setChatOrchestrator(orchestrator2);
|
|
83831
84331
|
const apiServer = createApiServer(config2);
|
|
83832
84332
|
const telegramBot = createTelegramBot(config2, orchestrator2);
|
|
83833
84333
|
telegramBot?.start();
|
|
83834
84334
|
createTelegramNotifier(telegramBot, config2, eventBus);
|
|
83835
84335
|
registerShutdownHandlers(logger, async () => {
|
|
84336
|
+
if (pricingRefreshTimer) {
|
|
84337
|
+
clearInterval(pricingRefreshTimer);
|
|
84338
|
+
}
|
|
83836
84339
|
scheduler.stop();
|
|
83837
84340
|
telegramBot?.stop();
|
|
83838
84341
|
apiServer.server.close();
|
|
@@ -83857,6 +84360,7 @@ var init_index = __esm({
|
|
|
83857
84360
|
init_data_dir();
|
|
83858
84361
|
init_event_bus();
|
|
83859
84362
|
init_logger();
|
|
84363
|
+
init_models();
|
|
83860
84364
|
init_orchestrator2();
|
|
83861
84365
|
init_scheduler();
|
|
83862
84366
|
init_skills2();
|