mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 10:08:13 +00:00
* fix(native-chat): fold thoughts and tool calls between replies into one row A model that thinks before every tool call drew a 'Thought for Ns' row between each call, and each thought also stopped the calls from merging, so a turn read as dozens of alternating rows. The transcript now draws an unbroken stretch of tool calls and thoughts within a turn as one tool run; thoughts read in order inside it when opened and are not counted in its label. * fix(native-chat): keep work runs whole while a turn edits files A live turn that had edited a file kept splitting its newest call or thought off the run (the row carrying the turn's diff rollup could not join), so a lone "Thought for Ns" row came back at the bottom. - Run boundaries are now one pure pass in src/shared (nativeChatWorkRunSpans), applied over the built transcript slots. Section heads end runs by sitting between rows, and rows inside an expanded subagent section are grouped the same way. - The row carrying the turn's diff rollup joins as the run's last member; the run takes the rollup from it and the bar from its head. - A collapsed run reserves one tool row plus a lead's words, not every thought's text. - Lone rows and runs draw through the same MessageRow, with one flat keyed line list, so a row becoming a run no longer remounts (a revealed diff card no longer re-fires its scroll). - A run opens by default while the reader holds one of its thoughts open; the run's own choice still wins. - A drawn thought with no visible text joins a run instead of splitting it. * fix(native-chat): pair each row's result with its own call; keep open thoughts out of runs - A structured journal row's call and result now share one id (the provider's call id, else the row's own id), so a diff or output can no longer pair with an earlier unanswered call in the same work run or folded message. A quiet command followed by edits now shows each diff card under its own call, and the rollup's reveal lands on it. - A thought still being thought, while its turn or subagent works, keeps its own row after the run and joins once it ends. - Removed the rule that opened a run because a thought inside it was open; a thought keeps its own open state inside its run. * fix(native-chat): an open thought the live line lets go of joins its run Only a subagent section keeps a still-running thought out of its run. At the top level the live line owns the open thought; when it lets go (a Stop in flight, a prompt waiting on the reader) the thought now joins the run at once instead of flashing as its own row until the turn ends. * test(native-chat): guard the run row memo; name the slot post-pass test after it Settled work runs must not rebuild their lines and thoughts on every stream frame of the live run. Renames the slot-level run test so it no longer shares a name with the shared span test.
55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
nativeChatWorkRunSpans,
|
|
type NativeChatWorkRunMember,
|
|
type NativeChatWorkRunRow
|
|
} from './native-chat-work-run'
|
|
|
|
/** `t` thought, `c` call, `l` lead, `x` a drawn row that ends runs, `-` a row that draws nothing;
|
|
* `|` starts the next scope. */
|
|
function rowsOf(pattern: string): NativeChatWorkRunRow[] {
|
|
const members: Record<string, NativeChatWorkRunMember> = { t: 'thought', c: 'tool', l: 'lead' }
|
|
let scope = 0
|
|
return [...pattern].flatMap((char) => {
|
|
if (char === '|') {
|
|
scope += 1
|
|
return []
|
|
}
|
|
return [{ member: members[char] ?? null, draws: char !== '-', scope: String(scope) }]
|
|
})
|
|
}
|
|
|
|
const spans = (pattern: string): number[][] => nativeChatWorkRunSpans(rowsOf(pattern))
|
|
|
|
describe('work run spans', () => {
|
|
it('runs thoughts and calls together until something else draws', () => {
|
|
expect(spans('tctctxct')).toEqual([
|
|
[0, 1, 2, 3, 4],
|
|
[6, 7]
|
|
])
|
|
})
|
|
|
|
it('needs two members and a call', () => {
|
|
expect(spans('c')).toEqual([])
|
|
expect(spans('tt')).toEqual([])
|
|
expect(spans('txc')).toEqual([])
|
|
})
|
|
|
|
it('lets a lead head a run but never join one', () => {
|
|
expect(spans('ltclt')).toEqual([
|
|
[0, 1, 2],
|
|
[3, 4]
|
|
])
|
|
expect(spans('cl')).toEqual([])
|
|
})
|
|
|
|
it('stays open across a row that draws nothing', () => {
|
|
expect(spans('c-t-c')).toEqual([[0, 2, 4]])
|
|
})
|
|
|
|
it('never crosses a scope, even through a row that draws nothing', () => {
|
|
expect(spans('ct|c')).toEqual([[0, 1]])
|
|
expect(spans('c|-|c')).toEqual([])
|
|
})
|
|
})
|