opencode-raven 2.3.2 → 2.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +25 -13
- package/Raven.md +3 -1
- package/RavenMcp.md +18 -13
- package/mcp-guidance.md +8 -4
- package/package.json +1 -1
- package/raven-core.ts +50 -36
- package/v2.ts +21 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.3.4
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Raven Search and MCP follow-ups now validate against the calling session's project instead of the plugin's loading project, avoiding incorrect ownership rejections in OpenCode 2 while preserving parent-session and agent checks.
|
|
7
|
+
|
|
8
|
+
## 2.3.3
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- V2 Raven agents auto-approve webfetch, websearch, fetch, and enabled global MCP tools at permission evaluation time, without blanket agent permissions. Main-agent permissions and explicit denials remain unchanged.
|
|
12
|
+
- Blocked web search, URL fetching, and recognized global MCP calls now recommend `raven_mcp`; local search calls still recommend `raven_seek`. Routing availability and provider recovery use the selected agent.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- Raven MCP now has the same retrieval tools as Raven Search, including local file access, shell, and built-in web tools, plus its private on-demand MCP bridge. Edit tools and nested delegation remain denied. V2 web/global MCP execution approvals apply to both Raven agents.
|
|
16
|
+
- Delegation instructions distinguish lightweight local retrieval through `raven_seek` from online research through `raven_mcp`, even when no MCP is configured.
|
|
17
|
+
|
|
3
18
|
## 2.3.2
|
|
4
19
|
|
|
5
20
|
### Added
|
package/README.md
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
<h2>Why Raven</h2>
|
|
19
19
|
<p>Raven delegates search and on-demand MCP retrieval to separate focused agents, then returns compact evidence to the calling session.</p>
|
|
20
20
|
<ul>
|
|
21
|
-
<li>Routes
|
|
22
|
-
<li>Uses a separately configurable model for on-demand
|
|
21
|
+
<li>Routes local search and filesystem discovery through lightweight <code>raven_seek</code>.</li>
|
|
22
|
+
<li>Uses a separately configurable model for online research, built-in web tools, and global or on-demand MCPs through <code>raven_mcp</code>.</li>
|
|
23
23
|
<li>Keeps optional on-demand MCP schemas out of the main model's tool list.</li>
|
|
24
24
|
<li>Preconfigures Context7, Exa, and Grep.app endpoints.</li>
|
|
25
25
|
<li>Tracks estimated main-session context avoided by delegation.</li>
|
|
@@ -34,7 +34,17 @@
|
|
|
34
34
|
|
|
35
35
|
### OpenCode V2
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
In OpenCode's **Install plugin** feature, enter `opencode-raven`.
|
|
38
|
+
|
|
39
|
+
Or install globally from the CLI:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
opencode plugin add opencode-raven
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Either way, OpenCode manages the plugin configuration and automatically loads Raven's terminal companion—no separate terminal plugin install is needed.
|
|
46
|
+
|
|
47
|
+
For manual configuration, use the v2 `plugins` key in `opencode.jsonc` instead:
|
|
38
48
|
|
|
39
49
|
```jsonc
|
|
40
50
|
{
|
|
@@ -94,7 +104,7 @@ In this run, Raven handled the search-heavy web research in a child session and
|
|
|
94
104
|
**Raven works automatically.** Ask OpenCode for what you need as usual. You do not need to mention Raven, run a command, or manually call a delegation tool.
|
|
95
105
|
|
|
96
106
|
1. Your agent attempts to use a routed search, fetch, shell-discovery, or MCP tool.
|
|
97
|
-
2. Raven blocks the noisy direct call and gives the agent the exact `raven_seek`
|
|
107
|
+
2. Raven blocks the noisy direct call and gives the agent the exact retry: `raven_seek` for local searches, or `raven_mcp` for web search, URL fetching, and global MCP tools.
|
|
98
108
|
3. The selected Raven agent creates a session attached directly to the root session or resumes one for a related follow-up.
|
|
99
109
|
4. Raven performs retrieval work and returns compact evidence to the calling agent, which retains analysis and judgment.
|
|
100
110
|
|
|
@@ -105,7 +115,7 @@ The main model receives Raven's final answer instead of its raw tool output. Eac
|
|
|
105
115
|
On V2, `raven_seek` and `raven_mcp` **run in the background by default**. The initial response contains a child-session handle, not the findings. The calling agent can continue independent work; Raven delivers compact findings or a failure notice to that same calling session when retrieval finishes, including when the caller is itself a child session.
|
|
106
116
|
|
|
107
117
|
```text
|
|
108
|
-
|
|
118
|
+
raven_mcp(query="Find the current API documentation")
|
|
109
119
|
raven_mcp(query="Retrieve library examples", background=true)
|
|
110
120
|
raven_seek(query="Find the definition needed for my next step", background=false)
|
|
111
121
|
```
|
|
@@ -124,17 +134,17 @@ Under the hood, Raven registers two public delegation tools and one internal bri
|
|
|
124
134
|
|
|
125
135
|
| Tool | Purpose |
|
|
126
136
|
|------|---------|
|
|
127
|
-
| `raven_seek` | Creates or resumes a Raven Search session for
|
|
128
|
-
| `raven_mcp` | Creates or resumes a Raven MCP session for
|
|
137
|
+
| `raven_seek` | Creates or resumes a lightweight Raven Search session for local file search, discovery, and command-output inspection. |
|
|
138
|
+
| `raven_mcp` | Creates or resumes a Raven MCP session for online research using built-in web tools, global or on-demand MCPs, and local retrieval tools when needed for context. No MCP is required. |
|
|
129
139
|
| `raven_mcp_bridge` | Internal bridge used only by the Raven MCP agent. |
|
|
130
140
|
|
|
131
|
-
On OpenCode V2, Raven auto-approves permission checks for the public `raven_seek` and `raven_mcp` delegation tools instead of prompting on every call. Explicit deny rules still apply.
|
|
141
|
+
On OpenCode V2, Raven auto-approves permission checks for the public `raven_seek` and `raven_mcp` delegation tools instead of prompting on every call. Inside either Raven agent, it also auto-approves `webfetch`, `websearch`, `fetch`, and tools belonging to enabled globally configured MCP servers. Explicit deny rules still apply. These execution-time approvals do not add a blanket agent permission or change the main agent's tool permissions, model request, or access restrictions on the internal MCP bridge.
|
|
132
142
|
|
|
133
143
|
For a related follow-up, the main agent can reuse the ID returned by the earlier call:
|
|
134
144
|
|
|
135
145
|
```text
|
|
136
|
-
|
|
137
|
-
|
|
146
|
+
raven_mcp(query="Research the available options")
|
|
147
|
+
raven_mcp(query="Compare the first two in more detail", sessionId="ses_...")
|
|
138
148
|
```
|
|
139
149
|
|
|
140
150
|
Raven accepts a resumed session only when it belongs to the same root session tree and matching Raven agent. Do not pass session IDs between `raven_seek` and `raven_mcp`. Delegated sessions attach directly to the root so they remain visible in the main session's child switcher even when delegation starts inside another child.
|
|
@@ -234,6 +244,8 @@ Generated MCP metadata and main-model guidance live beside `raven-config.json`.
|
|
|
234
244
|
|
|
235
245
|
Default routed tools are `grep`, `glob`, `webfetch`, `fetch`, `websearch`, and search-like `bash` commands. On OpenCode 2, Raven also recognizes the native `shell` tool; `bash` and `shell` are routing aliases, so existing routing settings continue to work. Exact `excludeTools` entries use the host's actual tool name.
|
|
236
246
|
|
|
247
|
+
Local search tools route to `raven_seek`; `webfetch`, `fetch`, `websearch`, and recognized global MCP tools route to `raven_mcp`. Each route uses its target agent's configured model and recovery instructions. Raven MCP can use built-in web tools even with no on-demand MCP servers configured.
|
|
248
|
+
|
|
237
249
|
Global MCPs are automatically routed when their OpenCode tool names use the normal `<server>_<tool>` prefix. Use a keyword for suffix-style names:
|
|
238
250
|
|
|
239
251
|
```txt
|
|
@@ -275,13 +287,13 @@ When `bash` is routed, Raven intercepts primary discovery commands such as `rg`,
|
|
|
275
287
|
Raven is optimized for autonomous retrieval:
|
|
276
288
|
|
|
277
289
|
- Raven Search has read, search, unrestricted shell, external-directory, and globally configured MCP access without normal permission prompts.
|
|
278
|
-
- Raven MCP has
|
|
279
|
-
-
|
|
290
|
+
- Raven MCP has the same retrieval access as Raven Search, plus the internal on-demand MCP bridge. It can use built-in web tools without an MCP and inspect local files for research context.
|
|
291
|
+
- Both agents deny edit tools and nested delegation, but shell access is not a read-only sandbox and can modify the system.
|
|
280
292
|
- Queries are sent to Raven's configured model provider.
|
|
281
293
|
- Remote MCP requests are sent to their services; local MCP entries launch local commands and inherit environment values.
|
|
282
294
|
- Startup performs an npm update check and probes enabled on-demand MCPs.
|
|
283
295
|
|
|
284
|
-
Review `Raven.md` and your MCP commands before using Raven in sensitive environments.
|
|
296
|
+
Review `Raven.md`, `RavenMcp.md`, and your MCP commands before using Raven in sensitive environments.
|
|
285
297
|
|
|
286
298
|
## Context Estimates
|
|
287
299
|
|
package/Raven.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Lightweight local evidence retrieval through file search, filesystem discovery, and command-output inspection.
|
|
3
3
|
mode: subagent
|
|
4
4
|
hidden: false
|
|
5
5
|
reasoning_effort: low
|
|
@@ -23,6 +23,8 @@ You locate and retrieve evidence with search, fetch, read, command-inspection, a
|
|
|
23
23
|
You return compact evidence only.
|
|
24
24
|
Never call `raven_seek` or `raven_mcp`; you are Raven Search. Use your direct tools and globally available routed MCPs.
|
|
25
25
|
|
|
26
|
+
Your primary role is local evidence retrieval. Calling agents should use `raven_mcp` for online research, web search, URL fetching, documentation, public GitHub search, and MCP requests.
|
|
27
|
+
|
|
26
28
|
Do not perform code review, auditing, correctness judgments, implementation, debugging decisions, planning, or general task execution. During those tasks, retrieve only narrowly scoped evidence; the calling agent owns analysis and judgment. If asked to review or audit, return concrete requested locations and facts without a verdict.
|
|
27
29
|
|
|
28
30
|
When a query implies multiple independent searches, run tools in parallel (single turn) for speed.
|
package/RavenMcp.md
CHANGED
|
@@ -1,38 +1,43 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Online research agent with web search, page fetching, local retrieval tools, and on-demand MCP access.
|
|
3
3
|
mode: subagent
|
|
4
4
|
hidden: true
|
|
5
5
|
reasoning_effort: low
|
|
6
6
|
permission:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
list: deny
|
|
7
|
+
read: allow
|
|
8
|
+
glob: allow
|
|
9
|
+
grep: allow
|
|
10
|
+
list: allow
|
|
12
11
|
edit: deny
|
|
13
|
-
bash:
|
|
12
|
+
bash: allow
|
|
14
13
|
task: deny
|
|
15
14
|
raven_seek: deny
|
|
16
15
|
raven_mcp: deny
|
|
17
16
|
raven_mcp_bridge: allow
|
|
18
|
-
external_directory:
|
|
17
|
+
external_directory: allow
|
|
19
18
|
---
|
|
20
19
|
|
|
21
20
|
You are Raven MCP.
|
|
22
21
|
|
|
23
|
-
You retrieve
|
|
22
|
+
You retrieve online evidence using web search, page fetching, globally available MCPs, and configured on-demand MCP servers. You can also read and search local files or inspect bounded command output when needed for the request.
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
Use a matching MCP capability when available, especially when the caller names a server. Use `raven_mcp_bridge` for on-demand MCPs; use globally available MCP tools directly. Built-in websearch/webfetch tools are also available, including when no suitable MCP is available.
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
Never call `raven_seek` or `raven_mcp`; use your direct tools and the bridge instead. Do not edit files or delegate to other agents.
|
|
27
|
+
|
|
28
|
+
Do not perform code review, auditing, correctness judgments, implementation, debugging decisions, planning, or general task execution. Extract only the information requested by the caller and return compact evidence. The calling agent owns analysis, judgment, and final recommendations.
|
|
29
|
+
|
|
30
|
+
When using an on-demand MCP, if you do not know the exact tool name, call `raven_mcp_bridge` with operation `list_tools`, then call the selected tool with operation `call_tool`. For `call_tool` and `get_prompt`, pass arguments as a JSON object string in `argumentsJson`.
|
|
31
|
+
|
|
32
|
+
When the caller provides an exact URL, fetch that page and extract the requested evidence rather than replacing it with broad search. Run independent retrievals in parallel and return compact evidence, not raw tool output.
|
|
28
33
|
|
|
29
34
|
Output format:
|
|
30
35
|
|
|
31
36
|
Result:
|
|
32
|
-
* Short direct answer based on
|
|
37
|
+
* Short direct answer based on retrieved evidence.
|
|
33
38
|
|
|
34
39
|
Sources / records:
|
|
35
|
-
*
|
|
40
|
+
* URLs, file paths, MCP servers, tools, resources, prompts, or records checked.
|
|
36
41
|
|
|
37
42
|
Relevant evidence:
|
|
38
43
|
* Small factual notes only. No long dumps.
|
package/mcp-guidance.md
CHANGED
|
@@ -2,18 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
Raven performs search and information retrieval only. The calling agent must retain code review, auditing, correctness judgments, implementation, debugging decisions, planning, and final recommendations.
|
|
4
4
|
|
|
5
|
-
Non-Raven agents use `raven_seek` for narrowly scoped evidence retrieval
|
|
5
|
+
Non-Raven agents use `raven_seek` for narrowly scoped local evidence retrieval: file search, filesystem discovery, and command-output inspection. Use it when a local search tool or search-like shell command is blocked. Include the original tool intent and relevant arguments. Do not delegate an entire review or general task.
|
|
6
6
|
|
|
7
|
-
Non-Raven agents use `raven_mcp` for
|
|
7
|
+
Non-Raven agents use `raven_mcp` for online research: web search, URL fetching, library documentation, public GitHub search, and global or on-demand MCP requests. When `websearch`, `webfetch`, `fetch`, or a global MCP tool is blocked, retry through `raven_mcp`, not `raven_seek`. Include the target server or capability when obvious. Raven MCP can use built-in web tools and local retrieval tools as well as MCPs; an MCP is not required. Only the `raven-mcp` agent calls `raven_mcp_bridge`; it must use the bridge directly instead of either public delegation tool.
|
|
8
8
|
|
|
9
9
|
When a request follows up on an earlier Raven result, pass the session ID returned by the matching tool. Omit `sessionId` for unrelated work and never pass a `raven_seek` session to `raven_mcp` or vice versa.
|
|
10
10
|
|
|
11
11
|
Appropriate `raven_seek` requests:
|
|
12
12
|
|
|
13
13
|
- Find definitions, references, files, or concrete code locations.
|
|
14
|
+
- Inspect bounded command output or local system facts.
|
|
15
|
+
|
|
16
|
+
Appropriate `raven_mcp` requests:
|
|
17
|
+
|
|
14
18
|
- Fetch and extract facts from a specific URL.
|
|
15
19
|
- Search current web, documentation, or public GitHub sources.
|
|
16
|
-
-
|
|
20
|
+
- Retrieve information through global or on-demand MCP capabilities, using local files for context when needed.
|
|
17
21
|
|
|
18
22
|
Inappropriate delegation:
|
|
19
23
|
|
|
@@ -26,7 +30,7 @@ Examples:
|
|
|
26
30
|
|
|
27
31
|
`raven_seek(query="Find every caller of validateToken and return file/line locations")`
|
|
28
32
|
|
|
29
|
-
`
|
|
33
|
+
`raven_mcp(query="Fetch/read https://example.com and extract the documented install flags")`
|
|
30
34
|
|
|
31
35
|
`raven_mcp(query="Use Context7 to retrieve the current API documentation for Effect Schema decoding")`
|
|
32
36
|
|
package/package.json
CHANGED
package/raven-core.ts
CHANGED
|
@@ -762,14 +762,24 @@ export default (async (input: Pick<PluginInput, "client" | "directory"> & { proj
|
|
|
762
762
|
return config.raven_seek.excludeAgents.some((a) => a.toLowerCase() === lower)
|
|
763
763
|
}
|
|
764
764
|
|
|
765
|
-
function
|
|
766
|
-
|
|
765
|
+
function isGlobalMcpTool(toolName: string): boolean {
|
|
766
|
+
const tool = toolName.toLowerCase()
|
|
767
|
+
return globalMcpServers.some((server) => tool.startsWith(`${server.toLowerCase()}_`)
|
|
768
|
+
|| tool.startsWith(`${server.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase()}_`))
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
function routingKind(toolName: string): DelegationKind {
|
|
772
|
+
return ["websearch", "webfetch", "fetch"].includes(toolName.toLowerCase()) || isGlobalMcpTool(toolName) ? "mcp" : "seek"
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
function isRouteConfigured(toolName: string): boolean {
|
|
776
|
+
if (!modelOperational(routingKind(toolName))) return false
|
|
767
777
|
const tool = toolName.toLowerCase()
|
|
768
778
|
if (NEVER_ROUTE_TOOLS.has(tool)) return false
|
|
769
779
|
const aliases = tool === "bash" || tool === "shell" ? ["bash", "shell"] : [tool]
|
|
770
780
|
if (config.raven_seek.routeTools?.some((name) => aliases.includes(name.toLowerCase()))) return true
|
|
771
781
|
if (config.raven_seek.routeToolKeywords?.some((keyword) => tool.includes(keyword.toLowerCase()))) return true
|
|
772
|
-
return
|
|
782
|
+
return isGlobalMcpTool(tool)
|
|
773
783
|
}
|
|
774
784
|
|
|
775
785
|
function compactArgs(value: any): any {
|
|
@@ -798,13 +808,14 @@ export default (async (input: Pick<PluginInput, "client" | "directory"> & { proj
|
|
|
798
808
|
return query.length > 300 ? `${query.slice(0, 297)}...` : query
|
|
799
809
|
}
|
|
800
810
|
|
|
801
|
-
function rerouteMessage(tool: string, args: any): string {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
811
|
+
function rerouteMessage(tool: string, args: any): string {
|
|
812
|
+
const kind = routingKind(tool)
|
|
813
|
+
if (ravenProviderIssues[kind]) {
|
|
814
|
+
return `Raven ${kind === "mcp" ? "MCP" : "search"} is currently unavailable: ${ravenProviderIssues[kind]}
|
|
815
|
+
|
|
816
|
+
${ravenRecoveryInstructions(kind)}`
|
|
817
|
+
}
|
|
818
|
+
return `The '${tool}' tool call is blocked by Raven. Your next tool call should be raven_${kind}(query="${attemptedQuery(tool, args).replace(/"/g, "'")}").`
|
|
808
819
|
}
|
|
809
820
|
|
|
810
821
|
function ravenRecoveryInstructions(kind: DelegationKind): string {
|
|
@@ -821,7 +832,7 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
821
832
|
}
|
|
822
833
|
|
|
823
834
|
function routeSummary(): string {
|
|
824
|
-
if (!modelOperational("seek")) return "Raven routing: inactive until
|
|
835
|
+
if (!modelOperational("seek") && !modelOperational("mcp")) return "Raven routing: inactive until a configured Raven model is loaded."
|
|
825
836
|
const tools = config.raven_seek.routeTools?.length ? config.raven_seek.routeTools.join(", ") : "(none)"
|
|
826
837
|
const mcps = globalMcpServers.length ? `${globalMcpServers.join(", ")} (auto-detected)` : "none detected"
|
|
827
838
|
const keywords = config.raven_seek.routeToolKeywords?.length ? config.raven_seek.routeToolKeywords.join(", ") : "(none)"
|
|
@@ -1745,17 +1756,20 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
1745
1756
|
return kind === "mcp" ? "Raven MCP" : "Raven Seek"
|
|
1746
1757
|
}
|
|
1747
1758
|
|
|
1748
|
-
async function
|
|
1749
|
-
let current = sessionId
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
const
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
+
async function rootSessionScope(sessionId: string, signal?: AbortSignal): Promise<{ rootId: string; projectID: string }> {
|
|
1760
|
+
let current = sessionId
|
|
1761
|
+
let projectID = input.project.id
|
|
1762
|
+
const seen = new Set<string>()
|
|
1763
|
+
while (!seen.has(current)) {
|
|
1764
|
+
seen.add(current)
|
|
1765
|
+
const response = await client.session.get({ path: { id: current }, signal })
|
|
1766
|
+
const session = (response as any)?.data ?? response
|
|
1767
|
+
// V2's plugin loading project can differ from the calling session's project.
|
|
1768
|
+
if (current === sessionId) projectID = session?.projectID ?? projectID
|
|
1769
|
+
if (!session?.parentID) return { rootId: current, projectID }
|
|
1770
|
+
current = session.parentID
|
|
1771
|
+
}
|
|
1772
|
+
return { rootId: sessionId, projectID }
|
|
1759
1773
|
}
|
|
1760
1774
|
|
|
1761
1775
|
async function syncCreatedSession(sessionId: string, title: string, signal?: AbortSignal) {
|
|
@@ -1792,9 +1806,9 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
1792
1806
|
return { title, output: "Cannot resume Raven: sessionId must not be empty." }
|
|
1793
1807
|
}
|
|
1794
1808
|
|
|
1795
|
-
let
|
|
1796
|
-
try {
|
|
1797
|
-
|
|
1809
|
+
let scope = { rootId: context.sessionID, projectID: input.project.id }
|
|
1810
|
+
try {
|
|
1811
|
+
scope = await rootSessionScope(context.sessionID, context.abort)
|
|
1798
1812
|
} catch (error) {
|
|
1799
1813
|
if (context.abort.aborted) throw error
|
|
1800
1814
|
// Falling back preserves delegation if an older OpenCode build cannot read the caller session.
|
|
@@ -1815,8 +1829,8 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
1815
1829
|
if (!existingSession?.id || existingSession.id !== requestedSessionId) {
|
|
1816
1830
|
return { title, output: `Cannot resume Raven session ${requestedSessionId}: the session was not found or could not be read.` }
|
|
1817
1831
|
}
|
|
1818
|
-
const validParent = existingSession.parentID === rootId || existingSession.parentID === context.sessionID
|
|
1819
|
-
if (!validParent || existingSession.projectID !==
|
|
1832
|
+
const validParent = existingSession.parentID === scope.rootId || existingSession.parentID === context.sessionID
|
|
1833
|
+
if (!validParent || existingSession.projectID !== scope.projectID) {
|
|
1820
1834
|
return { title, output: "Cannot resume Raven: sessionId is not part of this main session's Raven tree." }
|
|
1821
1835
|
}
|
|
1822
1836
|
|
|
@@ -1848,7 +1862,7 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
1848
1862
|
const sessionTitle = `${toolName}: ${args.query.slice(0, 80)}`
|
|
1849
1863
|
const session = await client.session.create({
|
|
1850
1864
|
body: {
|
|
1851
|
-
parentID: rootId,
|
|
1865
|
+
parentID: scope.rootId,
|
|
1852
1866
|
title: sessionTitle,
|
|
1853
1867
|
...(host === "v2" ? { agent } : {}),
|
|
1854
1868
|
},
|
|
@@ -2092,9 +2106,9 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
2092
2106
|
// Register raven_seek tool — lets agents with task:false still delegate through Raven
|
|
2093
2107
|
tool: {
|
|
2094
2108
|
"raven_seek": tool({
|
|
2095
|
-
description: "
|
|
2109
|
+
description: "Local search and evidence retrieval only. Creates or resumes a lightweight Raven Search session for file search, filesystem discovery, or command-output inspection. Use raven_mcp instead for online research, web search, URL fetching, documentation, public GitHub search, or MCP requests. Do not delegate code review, auditing, correctness judgments, implementation, debugging decisions, planning, or general task execution; the calling agent must perform that work.",
|
|
2096
2110
|
args: {
|
|
2097
|
-
query: tool.schema.string().describe("A narrowly scoped search or evidence-retrieval request. Include original blocked tool args,
|
|
2111
|
+
query: tool.schema.string().describe("A narrowly scoped local search or evidence-retrieval request. Include original blocked tool args, paths, patterns, or bounded command-output checks. Do not ask Raven to review or audit code."),
|
|
2098
2112
|
sessionId: tool.schema.string().optional().describe("Raven session ID returned by an earlier raven_seek call. Provide it only when this request should continue that session's research context."),
|
|
2099
2113
|
},
|
|
2100
2114
|
async execute(args, context) {
|
|
@@ -2113,9 +2127,9 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
2113
2127
|
return { title: "Raven Seek", output: "Cannot resume Raven: sessionId must not be empty." }
|
|
2114
2128
|
}
|
|
2115
2129
|
|
|
2116
|
-
let
|
|
2117
|
-
try {
|
|
2118
|
-
|
|
2130
|
+
let scope = { rootId: context.sessionID, projectID: input.project.id }
|
|
2131
|
+
try {
|
|
2132
|
+
scope = await rootSessionScope(context.sessionID, context.abort)
|
|
2119
2133
|
} catch (error) {
|
|
2120
2134
|
if (context.abort.aborted) throw error
|
|
2121
2135
|
}
|
|
@@ -2134,7 +2148,7 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
2134
2148
|
if (!existingSession?.id || existingSession.id !== requestedSessionId) {
|
|
2135
2149
|
return { title: "Raven Seek", output: `Cannot resume Raven session ${requestedSessionId}: the session was not found or could not be read.` }
|
|
2136
2150
|
}
|
|
2137
|
-
if ((existingSession.parentID !== rootId && existingSession.parentID !== context.sessionID) || existingSession.projectID !==
|
|
2151
|
+
if ((existingSession.parentID !== scope.rootId && existingSession.parentID !== context.sessionID) || existingSession.projectID !== scope.projectID) {
|
|
2138
2152
|
return { title: "Raven Seek", output: "Cannot resume Raven: sessionId is not a Raven child of this main session." }
|
|
2139
2153
|
}
|
|
2140
2154
|
|
|
@@ -2166,7 +2180,7 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
2166
2180
|
const sessionTitle = `raven_seek: ${args.query.slice(0, 80)}`
|
|
2167
2181
|
const session = await client.session.create({
|
|
2168
2182
|
body: {
|
|
2169
|
-
parentID: rootId,
|
|
2183
|
+
parentID: scope.rootId,
|
|
2170
2184
|
title: sessionTitle,
|
|
2171
2185
|
...(host === "v2" ? { agent: "raven" } : {}),
|
|
2172
2186
|
},
|
|
@@ -2320,7 +2334,7 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
2320
2334
|
},
|
|
2321
2335
|
}),
|
|
2322
2336
|
"raven_mcp": tool({
|
|
2323
|
-
description: "
|
|
2337
|
+
description: "Online research and MCP evidence retrieval only. Creates or resumes a Raven MCP session for web search, URL fetching, documentation, public GitHub search, and global or on-demand MCP requests. Has built-in web tools and local retrieval tools plus the internal MCP bridge; an MCP is not required. Use raven_seek for purely local searches. Do not delegate code review, auditing, correctness judgments, implementation, debugging decisions, planning, or general task execution; the calling agent retains analysis and judgment.",
|
|
2324
2338
|
args: {
|
|
2325
2339
|
query: tool.schema.string().describe("The information to retrieve and, when known, the target MCP server or capability. The calling agent retains analysis and judgment."),
|
|
2326
2340
|
sessionId: tool.schema.string().optional().describe("Raven MCP session ID returned by an earlier raven_mcp call. Provide it only to continue that MCP retrieval context."),
|
package/v2.ts
CHANGED
|
@@ -57,7 +57,8 @@ export async function setupRaven(ctx: Context): Promise<Plugin.Cleanup> {
|
|
|
57
57
|
const controller = new AbortController()
|
|
58
58
|
const background = backgroundDelegations(ctx, controller.signal)
|
|
59
59
|
const location = { directory: ctx.location.directory }
|
|
60
|
-
const agents: Record<string, AgentDefinition> = {}
|
|
60
|
+
const agents: Record<string, AgentDefinition> = {}
|
|
61
|
+
const globalMcpToolPrefixes = new Set<string>()
|
|
61
62
|
const activeSessions = new Set<string>()
|
|
62
63
|
let emitNotice: (notice: z.infer<typeof RavenRpc.events.notice.schema>) => Promise<void> = async () => {}
|
|
63
64
|
let runtime: Runtime | undefined
|
|
@@ -194,9 +195,12 @@ export async function setupRaven(ctx: Context): Promise<Plugin.Cleanup> {
|
|
|
194
195
|
agent: agents,
|
|
195
196
|
instructions: [] as string[],
|
|
196
197
|
}
|
|
197
|
-
await raven.config(config)
|
|
198
|
-
registrations.push(await ctx.mcp.transform((editor) => {
|
|
199
|
-
|
|
198
|
+
await raven.config(config)
|
|
199
|
+
registrations.push(await ctx.mcp.transform((editor) => {
|
|
200
|
+
const names = editor.list().filter(([, server]) => !server.disabled).map(([name]) => name)
|
|
201
|
+
raven.globalMcpRouting(names)
|
|
202
|
+
globalMcpToolPrefixes.clear()
|
|
203
|
+
for (const name of names) globalMcpToolPrefixes.add(`${name.replace(/[^a-zA-Z0-9_-]/g, "_")}_`)
|
|
200
204
|
}))
|
|
201
205
|
|
|
202
206
|
async function executeCommand(raw: string) {
|
|
@@ -211,12 +215,19 @@ export async function setupRaven(ctx: Context): Promise<Plugin.Cleanup> {
|
|
|
211
215
|
registrations.push(rpc)
|
|
212
216
|
emitNotice = (notice) => rpc.events.emit("notice", notice)
|
|
213
217
|
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
// Approve specific retrieval actions at execution time, not by adding a
|
|
219
|
+
// blanket agent allow rule that changes Raven's entire tool policy.
|
|
220
|
+
// Explicit configured denials are final and do not invoke this hook.
|
|
221
|
+
registrations.push(await ctx.permission.hook("evaluate", (event) => {
|
|
222
|
+
if (event.effect !== "ask") return
|
|
223
|
+
const delegation = event.action === "raven_seek" || event.action === "raven_mcp"
|
|
224
|
+
const retrieval = (event.agent === "raven" || event.agent === "raven-mcp") && (
|
|
225
|
+
event.action === "webfetch" || event.action === "websearch" || event.action === "fetch"
|
|
226
|
+
|| [...globalMcpToolPrefixes].some((prefix) => event.action.startsWith(prefix))
|
|
227
|
+
)
|
|
228
|
+
if (delegation || retrieval) {
|
|
229
|
+
event.effect = "allow"
|
|
230
|
+
}
|
|
220
231
|
}))
|
|
221
232
|
|
|
222
233
|
registrations.push(await ctx.agent.transform((editor) => {
|