diff --git a/src/app/shell/AppShell.tsx b/src/app/shell/AppShell.tsx index 3b50226..4d13594 100644 --- a/src/app/shell/AppShell.tsx +++ b/src/app/shell/AppShell.tsx @@ -5,6 +5,7 @@ import { ChatSidebar, type ChatSidebarTab } from "./ChatSidebar"; import { TopBar } from "./TopBar"; import { WindowTitleBar } from "./WindowTitleBar"; import { SpotifyMobileWidget } from "../../features/spotify/components/SpotifyMiniPlayer"; +import { AgentDebugPanel } from "../../features/agents/components/AgentDebugPanel"; import { ChatNotificationBubbles } from "../../features/chats/components/ChatNotificationBubbles"; import { getTrackerPanelWidthForProfile, @@ -1022,6 +1023,7 @@ export function AppShell() { )} + diff --git a/src/engine/agents-runtime/executor/agent-executor.ts b/src/engine/agents-runtime/executor/agent-executor.ts index 9add8c9..ffd73dd 100644 --- a/src/engine/agents-runtime/executor/agent-executor.ts +++ b/src/engine/agents-runtime/executor/agent-executor.ts @@ -7,16 +7,15 @@ import type { LLMToolCall, LLMToolDefinition, } from "../../generation-core/llm/base-provider.js"; -import type { AgentResult, AgentContext, AgentResultType } from "../../contracts/types/agent"; +import type { AgentResult, AgentContext, AgentResultType, AgentDebugEntry } from "../../contracts/types/agent"; import { getDefaultAgentPrompt } from "../../contracts/constants/agent-prompts"; import { DEFAULT_AGENT_CONTEXT_SIZE, DEFAULT_AGENT_MAX_TOKENS, MAX_AGENT_MAX_TOKENS, MIN_AGENT_MAX_TOKENS } from "../../contracts/types/agent"; -const isDebugAgentsEnabled = () => false; -const logger = { - debug: (..._args: unknown[]) => {}, - info: (..._args: unknown[]) => {}, - warn: (..._args: unknown[]) => {}, - error: (..._args: unknown[]) => {}, - isLevelEnabled: (_level: string) => false, +type Logger = { + debug: (...args: unknown[]) => void; + info: (...args: unknown[]) => void; + warn: (...args: unknown[]) => void; + error: (...args: unknown[]) => void; + isLevelEnabled: (level: string) => boolean; }; const MAX_AGENT_CONTEXT_MESSAGES = 200; @@ -56,6 +55,34 @@ export function normalizeAgentContextSize(value: unknown, fallback = DEFAULT_AGE return Math.max(1, Math.min(MAX_AGENT_CONTEXT_MESSAGES, Math.trunc(parsed))); } +function createLogger(enabled: boolean): Logger { + const log = (level: "debug" | "info" | "warn" | "error", args: unknown[]) => { + if (!enabled) return; + const target = + typeof console !== "undefined" && typeof console[level] === "function" + ? console[level] + : typeof console !== "undefined" && typeof console.log === "function" + ? console.log + : undefined; + target?.(...args); + }; + + return { + debug: (...args: unknown[]) => log("debug", args), + info: (...args: unknown[]) => log("info", args), + warn: (...args: unknown[]) => log("warn", args), + error: (...args: unknown[]) => log("error", args), + isLevelEnabled: () => enabled, + }; +} + +function emitDebug(context: AgentContext, entry: Omit & { timestamp?: number }) { + context.debugSink?.({ + ...entry, + timestamp: entry.timestamp ?? Date.now(), + }); +} + function redactSensitiveValue(value: unknown): unknown { if (Array.isArray(value)) { return value.map((item) => redactSensitiveValue(item)); @@ -118,6 +145,8 @@ export async function executeAgent( toolContext?: AgentToolContext, ): Promise { const startTime = Date.now(); + const logger = createLogger(context.debugMode === true); + const emit = (entry: Omit & { timestamp?: number }) => emitDebug(context, entry); try { const template = config.promptTemplate || getDefaultAgentPrompt(config.type); @@ -151,16 +180,25 @@ export async function executeAgent( toolContext, streamResponses, startTime, + context, context.signal, ); } // Call LLM (streaming to avoid proxy timeouts, no tools) logger.info(`[agent] ${config.type} (${config.name}) — ${model}`); + emit({ + level: "info", + phase: config.phase, + message: "agent-start", + args: [config.type, config.name, model], + }); for (const msg of messages) { logger.debug(`[agent] [${msg.role}] ${msg.content}`); + emit({ level: "debug", phase: config.phase, message: "prompt-message", args: [msg.role, msg.content] }); } logger.debug(`[agent] ═══ END PROMPT — temperature=${temperature} maxTokens=${maxTokens} ═══\n`); + emit({ level: "debug", phase: config.phase, message: "prompt-end", args: [temperature, maxTokens] }); let responseText = ""; const result = await provider.chatComplete(messages, { @@ -182,6 +220,18 @@ export async function executeAgent( logger.info(`[agent] ${config.type} done (${responseText.length} chars, ${durationMs}ms)`); logger.debug(`[agent] ${config.type} raw response: ${responseText.slice(0, 500)}`); + emit({ + level: "info", + phase: config.phase, + message: "agent-complete", + args: [config.type, responseText.length, durationMs], + }); + emit({ + level: "debug", + phase: config.phase, + message: "raw-response", + args: [config.type, responseText.slice(0, 500)], + }); // Parse the result based on agent type const parsed = parseAgentResponse(config, responseText); @@ -215,12 +265,15 @@ async function executeAgentWithTools( toolContext: AgentToolContext, streamResponses: boolean, startTime: number, + context: AgentContext, signal?: AbortSignal, ): Promise { const MAX_TOOL_ROUNDS = 5; const loopMessages = [...initialMessages]; let totalTokens = 0; - const debugAgentsEnabled = isDebugAgentsEnabled() && logger.isLevelEnabled("debug"); + const logger = createLogger(context.debugMode === true); + const debugAgentsEnabled = logger.isLevelEnabled("debug"); + const emit = (entry: Omit & { timestamp?: number }) => emitDebug(context, entry); for (let round = 0; round < MAX_TOOL_ROUNDS; round++) { const result = await provider.chatComplete(loopMessages, { @@ -261,6 +314,12 @@ async function executeAgentWithTools( // Execute each tool call and append results for (const tc of result.toolCalls) { logger.info("[agent-tools] %s calling: %s", config.type, tc.function.name); + emit({ + level: "info", + phase: config.phase, + message: "tool-call", + toolCall: { name: tc.function.name, arguments: formatToolPayloadForLog(tc.function.arguments), allowed: true }, + }); if (debugAgentsEnabled) { logger.debug("[agent-tools] %s args: %s", config.type, formatToolPayloadForLog(tc.function.arguments)); } @@ -272,6 +331,12 @@ async function executeAgentWithTools( throw err; } logger.info("[agent-tools] %s %s completed", config.type, tc.function.name); + emit({ + level: "info", + phase: config.phase, + message: "tool-result", + toolResult: { name: tc.function.name, result: formatToolPayloadForLog(toolResult), success: true }, + }); if (debugAgentsEnabled) { logger.debug("[agent-tools] %s result: %s", config.type, formatToolPayloadForLog(toolResult)); } @@ -325,6 +390,8 @@ export async function executeAgentBatch( model: string, ): Promise { if (configs.length === 0) return []; + const logger = createLogger(context.debugMode === true); + const emit = (entry: Omit & { timestamp?: number }) => emitDebug(context, entry); const isolatedConfigs = configs.filter(shouldRunAgentIndividually); if (isolatedConfigs.length === configs.length) { logger.info( @@ -396,12 +463,26 @@ export async function executeAgentBatch( logger.info( `[agent-batch] maxTokens: ${batchMaxTokens} (sum=${rawBatchMaxTokens} from [${perAgentTokens.join(", ")}]${provider.maxTokensOverrideValue !== null ? `, capped at ${provider.maxTokensOverrideValue}` : ""})`, ); + emit({ + level: "info", + phase: configs[0]!.phase, + message: "batch-start", + agents: configs.map((c) => ({ + type: c.type, + name: c.name, + model, + maxTokens: normalizeAgentMaxTokens(c.settings.maxTokens), + })), + batchMaxTokens, + }); logger.debug(`\n[agent-batch] ═══ BATCH PROMPT — [${configs.map((c) => c.type).join(", ")}] — ${model} ═══`); for (const msg of messages) { logger.debug(`[agent-batch] [${msg.role}] ${msg.content}`); + emit({ level: "debug", phase: configs[0]!.phase, message: "batch-prompt-message", args: [msg.role, msg.content] }); } logger.debug(`[agent-batch] ═══ END BATCH PROMPT — temperature=${temperature} maxTokens=${batchMaxTokens} ═══\n`); + emit({ level: "debug", phase: configs[0]!.phase, message: "batch-prompt-end", args: [temperature, batchMaxTokens] }); // Use streaming (onToken) to keep the connection alive — avoids proxy // timeouts (e.g. Cloudflare 524) on large batch responses. @@ -428,6 +509,13 @@ export async function executeAgentBatch( logger.info(`[agent-batch] Got response (${responseText.length} chars, ${durationMs}ms, ${totalTokens} tokens)`); logger.debug(`[agent-batch] ${responseText}`); + emit({ + level: "info", + phase: configs[0]!.phase, + message: "batch-response", + args: [responseText.length, durationMs, totalTokens], + }); + emit({ level: "debug", phase: configs[0]!.phase, message: "batch-raw-response", args: [responseText] }); // Parse the batched response into individual results const { parsed, failed } = parseBatchResponse(configs, responseText, durationMs, totalTokens); diff --git a/src/engine/agents-runtime/knowledge/knowledge-router.ts b/src/engine/agents-runtime/knowledge/knowledge-router.ts index cccd5e5..3365748 100644 --- a/src/engine/agents-runtime/knowledge/knowledge-router.ts +++ b/src/engine/agents-runtime/knowledge/knowledge-router.ts @@ -260,6 +260,17 @@ export async function executeKnowledgeRouter( options: KnowledgeRouterCandidateOptions = {}, ): Promise { const startTime = Date.now(); + const logger = { + debug: (...args: unknown[]) => { + if (baseContext.debugMode === true) console.debug(...args); + }, + warn: (...args: unknown[]) => { + if (baseContext.debugMode === true) console.warn(...args); + }, + error: (...args: unknown[]) => { + if (baseContext.debugMode === true) console.error(...args); + }, + }; // Empty input → no work, no LLM call. if (entries.length === 0) { diff --git a/src/engine/agents-runtime/pipeline/agent-pipeline.ts b/src/engine/agents-runtime/pipeline/agent-pipeline.ts index 7e14545..6194a40 100644 --- a/src/engine/agents-runtime/pipeline/agent-pipeline.ts +++ b/src/engine/agents-runtime/pipeline/agent-pipeline.ts @@ -1,4 +1,4 @@ -import type { AgentContext, AgentResult } from "../../contracts/types/agent"; +import type { AgentContext, AgentDebugEntry, AgentResult } from "../../contracts/types/agent"; import type { BaseLLMProvider } from "../../generation-core/llm/base-provider.js"; import { executeAgent, @@ -7,11 +7,26 @@ import { type AgentToolContext, } from "../executor/agent-executor.js"; -const logger = { - debug: (..._args: unknown[]) => {}, - warn: (..._args: unknown[]) => {}, - error: (..._args: unknown[]) => {}, -}; +function createLogger(enabled: boolean) { + return { + debug: (...args: unknown[]) => { + if (enabled) console.debug(...args); + }, + warn: (...args: unknown[]) => { + if (enabled) console.warn(...args); + }, + error: (...args: unknown[]) => { + if (enabled) console.error(...args); + }, + }; +} + +function emitDebug(context: AgentContext, entry: Omit & { timestamp?: number }) { + context.debugSink?.({ + ...entry, + timestamp: entry.timestamp ?? Date.now(), + }); +} /** A fully resolved agent ready for execution. */ export interface ResolvedAgent extends AgentExecConfig { @@ -143,6 +158,18 @@ async function executeGroup( context: AgentContext, onResult?: AgentResultCallback, ): Promise { + const logger = createLogger(context.debugMode === true); + emitDebug(context, { + level: "debug", + phase: group.agents[0]?.phase ?? "unknown", + message: "group-start", + agents: group.agents.map((agent) => ({ + type: agent.type, + name: agent.name, + model: agent.model, + maxTokens: normalizeAgentMaxParallelJobs(agent.maxParallelJobs), + })), + }); const groupContext = buildAgentContext(group.agents[0]!, context); // Separate tool-using agents (can't be batched) from regular agents const toolAgents = group.agents.filter((a) => a.toolContext?.tools.length); @@ -202,7 +229,14 @@ async function executePhase( const phaseAgents = agents.filter((a) => a.phase === phase); if (phaseAgents.length === 0) return []; + const logger = createLogger(context.debugMode === true); const groups = groupByProviderModel(phaseAgents).flatMap(splitGroupForParallelJobs); + emitDebug(context, { + level: "debug", + phase, + message: "phase-groups", + args: [phaseAgents.length, groups.length], + }); logger.debug( '[agent-pipeline] Phase "%s": %d agents → %d job group(s) %j', @@ -238,6 +272,12 @@ async function executePhase( String(entry.reason), ); } + emitDebug(context, { + level: "error", + phase, + message: "group-error", + args: [group.agents.map((a) => a.type).join(", "), String(entry.reason)], + }); for (const agent of group.agents) { const errorResult: AgentResult = { agentId: agent.id, diff --git a/src/engine/contracts/types/agent.ts b/src/engine/contracts/types/agent.ts index 2a46f0c..6063002 100644 --- a/src/engine/contracts/types/agent.ts +++ b/src/engine/contracts/types/agent.ts @@ -81,6 +81,33 @@ export interface AgentResult { error: string | null; } +/** Structured debug entry emitted by the agent runtime. */ +export interface AgentDebugEntry { + level?: "debug" | "info" | "warn" | "error"; + phase: string; + message?: string; + args?: unknown[]; + agents?: Array<{ + type: string; + name: string; + model: string; + maxTokens: number; + }>; + results?: AgentResult[]; + toolCall?: { + name: string; + arguments: string; + allowed: boolean; + }; + toolResult?: { + name: string; + result: string; + success: boolean; + }; + batchMaxTokens?: number; + timestamp: number; +} + /** Shared context passed to every agent. */ export interface AgentContext { chatId: string; @@ -134,6 +161,8 @@ export interface AgentContext { } | null; /** The agent's own persistent memory (key-value) */ memory: Record; + /** Optional sink for structured runtime debug entries. */ + debugSink?: (entry: Omit & { timestamp?: number }) => void; /** Lorebook entries activated for this generation (read context) */ activatedLorebookEntries: Array<{ id: string; name: string; content: string; tag: string }> | null; /** All lorebook IDs the agent can write to */ @@ -146,6 +175,8 @@ export interface AgentContext { parallelResults?: AgentResult[]; /** Whether internal agent LLM calls should use transport streaming. */ streaming?: boolean; + /** Whether agent runtime logging should emit to the console. */ + debugMode?: boolean; /** Abort signal — when triggered, agent execution should stop. Typed as `any` to avoid DOM/Node lib dependency. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any signal?: any; diff --git a/src/engine/generation/agent-runner.ts b/src/engine/generation/agent-runner.ts index 1cea781..7b41dce 100644 --- a/src/engine/generation/agent-runner.ts +++ b/src/engine/generation/agent-runner.ts @@ -34,6 +34,8 @@ export interface GenerationAgentRuntimeInput { persona: GenerationPersonaContext | null; activatedLorebookEntries: Array<{ id: string; name: string; content: string; tag: string }>; chatSummary: string | null; + debugMode?: boolean; + debugSink?: AgentContext["debugSink"]; signal?: AbortSignal; agentTypes?: Set; } @@ -627,6 +629,8 @@ async function buildAgentContext(deps: AgentDeps, input: GenerationAgentRuntimeI activatedLorebookEntries: input.activatedLorebookEntries, writableLorebookIds: null, chatSummary: input.chatSummary, + debugMode: input.debugMode === true, + debugSink: input.debugSink, streaming: true, signal: input.signal, }; diff --git a/src/engine/generation/start-generation.ts b/src/engine/generation/start-generation.ts index 33c5e86..f9e771c 100644 --- a/src/engine/generation/start-generation.ts +++ b/src/engine/generation/start-generation.ts @@ -1,4 +1,4 @@ -import type { AgentResult } from "../contracts/types/agent"; +import type { AgentContext, AgentResult } from "../contracts/types/agent"; import type { GameState } from "../contracts/types/game-state"; import type { EventGateway } from "../capabilities/events"; import type { IntegrationGateway } from "../capabilities/integrations"; @@ -53,6 +53,8 @@ export interface StartGenerationInput extends JsonRecord { forCharacterId?: string | null; mentionedCharacterNames?: string[]; attachments?: PromptAttachment[]; + debugMode?: boolean; + debugSink?: AgentContext["debugSink"]; } export interface GenerationEngineDeps { @@ -535,6 +537,8 @@ export async function* startGeneration( persona: assembly.persona, activatedLorebookEntries: assembly.activatedLorebookEntries, chatSummary: assembly.chatSummary, + debugMode: input.debugMode === true, + debugSink: input.debugSink, signal, }, (result) => agentEvents.push(result), diff --git a/src/features/agents/components/AgentDebugPanel.tsx b/src/features/agents/components/AgentDebugPanel.tsx index b3e5329..d12c95a 100644 --- a/src/features/agents/components/AgentDebugPanel.tsx +++ b/src/features/agents/components/AgentDebugPanel.tsx @@ -6,7 +6,7 @@ // ────────────────────────────────────────────── import { useState } from "react"; import { AnimatePresence, motion } from "framer-motion"; -import { Bug, ChevronDown, ChevronUp, X, CheckCircle2, XCircle, Clock, Wrench } from "lucide-react"; +import { Bug, ChevronDown, ChevronUp, X, CheckCircle2, XCircle, Clock, FileText, Wrench } from "lucide-react"; import { useAgentStore } from "../../../shared/stores/agent.store"; import { useUIStore } from "../../../shared/stores/ui.store"; import { cn } from "../../../shared/lib/utils"; @@ -26,6 +26,7 @@ export function AgentDebugPanel() { const setupEntries = debugLog.filter((e) => e.agents && !e.results); const resultEntries = debugLog.filter((e) => e.results); const toolEntries = debugLog.filter((e) => e.toolCall || e.toolResult); + const detailEntries = debugLog.filter((e) => !e.agents && !e.results && !e.toolCall && !e.toolResult); return ( ( +
+
+ + {formatDebugMessage(entry.message)} + {entry.level && {entry.level}} +
+
{formatPhase(entry.phase)}
+ {entry.args && entry.args.length > 0 && ( +
+                      {formatDebugArgs(entry.args)}
+                    
+ )} +
+ ))} + {/* Fallback: show lastResults when no debug log entries */} - {resultEntries.length === 0 && toolEntries.length === 0 && lastResults.size > 0 && ( + {resultEntries.length === 0 && toolEntries.length === 0 && detailEntries.length === 0 && lastResults.size > 0 && (
Last Agent Results
@@ -210,6 +228,28 @@ export function AgentDebugPanel() { ); } +function formatDebugMessage(message?: string): string { + if (!message) return "Debug Event"; + return message + .split("-") + .filter(Boolean) + .map((part) => part[0]!.toUpperCase() + part.slice(1)) + .join(" "); +} + +function formatDebugArgs(args: unknown[]): string { + return args + .map((arg) => { + if (typeof arg === "string") return arg; + try { + return JSON.stringify(arg, null, 2); + } catch { + return String(arg); + } + }) + .join("\n\n"); +} + function formatPhase(phase: string): string { switch (phase) { case "pre_generation": diff --git a/src/features/characters/components/CharacterAvatarImage.tsx b/src/features/characters/components/CharacterAvatarImage.tsx new file mode 100644 index 0000000..5cc593e --- /dev/null +++ b/src/features/characters/components/CharacterAvatarImage.tsx @@ -0,0 +1,48 @@ +import type { AvatarCrop } from "../../../shared/lib/utils"; +import { cn, getAvatarCropStyle, parseAvatarCropJson } from "../../../shared/lib/utils"; + +function isAvatarCrop(value: unknown): value is AvatarCrop { + return ( + !!value && + typeof value === "object" && + Number.isFinite((value as AvatarCrop).srcX) && + Number.isFinite((value as AvatarCrop).srcY) && + Number.isFinite((value as AvatarCrop).srcWidth) && + Number.isFinite((value as AvatarCrop).srcHeight) && + (value as AvatarCrop).srcWidth > 0 && + (value as AvatarCrop).srcHeight > 0 && + (value as AvatarCrop).srcX >= 0 && + (value as AvatarCrop).srcY >= 0 && + (value as AvatarCrop).srcX + (value as AvatarCrop).srcWidth <= 1.001 && + (value as AvatarCrop).srcY + (value as AvatarCrop).srcHeight <= 1.001 + ); +} + +function resolveAvatarCrop(crop: unknown): AvatarCrop | null { + if (!crop) return null; + if (typeof crop === "string") return parseAvatarCropJson(crop); + return isAvatarCrop(crop) ? crop : null; +} + +export function CharacterAvatarImage({ + src, + alt, + crop, + className, +}: { + src: string; + alt: string; + crop?: unknown; + className?: string; +}) { + return ( + {alt} + ); +} diff --git a/src/features/characters/components/CharacterLibraryView.tsx b/src/features/characters/components/CharacterLibraryView.tsx index bf9d721..eb4b2fe 100644 --- a/src/features/characters/components/CharacterLibraryView.tsx +++ b/src/features/characters/components/CharacterLibraryView.tsx @@ -3,8 +3,9 @@ import { ArrowLeft, ArrowUpDown, Download, MessageCircle, Pencil, Plus, Search, import { useCharacters } from "../hooks/use-characters"; import { useStartChatFromCharacter } from "../hooks/use-start-chat-from-character"; import { getCharacterTitle } from "../../../shared/lib/character-display"; -import { cn, getAvatarCropStyle, type AvatarCrop } from "../../../shared/lib/utils"; +import { cn } from "../../../shared/lib/utils"; import { useUIStore } from "../../../shared/stores/ui.store"; +import { CharacterAvatarImage } from "./CharacterAvatarImage"; type CharacterData = Record & { name?: string; @@ -106,14 +107,10 @@ function CharacterLibraryDetailCard({
{character.avatarPath ? ( - {characterName ) : (
@@ -428,15 +425,11 @@ export function CharacterLibraryView() { >
{char.avatarPath ? ( - {charName} ) : (
diff --git a/src/features/characters/components/CharactersPanel.tsx b/src/features/characters/components/CharactersPanel.tsx index cf5d5d4..692944f 100644 --- a/src/features/characters/components/CharactersPanel.tsx +++ b/src/features/characters/components/CharactersPanel.tsx @@ -48,8 +48,9 @@ import { } from "lucide-react"; import { getCharacterTitle } from "../../../shared/lib/character-display"; import { useUIStore } from "../../../shared/stores/ui.store"; -import { cn, getAvatarCropStyle, type AvatarCrop } from "../../../shared/lib/utils"; +import { cn } from "../../../shared/lib/utils"; import { ExportFormatDialog, type ExportFormatChoice } from "../../../shared/components/ui/ExportFormatDialog"; +import { CharacterAvatarImage } from "./CharacterAvatarImage"; type CharacterRow = { id: string; @@ -946,12 +947,7 @@ export function CharactersPanel() { >
{member.avatarPath ? ( - {member.name} + ) : ( )} @@ -1120,14 +1116,10 @@ export function CharactersPanel() {
{avatarUrl ? (
- {charName}
) : ( diff --git a/src/features/generation/hooks/use-generate.ts b/src/features/generation/hooks/use-generate.ts index 0e374d5..c19febe 100644 --- a/src/features/generation/hooks/use-generate.ts +++ b/src/features/generation/hooks/use-generate.ts @@ -36,6 +36,7 @@ import { type GenerationReplay, } from "../../../engine/generation/generation-replay"; import { readNonNegativeInteger } from "../../../engine/generation/runtime-records"; +import type { AgentDebugEntry } from "../../../engine/contracts/types/agent"; export type GenerateArgs = GenerationReplayInput & { chatId: string; @@ -846,7 +847,12 @@ export function useGenerate() { (streamArgs, signal) => startGeneration( { storage: storageApi, llm: llmApi, integrations: integrationGateway }, - streamArgs, + { + ...streamArgs, + debugMode: useUIStore.getState().debugMode, + debugSink: (entry: Omit & { timestamp?: number }) => + useAgentStore.getState().addDebugEntry(entry), + }, signal, ) as AsyncGenerator, { diff --git a/src/features/settings/components/SettingsPanel.tsx b/src/features/settings/components/SettingsPanel.tsx index 7b1ad0e..e062dfa 100644 --- a/src/features/settings/components/SettingsPanel.tsx +++ b/src/features/settings/components/SettingsPanel.tsx @@ -3410,7 +3410,7 @@ function AdvancedSettings() { label="Debug mode" checked={debugMode} onChange={setDebugMode} - help="Logs the prompt and response payloads sent to the local Tauri console for debugging." + help="Shows the in-app agent debug panel with prompt, response, tool, and result details for troubleshooting." /> {/* ── Profile Export ── */} diff --git a/src/shared/stores/agent.store.ts b/src/shared/stores/agent.store.ts index 70bee10..20fbe16 100644 --- a/src/shared/stores/agent.store.ts +++ b/src/shared/stores/agent.store.ts @@ -2,7 +2,7 @@ // Zustand Store: Agent Slice // ────────────────────────────────────────────── import { create } from "zustand"; -import type { AgentResult, CharacterCardFieldUpdate } from "../../engine/contracts/types/agent"; +import type { AgentDebugEntry, AgentResult, CharacterCardFieldUpdate } from "../../engine/contracts/types/agent"; import type { AgentFailure } from "../lib/agent-failures"; /** @@ -23,29 +23,6 @@ export interface PendingCardUpdate { timestamp: number; } -export interface AgentDebugEntry { - phase: string; - agents?: Array<{ - type: string; - name: string; - model: string; - maxTokens: number; - }>; - results?: AgentResult[]; - toolCall?: { - name: string; - arguments: string; - allowed: boolean; - }; - toolResult?: { - name: string; - result: string; - success: boolean; - }; - batchMaxTokens?: number; - timestamp: number; -} - interface AgentState { activeAgents: string[]; lastResults: Map;