ui: CWD for agent (#26518)
* server : extend file_glob_search for UI pickers * ui : add per-conversation working directory with picker * ui : add path navigation and search scope to cwd picker Treat path-like queries (starting with / or ~) as directory navigation instead of glob-matching the whole query: search the parent for the last segment, and descend into an exactly-typed directory by listing its children. Show the effective search scope in the footer and auto-search on open so the current directory and its siblings appear immediately. Assisted-by: Claude * db : persist per-call tool cwd on tool result messages * ui : abbreviate tool paths under home with a tilde * ui : show the per-call cwd on exec shell rows * ui : clarify the synthetic cwd message for the model * ui : reuse the trailing cwd row on a repeated pick * ui : don't jump when a cwd row is injected mid-chat * chore: Formatting * refactor: Cleanup comments * ui : unify working directory naming and add a synthetic-message flag * ui : render synthetic cwd rows without a scroll jump * ui : decouple the working directory picker into utils and sub-components * ui : add get_info tool call block * chore: Formatting * refactor: Cleanup * refactor: Cleanup * refactor: Cleanup * fix: UI * server : harden file_glob_search listing (kind enum, timeout, symlink guard, absolute base) * ui : use persisted isSynthetic flag for cwd rows, drop legacy formats * ui : cache picker search, fail visibly on native resolve * ui : escape glob metacharacters in picker search glob * ui : simplify auto-scroll pin * chore: Format * fix: Use `SvelteMap` * refactor: Post-review fixes * ui: accept Windows roots in the working directory picker recognize a drive root (C:) and a UNC share (//host/share) as path navigation, alongside the POSIX root and ~, so a query like D:\repos lists that directory instead of glob-matching it under the home dir split below the root, so a bare drive resolves to its root rather than to a drive-relative prefix rewrite backslashes into forward slashes only when the query carries a Windows root, since a backslash is a legal POSIX filename character paths keep travelling with forward slashes, which is what the server returns and what Windows accepts --------- Co-authored-by: Pascal <admin@serveurperso.com>
This commit is contained in:
co-authored by
Pascal
parent
0713275082
commit
2f56fc3431
@@ -674,7 +674,8 @@ export class DatabaseService {
|
||||
serverId: o.serverId,
|
||||
enabled: o.enabled
|
||||
}))
|
||||
: undefined
|
||||
: undefined,
|
||||
cwd: sourceConv.cwd
|
||||
};
|
||||
|
||||
await db[IDXDB_TABLES.conversations].add(newConv);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { base } from '$app/paths';
|
||||
import { getJsonHeaders } from '$lib/utils/api-headers';
|
||||
import { parseSseJsonStream, type SseJsonEvent } from '$lib/utils/sse';
|
||||
import { apiFetch } from '$lib/utils';
|
||||
import { API_TOOLS } from '$lib/constants';
|
||||
import { API_TOOLS, X_TOOL_CWD_HEADER } from '$lib/constants';
|
||||
import { ToolResponseField } from '$lib/enums';
|
||||
import type { ToolExecutionResult, ServerBuiltinToolInfo } from '$lib/types';
|
||||
|
||||
@@ -18,15 +18,21 @@ export class ToolsService {
|
||||
|
||||
/**
|
||||
* Execute a built-in tool on the server.
|
||||
*
|
||||
* @param cwd - Working directory for the tool call, sent as the
|
||||
* x-tool-cwd request header. The server resolves relative paths
|
||||
* against it; the model cannot override it.
|
||||
*/
|
||||
static async executeTool(
|
||||
toolName: string,
|
||||
params: Record<string, unknown>,
|
||||
signal?: AbortSignal
|
||||
signal?: AbortSignal,
|
||||
cwd?: string
|
||||
): Promise<ToolExecutionResult> {
|
||||
const result = await apiFetch<Record<string, unknown>>(API_TOOLS.EXECUTE, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ tool: toolName, params }),
|
||||
headers: cwd ? { [X_TOOL_CWD_HEADER]: cwd } : undefined,
|
||||
signal
|
||||
});
|
||||
|
||||
@@ -41,6 +47,25 @@ export class ToolsService {
|
||||
return { content: JSON.stringify(result), isError: false };
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a built-in tool and return the raw JSON response. Unlike
|
||||
* executeTool, this preserves structured fields (e.g. file_glob_search's
|
||||
* `entries` and `base`) that the flattened ToolExecutionResult drops.
|
||||
*/
|
||||
static async executeToolRaw(
|
||||
toolName: string,
|
||||
params: Record<string, unknown>,
|
||||
signal?: AbortSignal,
|
||||
cwd?: string
|
||||
): Promise<Record<string, unknown>> {
|
||||
return apiFetch<Record<string, unknown>>(API_TOOLS.EXECUTE, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ tool: toolName, params }),
|
||||
headers: cwd ? { [X_TOOL_CWD_HEADER]: cwd } : undefined,
|
||||
signal
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream a built-in tool's output chunks from the server. The server
|
||||
* `POST /tools` endpoint with `{stream: true}` emits `data: {"chunk": "..."}`
|
||||
@@ -59,9 +84,11 @@ export class ToolsService {
|
||||
static async *streamTool(
|
||||
toolName: string,
|
||||
params: Record<string, unknown>,
|
||||
signal?: AbortSignal
|
||||
signal?: AbortSignal,
|
||||
cwd?: string
|
||||
): AsyncGenerator<ToolStreamEvent> {
|
||||
const headers = getJsonHeaders();
|
||||
if (cwd) headers[X_TOOL_CWD_HEADER] = cwd;
|
||||
const response = await fetch(`${base}${API_TOOLS.EXECUTE}`, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
|
||||
Reference in New Issue
Block a user