heyio 0.1.16 → 0.1.17
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/copilot/agents.js
CHANGED
|
@@ -5,6 +5,7 @@ import { join, dirname, resolve } from "path";
|
|
|
5
5
|
import { defineTool, approveAll } from "@github/copilot-sdk";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { getClient } from "./client.js";
|
|
8
|
+
import { getModelForTask } from "./model-router.js";
|
|
8
9
|
import { getSquad, updateSquadSession, updateSquadStatus, getDecisionsSummary, logDecision, } from "../store/squads.js";
|
|
9
10
|
import { createTask, completeTask, failTask, getActiveTasks, } from "../store/tasks.js";
|
|
10
11
|
import { SESSIONS_DIR } from "../paths.js";
|
|
@@ -40,7 +41,7 @@ export async function delegateToAgent(squadSlug, task, onComplete) {
|
|
|
40
41
|
if (!squad) {
|
|
41
42
|
throw new Error(`Squad not found: ${squadSlug}`);
|
|
42
43
|
}
|
|
43
|
-
const session = await getOrCreateSession(squadSlug);
|
|
44
|
+
const session = await getOrCreateSession(squadSlug, task);
|
|
44
45
|
const taskId = randomUUID();
|
|
45
46
|
createTask(taskId, squadSlug, task);
|
|
46
47
|
updateSquadStatus(squadSlug, "working");
|
|
@@ -83,7 +84,7 @@ export function getActiveAgentTasks() {
|
|
|
83
84
|
// ---------------------------------------------------------------------------
|
|
84
85
|
// Internal helpers
|
|
85
86
|
// ---------------------------------------------------------------------------
|
|
86
|
-
async function getOrCreateSession(squadSlug) {
|
|
87
|
+
async function getOrCreateSession(squadSlug, taskDescription) {
|
|
87
88
|
const existing = agentSessions.get(squadSlug);
|
|
88
89
|
if (existing)
|
|
89
90
|
return existing;
|
|
@@ -91,8 +92,9 @@ async function getOrCreateSession(squadSlug) {
|
|
|
91
92
|
const client = await getClient();
|
|
92
93
|
const decisions = getDecisionsSummary(squadSlug);
|
|
93
94
|
const agentTools = buildAgentTools(squadSlug);
|
|
95
|
+
const model = getModelForTask(taskDescription ?? "", squad.model);
|
|
94
96
|
const commonConfig = {
|
|
95
|
-
model
|
|
97
|
+
model,
|
|
96
98
|
configDir: SESSIONS_DIR,
|
|
97
99
|
streaming: false,
|
|
98
100
|
systemMessage: {
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { config } from "../config.js";
|
|
2
|
+
const DEFAULT_TIERS = {
|
|
3
|
+
high: ["claude-opus-4.7", "claude-opus-4.6"],
|
|
4
|
+
medium: ["claude-sonnet-4.6", "gpt-5.5", "claude-opus-4.5"],
|
|
5
|
+
low: ["claude-haiku-4.5", "gpt-5.4-mini"],
|
|
6
|
+
};
|
|
7
|
+
// Resolved model for each tier (populated at startup)
|
|
8
|
+
let resolvedTiers = null;
|
|
9
|
+
const HIGH_KEYWORDS = [
|
|
10
|
+
"architect", "refactor", "redesign", "debug", "design",
|
|
11
|
+
"complex", "migration", "security", "performance", "optimize",
|
|
12
|
+
"rewrite", "overhaul", "investigate", "diagnose", "plan",
|
|
13
|
+
];
|
|
14
|
+
const LOW_KEYWORDS = [
|
|
15
|
+
"read", "list", "format", "lookup", "check", "status",
|
|
16
|
+
"simple", "rename", "typo", "log", "print", "echo",
|
|
17
|
+
"delete file", "remove file", "copy file", "move file",
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* Resolve each tier to the first available model from its preference list.
|
|
21
|
+
* Call once at startup with the result of `client.listModels()`.
|
|
22
|
+
*/
|
|
23
|
+
export function resolveModelTiers(availableModelIds) {
|
|
24
|
+
const available = new Set(availableModelIds);
|
|
25
|
+
const tiers = config.modelTiers ?? {};
|
|
26
|
+
const result = {};
|
|
27
|
+
for (const tier of ["high", "medium", "low"]) {
|
|
28
|
+
const candidates = tiers[tier] ?? DEFAULT_TIERS[tier];
|
|
29
|
+
const match = candidates.find((m) => available.has(m));
|
|
30
|
+
if (match) {
|
|
31
|
+
result[tier] = match;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Fallback: use defaultModel, then first candidate regardless of availability
|
|
35
|
+
result[tier] = config.defaultModel || candidates[0];
|
|
36
|
+
}
|
|
37
|
+
console.error(`[io] Model tier "${tier}" resolved to: ${result[tier]}`);
|
|
38
|
+
}
|
|
39
|
+
resolvedTiers = result;
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Classify a task description into a complexity tier.
|
|
44
|
+
*/
|
|
45
|
+
export function classifyComplexity(taskDescription) {
|
|
46
|
+
const lower = taskDescription.toLowerCase();
|
|
47
|
+
const highScore = HIGH_KEYWORDS.filter((kw) => lower.includes(kw)).length;
|
|
48
|
+
const lowScore = LOW_KEYWORDS.filter((kw) => lower.includes(kw)).length;
|
|
49
|
+
// Strong signals
|
|
50
|
+
if (highScore >= 2)
|
|
51
|
+
return "high";
|
|
52
|
+
if (lowScore >= 2)
|
|
53
|
+
return "low";
|
|
54
|
+
// Weak signals
|
|
55
|
+
if (highScore > lowScore)
|
|
56
|
+
return "high";
|
|
57
|
+
if (lowScore > highScore)
|
|
58
|
+
return "low";
|
|
59
|
+
// Default to medium for ambiguous tasks
|
|
60
|
+
return "medium";
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get the resolved model for a tier.
|
|
64
|
+
*/
|
|
65
|
+
export function getModelForTier(tier) {
|
|
66
|
+
if (!resolvedTiers) {
|
|
67
|
+
console.error("[io] Warning: model tiers not yet resolved, using defaults");
|
|
68
|
+
return config.defaultModel || DEFAULT_TIERS[tier][0];
|
|
69
|
+
}
|
|
70
|
+
return resolvedTiers[tier];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get the best model for a task based on its description.
|
|
74
|
+
* If squadModel is provided, it always takes priority.
|
|
75
|
+
*/
|
|
76
|
+
export function getModelForTask(taskDescription, squadModel) {
|
|
77
|
+
if (squadModel)
|
|
78
|
+
return squadModel;
|
|
79
|
+
const tier = classifyComplexity(taskDescription);
|
|
80
|
+
const model = getModelForTier(tier);
|
|
81
|
+
console.error(`[io] Task classified as "${tier}" → model: ${model}`);
|
|
82
|
+
return model;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=model-router.js.map
|
|
@@ -5,6 +5,7 @@ import { getState, setState, deleteState, logConversation } from "../store/db.js
|
|
|
5
5
|
import { clearStaleTasks } from "../store/tasks.js";
|
|
6
6
|
import { getSquad, listSquads, createSquad, logDecision, getDecisionsSummary, updateSquadStatus, } from "../store/squads.js";
|
|
7
7
|
import { readPage, writePage, assertPagePath } from "../wiki/fs.js";
|
|
8
|
+
import { resolveModelTiers } from "./model-router.js";
|
|
8
9
|
import { searchWiki, getWikiSummary } from "../wiki/search.js";
|
|
9
10
|
import { getOrchestratorSystemMessage } from "./system-message.js";
|
|
10
11
|
import { createTools } from "./tools.js";
|
|
@@ -293,7 +294,7 @@ async function processQueue() {
|
|
|
293
294
|
export async function initOrchestrator(copilotClient) {
|
|
294
295
|
client = copilotClient;
|
|
295
296
|
clearStaleTasks();
|
|
296
|
-
// Validate the configured model
|
|
297
|
+
// Validate the configured model and resolve model tiers
|
|
297
298
|
try {
|
|
298
299
|
const models = await copilotClient.listModels();
|
|
299
300
|
const defaultModel = config.defaultModel || "gpt-4.1";
|
|
@@ -304,6 +305,7 @@ export async function initOrchestrator(copilotClient) {
|
|
|
304
305
|
else {
|
|
305
306
|
console.error(`[io] Model validated: ${defaultModel}`);
|
|
306
307
|
}
|
|
308
|
+
resolveModelTiers(modelIds);
|
|
307
309
|
}
|
|
308
310
|
catch (err) {
|
|
309
311
|
console.error("[io] Could not validate models:", err instanceof Error ? err.message : err);
|
|
@@ -62,6 +62,14 @@ Squads are persistent project teams. When a user works on a codebase:
|
|
|
62
62
|
3. Recall squad context with \`squad_recall\` before doing project work.
|
|
63
63
|
4. Check squad status with \`squad_status\`.
|
|
64
64
|
|
|
65
|
+
### Model Selection
|
|
66
|
+
Squad agents are automatically assigned a model based on task complexity:
|
|
67
|
+
- **High complexity** (architecture, refactoring, debugging, design) → most capable model
|
|
68
|
+
- **Medium complexity** (implementing features, writing tests, reviews) → balanced model
|
|
69
|
+
- **Low complexity** (file reads, formatting, lookups) → fast/cheap model
|
|
70
|
+
|
|
71
|
+
The model is selected automatically. Tell the user which model tier was chosen when delegating tasks.
|
|
72
|
+
|
|
65
73
|
## Tool Usage
|
|
66
74
|
|
|
67
75
|
### Knowledge Base
|
package/dist/store/db.js
CHANGED
|
@@ -21,6 +21,7 @@ export function getDb() {
|
|
|
21
21
|
name TEXT NOT NULL,
|
|
22
22
|
project_path TEXT NOT NULL,
|
|
23
23
|
copilot_session_id TEXT,
|
|
24
|
+
model TEXT,
|
|
24
25
|
status TEXT NOT NULL DEFAULT 'idle',
|
|
25
26
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
26
27
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
@@ -53,6 +54,13 @@ export function getDb() {
|
|
|
53
54
|
completed_at DATETIME
|
|
54
55
|
);
|
|
55
56
|
`);
|
|
57
|
+
// Migration: add model column to squads (for existing databases)
|
|
58
|
+
try {
|
|
59
|
+
db.exec(`ALTER TABLE squads ADD COLUMN model TEXT`);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Column already exists — ignore
|
|
63
|
+
}
|
|
56
64
|
return db;
|
|
57
65
|
}
|
|
58
66
|
export function closeDb() {
|
package/dist/store/squads.js
CHANGED
|
@@ -22,6 +22,11 @@ export function updateSquadStatus(slug, status) {
|
|
|
22
22
|
.prepare("UPDATE squads SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE slug = ?")
|
|
23
23
|
.run(status, slug);
|
|
24
24
|
}
|
|
25
|
+
export function updateSquadModel(slug, model) {
|
|
26
|
+
getDb()
|
|
27
|
+
.prepare("UPDATE squads SET model = ?, updated_at = CURRENT_TIMESTAMP WHERE slug = ?")
|
|
28
|
+
.run(model, slug);
|
|
29
|
+
}
|
|
25
30
|
export function deleteSquad(slug) {
|
|
26
31
|
const db = getDb();
|
|
27
32
|
db.prepare("DELETE FROM squad_decisions WHERE squad_slug = ?").run(slug);
|