Skip to content
Open
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
8 changes: 2 additions & 6 deletions coverage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,12 @@
ℹ common.js | 100.00 | 93.33 | 83.33 |
ℹ cron.js | 100.00 | 97.30 | 90.00 |
ℹ filesystem.js | 94.50 | 86.79 | 79.17 | 44-45 107-110 170-177 187-188 196-202 397-398 415-419 422-423
ℹ image.js | 97.90 | 95.83 | 50.00 | 92-94
ℹ index.js | 100.00 | 100.00 | 100.00 |
ℹ index.js | 99.34 | 90.00 | 100.00 | 75
ℹ memory.js | 97.58 | 83.78 | 93.75 | 52 95-96 191-195
ℹ moa.js | 100.00 | 96.77 | 80.00 |
ℹ sessionSearch.js | 100.00 | 88.10 | 91.67 |
ℹ skills.js | 98.15 | 78.57 | 71.43 | 109-111
ℹ terminal.js | 93.62 | 81.63 | 77.78 | 38-41 74 102-103 190-191 197-199 205-206 213-214 221-222 224
ℹ todo.js | 98.84 | 91.67 | 91.67 | 16-17
ℹ tts.js | 100.00 | 100.00 | 50.00 |
ℹ vision.js | 100.00 | 90.91 | 71.43 |
ℹ web.js | 95.47 | 64.79 | 60.00 | 24-25 39-40 43-45 86-88 123-125 177 189-191 330-331
ℹ tui | | | |
ℹ commandParser.js | 100.00 | 88.00 | 100.00 |
Expand All @@ -62,6 +58,6 @@
ℹ messages.js | 100.00 | 94.44 | 100.00 |
ℹ panels.js | 100.00 | 100.00 | 100.00 |
ℹ ---------------------------------------------------------------------------------------------------------------------
ℹ all files | 96.58 | 89.15 | 83.49 |
ℹ all files | 96.16 | 88.17 | 85.32 |
ℹ ---------------------------------------------------------------------------------------------------------------------
ℹ end of coverage report
10 changes: 1 addition & 9 deletions docs/FLOWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,7 @@ buildToolConfig({ permissions, allowedPaths, maxReadSize, registry, safety, time
│ ├── switch toolName:
│ │ ├── clarify | execute_code: → always create (no perms needed)
│ │ ├── web_search | web_extract: → if hasAllPerms && hasSearchKey()
│ │ ├── vision_analyze: → if OPENAI_API_KEY
│ │ ├── image_generate: → if hasAllPerms && FAL_API_KEY
│ │ ├── cronjob: → if hasAllPerms
│ │ ├── text_to_speech: → if OPENAI_API_KEY
│ │ ├── mixture_of_agents: → if OPENROUTER_API_KEY
│ │ └── default: → if requiredPerms.length === 0 || hasAllPerms
│ └── tools.push(TOOL_FACTORIES[toolName](runtimeOptions))
└── return tools[]
Expand Down Expand Up @@ -359,11 +355,7 @@ Permission gates per tool:
├── session_search → "filesystem:read"
├── skills_list, skill_view → "filesystem:read"
├── web_search, web_extract → "network:outbound" + hasSearchKey()
├── vision_analyze → OPENAI_API_KEY (no perms)
├── image_generate → "network:outbound" + FAL_API_KEY
├── cronjob → "network:outbound"
├── text_to_speech → OPENAI_API_KEY
└── mixture_of_agents → OPENROUTER_API_KEY
```

### Search Backend Detection
Expand Down Expand Up @@ -690,7 +682,7 @@ index.js
│ ├── tools/sessionSearch.js → node:fs/promises, memory/reader.js
│ ├── tools/code.js → node:child_process, node:fs/promises, node:path
│ ├── tools/filesystem.js → tool decorators + factory funcs
│ └── tools/... (vision, image, tts, moa, etc.)
│ └── tools/... (remaining core tools)
├── sandbox/pathResolver.js → node:path
├── sandbox/urlFilter.js → node:url
├── sandbox/runner.js → node:child_process, sandbox/timeoutHandler.js, envInjector.js, capability.js
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-06-01
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
## Context

The project uses a tool registry pattern in `src/tools/index.js` that imports, registers permissions, maps factories, and switches on tool names for all 18 tools. Four of these tools (`image_generate`, `vision_analyze`, `text_to_speech`, `mixture_of_agents`) depend on external APIs and add complexity (image downloaders, streaming audio handlers, multi-step agent coordination). The remaining tier-2 tools after removal are `web_search`, `web_extract`, `execute_code`, and `cronjob`.

## Goals / Non-Goals

**Goals:**
- Delete 4 tool files and their tests cleanly
- Remove all references in `src/tools/index.js` (imports, permissions, factories, switch cases)
- Update the `tools-tier2` spec to reflect only remaining tools
- Update `docs/FLOWS.md` to remove removed tool references
- Maintain 100% test coverage on remaining code

**Non-Goals:**
- No refactoring of remaining tool files
- No changes to the tool registration / permission gating architecture
- No changes to tier-1 tools

## Decisions

1. **Delete tool files outright rather than deprecate.** There is no external API consumer depending on these tools, and the project enforces 100% coverage — keeping dead code with skipped tests would conflict with pre-commit hooks.

2. **Remove `network:outbound` tier-2 requirement entirely.** After removal, the only tier-2 reference in the spec was the permission gating requirement itself. Since `web_search`, `web_extract`, `execute_code`, and `cronjob` have their own individual permission checks in code and in their own requirements, a blanket "all tier-2 tools need network:outbound" requirement becomes misleading.

3. **Use delta spec (REMOVED Requirements) rather than rewriting the whole spec.** Keeping the remaining requirements (web search, web extract, vision, tts, execute code, cronjob, safety limits) as-is preserves testability for the tools that stay. The four removed requirements and the blanket permission requirement are removed via delta.

## Risks / Trade-offs

- **[Breaking change for users relying on these tools]** → Document removal in FLOWS.md and release notes. No migration path exists since the tools are being removed entirely.
- **[Test coverage gap during transition]** → Deleting tests and cleaning up `index.js` must be coordinated so tests pass at each step. Run `npm run test` after each major change group.
- **[Spec drift during delta editing]** → The delta REMOVED spec must exactly match requirement headers in the original spec to avoid archive-time mismatches.

## Migration Plan

1. Implement all changes on the feature branch
2. Run `npm run test` to verify all remaining tests pass with 100% coverage
3. Open PR targeting `main`
4. No runtime migration needed — tools are removed, not deprecated

## Open Questions

None.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## Why

The codebase includes four tools (`image_generate`, `vision_analyze`, `text_to_speech`, `mixture_of_agents`) that add external API dependencies (FAL_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEY), increase attack surface through additional HTTP clients, image fetchers, and streaming audio handling, but are not part of the core agent workflow. Removing them simplifies the codebase, eliminates unnecessary API key requirements, and reduces maintenance burden.

## What Changes

- Delete `src/tools/image.js` — image generation tool using FAL API
- Delete `src/tools/vision.js` — vision analysis tool using OpenAI multimodal models
- Delete `src/tools/tts.js` — text-to-speech tool using OpenAI TTS API
- Delete `src/tools/moa.js` — mixture-of-agents tool using OpenRouter API
- Delete corresponding test files: `tests/unit/tools_image.test.js`, `tests/unit/tools_vision.test.js`, `tests/unit/tools_tts.test.js`, `tests/unit/tools_moa.test.js`
- Clean up `src/tools/index.js`: remove 4 imports, 4 TOOL_PERMISSIONS entries, 4 TOOL_FACTORIES entries, and their switch cases
- Update `openspec/specs/tools-tier2/spec.md`: remove all requirements for the 4 removed tools and the "Tier 2 Tools Require network:outbound Permission" requirement
- Update `docs/FLOWS.md`: remove tool reference entries for removed tools

## Capabilities

### New Capabilities
<!-- None -->

### Modified Capabilities
- `tools-tier2`: Remove requirements for `vision_analyze`, `image_generate`, `text_to_speech`, `mixture_of_agents`, and the general "Tier 2 Tools Require network:outbound Permission" requirement

## Impact

- **Code files**: 4 tool files deleted, 1 module file modified (`src/tools/index.js`), 1 spec file modified (`tools-tier2/spec.md`)
- **Test files**: 4 test files deleted, `tool_index.test.js` may need updates
- **Docs**: `docs/FLOWS.md` updated
- **API keys**: Removes requirements for FAL_API_KEY, OPENAI_API_KEY (used only for removed tools), OPENROUTER_API_KEY
- **Permissions**: The `network:outbound` permission check is simplified since tier-2 references to removed tools disappear
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
## 1. Delete Tool Source Files

- [x] 1.1 Delete `src/tools/image.js` (image_generate tool, FAL API)
- [x] 1.2 Delete `src/tools/vision.js` (vision_analyze tool, OpenAI multimodal)
- [x] 1.3 Delete `src/tools/tts.js` (text_to_speech tool, OpenAI TTS)
- [x] 1.4 Delete `src/tools/moa.js` (mixture_of_agents tool, OpenRouter)
- [x] 2.1 Delete `tests/unit/tools_image.test.js`
- [x] 2.2 Delete `tests/unit/tools_vision.test.js`
- [x] 2.3 Delete `tests/unit/tools_tts.test.js`
- [x] 2.4 Delete `tests/unit/tools_moa.test.js`

## 3. Clean Up src/tools/index.js

- [x] 3.1 Remove import for `createImageTool` from `./image.js` (line 15)
- [x] 3.2 Remove import for `createVisionTool` from `./vision.js` (line 14)
- [x] 3.3 Remove import for `createTtsTool` from `./tts.js` (line 18)
- [x] 3.4 Remove import for `createMoaTool` from `./moa.js` (line 19)
- [x] 3.5 Remove `vision_analyze: []` entry from `TOOL_PERMISSIONS` (line 42)
- [x] 3.6 Remove `image_generate: ["network:outbound"]` entry from `TOOL_PERMISSIONS` (line 43)
- [x] 3.7 Remove `text_to_speech: []` entry from `TOOL_PERMISSIONS` (line 46)
- [x] 3.8 Remove `mixture_of_agents: []` entry from `TOOL_PERMISSIONS` (line 47)
- [x] 3.9 Remove `vision_analyze: createVisionTool` entry from `TOOL_FACTORIES` (line 66)
- [x] 3.10 Remove `image_generate: createImageTool` entry from `TOOL_FACTORIES` (line 67)
- [x] 3.11 Remove `text_to_speech: createTtsTool` entry from `TOOL_FACTORIES` (line 70)
- [x] 3.12 Remove `mixture_of_agents: createMoaTool` entry from `TOOL_FACTORIES` (line 71)
- [x] 3.13 Remove `case "vision_analyze":` switch block (lines 150-154)
- [x] 3.14 Remove `case "image_generate":` switch block (lines 156-160)
- [x] 3.15 Remove `text_to_speech` and `mixture_of_agents` from the combined switch case block (lines 163-170)

## 4. Update Spec Delta

- [x] 4.1 Verify delta spec at `openspec/changes/remove-image-vision-tts-moa-tools/specs/tools-tier2/spec.md` has correct REMOVED Requirements for vision_analyze, text_to_speech, and tier-2 permission blocks
- [x] 5.1 Remove vision_analyze, image_generate, text_to_speech, mixture_of_agents from the tool permission matrix (lines ~209-213)
- [x] 5.2 Remove vision_analyze, image_generate, text_to_speech, mixture_of_agents from the tier-2 tool reference list (lines ~362-366)
- [x] 5.3 Update the tool directory listing reference (line ~693) to remove vision, image, tts, moa

## 6. Update and Run Tests

- [x] 6.1 Update `tests/unit/tool_index.test.js`: remove OPENAI_API_KEY/FAL_API_KEY/OPENROUTER_API_KEY from beforeEach/afterEach hooks (lines 53-71)
- [x] 6.2 Update comment on line 124 that references removed tools
- [x] 6.2.1 Delete `tests/unit/tool_registration.test.js` (references removed tools: vision_analyze, image_generate, text_to_speech, mixture_of_agents)
- [x] 6.3 Run `npm run test` to verify all remaining tests pass
- [x] 6.4 Run `npm run coverage` to verify 100% coverage is maintained
37 changes: 0 additions & 37 deletions openspec/specs/tools-tier2/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,6 @@ The `web_extract` tool SHALL extract content from a URL, returning markdown form
- **WHEN** `web_extract` is called with `url: "file:///etc/passwd"`
- **THEN** the tool returns an error without making any HTTP request

### Requirement: Vision Analyze Sends Image to Multimodal LLM
The `vision_analyze` tool SHALL fetch an image from a URL or decode a base64 data URI, then send it to the configured multimodal LLM for analysis. The tool must not require any additional API key beyond the agent's primary model provider.

#### Scenario: Vision analyzes image from URL
- **WHEN** `vision_analyze` is called with `url: "https://example.com/chart.png"`
- **THEN** the tool fetches the image (respecting max 4MB size) and returns the LLM's description

#### Scenario: Vision analyzes image from data URI
- **WHEN** `vision_analyze` is called with `dataUri: "data:image/png;base64,..."` (valid base64)
- **THEN** the tool decodes the base64 and returns the LLM's description

#### Scenario: Vision rejects oversized image
- **WHEN** `vision_analyze` is called with a URL that fetches an image over 4MB
- **THEN** the tool returns an error without sending it to the model

### Requirement: Text to Speech Saves Audio File
The `text_to_speech` tool SHALL call OpenAI's TTS API (`tts-1` or `tts-1-hd`), save the audio to `~/voice-memos/[timestamp]_[voice].mp3`, and return a `MEDIA:` path.

#### Scenario: TTS generates speech and saves file
- **WHEN** `text_to_speech` is called with `text: "Hello world"` and `voice: "alloy"`
- **THEN** the tool saves a file to `~/voice-memos/[timestamp]_alloy.mp3` and returns `{ path: "MEDIA:~/voice-memos/..." }`

#### Scenario: TTS requires OPENAI_API_KEY
- **WHEN** `OPENAI_API_KEY` is not set
- **THEN** the tool is not registered in the tools array

### Requirement: Execute Code Runs Python, JavaScript, or Shell Scripts in Sandboxed Subprocess
The `execute_code` tool SHALL write code to a temp file under `tmp/`, execute it via the appropriate interpreter based on `language` parameter (`python3`, `node`, or `sh`), enforce a configurable timeout and memory limit, and return stdout, stderr, and exit code.

Expand Down Expand Up @@ -113,17 +87,6 @@ The `cronjob` tool SHALL manage scheduled jobs persisted as JSON files under `me
- **WHEN** `cronjob` is called with `action: "run"` and `name: "daily-report"`
- **THEN** the job is invoked immediately via the scheduler manager

### Requirement: Tier 2 Tools Require network:outbound Permission
All Tier 2 tools (except `vision_analyze`) SHALL only be registered when `config.sandbox.permissions` includes `network:outbound`. `vision_analyze` registers when no permission is required (like `clarify`).

#### Scenario: Web tools register when network:outbound is enabled
- **WHEN** `sandbox.permissions` includes `network:outbound` and `EXA_API_KEY` is set
- **THEN** `web_search` and `web_extract` are registered

#### Scenario: Vision tool registers without network:outbound permission
- **WHEN** `sandbox.permissions` is empty
- **THEN** `vision_analyze` is still registered because it has no permission requirement

### Requirement: Safety Limits Are Configurable with Hardware-Aware Caps
The system SHALL expose all safety parameters (timeout, memory, URL filtering, Python import restrictions) as configurable settings in `config.yaml`. A value of `0` disables the guard entirely. Hard caps are enforced: memory limits cannot exceed system total RAM, and timeout values of `0` mean no limit.

Expand Down
143 changes: 0 additions & 143 deletions src/tools/image.js

This file was deleted.

Loading