feat(models): add background task model override config and runtime wiring
This commit is contained in:
+65
-1
@@ -13,7 +13,7 @@ import { createMediaSendTool, createAgentDelegateTool } from '../tools/index.js'
|
||||
import type { AgentDelegateDeps } from '../tools/index.js';
|
||||
import { createSandboxedShellTool, createSandboxedProcessStartTool, SandboxManager } from '../sandbox/index.js';
|
||||
import { MODEL_PROVIDERS, type Config, type ModelConfig, type ModelProvider } from '../config/index.js';
|
||||
import { ModelRouter, type ModelTier } from '../models/index.js';
|
||||
import { ModelRouter, type ModelClient, type ModelTier } from '../models/index.js';
|
||||
import { ToolRegistry, ToolExecutor } from '../tools/index.js';
|
||||
import { SessionManager } from '../session/index.js';
|
||||
import { AgentConfigRegistry, AgentRouter } from '../agents/index.js';
|
||||
@@ -77,6 +77,55 @@ function tierFromUseCase(config: Config, useCaseRaw: unknown): ModelTier | undef
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function buildBackgroundModelOverrides(config: Config): Partial<Record<keyof DelegationConfig, {
|
||||
client: ModelClient;
|
||||
label: string;
|
||||
fallbackTier: ModelTier;
|
||||
}>> {
|
||||
const overrides: Partial<Record<keyof DelegationConfig, {
|
||||
client: ModelClient;
|
||||
label: string;
|
||||
fallbackTier: ModelTier;
|
||||
}>> = {};
|
||||
const configured = config.agents?.background_models ?? {};
|
||||
const providerConfigs = buildProviderConfigMap(config);
|
||||
const tasks: Array<keyof DelegationConfig> = [
|
||||
'compaction',
|
||||
'memory_extraction',
|
||||
'classification',
|
||||
'tool_summarisation',
|
||||
'complex_reasoning',
|
||||
];
|
||||
|
||||
for (const task of tasks) {
|
||||
const entry = configured[task];
|
||||
if (!entry || entry.enabled === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const template = providerConfigs[entry.provider];
|
||||
try {
|
||||
const client = createClientFromConfig(
|
||||
template
|
||||
? { ...template, provider: entry.provider, model: entry.model }
|
||||
: { provider: entry.provider, model: entry.model },
|
||||
);
|
||||
overrides[task] = {
|
||||
client,
|
||||
label: `${entry.provider}/${entry.model}`,
|
||||
fallbackTier: entry.fallback_tier,
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`[Flynn:routing] Failed to initialize background model override for ${task} ` +
|
||||
`(${entry.provider}/${entry.model}): ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return overrides;
|
||||
}
|
||||
|
||||
function parseResearchPrefix(text: string): string | undefined {
|
||||
const trimmed = text.trim();
|
||||
const researchMatch = trimmed.match(/^research(?:\s*[:,-])?\s+(.+)$/i);
|
||||
@@ -174,6 +223,7 @@ export function createMessageRouter(deps: {
|
||||
// Cache agents by session ID + agent config name to avoid recreating on every message
|
||||
const agents = new Map<string, { orchestrator: AgentOrchestrator; collector: OutboundAttachmentCollector }>();
|
||||
const talkModeUntil = new Map<string, number>();
|
||||
const activeRuns = new Map<string, AgentOrchestrator>();
|
||||
|
||||
async function maybeBuildTtsAttachment(responseText: string, channel: string) {
|
||||
if (!isTtsEnabledForChannel(deps.config, channel)) {
|
||||
@@ -261,6 +311,7 @@ export function createMessageRouter(deps: {
|
||||
tool_summarisation: deps.config.agents.delegation.tool_summarisation ?? 'fast',
|
||||
complex_reasoning: deps.config.agents.delegation.complex_reasoning ?? 'complex',
|
||||
};
|
||||
const backgroundModelOverrides = buildBackgroundModelOverrides(deps.config);
|
||||
|
||||
// Clone the tool registry and replace high-risk tools with sandboxed versions if configured.
|
||||
let effectiveToolRegistry = deps.toolRegistry;
|
||||
@@ -377,6 +428,7 @@ export function createMessageRouter(deps: {
|
||||
toolExecutor: deps.toolExecutor,
|
||||
primaryTier: effectiveTier,
|
||||
delegation: delegationConfig,
|
||||
backgroundModelOverrides,
|
||||
maxDelegationDepth: deps.config.agents.max_delegation_depth ?? 3,
|
||||
maxIterations: deps.config.agents.max_iterations,
|
||||
compaction: deps.config.compaction.enabled ? {
|
||||
@@ -419,6 +471,7 @@ export function createMessageRouter(deps: {
|
||||
}
|
||||
|
||||
const handler = async (msg: InboundMessage, reply: (response: OutboundMessage) => Promise<void>): Promise<void> => {
|
||||
const sessionIdForRun = `${msg.channel}:${msg.senderId}`;
|
||||
let incomingText = msg.text;
|
||||
let matchedReactionName: string | undefined;
|
||||
const talkMode = deps.config.audio?.talk_mode;
|
||||
@@ -721,6 +774,14 @@ export function createMessageRouter(deps: {
|
||||
session.deleteConfig('modelTier');
|
||||
return '';
|
||||
},
|
||||
cancelRun: () => {
|
||||
const run = activeRuns.get(session.id);
|
||||
if (!run || !run.isCancellable()) {
|
||||
return 'No active operation to cancel.';
|
||||
}
|
||||
run.cancel();
|
||||
return 'Cancellation requested. The active operation will stop at the next safe point.';
|
||||
},
|
||||
|
||||
delegateAgent: async (agentName: string, task: string) => {
|
||||
const target = agentName.trim();
|
||||
@@ -1293,6 +1354,7 @@ export function createMessageRouter(deps: {
|
||||
}
|
||||
|
||||
let response: string;
|
||||
activeRuns.set(sessionIdForRun, agent);
|
||||
try {
|
||||
response = await agent.process(messageText, attachments);
|
||||
} catch (error) {
|
||||
@@ -1322,6 +1384,8 @@ export function createMessageRouter(deps: {
|
||||
text: 'Sorry, an error occurred while processing your message.',
|
||||
replyTo: msg.id,
|
||||
});
|
||||
} finally {
|
||||
activeRuns.delete(sessionIdForRun);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user