include llama.cpp since there were some edits
This commit is contained in:
1 parent
db7f28d087
commit
8c66990853
3918 files changed
+1640170
-1
No files matched your search
@@ -0,0 +1,212 @@
|
||||
// Guards the two Settings > Display toggles that drive the default expansion of
|
||||
// a tool call block.
|
||||
//
|
||||
// "Show tool call in progress" mirrors "Show thought in progress": a call is
|
||||
// expanded by default only while it is in flight and folds back on its own once
|
||||
// the result lands. "Always show tool call content" is the one that keeps
|
||||
// finished calls open and wins on its own. A manual toggle always overrides the
|
||||
// default, in both directions.
|
||||
|
||||
import ChatMessageAgenticContent from '$lib/components/app/chat/ChatMessages/ChatMessageAgenticContent.svelte';
|
||||
import { SETTINGS_KEYS } from '$lib/constants';
|
||||
import { MessageRole, MessageType } from '$lib/enums';
|
||||
import { settingsStore } from '$lib/stores';
|
||||
import type { DatabaseMessage } from '$lib/types';
|
||||
import { tick } from 'svelte';
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import { userEvent } from 'vitest/browser';
|
||||
import { render } from 'vitest-browser-svelte';
|
||||
|
||||
const TOOL_NAME = 'custom_tool';
|
||||
const TOOL_CALL_ID = 'call-1';
|
||||
// Both markers sit inside the collapsible body, which CollapsibleContentBlock
|
||||
// only mounts while open - so their presence is exactly "the block is expanded".
|
||||
const PENDING_BODY = 'Waiting for result...';
|
||||
const RESULT_BODY = 'marker-tool-output';
|
||||
const TRIGGER_SELECTOR = '[data-slot="collapsible-trigger"]';
|
||||
|
||||
function assistantMessage(): DatabaseMessage {
|
||||
return {
|
||||
children: [],
|
||||
content: '',
|
||||
convId: 'conv-1',
|
||||
id: 'assistant-1',
|
||||
parent: null,
|
||||
role: MessageRole.ASSISTANT,
|
||||
timestamp: 0,
|
||||
toolCalls: JSON.stringify([
|
||||
{ function: { arguments: '{"path":"a.txt"}', name: TOOL_NAME }, id: TOOL_CALL_ID }
|
||||
]),
|
||||
type: MessageType.TEXT
|
||||
};
|
||||
}
|
||||
|
||||
function toolResultMessage(): DatabaseMessage {
|
||||
return {
|
||||
...assistantMessage(),
|
||||
content: RESULT_BODY,
|
||||
id: 'tool-1',
|
||||
role: MessageRole.TOOL,
|
||||
toolCallId: TOOL_CALL_ID
|
||||
};
|
||||
}
|
||||
|
||||
function setSettings({
|
||||
alwaysShow,
|
||||
inProgress
|
||||
}: {
|
||||
alwaysShow: boolean;
|
||||
inProgress: boolean;
|
||||
}): void {
|
||||
settingsStore.updateMultipleConfig({
|
||||
[SETTINGS_KEYS.ALWAYS_SHOW_TOOL_CALL_CONTENT]: alwaysShow,
|
||||
[SETTINGS_KEYS.SHOW_TOOL_CALL_IN_PROGRESS]: inProgress
|
||||
});
|
||||
}
|
||||
|
||||
function textOf(container: Element): string {
|
||||
return container.textContent ?? '';
|
||||
}
|
||||
|
||||
async function collapseBlock(screen: { container: Element }): Promise<void> {
|
||||
const trigger = screen.container.querySelector(TRIGGER_SELECTOR);
|
||||
|
||||
if (!(trigger instanceof HTMLButtonElement)) throw new Error('trigger not found');
|
||||
|
||||
await userEvent.click(trigger);
|
||||
await tick();
|
||||
}
|
||||
|
||||
describe('Show tool call in progress', () => {
|
||||
beforeEach(() => {
|
||||
setSettings({ alwaysShow: false, inProgress: false });
|
||||
});
|
||||
|
||||
it('expands a call that is still executing when the setting is on', async () => {
|
||||
setSettings({ alwaysShow: false, inProgress: true });
|
||||
|
||||
const { container } = render(ChatMessageAgenticContent, {
|
||||
isStreaming: true,
|
||||
message: assistantMessage(),
|
||||
toolMessages: []
|
||||
});
|
||||
|
||||
await tick();
|
||||
|
||||
expect(textOf(container)).toContain(PENDING_BODY);
|
||||
});
|
||||
|
||||
it('keeps the call collapsed while executing when the setting is off', async () => {
|
||||
const { container } = render(ChatMessageAgenticContent, {
|
||||
isStreaming: true,
|
||||
message: assistantMessage(),
|
||||
toolMessages: []
|
||||
});
|
||||
|
||||
await tick();
|
||||
|
||||
// The header is still there, only the body stays hidden.
|
||||
expect(textOf(container)).toContain(TOOL_NAME);
|
||||
expect(textOf(container)).not.toContain(PENDING_BODY);
|
||||
});
|
||||
|
||||
it('folds the call back when its result arrives', async () => {
|
||||
setSettings({ alwaysShow: false, inProgress: true });
|
||||
|
||||
const screen = render(ChatMessageAgenticContent, {
|
||||
isStreaming: true,
|
||||
message: assistantMessage(),
|
||||
toolMessages: []
|
||||
});
|
||||
|
||||
await tick();
|
||||
|
||||
// Open while it waits for the result.
|
||||
expect(textOf(screen.container)).toContain(PENDING_BODY);
|
||||
|
||||
// Same block, now finished: it must close on its own, no toggle given.
|
||||
screen.rerender({
|
||||
isStreaming: true,
|
||||
message: assistantMessage(),
|
||||
toolMessages: [toolResultMessage()]
|
||||
});
|
||||
await tick();
|
||||
|
||||
expect(textOf(screen.container)).toContain(TOOL_NAME);
|
||||
expect(textOf(screen.container)).not.toContain(PENDING_BODY);
|
||||
expect(textOf(screen.container)).not.toContain(RESULT_BODY);
|
||||
});
|
||||
|
||||
it('keeps the manual choice once the result arrives', async () => {
|
||||
setSettings({ alwaysShow: false, inProgress: true });
|
||||
|
||||
const screen = render(ChatMessageAgenticContent, {
|
||||
isStreaming: true,
|
||||
message: assistantMessage(),
|
||||
toolMessages: []
|
||||
});
|
||||
|
||||
await tick();
|
||||
|
||||
// Collapsed by hand while running, so the result must not reopen it.
|
||||
await collapseBlock(screen);
|
||||
|
||||
screen.rerender({
|
||||
isStreaming: true,
|
||||
message: assistantMessage(),
|
||||
toolMessages: [toolResultMessage()]
|
||||
});
|
||||
await tick();
|
||||
|
||||
expect(textOf(screen.container)).toContain(TOOL_NAME);
|
||||
expect(textOf(screen.container)).not.toContain(RESULT_BODY);
|
||||
});
|
||||
|
||||
it('still expands a finished call when "always show" is on', async () => {
|
||||
setSettings({ alwaysShow: true, inProgress: false });
|
||||
|
||||
const { container } = render(ChatMessageAgenticContent, {
|
||||
isStreaming: true,
|
||||
message: assistantMessage(),
|
||||
toolMessages: [toolResultMessage()]
|
||||
});
|
||||
|
||||
await tick();
|
||||
|
||||
expect(textOf(container)).toContain(RESULT_BODY);
|
||||
});
|
||||
|
||||
it('lets a manual collapse win over the in-progress default', async () => {
|
||||
setSettings({ alwaysShow: false, inProgress: true });
|
||||
|
||||
const screen = render(ChatMessageAgenticContent, {
|
||||
isStreaming: true,
|
||||
message: assistantMessage(),
|
||||
toolMessages: []
|
||||
});
|
||||
|
||||
await tick();
|
||||
|
||||
expect(textOf(screen.container)).toContain(PENDING_BODY);
|
||||
|
||||
await collapseBlock(screen);
|
||||
|
||||
expect(textOf(screen.container)).not.toContain(PENDING_BODY);
|
||||
});
|
||||
|
||||
it('lets a manual expand win over the collapsed default', async () => {
|
||||
const screen = render(ChatMessageAgenticContent, {
|
||||
isStreaming: true,
|
||||
message: assistantMessage(),
|
||||
toolMessages: []
|
||||
});
|
||||
|
||||
await tick();
|
||||
|
||||
expect(textOf(screen.container)).not.toContain(PENDING_BODY);
|
||||
|
||||
await collapseBlock(screen);
|
||||
|
||||
expect(textOf(screen.container)).toContain(PENDING_BODY);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user