Skip to content

feat: Add per-session draft AI context state - #707

Merged
ilyabo merged 7 commits into
mainfrom
prompt-draft-context
Jun 10, 2026
Merged

ilyabo merged 7 commits into
mainfrom
prompt-draft-context

Conversation

@ilyabo

@ilyabo ilyabo commented Jun 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary:
This adds session-owned draft context state for AI conversations. Instead of hosts keeping context selector state globally and syncing it on session switches, each AI session can now store its own draft context item IDs.

Changes:

  • Added optional draftContextItemIds to AnalysisSessionSchema.
  • Added AI slice accessors:
    • getSessionDraftContextItemIds
    • setSessionDraftContextItemIds
  • Clear draftContextItemIds when startAnalysis captures context into runContext.
  • Added tests covering:
    • draft context isolation across sessions
    • draft context clearing after a run starts

Why:
This lets host apps model composer context the same way they already model prompt/session state: as per-session draft state. It avoids cross-session context leakage and removes the need for app-level synchronization effects.

Validation:

  • AiSlice.modelSelection.test.ts passed.
  • tsc --noEmit passed for ai-config and ai-core.

Summary by CodeRabbit

  • New Features

    • Per-session draft context management: users’ selected composer items are preserved per session before running analysis.
    • Draft context is captured into the analysis run when an analysis starts and is cleared afterward to avoid leaking across runs.
  • Tests

    • Added tests covering isolation of draft context between sessions and its lifecycle during analysis start/clear.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ilyabo, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 2 minutes and 19 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e225291b-e91f-44c9-817f-e1291d77a83a

📥 Commits

Reviewing files that changed from the base of the PR and between 4265a1d and fa36af2.

📒 Files selected for processing (2)
  • packages/ai-core/__tests__/contextSelection.test.ts
  • packages/ai-core/src/contextSelection.ts
📝 Walkthrough

Walkthrough

Adds per-session draftContextItemIds?: string[] to session schema, exposes getter/setter APIs in the AI slice, initializes and clears the field during session lifecycle and analysis capture, updates UI to read/write per-session drafts, refactors run-context derivation to be session-scoped, and adds tests and public exports.

Changes

Draft Context Session Lifecycle

Layer / File(s) Summary
Schema and API contract
packages/ai-config/src/schema/AnalysisSessionSchema.ts, packages/ai-core/src/AiSlice.ts
AnalysisSessionSchema adds optional draftContextItemIds. AiSlice types update to include getSessionDraftContextItemIds / setSessionDraftContextItemIds and getRunContext(sessionId) signature.
AiSlice implementation & lifecycle
packages/ai-core/src/AiSlice.ts
Implements session-level draft getter/setter (dedupes on set, undefined clears). New sessions initialize draftContextItemIds: undefined. startAnalysis(sessionId) calls getRunContext(sessionId) and clears draftContextItemIds.
Unit tests: isolation and capture
packages/ai-core/__tests__/AiSlice.modelSelection.test.ts
Tests make getRunContext session-aware and verify per-session draft isolation, capture of draft into runContext on analysis start, and clearing of the draft field.
Context-selection helpers & exports
packages/ai-core/src/contextSelection.ts, packages/ai-core/src/index.ts, packages/ai/src/index.ts
Adds isAnalysisSessionEmpty, getRunContextItemIds, getVisibleSessionContextItemIds, getEffectiveSessionContextItemIds and re-exports them and AnalysisSessionSchema for public consumption.
getRunContext refactor & store integration
apps/sqlrooms-cli-ui/src/context/getRunContext.ts, apps/sqlrooms-cli-ui/src/store.ts, apps/sqlrooms-cli-ui/src/store-types.ts
getRunContext now looks up a session by sessionId, prefers draft/context-derived IDs via the new helpers, supports an implicit artifact id for CLI artifact types, and store wiring passes sessionId into the AI slice; global aiContext fields removed from room state.
UI integration changes
apps/sqlrooms-cli-ui/src/components/*, apps/sqlrooms-cli-ui/src/context/*
Assistant components and helpers now derive visible/validated selected IDs from session-visible context and persist selections via ai.setSessionDraftContextItemIds(sessionId, ids). Removed useAutoContextReplacement and previous global manual context setters.

Sequence Diagram

sequenceDiagram
  participant User
  participant AssistantUI
  participant RoomStore
  participant AiSlice
  participant Session
  User->>AssistantUI: select context IDs
  AssistantUI->>RoomStore: ai.setSessionDraftContextItemIds(sessionId, ids)
  RoomStore->>AiSlice: setSessionDraftContextItemIds(sessionId, ids)
  User->>AssistantUI: start analysis (target sessionId)
  AssistantUI->>AiSlice: startAnalysis(sessionId)
  AiSlice->>AiSlice: getRunContext(sessionId)
  AiSlice->>RoomStore: getRunContext(store, sessionId)
  RoomStore->>Session: read draftContextItemIds / runContext
  AiSlice->>Session: store runContext (captured from draft)
  AiSlice->>Session: set draftContextItemIds = undefined
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • lixun910
  • dmitriy-kostianetskiy

Poem

I nibble code and hop with pride,
Drafts kept close, each session's guide,
Captured, cleared, no cross-side slide,
Tests confirm the tidy stride,
Hooray — a rabbit's contextual ride 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: introducing per-session draft AI context state, which is the primary focus across all file changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prompt-draft-context

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1951ded4dc

ℹ️ 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".

Comment thread packages/ai-core/src/AiSlice.ts Outdated
Comment on lines +1196 to +1197
draftSession.runContext = getRunContext?.();
draftSession.draftContextItemIds = undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Capture draft context for the target session

When startAnalysis is invoked for a session that is not the current session (for example from another open/background tab or a programmatic caller), getRunContext still receives no sessionId, so hosts using the new per-session draft state have to infer from getCurrentSession() and can capture the wrong session's draft context. This line then clears the target session's draftContextItemIds, losing its selection even though runContext may have been built from another session or as undefined; pass the target sessionId into context capture or build the context from draftSession before clearing it.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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-core/__tests__/AiSlice.modelSelection.test.ts`:
- Around line 299-300: The variable declaration for store uses let but is never
reassigned; change the declaration in the test to use const instead of let where
store is initialized with createTestStore (the identifier store and the call
createTestStore are the targets) so ESLint prefer-const is satisfied; update the
variable declaration to const store = createTestStore({...}) and remove the
separate let declaration.

In `@packages/ai-core/src/AiSlice.ts`:
- Around line 1195-1198: The run-context capture is calling getRunContext?.()
without the session identity which can capture another session's context; update
the call to pass the current session id (sessionId) into getRunContext so
draftSession.runContext = getRunContext?.(sessionId) (or the equivalent
parameter name used in startAnalysis) to ensure the captured context is scoped
to the target draftSession; adjust any call sites and types for getRunContext to
accept the sessionId parameter if needed.
🪄 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: 721b4cb9-8fb9-490b-871e-ddc1ac47400a

📥 Commits

Reviewing files that changed from the base of the PR and between aa35765 and 1951ded.

📒 Files selected for processing (3)
  • packages/ai-config/src/schema/AnalysisSessionSchema.ts
  • packages/ai-core/__tests__/AiSlice.modelSelection.test.ts
  • packages/ai-core/src/AiSlice.ts

Comment thread packages/ai-core/__tests__/AiSlice.modelSelection.test.ts Outdated
Comment thread packages/ai-core/src/AiSlice.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4265a1d74f

ℹ️ 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".

Comment on lines +39 to +42
if (session?.draftContextItemIds) {
return session.draftContextItemIds.length > 0
? session.draftContextItemIds
: (options.implicitItemIds ?? []);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve explicit empty context selections

When the user removes every selected item, setSessionDraftContextItemIds stores [] to represent an explicit manual empty selection, but this branch replaces that empty draft with implicitItemIds. In an empty/new session with a current artifact, clearing the selector and then starting analysis will still send the implicit artifact as context, regressing the previous manual no-context path; a defined draft should be honored even when it is empty.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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-core/src/contextSelection.ts`:
- Around line 1-49: Add JSDoc comments to the four public functions
isAnalysisSessionEmpty, getRunContextItemIds, getVisibleSessionContextItemIds,
and getEffectiveSessionContextItemIds describing their purpose, inputs, and
return values; explicitly document that session.draftContextItemIds ===
undefined means "no explicit draft configured; fall back to runContext/implicit
IDs", whereas an empty array means "explicitly set to empty (hide all items)";
for getEffectiveSessionContextItemIds describe the fallback order
(draftContextItemIds when present and non-empty → explicit empty array returns
provided implicitItemIds if specified → otherwise runContext ids → finally
options.implicitItemIds) and include a short example usage for each function
showing typical input and expected output; keep descriptions generic and
composable (no app-specific examples) and reference the AiRunContext and
AnalysisSessionSchema types in the JSDoc `@param/`@returns.
🪄 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: fe4f725e-6255-4b55-9feb-6425a48e795d

📥 Commits

Reviewing files that changed from the base of the PR and between 909049b and 4265a1d.

📒 Files selected for processing (13)
  • apps/sqlrooms-cli-ui/src/components/AssistantContextSelector.tsx
  • apps/sqlrooms-cli-ui/src/components/assistantUtils.ts
  • apps/sqlrooms-cli-ui/src/components/useAssistantContextItems.ts
  • apps/sqlrooms-cli-ui/src/components/useAutoContextReplacement.ts
  • apps/sqlrooms-cli-ui/src/context/createArtifactContextAiTools.ts
  • apps/sqlrooms-cli-ui/src/context/getRunContext.ts
  • apps/sqlrooms-cli-ui/src/store-types.ts
  • apps/sqlrooms-cli-ui/src/store.ts
  • packages/ai-core/__tests__/AiSlice.modelSelection.test.ts
  • packages/ai-core/src/AiSlice.ts
  • packages/ai-core/src/contextSelection.ts
  • packages/ai-core/src/index.ts
  • packages/ai/src/index.ts
💤 Files with no reviewable changes (3)
  • apps/sqlrooms-cli-ui/src/context/createArtifactContextAiTools.ts
  • apps/sqlrooms-cli-ui/src/components/useAutoContextReplacement.ts
  • apps/sqlrooms-cli-ui/src/store-types.ts

Comment on lines +1 to +49
import {getAiRunContextItems} from '@sqlrooms/ai-config';
import type {AiRunContext, AnalysisSessionSchema} from '@sqlrooms/ai-config';

export function isAnalysisSessionEmpty(
session: AnalysisSessionSchema | undefined,
) {
if (!session) return true;
const hasMessages = session.uiMessages.length > 0;
const hasCompletedResults = session.analysisResults.some(
(result) => result.id !== '__pending__',
);
return !hasMessages && !hasCompletedResults;
}

export function getRunContextItemIds(
runContext: AiRunContext | undefined,
): string[] {
return getAiRunContextItems(runContext).map((item) => item.id);
}

export function getVisibleSessionContextItemIds(
session: AnalysisSessionSchema | undefined,
): string[] {
if (session?.draftContextItemIds) {
return session.draftContextItemIds;
}

if (!isAnalysisSessionEmpty(session)) {
return getRunContextItemIds(session?.runContext);
}

return [];
}

export function getEffectiveSessionContextItemIds(
session: AnalysisSessionSchema | undefined,
options: {implicitItemIds?: string[]} = {},
): string[] {
if (session?.draftContextItemIds) {
return session.draftContextItemIds.length > 0
? session.draftContextItemIds
: (options.implicitItemIds ?? []);
}

const runContextIds = getRunContextItemIds(session?.runContext);
return runContextIds.length > 0
? runContextIds
: (options.implicitItemIds ?? []);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add JSDoc documentation for public exports.

These helper functions are exported from a packages/ module and will be part of the public API. Per coding guidelines, public exports should be documented. Add JSDoc comments explaining:

  • The purpose of each function
  • The meaning of empty array vs undefined for draftContextItemIds
  • The fallback behavior in getEffectiveSessionContextItemIds
  • Example usage

As per coding guidelines, "Public exports in packages/ should be kept generic, composable, documented, and free of app/example-specific assumptions."

🤖 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/contextSelection.ts` around lines 1 - 49, Add JSDoc
comments to the four public functions isAnalysisSessionEmpty,
getRunContextItemIds, getVisibleSessionContextItemIds, and
getEffectiveSessionContextItemIds describing their purpose, inputs, and return
values; explicitly document that session.draftContextItemIds === undefined means
"no explicit draft configured; fall back to runContext/implicit IDs", whereas an
empty array means "explicitly set to empty (hide all items)"; for
getEffectiveSessionContextItemIds describe the fallback order
(draftContextItemIds when present and non-empty → explicit empty array returns
provided implicitItemIds if specified → otherwise runContext ids → finally
options.implicitItemIds) and include a short example usage for each function
showing typical input and expected output; keep descriptions generic and
composable (no app-specific examples) and reference the AiRunContext and
AnalysisSessionSchema types in the JSDoc `@param/`@returns.

Source: Coding guidelines

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fa36af25e8

ℹ️ 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".

return session.draftContextItemIds;
}

if (!isAnalysisSessionEmpty(session)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Show implicit context before sending it

For a brand-new session with no draft selection, this returns an empty visible selection, but apps/sqlrooms-cli-ui/src/context/getRunContext.ts still passes the current artifact as implicitItemIds when starting analysis. That means the selector can look empty while the current artifact is silently sent as context, and because it is not shown as selected the user cannot remove it before the first run; the previous auto-context path made that implicit artifact visible.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant