feat: Add AI debug session view - #729
Conversation
|
Warning Review limit reached
More reviews will be available in 6 minutes and 15 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds an opt-in AI session devtools system. A new serializable ChangesAI Session Devtools
Sequence Diagram(s)sequenceDiagram
participant PythonCLI as sqlrooms CLI
participant Launcher as SqlroomsHttpServer
participant Config as /api/config
participant Store as CLI UI Store
participant AiSlice as AiSlice
participant SubAgent as Sub-agent<br/>Execution
participant ChatTransport as Chat Transport
participant ChatSessionDebugView as Debug View
PythonCLI->>Launcher: --ai-devtools flag
Launcher->>Launcher: ai_devtools = True
Config<<->>Launcher: aiDevtools: true
Store->>Store: aiDevtoolsEnabled = true
Store->>AiSlice: createAiSlice({<br/>devtools: {<br/>captureAgentSnapshots: true,<br/>persistAgentSnapshots: true<br/>}})
SubAgent->>AiSlice: streamSubAgent starts
AiSlice->>AiSlice: shouldCaptureAgentSnapshots() → true
SubAgent->>AiSlice: writeAgentSnapshot(id, {<br/>parentToolCallId,<br/>agentName, availableTools,<br/>startedAt})
SubAgent-->>AiSlice: agent completes
ChatTransport->>ChatTransport: onChatFinish/onChatError
ChatTransport->>AiSlice: state.ai.devtools.agentSnapshots
ChatTransport->>ChatTransport: writeAgentDebugStateToSession
ChatTransport-->>ChatSessionSchema: session.agentSnapshots persisted
Store->>ChatSessionDebugView: open (via AssistantPanel)
ChatSessionDebugView->>ChatSessionDebugView: sessionDebugModel.<br/>getSessionDebugTimeline
ChatSessionDebugView-->>Store: render multi-tab UI
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 397a6c29e8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| session.agentSnapshots = structuredClone( | ||
| state.ai.agentSnapshots, | ||
| ) as ChatSessionSchema['agentSnapshots']; |
There was a problem hiding this comment.
Persist only snapshots for this session
When agent snapshot persistence is enabled, this writes the slice-wide state.ai.agentSnapshots map into whichever session just finished. That map is populated globally across sessions, so after running an agent in session A and then completing a chat in session B, B's persisted agentSnapshots will include A's debug metadata even though B has no matching tool calls; this pollutes saved workspace state and can expose another session's tool names/descriptions in the raw debug view. Filter snapshots to toolCallIds present in session.uiMessages before assigning them here.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/ai-core/src/components/ChatHeader.tsx (1)
25-31:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd TSDoc for exported
ChatHeader.Line 25 exports a package API but there’s no TSDoc in the touched segment. Please document the component and the new
beforeCreateSessionActionprop contract.As per coding guidelines, "
packages/**/*.{ts,tsx}: Add tsdoc to exported types and functions".Suggested patch
+/** + * Header controls for chat sessions. + * + * `@param` onHistoryClick Opens session history. + * `@param` onCreateSession Optional override for creating a session. + * `@param` createSessionDisabled Disables create action. + * `@param` historyIsRunning Shows running indicator for background sessions. + * `@param` beforeCreateSessionAction Optional custom action rendered before the create-session button. + * `@param` className Optional container className. + */ export const ChatHeader: React.FC<ChatHeaderProps> = ({🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai-core/src/components/ChatHeader.tsx` around lines 25 - 31, The exported ChatHeader component is missing TSDoc documentation as required by the coding guidelines. Add a TSDoc comment block above the ChatHeader component export that documents the component's purpose and functionality. Additionally, ensure the ChatHeaderProps interface (which defines the props including the new beforeCreateSessionAction property) has proper TSDoc documentation that clearly describes the contract for each prop, particularly the beforeCreateSessionAction prop that handles the action to be executed before creating a new session.Source: Coding guidelines
🧹 Nitpick comments (2)
packages/codemirror/README.md (1)
320-321: ⚡ Quick winShow concrete usage for the folding helper in the example.
The snippet imports
foldAllExceptFirstFoldableRangebut doesn’t call it. Either remove the import or add a minimalonMountusage so readers can apply it directly.Also applies to: 346-350
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/codemirror/README.md` around lines 320 - 321, The README.md example imports the helper function foldAllExceptFirstFoldableRange but never demonstrates its actual usage in the code example, making it unclear how readers should apply it. Either remove the unused import of foldAllExceptFirstFoldableRange from the import statement at the top of the example, or add a concrete call to foldAllExceptFirstFoldableRange inside the onMount hook to show how it should be invoked with the editor instance. Ensure the example demonstrates practical usage so readers can directly apply the pattern.packages/codemirror/src/utils/folding.ts (1)
10-37: ⚡ Quick winAdd a focused test for the “skip first foldable range” contract.
This utility changes folding semantics; a small test asserting “root stays open, nested ranges fold” would prevent regressions.
As per coding guidelines,
**/*.test.{ts,tsx,js,jsx}: Add or update tests when changing behavior or public API, when practical.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/codemirror/src/utils/folding.ts` around lines 10 - 37, Add a focused test file (following the naming convention *.test.ts) for the foldAllExceptFirstFoldableRange function to prevent regressions. The test should verify that the function correctly implements its contract: the first foldable range in the document remains unfolded while all subsequent nested or sibling foldable ranges are folded. Create a test that sets up an EditorView with multiple foldable ranges at different nesting levels and assert that after calling foldAllExceptFirstFoldableRange, only the first range is left open and all others are folded.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/ai-config/src/schema/ChatSessionSchema.ts`:
- Around line 166-167: The agentSnapshots field in ChatSessionSchema uses
z.unknown() for its values, which allows malformed data that can crash
downstream code expecting structured AgentSnapshot objects. Replace the
z.unknown() schema validator in the agentSnapshots field definition with a
proper schema that validates the AgentSnapshot structure, ensuring that required
properties like availableTools are properly typed as arrays instead of accepting
arbitrary unknown values.
In `@packages/ai-core/src/AiSlice.ts`:
- Around line 533-535: The length check for the serialized snapshot is using
`serialized.length` which counts UTF-16 code units, not actual bytes, allowing
multibyte characters to bypass the byte limit. Replace the length comparison in
the condition that checks against `devtoolsOptions.maxAgentSnapshotBytes` to use
`Buffer.byteLength(serialized, 'utf8')` instead of `serialized.length` to
properly enforce the byte limit.
In `@packages/ai-core/src/chatSessionForking.ts`:
- Around line 82-101: The exported function getForkedAgentSnapshots is missing a
TSDoc comment block required by coding guidelines for exported functions in the
packages directory. Add a TSDoc comment block above the function definition that
includes a brief description of what the function does, `@param` tags documenting
the sourceSession and targetMessages parameters, and a `@returns` tag documenting
the return value. This will ensure the exported API is properly documented for
consistency with other exported types and functions in the package.
In `@packages/ai-core/src/chatTransport.ts`:
- Around line 112-127: The function writeAgentDebugStateToSession is currently
copying the entire global agentProgress and agentSnapshots maps from state.ai
into the session, which causes unrelated debug metadata to leak between
sessions. Modify the function to filter and persist only the debug state entries
that are scoped to the current session, rather than copying all global entries.
This requires identifying which entries in agentProgress and agentSnapshots
belong to the specific session being updated, and only cloning those relevant
entries into session.agentProgress and session.agentSnapshots respectively.
In `@packages/ai-core/src/devtools/ChatSessionDebugView.tsx`:
- Around line 27-38: Add TSDoc documentation to the exported
`ChatSessionDebugViewProps` type definition. Include a brief description
explaining the purpose of this props type for the debug view component above the
type export statement. Additionally, add similar TSDoc documentation to the
`ChatSessionDebugView` component export (referenced in the also applies to
section at lines 372-377) to describe what the component does and how it should
be used. Follow the existing TSDoc pattern already used in the individual
property comments within the type definition.
- Around line 679-683: The timing calculation in ChatSessionDebugView.tsx
subtracts startedAt from completedAt without verifying that both values exist.
Currently, the condition only checks if completedAt is present, but startedAt
could be undefined, resulting in NaN. Update the ternary operator to ensure both
toolTimings[toolCall.toolCallId]?.completedAt and
toolTimings[toolCall.toolCallId]?.startedAt exist before performing the
subtraction. If either value is missing, display 'n/a' instead.
In `@packages/ai-core/src/devtools/DebugJsonBlock.tsx`:
- Around line 16-22: Add TSDoc comments to document the exported
`DebugJsonBlockProps` type and the `DebugJsonBlock` component. For the
`DebugJsonBlockProps` type definition, add a JSDoc comment block above the type
that describes its purpose and briefly documents each property (title, value,
defaultOpen, className, editorClassName) to explain their semantics. For the
`DebugJsonBlock` component function (lines 33-79), add a JSDoc comment block
above the function declaration that explains its intended usage, describes what
it does, and documents any relevant behavior. Ensure all TSDoc comments follow
the project's coding guidelines for exported APIs.
In `@packages/ai-core/src/devtools/sessionDebugModel.ts`:
- Around line 10-26: Add TSDoc documentation comments above the
SessionDebugSummary exported type and all other exported types and functions in
the ranges 28-95 and 192-407 of this file. Each export should have a clear,
concise JSDoc/TSDoc comment block (/** */) that describes its purpose and usage
intent so that consumers get proper IntelliSense support and understand the API
surface of this debug-model module.
In `@packages/preset-eslint/base.js`:
- Around line 7-14: The pattern `@sqlrooms/*/*/**` in the
restrictedSqlroomsSubpathPatterns array is too broad and incorrectly blocks
valid one-level subexports like `@sqlrooms/ai/devtools`. Replace this pattern
with patterns that only block imports with 2 or more levels of nesting depth,
allowing single-level subexports. Apply the same fix to the equivalent patterns
appearing in the other restricted path arrays in this file (also present in the
sections around lines 39-42 and 51-54).
---
Outside diff comments:
In `@packages/ai-core/src/components/ChatHeader.tsx`:
- Around line 25-31: The exported ChatHeader component is missing TSDoc
documentation as required by the coding guidelines. Add a TSDoc comment block
above the ChatHeader component export that documents the component's purpose and
functionality. Additionally, ensure the ChatHeaderProps interface (which defines
the props including the new beforeCreateSessionAction property) has proper TSDoc
documentation that clearly describes the contract for each prop, particularly
the beforeCreateSessionAction prop that handles the action to be executed before
creating a new session.
---
Nitpick comments:
In `@packages/codemirror/README.md`:
- Around line 320-321: The README.md example imports the helper function
foldAllExceptFirstFoldableRange but never demonstrates its actual usage in the
code example, making it unclear how readers should apply it. Either remove the
unused import of foldAllExceptFirstFoldableRange from the import statement at
the top of the example, or add a concrete call to
foldAllExceptFirstFoldableRange inside the onMount hook to show how it should be
invoked with the editor instance. Ensure the example demonstrates practical
usage so readers can directly apply the pattern.
In `@packages/codemirror/src/utils/folding.ts`:
- Around line 10-37: Add a focused test file (following the naming convention
*.test.ts) for the foldAllExceptFirstFoldableRange function to prevent
regressions. The test should verify that the function correctly implements its
contract: the first foldable range in the document remains unfolded while all
subsequent nested or sibling foldable ranges are folded. Create a test that sets
up an EditorView with multiple foldable ranges at different nesting levels and
assert that after calling foldAllExceptFirstFoldableRange, only the first range
is left open and all others are folded.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 70fb9e12-613e-4dc1-a503-9c9c82fe3d32
📒 Files selected for processing (31)
apps/sqlrooms-cli-ui/src/components/AssistantChatContainer.tsxapps/sqlrooms-cli-ui/src/components/AssistantPanel.tsxapps/sqlrooms-cli-ui/src/runtimeConfig.tsapps/sqlrooms-cli-ui/src/store.tspackages/ai-config/src/schema/ChatSessionSchema.tspackages/ai-core/__tests__/sessionDebugModel.test.tspackages/ai-core/package.jsonpackages/ai-core/src/AiSlice.tspackages/ai-core/src/agents/AgentUtils.tspackages/ai-core/src/chatSessionForking.tspackages/ai-core/src/chatTransport.tspackages/ai-core/src/components/ChatHeader.tsxpackages/ai-core/src/devtools/ChatSessionDebugView.tsxpackages/ai-core/src/devtools/DebugJsonBlock.tsxpackages/ai-core/src/devtools/index.tspackages/ai-core/src/devtools/sessionDebugModel.tspackages/ai-core/src/index.tspackages/ai-core/src/types.tspackages/ai/README.mdpackages/ai/package.jsonpackages/ai/src/devtools.tspackages/ai/src/index.tspackages/codemirror/README.mdpackages/codemirror/src/index.tspackages/codemirror/src/utils/folding.tspackages/preset-eslint/base.jspython/sqlrooms-cli/README.mdpython/sqlrooms-cli/sqlrooms/cli.pypython/sqlrooms-cli/sqlrooms/web/launcher.pypython/sqlrooms-cli/tests/test_cli.pypython/sqlrooms-cli/tests/test_launcher.py
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 89017ed31a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "./devtools": { | ||
| "types": "./dist/devtools/index.d.ts", | ||
| "import": "./dist/devtools/index.js", | ||
| "default": "./dist/devtools/index.js" | ||
| } |
There was a problem hiding this comment.
Document the public ai-core devtools API
The root AGENTS.md says that when a public API is added or changed in an @sqlrooms/* package, that package's README.md must be updated. This new @sqlrooms/ai-core/devtools subexport and the related createAiSlice({ devtools }) snapshot controls are public ai-core APIs, but packages/ai-core/README.md still omits them from its setup/useful-exports docs, so lower-level @sqlrooms/ai-core consumers have no package-local documentation for enabling or importing the new debug surface.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/ai-core/src/AiSlice.ts (1)
332-337:⚠️ Potential issue | 🟠 Major | ⚡ Quick winApply the snapshot size gate during rehydration too.
writeAgentSnapshotenforcesmaxAgentSnapshotBytes, but persistedsession.agentSnapshotsare copied straight into live devtools state here. A stale/imported config with an oversized snapshot can still populateai.devtools.agentSnapshotsand freeze the debug view despite the configured cap.🛡️ Proposed fix
+ function cloneAgentSnapshotWithinLimit( + snapshot: AgentSnapshot, + ): AgentSnapshot | undefined { + try { + const serialized = JSON.stringify(snapshot); + const byteLength = new TextEncoder().encode(serialized).byteLength; + if (byteLength > devtoolsOptions.maxAgentSnapshotBytes) { + return undefined; + } + return JSON.parse(serialized) as AgentSnapshot; + } catch { + return undefined; + } + } + function rehydrateFromSessions(config: AiSliceConfig) { const timings: Record<string, ToolTimingEntry> = {}; const progress: Record<string, AgentToolCall[]> = {}; const snapshots: Record<string, AgentSnapshot> = {}; @@ if (session.agentSnapshots) { - Object.assign( - snapshots, - session.agentSnapshots as Record<string, AgentSnapshot>, - ); + for (const [parentToolCallId, snapshot] of Object.entries( + session.agentSnapshots as Record<string, AgentSnapshot>, + )) { + const clonedSnapshot = cloneAgentSnapshotWithinLimit(snapshot); + if (clonedSnapshot) { + snapshots[parentToolCallId] = clonedSnapshot; + } + } }Then reuse the helper in
writeAgentSnapshot:writeAgentSnapshot: ( parentToolCallId: string, snapshot: AgentSnapshot, ) => { if (!devtoolsOptions.captureAgentSnapshots) return; - let clonedSnapshot: AgentSnapshot; - try { - const serialized = JSON.stringify(snapshot); - const byteLength = new TextEncoder().encode( - serialized, - ).byteLength; - if (byteLength > devtoolsOptions.maxAgentSnapshotBytes) { - return; - } - clonedSnapshot = JSON.parse(serialized) as AgentSnapshot; - } catch { - return; - } + const clonedSnapshot = cloneAgentSnapshotWithinLimit(snapshot); + if (!clonedSnapshot) return; set((state) =>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai-core/src/AiSlice.ts` around lines 332 - 337, The rehydration logic in the session.agentSnapshots block is copying persisted snapshots directly into live devtools state without enforcing the maxAgentSnapshotBytes size limit that is already validated in writeAgentSnapshot. Extract the snapshot size validation logic from writeAgentSnapshot into a reusable helper function, then apply that helper to filter or validate each snapshot in session.agentSnapshots before they are merged into the snapshots object via Object.assign. This ensures that oversized snapshots from stale or imported configs cannot populate the live devtools state and cause performance issues.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/ai-core/src/AiSlice.ts`:
- Around line 332-337: The rehydration logic in the session.agentSnapshots block
is copying persisted snapshots directly into live devtools state without
enforcing the maxAgentSnapshotBytes size limit that is already validated in
writeAgentSnapshot. Extract the snapshot size validation logic from
writeAgentSnapshot into a reusable helper function, then apply that helper to
filter or validate each snapshot in session.agentSnapshots before they are
merged into the snapshots object via Object.assign. This ensures that oversized
snapshots from stale or imported configs cannot populate the live devtools state
and cause performance issues.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9bbf4333-2358-484c-a07d-88757e237c7f
📒 Files selected for processing (6)
packages/ai-core/README.mdpackages/ai-core/src/AiSlice.tspackages/ai-core/src/agents/AgentUtils.tspackages/ai-core/src/chatTransport.tspackages/ai-core/src/devtools/ChatSessionDebugView.tsxpackages/ai-core/src/types.ts
✅ Files skipped from review due to trivial changes (1)
- packages/ai-core/README.md
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/ai-core/src/agents/AgentUtils.ts
- packages/ai-core/src/chatTransport.ts
- packages/ai-core/src/devtools/ChatSessionDebugView.tsx
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a2f2538049
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| /** Optional persisted agent devtools snapshots, keyed by parent toolCallId */ | ||
| agentSnapshots: z.record(z.string(), AgentSnapshotSchema).optional(), |
There was a problem hiding this comment.
Document the ai-config snapshot field
The root AGENTS.md says that public API changes in @sqlrooms/* packages must update that package's README.md. This adds agentSnapshots to the exported @sqlrooms/ai-config ChatSessionSchema, but packages/ai-config/README.md still only documents the older session shape, so consumers of the schema do not get package-local docs for the new persisted devtools field.
Useful? React with 👍 / 👎.
| const copiedToolCallIds = getToolCallIdsFromMessages(targetMessages); | ||
| const agentSnapshots = Object.fromEntries( | ||
| Object.entries(sourceSession.agentSnapshots).filter(([toolCallId]) => | ||
| copiedToolCallIds.has(toolCallId), |
There was a problem hiding this comment.
Preserve nested agent snapshots when forking
When a retained top-level agent call has nested sub-agent calls, writeAgentDebugStateToSession persists snapshots for all reachable toolCallIds, but this fork helper recomputes IDs only from top-level targetMessages parts. The fork can still keep the parent agentProgress tree, so the nested calls render, but their matching agentSnapshots are dropped and the debug view loses the child agent tool metadata after forking such a session; include reachable IDs from sourceSession.agentProgress before filtering snapshots.
Useful? React with 👍 / 👎.
Summary
Testing
Summary by CodeRabbit