mirror of
https://github.com/KeygraphHQ/shannon.git
synced 2026-09-28 04:22:07 +02:00
feat: multi-provider model support, SARIF output, and exploit-mode fixes (#402)
* feat(worker): record token, cache, and turn usage per agent * feat: replace model tiers with a single SHANNON_AI_MODEL across five providers * feat(cli): rebuild the setup wizard for provider and model selection * docs: document single-model selection and supported providers * feat(worker): use chat completions for OpenAI behind a custom base URL * feat: add SHANNON_AI_OPENAI_FORMAT to pick the wire API for OpenAI gateways * refactor(cli): drop endpoint path hints from the gateway format picker * feat(worker): enable pi in-session provider retry with retry-after backoff * refactor(worker): hand provider error classification to pi and drop the Anthropic ladders * refactor: remove the subscription retry preset and pipeline config section * fix(worker): validate Bedrock credentials with the same live probe as other providers * feat(worker): render the report from structured findings instead of agent-written markdown * fix(worker): dispose the credential probe session on every path * fix(worker): refuse to replace the assembled report with an empty one * refactor(worker): catch post-processing throws across the whole finalization block * revert(worker): drop the report zero-findings guard * docs(worker): correct the retry split and Bedrock credential claims * docs: regenerate llms-full.txt from current sources * feat(cli): build and run the npx flow from a clone * refactor(cli): flatten the setup summary output * feat(cli): reject runs with more than one provider configured * fix(worker): say a rejected bash call never ran * chore(cli): drop grok-4.3 and gpt-5.6-luna from the setup suggestions * feat(worker): capture structured finding locations for SARIF output * fix(worker): enumerate queue confidence so the report inherits it verbatim * feat(worker): give the reporting phase a mode-specific output schema * feat(worker): emit a SARIF 2.1.0 log for exploitative runs * fix(worker): correct SARIF locations and defer fingerprinting to the upload action * fix(worker): drop the confidence suffix from the analysis-mode summary list * feat(worker): give exploit findings a dedicated code location field * feat(worker): carry structured code locations from the vuln queue to the report * fix(worker): join code locations from the vuln queue instead of re-asking agents * fix(worker): spell out the finding_id to category mapping in the tool schema * feat: drop Google/Gemini as a supported AI provider * fix(worker): stop asking the report agent for code locations * docs: correct the provider list and drop the removed rate-limit settings * docs: add provider cyber safeguards and suggested models per provider * docs: document the SARIF output and the report rating thresholds
This commit is contained in:
@@ -23,6 +23,11 @@ interface AttemptData {
|
||||
attempt_number: number;
|
||||
duration_ms: number;
|
||||
cost_usd: number;
|
||||
input_tokens?: number | undefined;
|
||||
output_tokens?: number | undefined;
|
||||
cache_read_tokens?: number | undefined;
|
||||
cache_write_tokens?: number | undefined;
|
||||
turns?: number | undefined;
|
||||
success: boolean;
|
||||
timestamp: string;
|
||||
model?: string | undefined;
|
||||
@@ -34,6 +39,10 @@ interface AgentAuditMetrics {
|
||||
attempts: AttemptData[];
|
||||
final_duration_ms: number;
|
||||
total_cost_usd: number;
|
||||
total_input_tokens: number;
|
||||
total_output_tokens: number;
|
||||
total_cache_read_tokens: number;
|
||||
total_cache_write_tokens: number;
|
||||
model?: string | undefined;
|
||||
checkpoint?: string | undefined;
|
||||
}
|
||||
@@ -174,6 +183,10 @@ export class MetricsTracker {
|
||||
attempts: [],
|
||||
final_duration_ms: 0,
|
||||
total_cost_usd: 0,
|
||||
total_input_tokens: 0,
|
||||
total_output_tokens: 0,
|
||||
total_cache_read_tokens: 0,
|
||||
total_cache_write_tokens: 0,
|
||||
};
|
||||
this.data.metrics.agents[agentName] = agent;
|
||||
|
||||
@@ -184,6 +197,11 @@ export class MetricsTracker {
|
||||
cost_usd: result.cost_usd,
|
||||
success: result.success,
|
||||
timestamp: formatTimestamp(),
|
||||
...(result.input_tokens !== undefined && { input_tokens: result.input_tokens }),
|
||||
...(result.output_tokens !== undefined && { output_tokens: result.output_tokens }),
|
||||
...(result.cache_read_tokens !== undefined && { cache_read_tokens: result.cache_read_tokens }),
|
||||
...(result.cache_write_tokens !== undefined && { cache_write_tokens: result.cache_write_tokens }),
|
||||
...(result.turns !== undefined && { turns: result.turns }),
|
||||
};
|
||||
|
||||
if (result.model) {
|
||||
@@ -197,8 +215,12 @@ export class MetricsTracker {
|
||||
// 3. Append attempt to history
|
||||
agent.attempts.push(attempt);
|
||||
|
||||
// 4. Recalculate total cost across all attempts (includes failures)
|
||||
// 4. Recalculate totals across all attempts (includes failures)
|
||||
agent.total_cost_usd = agent.attempts.reduce((sum, a) => sum + a.cost_usd, 0);
|
||||
agent.total_input_tokens = agent.attempts.reduce((sum, a) => sum + (a.input_tokens ?? 0), 0);
|
||||
agent.total_output_tokens = agent.attempts.reduce((sum, a) => sum + (a.output_tokens ?? 0), 0);
|
||||
agent.total_cache_read_tokens = agent.attempts.reduce((sum, a) => sum + (a.cache_read_tokens ?? 0), 0);
|
||||
agent.total_cache_write_tokens = agent.attempts.reduce((sum, a) => sum + (a.cache_write_tokens ?? 0), 0);
|
||||
|
||||
// 5. Update agent status based on outcome
|
||||
if (result.success) {
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
import fs from 'node:fs/promises';
|
||||
import { isFableModel, resolveModelId } from '../ai/models.js';
|
||||
import { formatDuration, formatTimestamp } from '../utils/formatting.js';
|
||||
import { LogStream } from './log-stream.js';
|
||||
import { generateWorkflowLogPath, type SessionMetadata } from './utils.js';
|
||||
@@ -87,19 +86,6 @@ export class WorkflowLogger {
|
||||
`Started: ${formatTimestamp()}`,
|
||||
];
|
||||
|
||||
// Surface Fable usage: its safety classifiers route cybersecurity tasks to
|
||||
// Opus 4.8, so those phases run on Opus 4.8 regardless of the tier setting.
|
||||
const fableTiers = (['small', 'medium', 'large'] as const)
|
||||
.map((tier) => ({ tier, model: resolveModelId(tier) }))
|
||||
.filter(({ model }) => isFableModel(model));
|
||||
if (fableTiers.length > 0) {
|
||||
const tierList = fableTiers.map(({ tier, model }) => `${tier} (${model})`).join(', ');
|
||||
lines.push(
|
||||
`Note: ${tierList} set to a Fable model. Fable's safety classifiers`,
|
||||
` route cybersecurity tasks to Opus 4.8, so those phases run on Opus 4.8.`,
|
||||
);
|
||||
}
|
||||
|
||||
lines.push(`================================================================================`, ``);
|
||||
|
||||
return this.logStream.write(lines.join('\n'));
|
||||
|
||||
Reference in New Issue
Block a user