feat(agent): unify MCP tools and adopt Responses delivery
Move project and host queries into native MCP with host-owned OAuth/context, while retaining memory, skills, actions and publication plugins. Add nearby-model queries and explicit chat/task/learning model defaults. Adopt Responses HTTP/SSE and native steer/queue inbox delivery, preserving scoped session ownership, pending input edits and investigation communication. Disable local-provider discovery: Server /health allowed native vLLM to probe /v1/models on port 8000. A native before/after regression prevents recurrence. Validation: 170 focused Bun tests; service/plugin typechecks; native discovery, provider-discovery and input-inbox smoke checks; no paid model inference.
This commit is contained in:
@@ -4,6 +4,8 @@ import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
||||
import { type Plugin } from "@opencode/plugin";
|
||||
import { z } from "zod";
|
||||
import { getInternalBridgeConfig } from "./internalBridge.js";
|
||||
import { DEFAULT_SESSION_WORKSPACE_ROOT, isManagedConversationWorkspace } from "../src/runtime/conversationWorkspace.js";
|
||||
import { TASK_READER_AGENT } from "../src/runtime/task-agent-policy.js";
|
||||
|
||||
type Context = Parameters<Plugin.Plugin["setup"]>[0];
|
||||
const inside = (root: string, path: string) => {
|
||||
@@ -32,12 +34,12 @@ export function canAccessConversationPath(workspace: string, path: string, edit
|
||||
}
|
||||
|
||||
export async function registerSessionSandbox(ctx: Context) {
|
||||
const root = resolve(process.env.TJWATER_AGENT_WORKSPACE_ROOT ?? ".agent-workspaces");
|
||||
const root = resolve(process.env.TJWATER_AGENT_WORKSPACE_ROOT ?? DEFAULT_SESSION_WORKSPACE_ROOT);
|
||||
const skills = resolve(process.env.OPENCODE_SKILLS_ROOT_DIR ?? ".opencode/skills");
|
||||
const workspace = async (sessionID: string) => {
|
||||
const session = await ctx.session.get({ sessionID });
|
||||
const directory = canonical(session.location.directory);
|
||||
if (dirname(directory) !== canonical(root) || !directory.split(sep).at(-1)?.startsWith("conversation-")) {
|
||||
if (!isManagedConversationWorkspace(directory, canonical(root), sessionID)) {
|
||||
throw new Error("session has no managed conversation workspace");
|
||||
}
|
||||
return directory;
|
||||
@@ -103,7 +105,10 @@ export async function registerSessionSandbox(ctx: Context) {
|
||||
}
|
||||
});
|
||||
await ctx.session.hook("context", async (event) => {
|
||||
// Native child sessions share the parent's Location, not its file identity.
|
||||
// Readers have no filesystem tools; task-agent-policy verifies their parent.
|
||||
if (event.agent === TASK_READER_AGENT) return;
|
||||
const directory = await workspace(event.sessionID);
|
||||
event.system.push({ type: "text", text: `当前会话目录:${directory}。Shell 的工作目录是 ${directory}/files。写入与计算文件放在 files/;目录根只读。shell 禁止网络与跨会话访问,业务数据、网页搜索和地理编码使用类型化工具。` });
|
||||
event.system.push({ type: "text", text: `当前会话目录:${directory}。Shell 的工作目录是 ${directory}/files。写入与计算文件放在 files/;目录根只读。shell 禁止网络与跨会话访问;业务数据和地理编码使用 MCP 查询,公开网页搜索使用原生 websearch。` });
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user