mirror of
https://github.com/imartinez/privateGPT.git
synced 2026-07-17 01:48:03 +00:00
docs: add present server
This commit is contained in:
@@ -15,7 +15,7 @@ The code execution subsystem provides:
|
||||
|
||||
| Type identifier | Role |
|
||||
|---|---|
|
||||
| `code_execution_v1` | Top-level wrapper — expands into `bash_v1`, `text_editor_v1`, and optionally `present_files_v1` |
|
||||
| `code_execution_v1` | Top-level wrapper — expands into `bash_v1`, `text_editor_v1`, and optionally `present_files_v1` and `present_server_v1` |
|
||||
| `bash_v1` | Run arbitrary bash commands in a sandboxed subprocess |
|
||||
| `text_editor_v1` | View, create, and edit files in the workspace |
|
||||
| `view_v1` | View file or directory contents |
|
||||
@@ -23,11 +23,12 @@ The code execution subsystem provides:
|
||||
| `create_v1` | Create a new file |
|
||||
| `insert_v1` | Insert text after a given line |
|
||||
| `present_files_v1` | Expose generated files to the caller |
|
||||
| `present_server_v1` | Expose an HTTP service running in the sandbox to the caller |
|
||||
|
||||
Standalone endpoints are not provided for code execution tools. Use them through `/v1/messages`.
|
||||
|
||||
<Note>
|
||||
`present_files_v1` is a server-only metadata tool that surfaces created files to API consumers. It is enabled automatically when `code_execution_v1` is used and does not require explicit configuration.
|
||||
`present_files_v1` and `present_server_v1` are server-only metadata tools that surface generated artifacts and running services to API consumers. They are enabled automatically when `code_execution_v1` is used and do not require explicit configuration.
|
||||
</Note>
|
||||
|
||||
---
|
||||
@@ -36,7 +37,7 @@ Standalone endpoints are not provided for code execution tools. Use them through
|
||||
|
||||
When the model submits a `code_execution_v1` tool call, the server expands it into its constituent tools, creates or reuses a per-session sandbox, and executes the requested operations:
|
||||
|
||||
1. **Tool expansion** — `code_execution_v1` expands into `bash_v1`, `text_editor_v1`, and optionally `present_files_v1`
|
||||
1. **Tool expansion** — `code_execution_v1` expands into `bash_v1`, `text_editor_v1`, and optionally `present_files_v1` and `present_server_v1`
|
||||
2. **Session management** — each chat session gets an isolated workspace on the host filesystem
|
||||
3. **Path translation** — canonical LLM-visible paths (`/home/agent/workspace/`) are transparently mapped to real host paths
|
||||
4. **Subprocess isolation** — bash commands run as child processes with OS-level resource limits (`setrlimit`)
|
||||
@@ -189,3 +190,23 @@ Code execution sessions are managed automatically:
|
||||
| Windows | None | None | Subprocesses run without resource limits |
|
||||
|
||||
All platforms support the same canonical path translation, output scrubbing, and session lifecycle management.
|
||||
|
||||
---
|
||||
|
||||
## `present_server` tool
|
||||
|
||||
`present_server_v1` exposes an HTTP service running inside the sandbox to the caller. Call it after starting a server (for example a web app, Jupyter, or Streamlit) so the user can open or interact with it.
|
||||
|
||||
The model invokes it with:
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|---|---|---|---|
|
||||
| `port` | `int` | Yes | Port the service is listening on inside the sandbox. |
|
||||
| `service_name` | `str` | No | Human-readable name for the service (defaults to `"App"`). |
|
||||
| `initial_path` | `str \| null` | No | Optional path appended to the URL to deep-link to a specific route. |
|
||||
|
||||
The tool result contains a `resource_link` block whose `uri` is the publicly reachable URL of the tunneled service, plus a `text` block describing the service. If the sandbox backend does not support HTTP ingress, the tool returns a `text` block explaining that no endpoint is available.
|
||||
|
||||
<Note>
|
||||
HTTP ingress support depends on the configured `code_execution.provider`. Only sandbox backends that support per-session endpoint tunneling can fulfill `present_server_v1` calls.
|
||||
</Note>
|
||||
|
||||
@@ -55,7 +55,8 @@ These are things not obvious from reading `index.html` that future agents should
|
||||
- **Scroll fades** — `.chat-list-wrap` and `.messages` both use `mask-image` with `--fade-top-stop`/`--fade-bot-stop` custom properties updated on scroll by `updateChatListFade()` and `updateMessagesFade()`.
|
||||
- **Toggle switches** — all `input[type="checkbox"]` elements are styled as custom CSS pill toggles with no native appearance.
|
||||
- **Floating panel frost** — `.modal-card`, `.menu-panel`, and `.model-dropdown` override the shared glass group with a near-solid dark background (`rgba(10,12,22,0.82–0.94)`), `blur(72px) saturate(1.4)`, and a `to bottom` gradient (lighter at top, denser at bottom) for readability and visual grounding.
|
||||
- **Code Execution tools** — the Code Execution toggle in the Tools menu sends `{ name: "code_execution", type: "code_execution_v1" }` in the tools array. The backend expands this into `bash`, `text_editor` (view/str_replace/create/insert), and `present_files` (Zylon only). Tool use blocks for these tools render as styled `.code-exec-block` details elements with terminal output, line-numbered file views, diff highlighting, and exit-code badges. Adjacent tool_use + tool_result blocks are combined into a single block via blocks pairing in `blocksToHtml`. The toggle is stored per-chat in `chat.settings.enabledCodeExecution`.
|
||||
- **Code Execution tools** — the Code Execution toggle in the Tools menu sends `{ name: "code_execution", type: "code_execution_v1" }` in the tools array. The backend expands this into `bash`, `text_editor` (view/str_replace/create/insert), `present_files`, and `present_server`. Tool use blocks for these tools render as styled `.code-exec-block` details elements with terminal output, line-numbered file views, diff highlighting, and exit-code badges. Adjacent tool_use + tool_result blocks are combined into a single block via blocks pairing in `blocksToHtml`. The `isCodeExecTool` allowlist (`bash`, `view`, `str_replace`, `create`, `insert`, `present_files`, `present_server`) drives pairing and per-tool rendering. The toggle is stored per-chat in `chat.settings.enabledCodeExecution`.
|
||||
- **Code Execution session continuity** — when code execution is enabled, `chat.id` is sent as `container` in `ChatBody` so the backend reuses the same sandbox session across all messages in a chat. The `container` field must be set whenever code execution tools are active.
|
||||
- **Code Execution file upload** — when Code Execution is enabled, a **Files** button appears in the composer toolbar. It opens a file picker that uploads directly to `POST /v1/files?scope_id={chat.id}` (multipart/form-data). Uploaded files land in the session workspace and are accessible to the model's bash/file tools.
|
||||
- **Code Execution file downloads** — `present_files` tool results that contain `local_resource` blocks are rendered as `.code-exec-download` anchor elements linking to `GET /v1/files/{file_id}/content?scope_id={chat.id}`. The `file_id` and `mime_type` come from the `local_resource` block schema.
|
||||
- **Code Execution server links** — `present_server` tool results that contain `resource_link` blocks are rendered as `.code-exec-server-link` anchor elements (globe icon + service name + tunneled URL) opening in a new tab. The `uri`, `name`, and `description` come from the `resource_link` block schema. The tool_use summary shows `service_name:port` (and an optional `initial_path` deep-link).
|
||||
|
||||
@@ -2407,6 +2407,11 @@
|
||||
color: rgba(200, 170, 255, 0.92);
|
||||
}
|
||||
|
||||
.code-exec-block .code-exec-tool-label.server {
|
||||
background: rgba(112, 183, 255, 0.14);
|
||||
color: rgba(140, 200, 255, 0.92);
|
||||
}
|
||||
|
||||
/* ── Code execution file downloads ──────────────────────────────────── */
|
||||
.code-exec-download {
|
||||
display: inline-flex;
|
||||
@@ -2447,6 +2452,46 @@
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
/* ── Code execution server links (present_server) ──────────────────── */
|
||||
.code-exec-server-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid rgba(112, 183, 255, 0.22);
|
||||
border-radius: 10px;
|
||||
background: rgba(112, 183, 255, 0.08);
|
||||
color: rgba(140, 200, 255, 0.92);
|
||||
font-size: 13px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
text-decoration: none;
|
||||
transition: background 150ms ease, border-color 150ms ease;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.code-exec-server-link:hover {
|
||||
background: rgba(112, 183, 255, 0.16);
|
||||
border-color: rgba(112, 183, 255, 0.36);
|
||||
}
|
||||
.code-exec-server-link svg {
|
||||
flex: 0 0 auto;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
.code-exec-server-link .code-exec-server-name {
|
||||
font-weight: 600;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.code-exec-server-link .code-exec-server-url {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* ── Modal backdrop blur ─────────────────────────────────────────────── */
|
||||
.modal-backdrop {
|
||||
backdrop-filter: blur(14px);
|
||||
@@ -5191,11 +5236,11 @@
|
||||
}
|
||||
|
||||
function isCodeExecTool(name) {
|
||||
return ["bash", "view", "str_replace", "create", "insert", "present_files"].includes(name);
|
||||
return ["bash", "view", "str_replace", "create", "insert", "present_files", "present_server"].includes(name);
|
||||
}
|
||||
|
||||
function codeExecToolLabel(name) {
|
||||
const map = { bash: "Bash", view: "Read", str_replace: "Edit", create: "Create", insert: "Insert", present_files: "Present" };
|
||||
const map = { bash: "Bash", view: "Read", str_replace: "Edit", create: "Create", insert: "Insert", present_files: "Present", present_server: "Server" };
|
||||
return map[name] || name;
|
||||
}
|
||||
|
||||
@@ -5205,6 +5250,7 @@
|
||||
if (name === "create") return "create";
|
||||
if (name === "str_replace") return "edit";
|
||||
if (name === "present_files") return "present";
|
||||
if (name === "present_server") return "server";
|
||||
return "file";
|
||||
}
|
||||
|
||||
@@ -5231,6 +5277,11 @@
|
||||
} else if (name === "present_files") {
|
||||
const files = Array.isArray(input.files) ? input.files : [];
|
||||
detail = `<div class="code-exec-present-files">${files.map(f => `<div class="code-exec-present-file"><span class="file-icon">${icons.file}</span><span class="file-name">${escapeHtml(typeof f === "string" ? f : f.path || f.name || "")}</span></div>`).join("")}</div>`;
|
||||
} else if (name === "present_server") {
|
||||
const port = input.port != null ? `:${input.port}` : "";
|
||||
const service = input.service_name || "App";
|
||||
const initialPath = input.initial_path ? ` → ${input.initial_path}` : "";
|
||||
detail = `<div class="code-exec-file-info">${icons.globe}<span class="code-exec-file-path">${escapeHtml(service)}${escapeHtml(port)}${escapeHtml(initialPath)}</span></div>`;
|
||||
}
|
||||
|
||||
// If we have a result block, render the result content in the same body
|
||||
@@ -5279,6 +5330,28 @@
|
||||
} else {
|
||||
resultHtml = rawText ? `<div class="code-exec-terminal">${escapeHtml(rawText)}</div>` : "";
|
||||
}
|
||||
} else if (name === "present_server") {
|
||||
const content = resultBlock.content;
|
||||
if (Array.isArray(content)) {
|
||||
const linkItems = content.filter(b => b?.type === "resource_link");
|
||||
const textItems = content.filter(b => b?.type === "text" || typeof b === "string");
|
||||
const textHtml = textItems.map(b => escapeHtml(typeof b === "string" ? b : (b.text || ""))).join(" ");
|
||||
if (linkItems.length > 0) {
|
||||
resultHtml = `<div class="code-exec-present-files">${linkItems.map(l => {
|
||||
const url = l.uri || "";
|
||||
const svc = l.name || "App";
|
||||
const desc = l.description ? escapeHtml(l.description) : "";
|
||||
if (url) {
|
||||
return `<a class="code-exec-server-link" href="${escapeAttr(url)}" target="_blank" rel="noreferrer">${icons.globe}<span class="code-exec-server-name">${escapeHtml(svc)}</span><span class="code-exec-server-url">${escapeHtml(url)}</span></a>${desc ? `<div class="code-exec-terminal" style="margin-top:6px">${desc}</div>` : ""}`;
|
||||
}
|
||||
return `<div class="code-exec-present-file"><span class="file-icon">${icons.globe}</span><span class="file-name">${escapeHtml(svc)}</span></div>`;
|
||||
}).join("")}</div>${textHtml ? `<div class="code-exec-terminal" style="margin-top:8px">${textHtml}</div>` : ""}`;
|
||||
} else {
|
||||
resultHtml = textHtml ? `<div class="code-exec-terminal">${textHtml}</div>` : "";
|
||||
}
|
||||
} else {
|
||||
resultHtml = rawText ? `<div class="code-exec-terminal">${escapeHtml(rawText)}</div>` : "";
|
||||
}
|
||||
} else {
|
||||
resultHtml = renderFileView(rawText);
|
||||
}
|
||||
@@ -5287,7 +5360,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
const summaryLabel = name === "bash" ? (input.command ? input.command.split("\n")[0].slice(0, 60) + (input.command.length > 60 ? "…" : "") : "") : (input.path || "");
|
||||
const summaryLabel = name === "bash" ? (input.command ? input.command.split("\n")[0].slice(0, 60) + (input.command.length > 60 ? "…" : "") : "") : name === "present_server" ? `${input.service_name || "App"}${input.port != null ? `:${input.port}` : ""}` : (input.path || "");
|
||||
return `<details class="code-exec-block"${resultBlock ? " open" : ""}><summary><span class="code-exec-tool-label ${labelClass}">${label}</span>${escapeHtml(summaryLabel)}</summary><div class="code-exec-body">${detail}</div></details>`;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user