fix: pipeline — case-insensitive agent join, remove stale model routing, single-task dispatch, 300s timeout
- JOIN agents uses lower() for case-insensitive name matching - Removed hardcoded 9router/cc/ model IDs — agents use their own OC config - Dispatch LIMIT 3 → 1 to prevent concurrent gateway saturation - Gateway timeout 120s → 300s (engineer agent has 130k token context) - Direct API classifyDirectModel simplified — all routing via OC gateway
This commit is contained in:
parent
4931e008b2
commit
b2ae69e3b8
|
|
@ -49,31 +49,8 @@ function classifyTaskModel(task: DispatchableTask): string | null {
|
||||||
const text = `${task.title} ${task.description ?? ''}`.toLowerCase()
|
const text = `${task.title} ${task.description ?? ''}`.toLowerCase()
|
||||||
const priority = task.priority?.toLowerCase() ?? ''
|
const priority = task.priority?.toLowerCase() ?? ''
|
||||||
|
|
||||||
// Complex signals → Opus
|
// Let the agent's own configured model handle it — no dispatch-side model override.
|
||||||
const complexSignals = [
|
// The OC gateway agents already have their models set in openclaw.json.
|
||||||
'debug', 'diagnos', 'architect', 'design system', 'security audit',
|
|
||||||
'root cause', 'investigate', 'incident', 'failure', 'broken', 'not working',
|
|
||||||
'refactor', 'migration', 'performance optim', 'why is',
|
|
||||||
]
|
|
||||||
if (priority === 'critical' || complexSignals.some(s => text.includes(s))) {
|
|
||||||
return '9router/cc/claude-opus-4-6'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Routine signals → Haiku
|
|
||||||
const routineSignals = [
|
|
||||||
'status check', 'health check', 'ping', 'list ', 'fetch ', 'format',
|
|
||||||
'rename', 'move file', 'read file', 'update readme', 'bump version',
|
|
||||||
'send message', 'post to', 'notify', 'summarize', 'translate',
|
|
||||||
'quick ', 'simple ', 'routine ', 'minor ',
|
|
||||||
]
|
|
||||||
if (priority === 'low' && routineSignals.some(s => text.includes(s))) {
|
|
||||||
return '9router/cc/claude-haiku-4-5-20251001'
|
|
||||||
}
|
|
||||||
if (routineSignals.some(s => text.includes(s)) && priority !== 'high' && priority !== 'critical') {
|
|
||||||
return '9router/cc/claude-haiku-4-5-20251001'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default: let the agent's own configured model handle it (no override)
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,34 +190,12 @@ function classifyDirectModel(task: DispatchableTask): string {
|
||||||
try {
|
try {
|
||||||
const cfg = JSON.parse(task.agent_config)
|
const cfg = JSON.parse(task.agent_config)
|
||||||
if (typeof cfg.dispatchModel === 'string' && cfg.dispatchModel) {
|
if (typeof cfg.dispatchModel === 'string' && cfg.dispatchModel) {
|
||||||
// Return model ID as-is — full provider/model paths are valid
|
|
||||||
return cfg.dispatchModel
|
return cfg.dispatchModel
|
||||||
}
|
}
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
const text = `${task.title} ${task.description ?? ''}`.toLowerCase()
|
// Default → Sonnet (agents configure their own models via OC gateway)
|
||||||
const priority = task.priority?.toLowerCase() ?? ''
|
|
||||||
|
|
||||||
// Complex → Opus
|
|
||||||
const complexSignals = [
|
|
||||||
'debug', 'diagnos', 'architect', 'design system', 'security audit',
|
|
||||||
'root cause', 'investigate', 'incident', 'refactor', 'migration',
|
|
||||||
]
|
|
||||||
if (priority === 'critical' || complexSignals.some(s => text.includes(s))) {
|
|
||||||
return 'claude-opus-4-6'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Routine → Haiku
|
|
||||||
const routineSignals = [
|
|
||||||
'status check', 'health check', 'format', 'rename', 'summarize',
|
|
||||||
'translate', 'quick ', 'simple ', 'routine ', 'minor ',
|
|
||||||
]
|
|
||||||
if (routineSignals.some(s => text.includes(s)) && priority !== 'high' && priority !== 'critical') {
|
|
||||||
return 'claude-haiku-4-5-20251001'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default → Sonnet
|
|
||||||
return 'claude-sonnet-4-6'
|
return 'claude-sonnet-4-6'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -441,7 +396,7 @@ export async function runAegisReviews(): Promise<{ ok: boolean; message: string
|
||||||
p.ticket_prefix, t.project_ticket_no, a.config as agent_config
|
p.ticket_prefix, t.project_ticket_no, a.config as agent_config
|
||||||
FROM tasks t
|
FROM tasks t
|
||||||
LEFT JOIN projects p ON p.id = t.project_id AND p.workspace_id = t.workspace_id
|
LEFT JOIN projects p ON p.id = t.project_id AND p.workspace_id = t.workspace_id
|
||||||
LEFT JOIN agents a ON a.name = t.assigned_to AND a.workspace_id = t.workspace_id
|
LEFT JOIN agents a ON lower(a.name) = lower(t.assigned_to) AND a.workspace_id = t.workspace_id
|
||||||
WHERE t.status = 'review'
|
WHERE t.status = 'review'
|
||||||
ORDER BY t.updated_at ASC
|
ORDER BY t.updated_at ASC
|
||||||
LIMIT 3
|
LIMIT 3
|
||||||
|
|
@ -489,8 +444,8 @@ export async function runAegisReviews(): Promise<{ ok: boolean; message: string
|
||||||
deliver: false,
|
deliver: false,
|
||||||
}
|
}
|
||||||
const finalResult = await runOpenClaw(
|
const finalResult = await runOpenClaw(
|
||||||
['gateway', 'call', 'agent', '--expect-final', '--timeout', '120000', '--params', JSON.stringify(invokeParams), '--json'],
|
['gateway', 'call', 'agent', '--expect-final', '--timeout', '300000', '--params', JSON.stringify(invokeParams), '--json'],
|
||||||
{ timeoutMs: 125_000 }
|
{ timeoutMs: 305_000 }
|
||||||
)
|
)
|
||||||
const finalPayload = parseGatewayJson(finalResult.stdout)
|
const finalPayload = parseGatewayJson(finalResult.stdout)
|
||||||
?? parseGatewayJson(String((finalResult as any)?.stderr || ''))
|
?? parseGatewayJson(String((finalResult as any)?.stderr || ''))
|
||||||
|
|
@ -732,7 +687,7 @@ export async function requeueStaleTasks(): Promise<{ ok: boolean; message: strin
|
||||||
SELECT t.id, t.title, t.assigned_to, t.dispatch_attempts, t.workspace_id,
|
SELECT t.id, t.title, t.assigned_to, t.dispatch_attempts, t.workspace_id,
|
||||||
a.status as agent_status, a.last_seen as agent_last_seen
|
a.status as agent_status, a.last_seen as agent_last_seen
|
||||||
FROM tasks t
|
FROM tasks t
|
||||||
LEFT JOIN agents a ON a.name = t.assigned_to AND a.workspace_id = t.workspace_id
|
LEFT JOIN agents a ON lower(a.name) = lower(t.assigned_to) AND a.workspace_id = t.workspace_id
|
||||||
WHERE t.status = 'in_progress'
|
WHERE t.status = 'in_progress'
|
||||||
AND t.updated_at < ?
|
AND t.updated_at < ?
|
||||||
`).all(staleThreshold) as Array<{
|
`).all(staleThreshold) as Array<{
|
||||||
|
|
@ -808,14 +763,14 @@ export async function dispatchAssignedTasks(): Promise<{ ok: boolean; message: s
|
||||||
SELECT t.*, a.name as agent_name, a.id as agent_id, a.config as agent_config,
|
SELECT t.*, a.name as agent_name, a.id as agent_id, a.config as agent_config,
|
||||||
p.ticket_prefix, t.project_ticket_no
|
p.ticket_prefix, t.project_ticket_no
|
||||||
FROM tasks t
|
FROM tasks t
|
||||||
JOIN agents a ON a.name = t.assigned_to AND a.workspace_id = t.workspace_id
|
JOIN agents a ON lower(a.name) = lower(t.assigned_to) AND a.workspace_id = t.workspace_id
|
||||||
LEFT JOIN projects p ON p.id = t.project_id AND p.workspace_id = t.workspace_id
|
LEFT JOIN projects p ON p.id = t.project_id AND p.workspace_id = t.workspace_id
|
||||||
WHERE t.status = 'assigned'
|
WHERE t.status = 'assigned'
|
||||||
AND t.assigned_to IS NOT NULL
|
AND t.assigned_to IS NOT NULL
|
||||||
ORDER BY
|
ORDER BY
|
||||||
CASE t.priority WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3 END ASC,
|
CASE t.priority WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3 END ASC,
|
||||||
t.created_at ASC
|
t.created_at ASC
|
||||||
LIMIT 3
|
LIMIT 1
|
||||||
`).all() as (DispatchableTask & { tags?: string })[]
|
`).all() as (DispatchableTask & { tags?: string })[]
|
||||||
|
|
||||||
if (tasks.length === 0) {
|
if (tasks.length === 0) {
|
||||||
|
|
@ -921,8 +876,8 @@ export async function dispatchAssignedTasks(): Promise<{ ok: boolean; message: s
|
||||||
// response payload (result.payloads[0].text). The two-step agent → agent.wait
|
// response payload (result.payloads[0].text). The two-step agent → agent.wait
|
||||||
// pattern only returns lifecycle metadata and never includes the agent's text.
|
// pattern only returns lifecycle metadata and never includes the agent's text.
|
||||||
const finalResult = await runOpenClaw(
|
const finalResult = await runOpenClaw(
|
||||||
['gateway', 'call', 'agent', '--expect-final', '--timeout', '120000', '--params', JSON.stringify(invokeParams), '--json'],
|
['gateway', 'call', 'agent', '--expect-final', '--timeout', '300000', '--params', JSON.stringify(invokeParams), '--json'],
|
||||||
{ timeoutMs: 125_000 }
|
{ timeoutMs: 305_000 }
|
||||||
)
|
)
|
||||||
const finalPayload = parseGatewayJson(finalResult.stdout)
|
const finalPayload = parseGatewayJson(finalResult.stdout)
|
||||||
?? parseGatewayJson(String((finalResult as any)?.stderr || ''))
|
?? parseGatewayJson(String((finalResult as any)?.stderr || ''))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue