qantara 0.1.0
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/LICENSE +21 -0
- package/README.md +272 -0
- package/dist/cli.js +32 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +63 -0
- package/dist/config.js.map +1 -0
- package/dist/debug.js +25 -0
- package/dist/debug.js.map +1 -0
- package/dist/exec.js +105 -0
- package/dist/exec.js.map +1 -0
- package/dist/jobs.js +22 -0
- package/dist/jobs.js.map +1 -0
- package/dist/registry.js +24 -0
- package/dist/registry.js.map +1 -0
- package/dist/runners/claude.js +73 -0
- package/dist/runners/claude.js.map +1 -0
- package/dist/runners/codex.js +81 -0
- package/dist/runners/codex.js.map +1 -0
- package/dist/runners/gemini.js +73 -0
- package/dist/runners/gemini.js.map +1 -0
- package/dist/server.js +232 -0
- package/dist/server.js.map +1 -0
- package/dist/sessions.js +14 -0
- package/dist/sessions.js.map +1 -0
- package/dist/setup.js +240 -0
- package/dist/setup.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { config, childEnv } from "../config.js";
|
|
2
|
+
import { runCommand, ExecError } from "../exec.js";
|
|
3
|
+
/**
|
|
4
|
+
* Maps the bridge's `thinking` levels to Claude's keyword triggers. Claude
|
|
5
|
+
* converts these keywords into a thinking-token budget internally, so we just
|
|
6
|
+
* append the keyword to the task text — no env vars, no version-specific flags.
|
|
7
|
+
*/
|
|
8
|
+
const THINKING_KEYWORDS = {
|
|
9
|
+
off: "",
|
|
10
|
+
think: "think",
|
|
11
|
+
think_hard: "think hard",
|
|
12
|
+
ultrathink: "ultrathink",
|
|
13
|
+
};
|
|
14
|
+
export const claudeRunner = {
|
|
15
|
+
name: "claude",
|
|
16
|
+
description: "Delegate a task to Claude Code (Anthropic). Good for deep reasoning, " +
|
|
17
|
+
"code review, and careful multi-step work. Supports model, effort, and thinking.",
|
|
18
|
+
defaults: { model: config.claude.model, reasoning: undefined },
|
|
19
|
+
supportsReasoning: true,
|
|
20
|
+
supportsThinking: true,
|
|
21
|
+
async run(task, opts) {
|
|
22
|
+
const thinkingKeyword = opts.thinking && opts.thinking !== "off"
|
|
23
|
+
? THINKING_KEYWORDS[opts.thinking] ?? ""
|
|
24
|
+
: "";
|
|
25
|
+
const prompt = thinkingKeyword ? `${task}\n\n${thinkingKeyword}` : task;
|
|
26
|
+
const args = [
|
|
27
|
+
"-p",
|
|
28
|
+
"--output-format",
|
|
29
|
+
"json",
|
|
30
|
+
"--permission-mode",
|
|
31
|
+
config.claude.permissionMode,
|
|
32
|
+
];
|
|
33
|
+
const model = opts.model ?? config.claude.model;
|
|
34
|
+
if (model)
|
|
35
|
+
args.push("--model", model);
|
|
36
|
+
// `reasoning` maps to Claude's --effort (low|medium|high|xhigh|max).
|
|
37
|
+
if (opts.reasoning)
|
|
38
|
+
args.push("--effort", opts.reasoning);
|
|
39
|
+
if (opts.sessionId)
|
|
40
|
+
args.push("--resume", opts.sessionId);
|
|
41
|
+
// The prompt is passed via stdin (not argv) so shell metacharacters in the
|
|
42
|
+
// task can never be interpreted by the Windows .cmd shell or inject commands.
|
|
43
|
+
const result = await runCommand("claude", args, {
|
|
44
|
+
cwd: opts.cwd,
|
|
45
|
+
env: childEnv(opts.depth),
|
|
46
|
+
timeoutMs: opts.timeoutMs ?? config.timeoutMs,
|
|
47
|
+
maxOutputBytes: config.maxOutputBytes,
|
|
48
|
+
stdin: prompt,
|
|
49
|
+
signal: opts.signal,
|
|
50
|
+
});
|
|
51
|
+
if (result.code !== 0) {
|
|
52
|
+
const tail = result.stderr.slice(-2000) || result.stdout.slice(-2000);
|
|
53
|
+
throw new ExecError(`claude exited with code ${result.code}: ${tail}`, result);
|
|
54
|
+
}
|
|
55
|
+
let parsed;
|
|
56
|
+
try {
|
|
57
|
+
parsed = JSON.parse(result.stdout.trim());
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
throw new ExecError(`Could not parse claude JSON output: ${result.stdout.slice(0, 500)}`, result);
|
|
61
|
+
}
|
|
62
|
+
if (parsed.is_error) {
|
|
63
|
+
throw new ExecError(`claude reported an error: ${parsed.result ?? parsed.subtype}`);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
text: parsed.result ?? "",
|
|
67
|
+
sessionId: parsed.session_id,
|
|
68
|
+
cost: parsed.total_cost_usd,
|
|
69
|
+
truncated: result.truncated,
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/runners/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { config, childEnv } from "../config.js";
|
|
2
|
+
import { runCommand, ExecError } from "../exec.js";
|
|
3
|
+
function parseCodexJsonl(stdout) {
|
|
4
|
+
let sessionId;
|
|
5
|
+
let text = "";
|
|
6
|
+
for (const line of stdout.split("\n")) {
|
|
7
|
+
const trimmed = line.trim();
|
|
8
|
+
if (!trimmed)
|
|
9
|
+
continue;
|
|
10
|
+
let evt;
|
|
11
|
+
try {
|
|
12
|
+
evt = JSON.parse(trimmed);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
continue; // ignore non-JSON noise
|
|
16
|
+
}
|
|
17
|
+
if (evt.type === "thread.started" && evt.thread_id) {
|
|
18
|
+
sessionId = evt.thread_id;
|
|
19
|
+
}
|
|
20
|
+
else if (evt.type === "item.completed" &&
|
|
21
|
+
evt.item?.type === "agent_message" &&
|
|
22
|
+
typeof evt.item.text === "string") {
|
|
23
|
+
// Last agent_message wins (the final answer of the turn).
|
|
24
|
+
text = evt.item.text;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return { text, sessionId };
|
|
28
|
+
}
|
|
29
|
+
export const codexRunner = {
|
|
30
|
+
name: "codex",
|
|
31
|
+
description: "Delegate a task to OpenAI Codex (GPT). Good for fast implementation, " +
|
|
32
|
+
"broad language coverage, and a second-opinion review. Supports model and reasoning.",
|
|
33
|
+
defaults: { model: config.codex.model, reasoning: undefined },
|
|
34
|
+
supportsReasoning: true,
|
|
35
|
+
supportsThinking: false,
|
|
36
|
+
async run(task, opts) {
|
|
37
|
+
const resuming = Boolean(opts.sessionId);
|
|
38
|
+
// `codex exec` for a fresh run; `codex exec resume <id>` to continue one.
|
|
39
|
+
const args = ["exec"];
|
|
40
|
+
if (resuming)
|
|
41
|
+
args.push("resume", opts.sessionId);
|
|
42
|
+
args.push("--json", "--skip-git-repo-check");
|
|
43
|
+
// `resume` does not accept -s/--sandbox; it inherits the session's config.
|
|
44
|
+
if (!resuming)
|
|
45
|
+
args.push("-s", config.codex.sandbox);
|
|
46
|
+
const model = opts.model ?? config.codex.model;
|
|
47
|
+
if (model)
|
|
48
|
+
args.push("-m", model);
|
|
49
|
+
// Reasoning maps to the model_reasoning_effort config override. A bare value
|
|
50
|
+
// fails TOML parsing and is used as a literal string, so no quotes needed.
|
|
51
|
+
const reasoning = opts.reasoning ?? config.codex.reasoning;
|
|
52
|
+
if (reasoning)
|
|
53
|
+
args.push("-c", `model_reasoning_effort=${reasoning}`);
|
|
54
|
+
// Read the prompt from stdin (passed below) rather than argv.
|
|
55
|
+
args.push("-");
|
|
56
|
+
const result = await runCommand("codex", args, {
|
|
57
|
+
cwd: opts.cwd,
|
|
58
|
+
env: childEnv(opts.depth),
|
|
59
|
+
timeoutMs: opts.timeoutMs ?? config.timeoutMs,
|
|
60
|
+
maxOutputBytes: config.maxOutputBytes,
|
|
61
|
+
stdin: task,
|
|
62
|
+
signal: opts.signal,
|
|
63
|
+
});
|
|
64
|
+
if (result.code !== 0) {
|
|
65
|
+
const tail = result.stderr.slice(-2000) || result.stdout.slice(-2000);
|
|
66
|
+
throw new ExecError(`codex exited with code ${result.code}: ${tail}`, result);
|
|
67
|
+
}
|
|
68
|
+
const { text, sessionId } = parseCodexJsonl(result.stdout);
|
|
69
|
+
if (!text && result.truncated) {
|
|
70
|
+
throw new ExecError("codex output was truncated before a final message", result);
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
text,
|
|
74
|
+
sessionId,
|
|
75
|
+
// Codex (subscription auth) does not report a USD cost in its JSON stream.
|
|
76
|
+
cost: undefined,
|
|
77
|
+
truncated: result.truncated,
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/runners/codex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { config, childEnv } from "../config.js";
|
|
2
|
+
import { runCommand, ExecError } from "../exec.js";
|
|
3
|
+
export const geminiRunner = {
|
|
4
|
+
name: "gemini",
|
|
5
|
+
description: "Delegate a task to Google Gemini (gemini-cli). Good for large-context " +
|
|
6
|
+
"analysis and a third-opinion review. Supports model and session resume.",
|
|
7
|
+
defaults: { model: config.gemini.model, reasoning: undefined },
|
|
8
|
+
// gemini-cli has no CLI reasoning/effort flag (thinking is settings.json-only).
|
|
9
|
+
supportsReasoning: false,
|
|
10
|
+
supportsThinking: false,
|
|
11
|
+
async run(task, opts) {
|
|
12
|
+
const args = [
|
|
13
|
+
"--output-format",
|
|
14
|
+
"json",
|
|
15
|
+
"--approval-mode",
|
|
16
|
+
config.gemini.approvalMode,
|
|
17
|
+
// Without this, gemini silently downgrades the approval mode in folders
|
|
18
|
+
// not marked trusted, and delegated edit tasks fail confusingly. Trust
|
|
19
|
+
// policy for delegations is owned by BRIDGE_GEMINI_APPROVAL instead.
|
|
20
|
+
"--skip-trust",
|
|
21
|
+
];
|
|
22
|
+
const model = opts.model ?? config.gemini.model;
|
|
23
|
+
if (model)
|
|
24
|
+
args.push("-m", model);
|
|
25
|
+
// Headless resume by session UUID. Note: gemini sessions are project-scoped
|
|
26
|
+
// (keyed by cwd), so resume only works from the same working directory.
|
|
27
|
+
if (opts.sessionId)
|
|
28
|
+
args.push("--resume", opts.sessionId);
|
|
29
|
+
// The prompt goes via stdin (piped stdin => headless mode, and stdin alone
|
|
30
|
+
// is used as the whole prompt), so shell metacharacters in the task can
|
|
31
|
+
// never be interpreted by the Windows .cmd shell or inject commands.
|
|
32
|
+
const result = await runCommand("gemini", args, {
|
|
33
|
+
cwd: opts.cwd,
|
|
34
|
+
env: childEnv(opts.depth),
|
|
35
|
+
timeoutMs: opts.timeoutMs ?? config.timeoutMs,
|
|
36
|
+
maxOutputBytes: config.maxOutputBytes,
|
|
37
|
+
stdin: task,
|
|
38
|
+
signal: opts.signal,
|
|
39
|
+
});
|
|
40
|
+
// Fatal errors also produce a JSON object in -o json mode, but on stderr
|
|
41
|
+
// (responses go to stdout) — try both streams for a clean message before
|
|
42
|
+
// falling back to raw tails.
|
|
43
|
+
let parsed;
|
|
44
|
+
for (const stream of [result.stdout, result.stderr]) {
|
|
45
|
+
try {
|
|
46
|
+
parsed = JSON.parse(stream.trim());
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
parsed = undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (result.code !== 0) {
|
|
54
|
+
const msg = parsed?.error?.message ??
|
|
55
|
+
(result.stderr.slice(-2000) || result.stdout.slice(-2000));
|
|
56
|
+
throw new ExecError(`gemini exited with code ${result.code}: ${msg}`, result);
|
|
57
|
+
}
|
|
58
|
+
if (!parsed) {
|
|
59
|
+
throw new ExecError(`Could not parse gemini JSON output: ${result.stdout.slice(0, 500)}`, result);
|
|
60
|
+
}
|
|
61
|
+
if (parsed.error) {
|
|
62
|
+
throw new ExecError(`gemini reported an error: ${parsed.error.message ?? parsed.error.type}`);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
text: parsed.response ?? "",
|
|
66
|
+
sessionId: parsed.session_id,
|
|
67
|
+
// gemini-cli reports token stats but no USD cost.
|
|
68
|
+
cost: undefined,
|
|
69
|
+
truncated: result.truncated,
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/runners/gemini.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { config } from "./config.js";
|
|
6
|
+
import { exposedRunners, register, } from "./registry.js";
|
|
7
|
+
import { getLastSession, setLastSession } from "./sessions.js";
|
|
8
|
+
import { createJob, getJob, listJobs } from "./jobs.js";
|
|
9
|
+
import { ExecError } from "./exec.js";
|
|
10
|
+
import { debug } from "./debug.js";
|
|
11
|
+
import { codexRunner } from "./runners/codex.js";
|
|
12
|
+
import { claudeRunner } from "./runners/claude.js";
|
|
13
|
+
import { geminiRunner } from "./runners/gemini.js";
|
|
14
|
+
// --- Register all available agents. Adding a new backend = one more line. ---
|
|
15
|
+
register(codexRunner);
|
|
16
|
+
register(claudeRunner);
|
|
17
|
+
register(geminiRunner);
|
|
18
|
+
function buildInputShape(runner) {
|
|
19
|
+
const shape = {
|
|
20
|
+
task: z
|
|
21
|
+
.string()
|
|
22
|
+
.min(1)
|
|
23
|
+
.describe("The full task or question to delegate to this agent."),
|
|
24
|
+
cwd: z
|
|
25
|
+
.string()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("Absolute working directory the agent should operate in."),
|
|
28
|
+
continue_session: z
|
|
29
|
+
.boolean()
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("If true, resume the most recent session with this agent instead of " +
|
|
32
|
+
"starting fresh. With parallel sessions, prefer session_id — this " +
|
|
33
|
+
"shorthand resumes whichever session finished last."),
|
|
34
|
+
session_id: z
|
|
35
|
+
.string()
|
|
36
|
+
.optional()
|
|
37
|
+
.describe("Resume this exact session (the id from a previous result's footer). " +
|
|
38
|
+
"Takes precedence over continue_session. Use when running parallel " +
|
|
39
|
+
"sessions with the same agent."),
|
|
40
|
+
model: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Override the model id for this call (omit to use the default)."),
|
|
44
|
+
background: z
|
|
45
|
+
.boolean()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("Run as a background job: returns a job id immediately instead of " +
|
|
48
|
+
"blocking. Poll it with check_job; the agent keeps working meanwhile. " +
|
|
49
|
+
"Use for tasks likely to take more than a few minutes."),
|
|
50
|
+
};
|
|
51
|
+
if (runner.supportsReasoning) {
|
|
52
|
+
shape.reasoning = z
|
|
53
|
+
.enum(["low", "medium", "high"])
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("Reasoning/effort level.");
|
|
56
|
+
}
|
|
57
|
+
if (runner.supportsThinking) {
|
|
58
|
+
shape.thinking = z
|
|
59
|
+
.enum(["off", "think", "think_hard", "ultrathink"])
|
|
60
|
+
.optional()
|
|
61
|
+
.describe("Extended-thinking level (off = none, ultrathink = maximum).");
|
|
62
|
+
}
|
|
63
|
+
return shape;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Headless CLIs instruct their model that nobody is present, so an ambiguous
|
|
67
|
+
* task gets a silent best guess. This preamble corrects that assumption: the
|
|
68
|
+
* caller is an agent that CAN answer follow-ups via session resume. Prepended
|
|
69
|
+
* only on fresh sessions (a resumed session already saw it).
|
|
70
|
+
*/
|
|
71
|
+
const CLARIFY_PREAMBLE = "[qantara] You were delegated this task by another AI agent, which can " +
|
|
72
|
+
"answer follow-up questions. If the task is ambiguous or missing information " +
|
|
73
|
+
"you need, do NOT guess: reply with your specific questions instead of doing " +
|
|
74
|
+
"the work, and the caller will resume this session with answers.";
|
|
75
|
+
function formatResult(agentName, text, sessionId, cost, truncated) {
|
|
76
|
+
const footer = [];
|
|
77
|
+
if (sessionId)
|
|
78
|
+
footer.push(`session: ${sessionId}`);
|
|
79
|
+
if (typeof cost === "number")
|
|
80
|
+
footer.push(`cost: $${cost.toFixed(4)}`);
|
|
81
|
+
if (truncated)
|
|
82
|
+
footer.push("output truncated");
|
|
83
|
+
const meta = footer.length ? `\n\n---\n[${agentName}] ${footer.join(" | ")}` : "";
|
|
84
|
+
return `${text}${meta}`;
|
|
85
|
+
}
|
|
86
|
+
function textResult(text, isError = false) {
|
|
87
|
+
return { ...(isError ? { isError: true } : {}), content: [{ type: "text", text }] };
|
|
88
|
+
}
|
|
89
|
+
function elapsedSec(job) {
|
|
90
|
+
return Math.round(((job.finishedAt ?? Date.now()) - job.startedAt) / 1000);
|
|
91
|
+
}
|
|
92
|
+
async function main() {
|
|
93
|
+
const server = new McpServer({
|
|
94
|
+
name: "qantara",
|
|
95
|
+
version: "0.1.0",
|
|
96
|
+
});
|
|
97
|
+
const runners = exposedRunners([...config.expose]);
|
|
98
|
+
for (const runner of runners) {
|
|
99
|
+
server.tool(`ask_${runner.name}`, runner.description, buildInputShape(runner), async (args) => {
|
|
100
|
+
debug(`tool ask_${runner.name} invoked: ${JSON.stringify(args).slice(0, 300)}`);
|
|
101
|
+
// --- Depth / fan-out guard: refuse if we're already too deep. ---
|
|
102
|
+
if (config.depth >= config.maxDepth) {
|
|
103
|
+
return {
|
|
104
|
+
isError: true,
|
|
105
|
+
content: [
|
|
106
|
+
{
|
|
107
|
+
type: "text",
|
|
108
|
+
text: `Refused: qantara recursion depth ${config.depth} has reached ` +
|
|
109
|
+
`the limit (BRIDGE_MAX_DEPTH=${config.maxDepth}). ` +
|
|
110
|
+
`This prevents runaway agent-to-agent loops.`,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Explicit session id wins; continue_session is the sequential shorthand.
|
|
116
|
+
const sessionId = args.session_id ??
|
|
117
|
+
(args.continue_session ? getLastSession(runner.name) : undefined);
|
|
118
|
+
// A resumed session already saw the preamble on its first turn.
|
|
119
|
+
const task = config.clarify && !sessionId
|
|
120
|
+
? `${CLARIFY_PREAMBLE}\n\n${args.task}`
|
|
121
|
+
: args.task;
|
|
122
|
+
const runOpts = {
|
|
123
|
+
cwd: args.cwd,
|
|
124
|
+
sessionId,
|
|
125
|
+
model: args.model,
|
|
126
|
+
reasoning: args.reasoning,
|
|
127
|
+
thinking: args.thinking,
|
|
128
|
+
depth: config.depth,
|
|
129
|
+
};
|
|
130
|
+
if (args.background) {
|
|
131
|
+
const job = createJob(runner.name, args.task);
|
|
132
|
+
runner
|
|
133
|
+
.run(task, {
|
|
134
|
+
...runOpts,
|
|
135
|
+
timeoutMs: config.jobTimeoutMs,
|
|
136
|
+
signal: job.abort.signal,
|
|
137
|
+
})
|
|
138
|
+
.then((res) => {
|
|
139
|
+
if (job.status !== "running")
|
|
140
|
+
return; // cancelled meanwhile
|
|
141
|
+
job.status = "done";
|
|
142
|
+
job.finishedAt = Date.now();
|
|
143
|
+
job.result = res;
|
|
144
|
+
setLastSession(runner.name, res.sessionId);
|
|
145
|
+
})
|
|
146
|
+
.catch((err) => {
|
|
147
|
+
if (job.status !== "running")
|
|
148
|
+
return;
|
|
149
|
+
job.status = "failed";
|
|
150
|
+
job.finishedAt = Date.now();
|
|
151
|
+
job.error = err instanceof Error ? err.message : String(err);
|
|
152
|
+
});
|
|
153
|
+
debug(`job ${job.id} started`);
|
|
154
|
+
return textResult(`Started background job "${job.id}" (${runner.name}). It runs while you ` +
|
|
155
|
+
`continue working. Poll it with check_job (job_id: "${job.id}"); ` +
|
|
156
|
+
`cancel with cancel_job. Jobs do not survive a host restart.`);
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
const res = await runner.run(task, runOpts);
|
|
160
|
+
setLastSession(runner.name, res.sessionId);
|
|
161
|
+
return textResult(formatResult(runner.name, res.text, res.sessionId, res.cost, res.truncated));
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
const msg = err instanceof ExecError
|
|
165
|
+
? err.message
|
|
166
|
+
: err instanceof Error
|
|
167
|
+
? err.message
|
|
168
|
+
: String(err);
|
|
169
|
+
return textResult(`ask_${runner.name} failed: ${msg}`, true);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (runners.length > 0) {
|
|
174
|
+
server.tool("check_job", "Check background delegation jobs started with ask_*'s background option. " +
|
|
175
|
+
"With job_id: returns status, and the agent's full result once finished. " +
|
|
176
|
+
"Without job_id: lists all jobs of this session.", {
|
|
177
|
+
job_id: z
|
|
178
|
+
.string()
|
|
179
|
+
.optional()
|
|
180
|
+
.describe("The job id returned when the job was started. Omit to list all jobs."),
|
|
181
|
+
}, async (args) => {
|
|
182
|
+
if (!args.job_id) {
|
|
183
|
+
const all = listJobs();
|
|
184
|
+
if (all.length === 0)
|
|
185
|
+
return textResult("No background jobs in this session.");
|
|
186
|
+
const lines = all.map((j) => `${j.id} | ${j.agent} | ${j.status} | ${elapsedSec(j)}s | ${j.taskSummary}`);
|
|
187
|
+
return textResult(lines.join("\n"));
|
|
188
|
+
}
|
|
189
|
+
const job = getJob(args.job_id);
|
|
190
|
+
if (!job) {
|
|
191
|
+
return textResult(`No job "${args.job_id}". Call check_job without job_id to list jobs.`, true);
|
|
192
|
+
}
|
|
193
|
+
switch (job.status) {
|
|
194
|
+
case "running":
|
|
195
|
+
return textResult(`Job "${job.id}" (${job.agent}) is still running (${elapsedSec(job)}s elapsed). ` +
|
|
196
|
+
`Check again later.`);
|
|
197
|
+
case "done":
|
|
198
|
+
return textResult(`Job "${job.id}" (${job.agent}) finished in ${elapsedSec(job)}s:\n\n` +
|
|
199
|
+
formatResult(job.agent, job.result.text, job.result.sessionId, job.result.cost, job.result.truncated));
|
|
200
|
+
case "failed":
|
|
201
|
+
return textResult(`Job "${job.id}" (${job.agent}) failed after ${elapsedSec(job)}s: ${job.error}`, true);
|
|
202
|
+
case "cancelled":
|
|
203
|
+
return textResult(`Job "${job.id}" (${job.agent}) was cancelled.`);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
server.tool("cancel_job", "Cancel a running background delegation job (kills the delegated agent).", {
|
|
207
|
+
job_id: z.string().describe("The job id to cancel."),
|
|
208
|
+
}, async (args) => {
|
|
209
|
+
const job = getJob(args.job_id);
|
|
210
|
+
if (!job)
|
|
211
|
+
return textResult(`No job "${args.job_id}".`, true);
|
|
212
|
+
if (job.status !== "running") {
|
|
213
|
+
return textResult(`Job "${job.id}" is already ${job.status}.`);
|
|
214
|
+
}
|
|
215
|
+
job.status = "cancelled";
|
|
216
|
+
job.finishedAt = Date.now();
|
|
217
|
+
job.abort.abort();
|
|
218
|
+
debug(`job ${job.id} cancelled`);
|
|
219
|
+
return textResult(`Job "${job.id}" cancelled.`);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
const transport = new StdioServerTransport();
|
|
223
|
+
await server.connect(transport);
|
|
224
|
+
// Announce readiness on stderr (stdout is reserved for the MCP protocol).
|
|
225
|
+
const names = runners.map((r) => `ask_${r.name}`).join(", ");
|
|
226
|
+
process.stderr.write(`qantara ready (depth ${config.depth}/${config.maxDepth}); tools: ${names || "none"}\n`);
|
|
227
|
+
}
|
|
228
|
+
main().catch((err) => {
|
|
229
|
+
process.stderr.write(`qantara fatal: ${err?.stack ?? err}\n`);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
});
|
|
232
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/sessions.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks the last session id per agent so `continue_session: true` can resume
|
|
3
|
+
* the most recent conversation with that agent. In-memory only — scoped to the
|
|
4
|
+
* lifetime of this MCP server process, which matches a single host session.
|
|
5
|
+
*/
|
|
6
|
+
const lastSessionByAgent = new Map();
|
|
7
|
+
export function getLastSession(agent) {
|
|
8
|
+
return lastSessionByAgent.get(agent);
|
|
9
|
+
}
|
|
10
|
+
export function setLastSession(agent, sessionId) {
|
|
11
|
+
if (sessionId)
|
|
12
|
+
lastSessionByAgent.set(agent, sessionId);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAkB,CAAC;AAErD,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,SAA6B;IACzE,IAAI,SAAS;QAAE,kBAAkB,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAC1D,CAAC"}
|