fmt(js): npm run fix on merge (#106039)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
hermes-seaeye[bot]
2026-09-08 21:23:02 +00:00
committed by GitHub
parent f03ed94a34
commit e9bb6e86fb
14 changed files with 208 additions and 57 deletions

View File

@@ -162,8 +162,7 @@ export type CommandDispatchResponse =
| SendCommandDispatchResponse
| PrefillCommandDispatchResponse
export type SidebarNavId =
'artifacts' | 'command-center' | 'cron' | 'messaging' | 'new-session' | 'settings' | 'skills'
export type SidebarNavId = 'artifacts' | 'command-center' | 'cron' | 'messaging' | 'new-session' | 'settings' | 'skills'
export interface SidebarNavItem {
/** Built-in view id, or a contributed row's namespaced contribution id. */

View File

@@ -62,7 +62,15 @@ import { displayName, stripPreviewMarkdown } from './labels'
import { duplicateBot } from './profile-ops'
import { openRosterBot } from './roster-actions'
import { botRosterMeta, botWorkspaceOwnerKey, setBotsWorkspaceOwner } from './routing'
import { A2A_PREFIX_RE, botCanonicalSessionId, botRowOwnsWorkspace, botWorkingMood, previewKind, useTurnBusy, workerActiveAt } from './row-helpers'
import {
A2A_PREFIX_RE,
botCanonicalSessionId,
botRowOwnsWorkspace,
botWorkingMood,
previewKind,
useTurnBusy,
workerActiveAt
} from './row-helpers'
import type { GroupMember, RosterRow, SidebarRowLabels } from './types'
import { $botSections, $draggingBot, BOT_DRAG_MIME, botSectionId, moveBotsToSection } from './user-sections'

View File

@@ -28,8 +28,8 @@ export function followGroupChat(group: string, onRename: (name: string) => void)
return
}
const moved = Object.entries(rooms).find(([, room]) =>
!room.tombstone && (prior.roomId ? room.roomId === prior.roomId : room === prior)
const moved = Object.entries(rooms).find(
([, room]) => !room.tombstone && (prior.roomId ? room.roomId === prior.roomId : room === prior)
)
if (!moved) {

View File

@@ -14,16 +14,31 @@ describe('room display order', () => {
expect(sortGroupRosterRows(rows, {}).map(row => row.name)).toEqual(['Pinned', 'Newer', 'Bot', 'Older'])
const rooms = { Older: { rosterOrder: 0 }, Newer: { rosterOrder: 1 } }
expect(sortGroupRosterRows(rows, rooms).map(row => row.name)).toEqual(['Pinned', 'Older', 'Bot', 'Newer'])
expect(sortGroupRosterRows(rows.map(row => ({ ...row, activity: row.name === 'Newer' ? 999 : row.activity })), rooms).filter(row => row.kind === 'group').map(row => row.name)).toEqual(['Pinned', 'Older', 'Newer'])
expect(
sortGroupRosterRows(
rows.map(row => ({ ...row, activity: row.name === 'Newer' ? 999 : row.activity })),
rooms
)
.filter(row => row.kind === 'group')
.map(row => row.name)
).toEqual(['Pinned', 'Older', 'Newer'])
expect(rows[0].name).toBe('Older')
})
it('moves only visible same-band rooms while retaining hidden slots and ignoring stale targets', () => {
const ordered = sortGroupRosterRows(rows.filter(row => row.kind === 'group'), {})
const ordered = sortGroupRosterRows(
rows.filter(row => row.kind === 'group'),
{}
)
expect(reorderGroupRows(ordered, 'Older', -1)).toEqual(['Pinned', 'Older', 'Newer'])
expect(reorderGroupRows(ordered, 'Newer', -1)).toBeNull()
expect(reorderGroupRows(ordered, 'deleted', 1)).toBeNull()
const hidden = { kind: 'group' as const, name: 'Hidden', activity: 2, pinned: false }
expect(reorderGroupRows([ordered[0], ordered[1], hidden, ordered[2]], 'Older', -1, ['Newer', 'Older'])).toEqual(['Pinned', 'Older', 'Hidden', 'Newer'])
expect(reorderGroupRows([ordered[0], ordered[1], hidden, ordered[2]], 'Older', -1, ['Newer', 'Older'])).toEqual([
'Pinned',
'Older',
'Hidden',
'Newer'
])
})
})

View File

@@ -6,23 +6,32 @@ interface OrderRow {
}
/** Reorder room slots, not bots or folders. Pinning remains the outer band. */
export function sortGroupRosterRows<T extends OrderRow>(rows: T[], rooms: Record<string, { rosterOrder?: number }>): T[] {
export function sortGroupRosterRows<T extends OrderRow>(
rows: T[],
rooms: Record<string, { rosterOrder?: number }>
): T[] {
const legacy = rows.slice().sort((a, b) => Number(b.pinned) - Number(a.pinned) || b.activity - a.activity)
const groups = legacy.filter(row => row.kind === 'group').sort((a, b) =>
Number(b.pinned) - Number(a.pinned) ||
(rooms[a.name!]?.rosterOrder ?? Infinity) - (rooms[b.name!]?.rosterOrder ?? Infinity)
)
const groups = legacy
.filter(row => row.kind === 'group')
.sort(
(a, b) =>
Number(b.pinned) - Number(a.pinned) ||
(rooms[a.name!]?.rosterOrder ?? Infinity) - (rooms[b.name!]?.rosterOrder ?? Infinity)
)
let index = 0
return legacy.map(row => row.kind === 'group' ? groups[index++] : row)
return legacy.map(row => (row.kind === 'group' ? groups[index++] : row))
}
/** Swap visible neighbours without dropping filtered-out rooms from the order. */
export function reorderGroupRows(rows: OrderRow[], name: string, delta: -1 | 1, visible?: string[]): string[] | null {
const row = rows.find(row => row.name === name)
const band = rows.filter(candidate => candidate.kind === 'group' && candidate.pinned === row?.pinned && (!visible || visible.includes(candidate.name!)))
const band = rows.filter(
candidate =>
candidate.kind === 'group' && candidate.pinned === row?.pinned && (!visible || visible.includes(candidate.name!))
)
const index = band.findIndex(candidate => candidate.name === name)
const neighbour = index >= 0 ? band[index + delta] : undefined
@@ -30,5 +39,7 @@ export function reorderGroupRows(rows: OrderRow[], name: string, delta: -1 | 1,
return null
}
return rows.filter(row => row.kind === 'group').map(row => row.name === name ? neighbour.name! : row.name === neighbour.name ? name : row.name!)
return rows
.filter(row => row.kind === 'group')
.map(row => (row.name === name ? neighbour.name! : row.name === neighbour.name ? name : row.name!))
}

View File

@@ -369,7 +369,8 @@ describe('clarify and approvals (#90694)', () => {
// on $groupNeedsYou/$groupClarify AFTER the turn lands proves nothing:
// the clarify has already resolved and its mirror is gone by then.
onResumePoll: () => {
sawPendingAttention = sawPendingAttention || live!.turns.groupHasPendingClarify(live!.chat.$groupClarify.get(), 'Core')
sawPendingAttention =
sawPendingAttention || live!.turns.groupHasPendingClarify(live!.chat.$groupClarify.get(), 'Core')
},
turn: () => 'targeting staging'
})
@@ -506,17 +507,24 @@ describe('clarify and approvals (#90694)', () => {
it('keeps late prompt snapshots on the live room and never revives a disbanded room', async ({ onTestFinished }) => {
for (const roomId of ['stable-room', undefined]) {
for (const disband of [false, true]) {
const room = await loadRoom({ turn: ({ n }) => n === 1 ? 'Completed reply' : '(pass)' })
const room = await loadRoom({ turn: ({ n }) => (n === 1 ? 'Completed reply' : '(pass)') })
const view = await import('./group-chat-view')
const member = { name: 'research', title: '' }
room.chat.updateGroupChat('Core', current => ({
...current, roomId, running: true, epoch: 1,
...current,
roomId,
running: true,
epoch: 1,
log: [{ id: 'input', at: 1, from: { kind: 'user', name: 'You' }, text: '@research check', thread: 'thread' }]
}))
let entered!: () => void
let release!: () => void
const polled = new Promise<void>(resolve => { entered = resolve })
const held = new Promise<void>(resolve => { release = resolve })
const polled = new Promise<void>(resolve => {
entered = resolve
})
const held = new Promise<void>(resolve => {
release = resolve
})
const original = host.request as (method: string, params: Record<string, unknown>) => Promise<any>
let submitted = false
let answered = false
@@ -525,12 +533,19 @@ describe('clarify and approvals (#90694)', () => {
host.request = async (method: string, params: Record<string, unknown>) => {
const result = await original(method, params)
if (method === 'prompt.submit') {submitted = true}
if (method === 'prompt.submit') {
submitted = true
}
if (method === 'clarify.respond') {answered = true}
if (method === 'clarify.respond') {
answered = true
}
if (method === 'session.resume' && submitted && !answered) {
if (++polls === 1) { entered(); await held }
if (++polls === 1) {
entered()
await held
}
return { ...result, pending_clarify: CLARIFY }
}
@@ -546,14 +561,19 @@ describe('clarify and approvals (#90694)', () => {
release()
await drive
expect(Object.values(room.chat.$groupClarify.get())).toHaveLength(0)
expect(room.chat.$groupChats.get().Core === undefined || room.chat.$groupChats.get().Core.tombstone).toBe(true)
expect(room.chat.$groupChats.get().Core === undefined || room.chat.$groupChats.get().Core.tombstone).toBe(
true
)
expect(room.chat.$groupChats.get().Core?.log || []).toHaveLength(0)
} else {
await view.renameGroupChat('Core', 'Renamed', [])
const mirrored = new Promise<void>(resolve => {
const stop = room.chat.$groupClarify.listen(entries => {
if (Object.keys(entries).length) { stop(); resolve() }
if (Object.keys(entries).length) {
stop()
resolve()
}
})
})
@@ -566,7 +586,12 @@ describe('clarify and approvals (#90694)', () => {
expect(correctRoom).toBe('Renamed')
expect(Object.keys(room.chat.$groupChats.get())).toEqual(['Renamed'])
expect(room.chat.$groupChats.get().Renamed.running).toBe(false)
expect(room.chat.$groupChats.get().Renamed.log.filter(entry => entry.from.kind === 'member').map(entry => entry.text)).toEqual(['Completed reply'])
expect(
room.chat.$groupChats
.get()
.Renamed.log.filter(entry => entry.from.kind === 'member')
.map(entry => entry.text)
).toEqual(['Completed reply'])
expect(Object.values(room.chat.$groupClarify.get())).toHaveLength(0)
}
}
@@ -581,10 +606,20 @@ describe('clarify and approvals (#90694)', () => {
const data = await import('./data')
const members = [{ name: 'research' }, { name: 'ops' }]
room.chat.updateGroupChat('Core', current => ({
...current, roomId: 'old-rejection-room', running: true,
...current,
roomId: 'old-rejection-room',
running: true,
log: continuation
? [{ id: 'handoff', at: 1, from: { kind: 'member', name: 'research' }, text: '@ops check', thread: 'thread' },
{ id: 'input', at: 2, from: { kind: 'user', name: 'You' }, text: '@research check', thread: 'thread' }]
? [
{
id: 'handoff',
at: 1,
from: { kind: 'member', name: 'research' },
text: '@ops check',
thread: 'thread'
},
{ id: 'input', at: 2, from: { kind: 'user', name: 'You' }, text: '@research check', thread: 'thread' }
]
: [{ id: 'input', at: 1, from: { kind: 'user', name: 'You' }, text: 'check', thread: 'thread' }],
watermarks: { 'thread::research': continuation ? 2 : 0 }
}))
@@ -592,23 +627,47 @@ describe('clarify and approvals (#90694)', () => {
// handoff is driven by the continuation phase.
let phaseEntered!: () => void
let release!: () => void
const entered = new Promise<void>(resolve => { phaseEntered = resolve })
const held = new Promise<void>(resolve => { release = resolve })
const entered = new Promise<void>(resolve => {
phaseEntered = resolve
})
const held = new Promise<void>(resolve => {
release = resolve
})
const original = host.request as (method: string, params: Record<string, unknown>) => Promise<any>
host.request = async (method: string, params: Record<string, unknown>) => {
if (method === rejectedMethod) { phaseEntered(); await held; throw new Error('401 unauthorized late rejection') }
if (method === rejectedMethod) {
phaseEntered()
await held
throw new Error('401 unauthorized late rejection')
}
return original(method, params)
}
const drive = room.rounds.runGroupChatRounds('Core', members, 'thread')
await entered
await view.disbandGroupChat('Core', [])
room.chat.updateGroupChat('Core', current => ({ ...current, roomId: 'replacement-rejection-room', tombstone: false }))
room.chat.updateGroupChat('Core', current => ({
...current,
roomId: 'replacement-rejection-room',
tombstone: false
}))
room.chat.appendGroupChatEntry('Core', { kind: 'member', name: 'research' }, '@user replacement needs you')
const before = structuredClone({ rooms: room.chat.$groupChats.get(), activity: activity.$groupActivity.get(), attention: data.$botAttention.get(), needsYou: room.chat.$groupNeedsYou.get() })
const before = structuredClone({
rooms: room.chat.$groupChats.get(),
activity: activity.$groupActivity.get(),
attention: data.$botAttention.get(),
needsYou: room.chat.$groupNeedsYou.get()
})
release()
await drive
expect({ rooms: room.chat.$groupChats.get(), activity: activity.$groupActivity.get(), attention: data.$botAttention.get(), needsYou: room.chat.$groupNeedsYou.get() }).toEqual(before)
expect({
rooms: room.chat.$groupChats.get(),
activity: activity.$groupActivity.get(),
attention: data.$botAttention.get(),
needsYou: room.chat.$groupNeedsYou.get()
}).toEqual(before)
expect(room.gateway.rpcFor('prompt.submit')).toHaveLength(0)
}
}
@@ -624,8 +683,12 @@ describe('clarify and approvals (#90694)', () => {
room.chat.updateGroupChat('Core', current => ({ ...current, roomId: 'retired-room' }))
let entered!: () => void
let release!: () => void
const polled = new Promise<void>(resolve => { entered = resolve })
const held = new Promise<void>(resolve => { release = resolve })
const polled = new Promise<void>(resolve => {
entered = resolve
})
const held = new Promise<void>(resolve => {
release = resolve
})
const original = host.request as (method: string, params: Record<string, unknown>) => Promise<any>
let submitted = false
@@ -638,7 +701,9 @@ describe('clarify and approvals (#90694)', () => {
const result = await original(method, params)
if (method === 'prompt.submit') { submitted = true }
if (method === 'prompt.submit') {
submitted = true
}
return result
}
@@ -667,30 +732,47 @@ describe('clarify and approvals (#90694)', () => {
const view = await import('./group-chat-view')
const members = [{ name: 'research' }, { name: 'ops' }]
room.chat.updateGroupChat('Core', current => ({
...current, roomId: 'old-harvest-room', running: true,
...current,
roomId: 'old-harvest-room',
running: true,
stranded: { research: 0, ops: 0 }
}))
let tick!: () => void
const previousWindow = globalThis.window
vi.stubGlobal('window', { setTimeout: (callback: () => void) => { tick = callback;
vi.stubGlobal('window', {
setTimeout: (callback: () => void) => {
tick = callback
return 0 } })
onTestFinished(() => { vi.stubGlobal('window', previousWindow) })
return 0
}
})
onTestFinished(() => {
vi.stubGlobal('window', previousWindow)
})
let entered!: () => void
let release!: () => void
const polled = new Promise<void>(resolve => { entered = resolve })
const held = new Promise<void>(resolve => { release = resolve })
const polled = new Promise<void>(resolve => {
entered = resolve
})
const held = new Promise<void>(resolve => {
release = resolve
})
let background = false
const backgroundProfiles: unknown[] = []
const original = host.request as (method: string, params: Record<string, unknown>) => Promise<any>
host.request = async (method: string, params: Record<string, unknown>) => {
if (method !== 'session.resume') { return original(method, params) }
if (method !== 'session.resume') {
return original(method, params)
}
if (background) {
backgroundProfiles.push(params.profile)
if (params.profile === 'research') { entered(); await held }
if (params.profile === 'research') {
entered()
await held
}
}
return { running: true, pending_clarify: CLARIFY }
@@ -704,7 +786,9 @@ describe('clarify and approvals (#90694)', () => {
const { setImmediate } = await import('node:timers/promises')
await setImmediate()
room.chat.updateGroupChat('Core', current => ({
...current, roomId: 'new-harvest-room', stranded: { research: 0, ops: 0 }
...current,
roomId: 'new-harvest-room',
stranded: { research: 0, ops: 0 }
}))
const roomsBefore = structuredClone(room.chat.$groupChats.get())
const promptsBefore = structuredClone(room.chat.$groupClarify.get())
@@ -723,7 +807,8 @@ describe('clarify and approvals (#90694)', () => {
const room = await loadRoom({
approvalUntil: { research: { payload: APPROVAL, until: 3 } },
onResumePoll: () => {
sawPendingAttention = sawPendingAttention || live!.turns.groupHasPendingClarify(live!.chat.$groupClarify.get(), 'Core')
sawPendingAttention =
sawPendingAttention || live!.turns.groupHasPendingClarify(live!.chat.$groupClarify.get(), 'Core')
},
turn: () => 'build cleaned'
})

View File

@@ -103,9 +103,15 @@ describe('the pet gallery', () => {
})
it('keeps selection while scrolling for more and resets the search window', async () => {
useQueryMock.mockReturnValue({ data: { pets: Array.from({ length: 60 }, (_, i) => ({
displayName: `Pet ${i}`, slug: `pet-${i}`, spritesheetUrl: SHEET
})) } })
useQueryMock.mockReturnValue({
data: {
pets: Array.from({ length: 60 }, (_, i) => ({
displayName: `Pet ${i}`,
slug: `pet-${i}`,
spritesheetUrl: SHEET
}))
}
})
stubFetch(async () => ({ blob: async () => new Blob() }))
const PetTab = await loadPetTab()
const onImage = vi.fn()
@@ -115,7 +121,9 @@ describe('the pet gallery', () => {
await waitFor(() => expect(onImage).toHaveBeenCalledWith('data:image/png;base64,ok'))
const scroller = first.parentElement!.parentElement!
Object.defineProperties(scroller, {
clientHeight: { value: 220 }, scrollHeight: { value: 600 }, scrollTop: { value: 400 }
clientHeight: { value: 220 },
scrollHeight: { value: 600 },
scrollTop: { value: 400 }
})
fireEvent.scroll(scroller)
expect(view.getByText('Pet 47')).toBeTruthy()

View File

@@ -43,7 +43,12 @@ export function RosterGroupRowView({
activity: groupLastActivity(current[name])
}))
const order = reorderGroupRows(sortGroupRosterRows(rows, current), name, delta, sortedGroupRows.map(row => row.name))
const order = reorderGroupRows(
sortGroupRosterRows(rows, current),
name,
delta,
sortedGroupRows.map(row => row.name)
)
order?.forEach((name, rosterOrder) => {
updateGroupChat(name, room => ({ ...room, rosterOrder }), { sync: false })

View File

@@ -296,7 +296,9 @@ export function BotsPane() {
// and the persisted connection registry hydrate. Keep that transition in a
// neutral loading state instead of flashing the first-run "No bots" copy.
const initialRosterLoading = !data && !error && roster.length === 0
const activeRosterKeys = new Set(activeBots(roster, workingOwner, turnBusy, Date.now(), activeConnectionId).map(botRosterKey))
const activeRosterKeys = new Set(
activeBots(roster, workingOwner, turnBusy, Date.now(), activeConnectionId).map(botRosterKey)
)
const gatewayOptions = rosterGatewayOptions(sourceSnapshot, roster)
const selectedGateway = gatewayOptions.find(option => option.connectionId === gatewayFilter)
const gatewayFilterExists = gatewayFilter === 'all' || Boolean(selectedGateway)

View File

@@ -105,7 +105,9 @@ describe('which bots are working right now', () => {
expect(activeBots([local, remote], owner, false, NOW)).toEqual([])
expect(activeBots([local, remote], null, true, NOW)).toEqual([])
expect(activeBots([local, remote], { ...owner, authoritative: false }, true, NOW)).toEqual([])
expect(activeBots([row({ name: 'analyst', remoteSource: true })], { ...owner, connectionId: '' }, true, NOW)).toEqual([])
expect(
activeBots([row({ name: 'analyst', remoteSource: true })], { ...owner, connectionId: '' }, true, NOW)
).toEqual([])
})
it('includes activity inside the liveness window and excludes activity outside it', () => {

View File

@@ -108,7 +108,13 @@ export function botWorkingMood(
): 'idle' | 'think' | 'work' {
const botConnectionId = bot.connectionId || (bot.remoteSource ? '' : activeConnectionId)
if (turnBusy && owner?.authoritative && owner.connectionId && owner.name === bot.name && owner.connectionId === botConnectionId) {
if (
turnBusy &&
owner?.authoritative &&
owner.connectionId &&
owner.name === bot.name &&
owner.connectionId === botConnectionId
) {
return 'think'
}

View File

@@ -8,11 +8,13 @@ import { describe, expect, it } from 'vitest'
const { matchKnownFailure, rules } = createRequire(import.meta.url)('../tests/install/e2e-assets/known-failures.cjs')
const classifier = path.resolve(import.meta.dirname, '../tests/install/e2e-assets/known-failures.cjs')
const lockedLog = [
'error: failed to remove file `C:/install/venv/Lib/site-packages/../../Scripts/hermes.exe`: Access is denied. (os error 5)',
'File "C:/install/venv/Scripts/hermes.exe/__main__.py", line 10, in <module>',
"subprocess.CalledProcessError: Command '['uv', 'pip', 'install', '-e', '.', '--quiet']' returned non-zero exit status 2.",
].join('\n')
const base = {
platform: 'windows', phase: 'update', commit: 'a370ab8391ca5f8de7ebbc449f05cb0df36ade7c',
installMethod: 'installer-script', updateMethod: 'hermes-update',
@@ -42,6 +44,7 @@ describe('known install failures', () => {
error: 'E2E ASSERTION FAILED: app driven via captured hermes desktop spec; update completed',
logs: { desktop: '[hermes] [updates] no staged updater; surfacing manual `hermes update` for CLI install at C:/install\n[hermes] [updates] manual: hermes update\n' },
}
expect(matchKnownFailure(sample)?.id).toBe('windows-july-manual-app-update')
expect(matchKnownFailure({ ...sample, installMethod: 'desktop-installer@latest' })).toBeNull()
expect(matchKnownFailure({ ...sample, error: 'onboarding timed out' })).toBeNull()
@@ -50,6 +53,7 @@ describe('known install failures', () => {
it('CLI writes a receipt and exits zero only on a confirmed match', () => {
const root = mkdtempSync(path.join(os.tmpdir(), 'known-install-'))
try {
mkdirSync(path.join(root, 'logs'))
writeFileSync(path.join(root, 'shas.json'), '\uFEFF' + JSON.stringify({ old: base.commit, current: 'f'.repeat(40), old_ref: 'v2026.3.12' }))

View File

@@ -24,6 +24,7 @@ it('waits for native close, not exit, and retains a close observed before hand-o
it('fails if the launched process never closes', async () => {
vi.useFakeTimers()
try {
const waitForClose = observeProcessClose(Object.assign(new EventEmitter(), { stdio: [], exitCode: null, signalCode: null }))
const completion = expect(waitForClose(2_000)).rejects.toThrow('Electron process did not close')

View File

@@ -505,6 +505,7 @@ export function startMockServer(options: MockServerOptions = {}): Promise<MockSe
const isSidebarCrossTrigger = userText.includes('E2E_SIDEBAR_CROSS')
const isQueueStopTrigger = userText.includes('E2E_QUEUE_STOP_TRIGGER')
const isTaskPanelResumeTrigger = userText.includes(TASK_PANEL_RESUME_TRIGGER)
const isVerificationStopTrigger = messages.some(
message => typeof message?.content === 'string' && message.content.includes(VERIFICATION_STOP_TRIGGER),
)
@@ -517,7 +518,9 @@ export function startMockServer(options: MockServerOptions = {}): Promise<MockSe
const turn =
TASK_PANEL_RESUME_SCRIPT[_taskPanelResumeIndex] ??
TASK_PANEL_RESUME_SCRIPT[TASK_PANEL_RESUME_SCRIPT.length - 1]
_taskPanelResumeIndex++
const respond = () => {
if (stream) {
streamScriptedTurn(res, model, turn)
@@ -533,6 +536,7 @@ export function startMockServer(options: MockServerOptions = {}): Promise<MockSe
} else {
respond()
}
return
}
@@ -550,6 +554,7 @@ export function startMockServer(options: MockServerOptions = {}): Promise<MockSe
} else {
nonStreamingScriptedTurn(res, model, BATCH_CLARIFY_TURN)
}
return
}
}