feat(metrics): add phase-0 baseline counters
Diagrams reviewed: docs/architecture/AGENT_DIAGRAM.md, docs/architecture/GATEWAY_SESSIONS_AND_QUEUE.md, docs/api/PROTOCOL.md (no changes required).
This commit is contained in:
@@ -260,6 +260,7 @@ export async function startDaemon(config: Config, options?: StartDaemonOptions):
|
||||
const messageRouter = createMessageRouter({
|
||||
sessionManager, modelRouter, systemPrompt, toolRegistry, toolExecutor,
|
||||
config, memoryStore, agentConfigRegistry, agentRouter, sandboxManager, commandRegistry, hookEngine, intentRegistry, routingPolicy, skillRegistry, skillInstaller,
|
||||
metrics: gateway.getMetrics(),
|
||||
getBackendMode: () => backendMode,
|
||||
setBackendMode: (mode) => {
|
||||
backendMode = mode;
|
||||
|
||||
+17
-3
@@ -32,6 +32,7 @@ import { loadSkillRegistryCatalog } from '../skills/index.js';
|
||||
import type { SkillInstaller, SkillRegistry, SkillRegistryEntry, SkillRegistrySource } from '../skills/index.js';
|
||||
import { auditLogger } from '../audit/index.js';
|
||||
import { getElevationStatusMessage, setElevationFromInput } from '../security/elevation.js';
|
||||
import type { MetricsCollector } from '../gateway/metrics.js';
|
||||
import { dirname, resolve } from 'path';
|
||||
import { loadCouncilScaffoldSafe } from '../councils/scaffold.js';
|
||||
import { buildCouncilPreflightReport, shouldRunCouncilPreflight } from '../councils/preflight.js';
|
||||
@@ -363,6 +364,7 @@ export function createMessageRouter(deps: {
|
||||
systemPrompt: string;
|
||||
toolRegistry: ToolRegistry;
|
||||
toolExecutor: ToolExecutor;
|
||||
metrics?: MetricsCollector;
|
||||
config: Config;
|
||||
memoryStore?: MemoryStore;
|
||||
agentConfigRegistry?: AgentConfigRegistry;
|
||||
@@ -779,6 +781,7 @@ export function createMessageRouter(deps: {
|
||||
reason: 'no_rules',
|
||||
candidate_count: 0,
|
||||
});
|
||||
deps.metrics?.recordReactionDecision({ matched: false, reason: 'no_rules' });
|
||||
} else {
|
||||
const reactionMatch = matchReactionPrompt(automationReactions, {
|
||||
channel: msg.channel,
|
||||
@@ -799,6 +802,7 @@ export function createMessageRouter(deps: {
|
||||
candidate_count: automationReactions.length,
|
||||
filter_summary: buildReactionFilterSummary(matchedRule),
|
||||
});
|
||||
deps.metrics?.recordReactionDecision({ matched: true });
|
||||
} else {
|
||||
auditLogger?.reactionSkip?.({
|
||||
session_id: sessionIdForRun,
|
||||
@@ -808,6 +812,7 @@ export function createMessageRouter(deps: {
|
||||
reason: 'no_match',
|
||||
candidate_count: automationReactions.length,
|
||||
});
|
||||
deps.metrics?.recordReactionDecision({ matched: false, reason: 'no_match' });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1064,6 +1069,7 @@ export function createMessageRouter(deps: {
|
||||
const cancelStartedAt = Date.now();
|
||||
const run = activeRuns.get(session.id);
|
||||
if (!run || !run.isCancellable()) {
|
||||
deps.metrics?.recordCancelLatency(Date.now() - cancelStartedAt);
|
||||
auditLogger?.runCancel?.({
|
||||
session_id: session.id,
|
||||
channel: msg.channel,
|
||||
@@ -1078,6 +1084,7 @@ export function createMessageRouter(deps: {
|
||||
}
|
||||
run.cancel();
|
||||
const cancelLatencyMs = Date.now() - cancelStartedAt;
|
||||
deps.metrics?.recordCancelLatency(cancelLatencyMs);
|
||||
auditLogger?.runCancel?.({
|
||||
session_id: session.id,
|
||||
channel: msg.channel,
|
||||
@@ -1097,6 +1104,7 @@ export function createMessageRouter(deps: {
|
||||
request_id: msg.id,
|
||||
duration_ms: cancelLatencyMs,
|
||||
});
|
||||
deps.metrics?.recordRunState('cancel_requested');
|
||||
return 'Cancellation requested. The active operation will stop at the next safe point.';
|
||||
},
|
||||
|
||||
@@ -1503,6 +1511,7 @@ export function createMessageRouter(deps: {
|
||||
state: 'start',
|
||||
request_id: msg.id,
|
||||
});
|
||||
deps.metrics?.recordRunState('start');
|
||||
|
||||
// Determine if the active model supports native audio input
|
||||
let effectiveTier: string = deps.config.agents.primary_tier ?? 'default';
|
||||
@@ -1577,6 +1586,7 @@ export function createMessageRouter(deps: {
|
||||
request_id: msg.id,
|
||||
duration_ms: Date.now() - runStartedAt,
|
||||
});
|
||||
deps.metrics?.recordRunState('complete');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1673,6 +1683,7 @@ export function createMessageRouter(deps: {
|
||||
request_id: msg.id,
|
||||
duration_ms: Date.now() - runStartedAt,
|
||||
});
|
||||
deps.metrics?.recordRunState('complete');
|
||||
return;
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
@@ -1716,17 +1727,19 @@ export function createMessageRouter(deps: {
|
||||
replyTo: msg.id,
|
||||
attachments: mergedAttachments.length > 0 ? mergedAttachments : undefined,
|
||||
});
|
||||
const finalState = response.trim().toLowerCase() === 'operation cancelled by user.'
|
||||
? 'cancelled'
|
||||
: 'complete';
|
||||
auditLogger?.runState?.({
|
||||
session_id: sessionIdForRun,
|
||||
channel: msg.channel,
|
||||
sender: msg.senderId,
|
||||
source: 'channel',
|
||||
state: response.trim().toLowerCase() === 'operation cancelled by user.'
|
||||
? 'cancelled'
|
||||
: 'complete',
|
||||
state: finalState,
|
||||
request_id: msg.id,
|
||||
duration_ms: Date.now() - runStartedAt,
|
||||
});
|
||||
deps.metrics?.recordRunState(finalState);
|
||||
} catch (error) {
|
||||
console.error(`Error processing message from ${msg.channel}:${msg.senderId}:`, error);
|
||||
await reply({
|
||||
@@ -1742,6 +1755,7 @@ export function createMessageRouter(deps: {
|
||||
request_id: msg.id,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
deps.metrics?.recordRunState('error');
|
||||
} finally {
|
||||
activeRuns.delete(sessionIdForRun);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user