first commit
This commit is contained in:
110
src/examples/claude.ts
Normal file
110
src/examples/claude.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import "dotenv/config";
|
||||
import { query, type Options } from "@anthropic-ai/claude-agent-sdk";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { getAgentManager, getResourceProvisioningOrchestrator } from "../agents/runtime.js";
|
||||
import { loadMcpConfigFromEnv } from "../mcp.js";
|
||||
|
||||
function requiredPrompt(argv: string[]): string {
|
||||
const prompt = argv.slice(2).join(" ").trim();
|
||||
if (!prompt) {
|
||||
throw new Error("Usage: npm run claude -- \"your prompt\"");
|
||||
}
|
||||
return prompt;
|
||||
}
|
||||
|
||||
function buildOptions(): Options {
|
||||
return {
|
||||
maxTurns: 1,
|
||||
...(process.env.CLAUDE_MODEL ? { model: process.env.CLAUDE_MODEL } : {}),
|
||||
...(process.env.CLAUDE_CODE_PATH
|
||||
? { pathToClaudeCodeExecutable: process.env.CLAUDE_CODE_PATH }
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
export async function runClaudePrompt(prompt: string): Promise<void> {
|
||||
const agentManager = getAgentManager();
|
||||
const agentSession = agentManager.createSession();
|
||||
const resourceProvisioning = getResourceProvisioningOrchestrator();
|
||||
const mcp = loadMcpConfigFromEnv({
|
||||
providerHint: "claude",
|
||||
prompt,
|
||||
});
|
||||
let provisionedResources:
|
||||
| Awaited<ReturnType<typeof resourceProvisioning.provisionSession>>
|
||||
| undefined;
|
||||
|
||||
try {
|
||||
provisionedResources = await resourceProvisioning.provisionSession({
|
||||
sessionId: agentSession.id,
|
||||
resources: [{ kind: "git-worktree" }, { kind: "port-range" }],
|
||||
});
|
||||
const runtimeInjection = await provisionedResources.buildRuntimeInjection({
|
||||
discoveryFileRelativePath: process.env.AGENT_DISCOVERY_FILE_RELATIVE_PATH,
|
||||
baseEnv: process.env,
|
||||
});
|
||||
const promptWithContext = provisionedResources.composePrompt(prompt, [
|
||||
`Discovery file: ${runtimeInjection.discoveryFilePath}`,
|
||||
"Resource env vars are pre-injected (AGENT_WORKTREE_PATH, AGENT_PORT_RANGE_START, AGENT_PORT_RANGE_END, AGENT_PORT_PRIMARY).",
|
||||
]);
|
||||
|
||||
const finalResponse = await agentSession.runAgent({
|
||||
depth: 0,
|
||||
run: async () => {
|
||||
const session = query({
|
||||
prompt: promptWithContext,
|
||||
options: {
|
||||
...buildOptions(),
|
||||
...(mcp.claudeMcpServers ? { mcpServers: mcp.claudeMcpServers } : {}),
|
||||
cwd: runtimeInjection.workingDirectory,
|
||||
env: runtimeInjection.env,
|
||||
},
|
||||
});
|
||||
|
||||
let result = "";
|
||||
|
||||
try {
|
||||
for await (const message of session) {
|
||||
if (message.type === "result" && message.subtype === "success") {
|
||||
result = message.result.trim();
|
||||
}
|
||||
|
||||
if (message.type === "result" && message.subtype !== "success") {
|
||||
const detail = message.errors.join("; ");
|
||||
throw new Error(
|
||||
`Claude query failed (${message.subtype})${detail ? `: ${detail}` : ""}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
session.close();
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
throw new Error("Claude run completed without a final result.");
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
});
|
||||
|
||||
console.log(finalResponse);
|
||||
} finally {
|
||||
if (provisionedResources) {
|
||||
await provisionedResources.release();
|
||||
}
|
||||
agentSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const prompt = requiredPrompt(process.argv);
|
||||
await runClaudePrompt(prompt);
|
||||
}
|
||||
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
||||
main().catch((error: unknown) => {
|
||||
console.error(error instanceof Error ? error.message : String(error));
|
||||
process.exitCode = 1;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user