mirror of
https://github.com/stablyai/orca.git
synced 2026-10-07 08:02:21 +00:00
fix(native-chat): a chat whose draft holds text is never reused or claimed as empty
The empty-chat check read the pane's old draft key, while the composer and every hand-back write the conversation's. A chat with typed or given-back text read as empty, so a bare new chat reused it and a text request claimed it. It reads the conversation's draft now.
This commit is contained in:
@@ -113,10 +113,8 @@ import {
|
|||||||
clearNativeChatDraftCacheForTests,
|
clearNativeChatDraftCacheForTests,
|
||||||
writeNativeChatDraftCache
|
writeNativeChatDraftCache
|
||||||
} from '@/components/native-chat/native-chat-draft-cache'
|
} from '@/components/native-chat/native-chat-draft-cache'
|
||||||
import {
|
import { structuredAgentSessionTabId } from '../../../shared/structured-agent-session-projection'
|
||||||
structuredAgentSessionPaneKey,
|
import { structuredAgentSessionDraftScopeKey } from '@/components/native-chat/native-chat-composer-draft-store'
|
||||||
structuredAgentSessionTabId
|
|
||||||
} from '../../../shared/structured-agent-session-projection'
|
|
||||||
import { adoptAgentSessionLaunchVerdict } from './agent-session-launch-plan'
|
import { adoptAgentSessionLaunchVerdict } from './agent-session-launch-plan'
|
||||||
import {
|
import {
|
||||||
beginStructuredAgentSessionProvisionalLaunch,
|
beginStructuredAgentSessionProvisionalLaunch,
|
||||||
@@ -279,8 +277,8 @@ describe('a second "new chat" with no text', () => {
|
|||||||
it('opens a new chat when the idle chat has a typed draft', async () => {
|
it('opens a new chat when the idle chat has a typed draft', async () => {
|
||||||
pick('plus-pick-1')
|
pick('plus-pick-1')
|
||||||
await publishIdle(first.sessionId)
|
await publishIdle(first.sessionId)
|
||||||
const tabId = structuredAgentSessionTabId(first.sessionId)
|
// Under the conversation's key, which the composer and every hand-back write.
|
||||||
writeNativeChatDraftCache(structuredAgentSessionPaneKey(tabId, first.sessionId), 'half a q')
|
writeNativeChatDraftCache(structuredAgentSessionDraftScopeKey(first.sessionId), 'half a q')
|
||||||
|
|
||||||
expect(pick('plus-pick-2').sessionId).toBe(second.sessionId)
|
expect(pick('plus-pick-2').sessionId).toBe(second.sessionId)
|
||||||
})
|
})
|
||||||
@@ -288,8 +286,7 @@ describe('a second "new chat" with no text', () => {
|
|||||||
it('opens a new chat when the idle chat has an image in its composer', async () => {
|
it('opens a new chat when the idle chat has an image in its composer', async () => {
|
||||||
pick('plus-pick-1')
|
pick('plus-pick-1')
|
||||||
await publishIdle(first.sessionId)
|
await publishIdle(first.sessionId)
|
||||||
const tabId = structuredAgentSessionTabId(first.sessionId)
|
appendNativeChatAttachmentCache(structuredAgentSessionDraftScopeKey(first.sessionId), [
|
||||||
appendNativeChatAttachmentCache(structuredAgentSessionPaneKey(tabId, first.sessionId), [
|
|
||||||
{ id: 'shot', path: '/tmp/shot.png' }
|
{ id: 'shot', path: '/tmp/shot.png' }
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -484,6 +481,15 @@ describe('a "new chat" with text', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('leaves a starting chat whose draft holds text, given back or typed, to its user', () => {
|
||||||
|
mocks.launch.mockImplementation(() => new Promise(() => undefined))
|
||||||
|
const blank = pick('plus-pick-1')
|
||||||
|
writeNativeChatDraftCache(structuredAgentSessionDraftScopeKey(blank.sessionId), 'my words')
|
||||||
|
|
||||||
|
expect(pick('notes-send', { prompt: 'review notes' }).sessionId).toBe(second.sessionId)
|
||||||
|
expect(readOutbox(blank.sessionId)).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
it('takes an empty chat still starting, as before', () => {
|
it('takes an empty chat still starting, as before', () => {
|
||||||
mocks.launch.mockImplementation(() => new Promise(() => undefined))
|
mocks.launch.mockImplementation(() => new Promise(() => undefined))
|
||||||
const blank = pick('plus-pick-1')
|
const blank = pick('plus-pick-1')
|
||||||
|
|||||||
@@ -67,10 +67,7 @@ import {
|
|||||||
readNativeChatDraftCache,
|
readNativeChatDraftCache,
|
||||||
writeNativeChatDraftCache
|
writeNativeChatDraftCache
|
||||||
} from '@/components/native-chat/native-chat-draft-cache'
|
} from '@/components/native-chat/native-chat-draft-cache'
|
||||||
import {
|
import { structuredAgentSessionDraftScopeKey } from '@/components/native-chat/native-chat-composer-draft-store'
|
||||||
structuredAgentSessionPaneKey,
|
|
||||||
structuredAgentSessionTabId
|
|
||||||
} from '../../../shared/structured-agent-session-projection'
|
|
||||||
import { StructuredAgentSessionCreateRefusalError } from '@/lib/launch-structured-agent-session'
|
import { StructuredAgentSessionCreateRefusalError } from '@/lib/launch-structured-agent-session'
|
||||||
import {
|
import {
|
||||||
getStructuredAgentSessionLaunchLifecycle,
|
getStructuredAgentSessionLaunchLifecycle,
|
||||||
@@ -520,10 +517,8 @@ describe('an empty chat still starting', () => {
|
|||||||
|
|
||||||
it('leaves a chat its user is typing into to them, and opens a new chat for the notes', async () => {
|
it('leaves a chat its user is typing into to them, and opens a new chat for the notes', async () => {
|
||||||
const blank = startStructuredAgentLaunch(WORKTREE_ID, 'codex', { requestId: 'plus-pick' })
|
const blank = startStructuredAgentLaunch(WORKTREE_ID, 'codex', { requestId: 'plus-pick' })
|
||||||
const paneKey = structuredAgentSessionPaneKey(
|
// The conversation's draft, which its composer writes.
|
||||||
structuredAgentSessionTabId(blank.sessionId),
|
const paneKey = structuredAgentSessionDraftScopeKey(blank.sessionId)
|
||||||
blank.sessionId
|
|
||||||
)
|
|
||||||
writeNativeChatDraftCache(paneKey, 'half a question')
|
writeNativeChatDraftCache(paneKey, 'half a question')
|
||||||
|
|
||||||
const notes = startStructuredAgentLaunch(WORKTREE_ID, 'codex', notesSend)
|
const notes = startStructuredAgentLaunch(WORKTREE_ID, 'codex', notesSend)
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import {
|
|
||||||
structuredAgentSessionPaneKey,
|
|
||||||
structuredAgentSessionTabId
|
|
||||||
} from '../../../shared/structured-agent-session-projection'
|
|
||||||
import { getStructuredAgentSessionOutbox } from '@/components/native-chat/structured-agent-session-outbox-storage'
|
import { getStructuredAgentSessionOutbox } from '@/components/native-chat/structured-agent-session-outbox-storage'
|
||||||
import { readNativeChatDraftCache } from '@/components/native-chat/native-chat-draft-cache'
|
import { readNativeChatDraftCache } from '@/components/native-chat/native-chat-draft-cache'
|
||||||
// The draft store, not the composer hook: the launch must not load the composer (a store cycle).
|
// The draft store, not the composer hook: the launch must not load the composer (a store cycle).
|
||||||
import { readNativeChatComposerDraft } from '@/components/native-chat/native-chat-composer-draft-store'
|
import {
|
||||||
|
readNativeChatComposerDraft,
|
||||||
|
structuredAgentSessionDraftScopeKey
|
||||||
|
} from '@/components/native-chat/native-chat-composer-draft-store'
|
||||||
|
|
||||||
/** A starting chat is empty until its user sends into it or puts text or images in its composer;
|
/** A starting chat is empty until its user sends into it or puts text or images in its draft (typed,
|
||||||
* after that it is theirs, and another request never goes into it. */
|
* or given back); after that it is theirs, and another request never goes into it. Read by the
|
||||||
|
* conversation's key, which the composer and every hand-back write. */
|
||||||
export function isStructuredLaunchChatEmpty(sessionId: string): boolean {
|
export function isStructuredLaunchChatEmpty(sessionId: string): boolean {
|
||||||
const paneKey = structuredAgentSessionPaneKey(structuredAgentSessionTabId(sessionId), sessionId)
|
const scopeKey = structuredAgentSessionDraftScopeKey(sessionId)
|
||||||
return (
|
return (
|
||||||
getStructuredAgentSessionOutbox(sessionId).length === 0 &&
|
getStructuredAgentSessionOutbox(sessionId).length === 0 &&
|
||||||
readNativeChatDraftCache(paneKey).trim() === '' &&
|
readNativeChatDraftCache(scopeKey).trim() === '' &&
|
||||||
readNativeChatComposerDraft(paneKey).images.length === 0
|
readNativeChatComposerDraft(scopeKey).images.length === 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user