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:
@@ -0,0 +1,46 @@
|
||||
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { serviceOpencodeConfig } from "../src/runtime/opencode2-config.js";
|
||||
import { startOpencode2 } from "../src/runtime/opencode2-server.js";
|
||||
import { assertWebSearchReady } from "../src/runtime/web-search-check.js";
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
if (args.some((arg) => arg !== "--search") || args.length > 1) throw new Error("Usage: bun scripts/check-websearch.ts [--search]");
|
||||
const root = await mkdtemp(join(tmpdir(), "tjwater-websearch-check-"));
|
||||
let native: Awaited<ReturnType<typeof startOpencode2>> | undefined;
|
||||
const abort = new AbortController();
|
||||
const stop = () => abort.abort();
|
||||
process.once("SIGINT", stop);
|
||||
process.once("SIGTERM", stop);
|
||||
try {
|
||||
const source = JSON.parse(await readFile("opencode.json", "utf8"));
|
||||
native = await startOpencode2({ command: process.env.OPENCODE_COMMAND ?? "opencode2", hostname: "127.0.0.1", port: 0,
|
||||
timeout: 30_000, signal: abort.signal, config: serviceOpencodeConfig({ ...source, mcp: { servers: {} } }, undefined, root),
|
||||
env: { AGENT_INTERNAL_TOKEN: "SEARCH_CHECK_ONLY", TJWATER_AGENT_WORKSPACE_ROOT: root,
|
||||
TJWATER_AGENT_MCP_CONNECTION_PATH: join(root, "absent.json"), OPENCODE_DB: join(root, "data", "opencode.db"),
|
||||
XDG_DATA_HOME: join(root, "data"), XDG_CONFIG_HOME: join(root, "config"),
|
||||
XDG_CACHE_HOME: join(root, "cache"), XDG_STATE_HOME: join(root, "state") },
|
||||
});
|
||||
const location = { directory: process.cwd() };
|
||||
await native.client.rpc.call({ rpcID: "tjwater.tools", method: "list", input: {}, location }, {
|
||||
signal: AbortSignal.any([abort.signal, AbortSignal.timeout(15_000)]),
|
||||
});
|
||||
const report = await assertWebSearchReady(native.client, location.directory);
|
||||
if (!args.includes("--search")) console.log(JSON.stringify({ status: "catalog_ready", ...report }));
|
||||
else {
|
||||
const result = await native.client.websearch.query({ location, query: "OpenCode official documentation" }, {
|
||||
signal: AbortSignal.any([abort.signal, AbortSignal.timeout(30_000)]),
|
||||
});
|
||||
console.log(JSON.stringify({ status: "search_succeeded", provider: result.data.providerID, result_count: result.data.results.length }));
|
||||
}
|
||||
} catch {
|
||||
console.error("Web search check failed; verify the configured provider, credentials and network. No model inference was requested.");
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
native?.close();
|
||||
if (native) await native.exited;
|
||||
process.removeListener("SIGINT", stop);
|
||||
process.removeListener("SIGTERM", stop);
|
||||
await rm(root, { recursive: true, force: true });
|
||||
}
|
||||
@@ -28,9 +28,10 @@ await mkdir(dataRoot, { recursive: true });
|
||||
const sharedEnvironment = {
|
||||
...process.env,
|
||||
AGENT_INTERNAL_TOKEN: bridgeToken,
|
||||
CONVERSATION_WORKSPACE_ROOT: join(dataRoot, "conversation-workspaces"),
|
||||
TJWATER_AGENT_WORKSPACE_ROOT: join(dataRoot, "conversation-workspaces"),
|
||||
CONVERSATION_WORKSPACE_ROOT: join(dataRoot, "session-workspaces"),
|
||||
TJWATER_AGENT_WORKSPACE_ROOT: join(dataRoot, "session-workspaces"),
|
||||
TJWATER_AGENT_INTERNAL_BASE_URL: agentBaseUrl,
|
||||
TJWATER_AGENT_MCP_CONNECTION_PATH: join(dataRoot, "mcp-query", "connection.json"),
|
||||
// Retained for tools loaded by an older compatible OpenCode process.
|
||||
TJWATER_AGENT_INTERNAL_TOKEN: bridgeToken,
|
||||
};
|
||||
@@ -40,11 +41,12 @@ const opencode = await startOpencode2({
|
||||
hostname: "127.0.0.1",
|
||||
port: opencodePort,
|
||||
timeout: 30_000,
|
||||
config: serviceOpencodeConfig(JSON.parse(await readFile(join(projectRoot, "opencode.json"), "utf8"))),
|
||||
config: serviceOpencodeConfig(JSON.parse(await readFile(join(projectRoot, "opencode.json"), "utf8")), undefined, sharedEnvironment.CONVERSATION_WORKSPACE_ROOT),
|
||||
env: {
|
||||
...sharedEnvironment,
|
||||
XDG_CACHE_HOME: join(dataRoot, "xdg-cache"),
|
||||
XDG_DATA_HOME: join(dataRoot, "xdg-data"),
|
||||
OPENCODE_DB: join(dataRoot, "xdg-data", "opencode", "opencode.db"),
|
||||
XDG_STATE_HOME: join(dataRoot, "xdg-state"),
|
||||
},
|
||||
});
|
||||
@@ -81,7 +83,6 @@ try {
|
||||
MEMORY_STORAGE_DIR: join(dataRoot, "memory"),
|
||||
OPENCODE_SKILLS_ROOT_DIR: join(dataRoot, "skills"),
|
||||
PERSISTENCE_BACKUP_DIR: join(dataRoot, "backup"),
|
||||
RESULT_REF_STORAGE_DIR: join(dataRoot, "result-refs"),
|
||||
SESSION_LEARNING_STATE_STORAGE_DIR: join(dataRoot, "session-learning-state"),
|
||||
SESSION_METADATA_STORAGE_DIR: join(dataRoot, "session-metadata"),
|
||||
SESSION_TRANSCRIPT_STORAGE_DIR: join(dataRoot, "session-transcripts"),
|
||||
|
||||
Reference in New Issue
Block a user