Skip to content
Merged

Dev #42

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions AGENTS.md

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ Concretely, that means:
## Features

- **Declarative sub-agent pooling (optional)** — with `--use-pool`, the root agent can fan tasks out concurrently to vendor-agnostic sub-agents defined in an optional [agents.yaml](agents.yaml) file via a `dispatch` tool. Each pool entry binds a model _and_ a backend, so dispatch decisions are also compute-location decisions — a frontier model can plan while sensitive work stays on a local model, or a local root can fan out to faster remote SLMs for latency-sensitive tool calls.
- **Agent profiles** — drop-in system prompts with permission manifests, base-profile inheritance, and auto-generated profiles via `/profile create`. Bundled profiles: `default`, `coder`, `reviewer`, `writer`, `planner`, `researcher`, `analyst`.
- **Rich built-in tool set** — file ops, shell access, web search/fetch, Wikipedia/GitHub/arXiv search, task tracking, reasoning scratchpad, notebook, and more. Sandbox-locked with shell allowlists, SSRF protection, and sensitive-file gating.
- **Agent profiles** — drop-in system prompts with permission manifests, base-profile inheritance, and auto-generated profiles via `/profile create`. Bundled profiles: `default`, `coder`, `reviewer`, `editor`, `writer`, `planner`, `researcher`, `analyst`.
- **Rich built-in tool set** — file ops, shell access, web search/fetch, Wikipedia/GitHub/arXiv search, task tracking, reasoning scratchpad, notebook, interactive user-question modals, and more. Sandbox-locked with shell allowlists, SSRF protection, and sensitive-file gating.
- **Permission system** — write operations and sensitive reads require user approval. Session grants, workspace scoping, and profile-level allow/deny lists.
- **OpenAI-compatible API server** — run the same agent harness behind `/v1/models` and `/v1/chat/completions` (streaming + non-streaming) so any workflow that speaks the OpenAI wire protocol (the `openai` Python SDK, curl, or plain REST) can drive the agent.
- **Voice mode (optional, experimental)** — `/voice` toggles a hands-free mic → STT → LLM → TTS loop (faster-whisper, Piper TTS, WebRTC VAD) for the TUI. Fully local; requires the `voice` extras and a downloaded Piper model.
Expand Down Expand Up @@ -85,6 +85,7 @@ oli --profile researcher
| `default` | ✅ | ✅ | ✅ | General-purpose tasks |
| `coder` | ✅ | ✅ | ✅ | Software development end-to-end |
| `reviewer` | ❌ | ✅ | ❌ | Code review, quality analysis |
| `editor` | ✅ | ❌ | ❌ | Proofreading, grammar, prose, creative edits|
| `writer` | ✅ | ❌ | ✅ | Docs, READMEs, changelogs, prose |
| `planner` | ✅ | ❌ | ✅ | Roadmaps, task decomposition, saved plans |
| `researcher` | ❌ | ❌ | ✅ | Web research with structured JSON output |
Expand Down
1 change: 1 addition & 0 deletions docs/PROFILES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ When a profile is loaded, both `AGENTS.md` and `SKILLS.md` are combined into the
| `analyst` | Specialist data-analyst agent — extracts claims, triangulates across sources, flags tensions |
| `coder` | Software-engineer profile — read, write, and run access for end-to-end development workflows |
| `reviewer` | Code-review profile — read-only analysis with test/lint execution; no file modifications |
| `editor` | Writing-editor profile — proofreading, grammar and prose health, creative-writing feedback |
| `writer` | Technical writer profile — prose, documentation, READMEs, changelogs, and guides |
| `planner` | Planning agent — decomposes goals into structured, saved plans; no file modifications |

Expand Down
3 changes: 2 additions & 1 deletion docs/TOOLS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ All built-in tools are exposed to the model as `builtin__<name>`.
| **extract_article** | Extract full text from an article URL via newspaper4k; returns title, authors, publish date, and a text preview. |
| **compare** | Compare files or directories and summarize differences. |
| **todowrite** | Create and maintain a structured task list for the current session; tracks progress, organizes multi-step work. |
| **question** | Pose one or more questions to the user and block until they answer. Each item takes a `question` string, optional `options` (shown as selectable choices), and an optional `recommended` (a 1-based option index or exact option text marking the model's suggestion). Rendered in the TUI as a modal widget with a "write your own answer" field per question and a final Confirm button; the answers are returned as the tool result so the model can proceed. When no interactive user is attached (e.g. the API server), the tool returns an error telling the model to proceed on its own. |
| **think** | Internal reasoning scratchpad -- stores chain-of-thought in conversation history without displaying it to the user. |
| **notebook** | Agent working memory -- store and retrieve Markdown notes across named pages under `~/.config/oli/notes/`. Pages named `plan-<name>` (as used by `/mode plan`) auto-increment to `plan-<name>-2`, `-3`, ... on collision instead of overwriting. |

Expand All @@ -40,7 +41,7 @@ The agent requires user approval for operations that could affect your system:
- **Sensitive files** (`.env*`, `*.pem`, `*.key`, `~/.ssh/`, `~/.aws/`, files with `secret`/`credential`/`password`/`token` in the name) -- prompt on `read_file` even inside the workspace.
- **Sensitive glob/grep patterns** -- requests whose pattern or `include` field references sensitive keywords also prompt.
- **Outbound HTTP tools** (`fetch`, `download_file`, `upload_file`, `search_github`, `view_image` URL branch) -- no permission prompt, but every request passes through the SSRF guard (see below).
- **Unrestricted tools** -- `websearch`, `search_wikipedia`, `search_arxiv`, `search_stackoverflow`, `search_open_library`, `think`, `todowrite`, `notebook` -- no permission gating (the network ones are still blocked by offline mode).
- **Unrestricted tools** -- `websearch`, `search_wikipedia`, `search_arxiv`, `search_stackoverflow`, `search_open_library`, `think`, `todowrite`, `notebook`, `question` -- no permission gating (the network ones are still blocked by offline mode).

Each permission prompt offers three choices: **Allow once**, **Allow for session**, or **Deny**. Session grants persist for the lifetime of the TUI process.

Expand Down
7 changes: 7 additions & 0 deletions oli_bot/api/harness.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ async def _api_confirm(description: str) -> str:
return "session"


# Note: the ``builtin__question`` tool needs an interactive human. The API
# server never registers a question callback on ``BuiltinToolManager``, so a
# call to it returns an error result telling the model to proceed on its own.
# If an out-of-band ask flow is ever desired, wire ``set_question_callback``
# here the same way ``set_todo_callback`` is wired in ``_wire_todo_relay``.


def _wire_todo_relay(agent: Agent) -> None:
"""Relay ``builtin__todowrite`` updates to WebSocket clients.

Expand Down
10 changes: 10 additions & 0 deletions oli_bot/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
WorkspaceListScreen,
MCPSetupScreen,
PermissionScreen,
QuestionScreen,
ConfirmScreen,
SessionListScreen,
SubAgentViewScreen,
Expand Down Expand Up @@ -549,6 +550,7 @@ def on_mount(self) -> None:
# Wire up the todo-change callback so updates fire immediately
self._builtin_tools.set_todo_callback(self._on_todos_changed)
self._builtin_tools.set_sub_todo_callback(self._on_sub_todos_changed)
self._builtin_tools.set_question_callback(self._question_callback)

# Set border title for the todo panel
todo_panel = self.query_one("#todo-panel", TodoWidget)
Expand Down Expand Up @@ -2629,6 +2631,14 @@ async def _permission_callback(self, description: str) -> str:
async with self._permission_lock:
return await self.push_screen_wait(PermissionScreen(description))

async def _question_callback(self, questions: list[dict]) -> str | None:
"""Present the agent's ``builtin__question`` batch and return the
user's answers, serialized with permission prompts so concurrent
sub-agents queue their questions instead of stacking modals.
"""
async with self._permission_lock:
return await self.push_screen_wait(QuestionScreen(questions))

def _register_dispatch_tool(self) -> None:
"""Register the `dispatch` built-in tool that fans a batch of tasks
out to pooled sub-agents concurrently. Schema generation is shared
Expand Down
3 changes: 2 additions & 1 deletion oli_bot/profiles/default/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ All built-in tools are called via `builtin__<name>`.
| `builtin__extract_article` | `url: string` | no permission needed (blocked by offline mode) | Extract full text from an article URL via newspaper4k; returns title, authors, publish date, and a text preview |
| `builtin__think` | `thought: string` | no permission needed | Internal reasoning scratchpad (not shown to user). Use to plan multi-step work, reason about problems, or analyze before acting. |
| `builtin__todowrite` | `todos: array[{content, status, priority}]` | no permission needed | Create and maintain a structured task list. Track progress, mark items complete, and verify all tasks are done. Call with the full list each time. |
| `builtin__question` | `questions: array[{question, options?: [string], recommended?: string}]` | no permission needed (interactive) | Pose questions to the user and wait for their answers before proceeding. Each question may list suggested options (mark one as `recommended` when you believe it is best — a 1-based option index or exact option text); the user can select an option or type a custom answer in the modal widget. The tool blocks until the user confirms. Use when a decision or input from the user is required. |
| `builtin__compare` | `target_a: string, target_b: string, mode?: string, ignore_whitespace?: boolean` | no permission needed | Compare files or directories and summarize differences. |
| `builtin__tree` | `path?: string`, `depth?: number` | same as read tools | Display directory structure as a tree. Shows recursive layout of files and subdirectories. |
| `builtin__dispatch` | `batch: array[{agent, task}]` | same as read tools (root agent only); no permission needed for plain text/read-only agents | **Available only when agent pooling is enabled** (`--use-pool` / `OLI_USE_AGENT_POOL=true`) and the `agents.yaml` pool is non-empty. Fans out agent/task pairs concurrently (`asyncio.gather`) to the configured sub-agents and returns all results aggregated into a single labeled string. If pooling is not enabled or the pool is empty, this tool is **not registered** and must not be called. |
Expand All @@ -37,7 +38,7 @@ All built-in tools are called via `builtin__<name>`.
- **Write tools** (`write_file`, `edit_file`, `download_file`, `upload_file`) — always require user permission
- **Read tools** (`read_file`, `view_image`, `glob`, `grep`, `list_directory`, `tree`) — require permission only when targeting paths outside the session workspace
- **Shell tools** (`run_command`) — require permission only when their working directory is outside the session workspace (same boundary logic as read tools)
- `websearch`, `fetch`, `search_wikipedia`, `search_github`, `search_arxiv`, `search_stackoverflow`, `search_open_library`, `extract_article`, `think`, `todowrite`, `notebook` — no permission gating
- `websearch`, `fetch`, `search_wikipedia`, `search_github`, `search_arxiv`, `search_stackoverflow`, `search_open_library`, `extract_article`, `think`, `todowrite`, `notebook`, `question` — no permission gating

## Shell command allowlist

Expand Down
Loading
Loading