@justin06lee/yagami 0.4.1 → 0.5.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/README.md +114 -95
- package/dist/{chunk-ASS6MJ7C.js → chunk-2UG5CR5X.js} +273 -6
- package/dist/chunk-2UG5CR5X.js.map +1 -0
- package/dist/{chunk-M5UHR273.js → chunk-GPX47OIO.js} +80 -20
- package/dist/chunk-GPX47OIO.js.map +1 -0
- package/dist/cli.js +33 -8
- package/dist/cli.js.map +1 -1
- package/dist/{engine-pmCK3S7z.d.ts → hostConfig-Bzr9JB8R.d.ts} +20 -1
- package/dist/index.d.ts +199 -4
- package/dist/index.js +77 -3
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +3 -3
- package/dist/server.js +4 -3
- package/package.json +2 -2
- package/dist/chunk-ASS6MJ7C.js.map +0 -1
- package/dist/chunk-M5UHR273.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/server/app.ts","../src/server/config.ts"],"sourcesContent":["import { serve, type ServerType } from \"@hono/node-server\";\nimport { YagamiEngine } from \"./core/engine.js\";\nimport { SessionCache } from \"./core/sessionCache.js\";\nimport { createApp } from \"./server/app.js\";\nimport {\n loadConfig,\n sessionCachePath,\n type YagamiConfig,\n} from \"./server/config.js\";\nimport { VERSION } from \"./version.js\";\n\nexport interface RunningServer {\n server: ServerType;\n engine: YagamiEngine;\n sessionCache: SessionCache;\n config: YagamiConfig;\n url: string;\n close(): Promise<void>;\n}\n\nexport interface StartOptions extends Partial<YagamiConfig> {\n /** Sink for one-line request logs (default: console.log). Pass null to disable. */\n log?: ((line: string) => void) | null;\n}\n\n/**\n * Start a yagami server. Overrides are merged over the loaded config\n * (~/.config/yagami/config.json plus YAGAMI_* env vars).\n */\nexport async function startYagami(overrides: StartOptions = {}): Promise<RunningServer> {\n const { log, ...configOverrides } = overrides;\n const config: YagamiConfig = { ...loadConfig(), ...definedProps(configOverrides) };\n if (config.apiKeys.length === 0) {\n throw new Error(\n \"no API keys configured — run `yagami keygen` (or set YAGAMI_API_KEY) so the endpoint isn't unauthenticated\",\n );\n }\n\n const sessionCache = new SessionCache({ persistPath: sessionCachePath() });\n const engine = new YagamiEngine({\n ...(config.providers ? { providerConfig: config.providers } : {}),\n ...(config.defaultProvider ? { defaultProvider: config.defaultProvider } : {}),\n ...(config.claudePath ? { claudePath: config.claudePath } : {}),\n ...(config.claudeConfigDir ? { claudeConfigDir: config.claudeConfigDir } : {}),\n ...(config.defaultModel ? { defaultModel: config.defaultModel } : {}),\n sessionCache,\n appName: \"yagami\",\n });\n\n const app = createApp({\n engine,\n apiKeys: config.apiKeys,\n cors: config.cors,\n version: VERSION,\n ...(log === null ? {} : { log: log ?? ((line: string) => console.log(line)) }),\n });\n\n const server = await new Promise<ServerType>((resolve) => {\n const s = serve({ fetch: app.fetch, hostname: config.host, port: config.port }, () => resolve(s));\n });\n\n const address = server.address();\n const port = typeof address === \"object\" && address ? address.port : config.port;\n\n return {\n server,\n engine,\n sessionCache,\n config: { ...config, port },\n url: `http://${config.host}:${port}`,\n close: () =>\n new Promise<void>((resolve, reject) => {\n server.close((err) => (err ? reject(err) : resolve()));\n }),\n };\n}\n\nfunction definedProps<T extends object>(obj: T): Partial<T> {\n return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined)) as Partial<T>;\n}\n\nexport { createApp } from \"./server/app.js\";\nexport type { AppOptions, EngineLike } from \"./server/app.js\";\nexport {\n loadConfig,\n loadFileConfig,\n saveConfig,\n generateApiKey,\n configFilePath,\n sessionCachePath,\n serverStatePath,\n logFilePath,\n readServerState,\n writeServerState,\n clearServerState,\n isProcessAlive,\n yagamiConfigDir,\n type YagamiConfig,\n type ServerState,\n} from \"./server/config.js\";\n","import { createHash, randomUUID, timingSafeEqual } from \"node:crypto\";\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { streamSSE } from \"hono/streaming\";\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\";\nimport { ApiError, type MessagesRequest } from \"../core/types.js\";\nimport { toApiError } from \"../core/errors.js\";\nimport type { CompleteResult, EngineModel, StreamOptions, StreamStart } from \"../core/engine.js\";\nimport {\n ChatChunkTranslator,\n chatToMessagesRequest,\n modelListBody,\n openAiErrorBody,\n toChatCompletion,\n type ChatCompletionsRequest,\n} from \"../core/openai.js\";\n\n/** What the app needs from an engine — lets tests inject a fake. */\nexport interface EngineLike {\n /** Executable of the default provider. */\n executable: string;\n defaultProviderId: string;\n providerIds: string[];\n complete(req: MessagesRequest): Promise<CompleteResult>;\n stream(req: MessagesRequest, opts?: StreamOptions): StreamStart;\n listModels(): Promise<EngineModel[]>;\n}\n\nexport interface AppOptions {\n engine: EngineLike;\n apiKeys: string[];\n cors?: boolean;\n version?: string;\n /** Sink for one-line request logs; omit to disable request logging. */\n log?: (line: string) => void;\n}\n\n/** Served by GET /v1/models only when probing the CLI fails. */\nconst FALLBACK_MODELS: EngineModel[] = [\n \"claude-fable-5\",\n \"claude-opus-5\",\n \"claude-sonnet-5\",\n \"claude-haiku-4-5-20251001\",\n].map((id) => ({ id, display_name: id }));\n\nfunction safeEqual(a: string, b: string): boolean {\n const ha = createHash(\"sha256\").update(a).digest();\n const hb = createHash(\"sha256\").update(b).digest();\n return timingSafeEqual(ha, hb);\n}\n\nfunction errorBody(type: ApiError[\"type\"], message: string) {\n return { type: \"error\" as const, error: { type, message } };\n}\n\nfunction requestLine(\n path: string,\n status: number,\n model: string,\n startedAt: number,\n extra: { cost?: number; session?: string; stream?: boolean; error?: string } = {},\n): string {\n const parts = [\n new Date().toISOString(),\n `POST ${path} ${status}`,\n `model=${model}`,\n `${((Date.now() - startedAt) / 1000).toFixed(1)}s`,\n ];\n if (extra.stream) parts.push(\"stream\");\n if (extra.cost !== undefined) parts.push(`cost=$${extra.cost.toFixed(6)}`);\n if (extra.session) parts.push(`session=${extra.session}`);\n if (extra.error) parts.push(`error=${extra.error}`);\n return parts.join(\" \");\n}\n\nexport function createApp(options: AppOptions): Hono {\n const { engine, apiKeys, log } = options;\n const app = new Hono();\n const stats = { startedAt: Date.now(), requests: 0, totalCostUsd: 0 };\n\n if (options.cors) app.use(\"*\", cors());\n\n app.use(\"*\", async (c, next) => {\n c.header(\"request-id\", `req_${randomUUID().replace(/-/g, \"\")}`);\n await next();\n });\n\n app.get(\"/healthz\", (c) =>\n c.json({\n ok: true,\n service: \"yagami\",\n version: options.version,\n provider: engine.defaultProviderId,\n providers: engine.providerIds,\n executable: engine.executable,\n uptime_s: Math.round((Date.now() - stats.startedAt) / 1000),\n requests: stats.requests,\n total_cost_usd: stats.totalCostUsd,\n }),\n );\n\n app.use(\"/v1/*\", async (c, next) => {\n const header = c.req.header(\"x-api-key\") ?? c.req.header(\"authorization\")?.replace(/^Bearer\\s+/i, \"\");\n const ok = header != null && apiKeys.some((key) => safeEqual(key, header));\n if (!ok) {\n const err = new ApiError(401, \"authentication_error\", \"invalid API key (x-api-key or Authorization: Bearer)\");\n // The chat-completions path answers in the OpenAI error shape.\n return c.req.path.startsWith(\"/v1/chat\")\n ? c.json(openAiErrorBody(err), 401)\n : c.json(err.toBody(), 401);\n }\n await next();\n });\n\n // Served in a merged shape: Anthropic fields + OpenAI fields per model, so\n // both SDKs' models.list() parse it.\n app.get(\"/v1/models\", async (c) => {\n let models = FALLBACK_MODELS;\n let source = \"fallback\";\n try {\n const probed = await engine.listModels();\n if (probed.length > 0) {\n models = probed;\n source = \"engine\";\n }\n } catch {\n // engine unavailable or slow — the static list keeps clients working\n }\n c.header(\"x-yagami-models-source\", source);\n return c.json(modelListBody(models));\n });\n\n app.post(\"/v1/messages\", async (c) => {\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json(errorBody(\"invalid_request_error\", \"request body must be valid JSON\"), 400);\n }\n const req = body as MessagesRequest;\n const startedAt = Date.now();\n const model = typeof req.model === \"string\" ? req.model : \"(default)\";\n stats.requests += 1;\n\n try {\n if (req.stream === true) {\n const abortController = new AbortController();\n const { ignored, provider, events } = engine.stream(req, {\n signal: abortController.signal,\n onResult: (info) => {\n if (info.costUsd !== undefined) stats.totalCostUsd += info.costUsd;\n log?.(\n requestLine(\"/v1/messages\", 200, model, startedAt, {\n stream: true,\n ...(info.costUsd !== undefined ? { cost: info.costUsd } : {}),\n ...(info.sessionId ? { session: info.sessionId } : {}),\n }),\n );\n },\n });\n c.header(\"x-yagami-provider\", provider);\n if (ignored.length > 0) c.header(\"x-yagami-ignored\", ignored.join(\",\"));\n return streamSSE(c, async (stream) => {\n stream.onAbort(() => abortController.abort());\n for await (const ev of events) {\n await stream.writeSSE({ event: ev.event, data: JSON.stringify(ev.data) });\n }\n });\n }\n\n const result = await engine.complete(req);\n if (result.costUsd !== undefined) stats.totalCostUsd += result.costUsd;\n log?.(\n requestLine(\"/v1/messages\", 200, model, startedAt, {\n ...(result.costUsd !== undefined ? { cost: result.costUsd } : {}),\n ...(result.sessionId ? { session: result.sessionId } : {}),\n }),\n );\n c.header(\"x-yagami-provider\", result.provider);\n if (result.ignored.length > 0) c.header(\"x-yagami-ignored\", result.ignored.join(\",\"));\n if (result.costUsd !== undefined) c.header(\"x-yagami-cost-usd\", result.costUsd.toFixed(6));\n if (result.sessionId) c.header(\"x-yagami-session\", result.sessionId);\n return c.json(result.response);\n } catch (err) {\n const apiErr = toApiError(err);\n log?.(requestLine(\"/v1/messages\", apiErr.status, model, startedAt, { error: apiErr.type }));\n return c.json(apiErr.toBody(), apiErr.status as ContentfulStatusCode);\n }\n });\n\n // OpenAI dialect: the same engine behind Chat Completions shapes, so apps\n // that expect an OpenAI base URL + API key work against the same key.\n app.post(\"/v1/chat/completions\", async (c) => {\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json(openAiErrorBody(new ApiError(400, \"invalid_request_error\", \"request body must be valid JSON\")), 400);\n }\n const startedAt = Date.now();\n const chatReq = body as ChatCompletionsRequest;\n const model = typeof chatReq?.model === \"string\" ? chatReq.model : \"(default)\";\n stats.requests += 1;\n\n try {\n const { req, extraIgnored, includeUsage } = chatToMessagesRequest(chatReq);\n\n if (req.stream === true) {\n const abortController = new AbortController();\n const { ignored, provider, events } = engine.stream(req, {\n signal: abortController.signal,\n onResult: (info) => {\n if (info.costUsd !== undefined) stats.totalCostUsd += info.costUsd;\n log?.(\n requestLine(\"/v1/chat/completions\", 200, model, startedAt, {\n stream: true,\n ...(info.costUsd !== undefined ? { cost: info.costUsd } : {}),\n ...(info.sessionId ? { session: info.sessionId } : {}),\n }),\n );\n },\n });\n c.header(\"x-yagami-provider\", provider);\n const allIgnored = [...ignored, ...extraIgnored];\n if (allIgnored.length > 0) c.header(\"x-yagami-ignored\", allIgnored.join(\",\"));\n const translator = new ChatChunkTranslator(includeUsage);\n return streamSSE(c, async (stream) => {\n stream.onAbort(() => abortController.abort());\n for await (const ev of events) {\n for (const chunk of translator.push(ev)) {\n await stream.writeSSE({ data: JSON.stringify(chunk) });\n }\n }\n if (!translator.errored) await stream.writeSSE({ data: \"[DONE]\" });\n });\n }\n\n const result = await engine.complete(req);\n if (result.costUsd !== undefined) stats.totalCostUsd += result.costUsd;\n log?.(\n requestLine(\"/v1/chat/completions\", 200, model, startedAt, {\n ...(result.costUsd !== undefined ? { cost: result.costUsd } : {}),\n ...(result.sessionId ? { session: result.sessionId } : {}),\n }),\n );\n c.header(\"x-yagami-provider\", result.provider);\n const allIgnored = [...result.ignored, ...extraIgnored];\n if (allIgnored.length > 0) c.header(\"x-yagami-ignored\", allIgnored.join(\",\"));\n if (result.costUsd !== undefined) c.header(\"x-yagami-cost-usd\", result.costUsd.toFixed(6));\n if (result.sessionId) c.header(\"x-yagami-session\", result.sessionId);\n return c.json(toChatCompletion(result.response));\n } catch (err) {\n const apiErr = toApiError(err);\n log?.(requestLine(\"/v1/chat/completions\", apiErr.status, model, startedAt, { error: apiErr.type }));\n return c.json(openAiErrorBody(apiErr), apiErr.status as ContentfulStatusCode);\n }\n });\n\n app.notFound((c) =>\n c.json(errorBody(\"not_found_error\", `no route for ${c.req.method} ${c.req.path}`), 404),\n );\n\n app.onError((err, c) => {\n const apiErr = toApiError(err);\n return c.json(apiErr.toBody(), apiErr.status as ContentfulStatusCode);\n });\n\n return app;\n}\n","import { randomBytes } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { yagamiConfigDir } from \"../core/hostConfig.js\";\nimport type { ProviderConfigEntry } from \"../core/providers/registry.js\";\n\nexport { yagamiConfigDir } from \"../core/hostConfig.js\";\n\nexport interface YagamiConfig {\n host: string;\n port: number;\n apiKeys: string[];\n /** @deprecated Use providers.claude.path. */\n claudePath?: string;\n /** @deprecated Use providers.claude.configDir. */\n claudeConfigDir?: string;\n defaultModel?: string;\n cors?: boolean;\n /** Provider used for bare model ids (default: claude). */\n defaultProvider?: string;\n /** Per-provider settings, keyed by provider id. */\n providers?: Record<string, ProviderConfigEntry>;\n}\n\nexport const DEFAULT_CONFIG: YagamiConfig = {\n host: \"127.0.0.1\",\n port: 8787,\n apiKeys: [],\n};\n\nexport function configFilePath(): string {\n return path.join(yagamiConfigDir(), \"config.json\");\n}\n\nexport function sessionCachePath(): string {\n return path.join(yagamiConfigDir(), \"sessions.json\");\n}\n\nexport function serverStatePath(): string {\n return path.join(yagamiConfigDir(), \"server.json\");\n}\n\nexport function logFilePath(): string {\n return path.join(yagamiConfigDir(), \"yagami.log\");\n}\n\n/** What a running server records about itself for `stop`/`status`. */\nexport interface ServerState {\n pid: number;\n host: string;\n port: number;\n url: string;\n startedAt: string;\n version: string;\n log?: string;\n}\n\nexport function readServerState(): ServerState | undefined {\n try {\n const state = JSON.parse(fs.readFileSync(serverStatePath(), \"utf8\")) as ServerState;\n return typeof state?.pid === \"number\" ? state : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function writeServerState(state: ServerState): void {\n fs.mkdirSync(yagamiConfigDir(), { recursive: true, mode: 0o700 });\n fs.writeFileSync(serverStatePath(), `${JSON.stringify(state, null, 2)}\\n`, { mode: 0o600 });\n}\n\n/** Remove the state file; with `pid`, only if it still belongs to that pid. */\nexport function clearServerState(pid?: number): void {\n try {\n if (pid !== undefined && readServerState()?.pid !== pid) return;\n fs.unlinkSync(serverStatePath());\n } catch {\n // already gone\n }\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Config as stored on disk, without env overrides (safe to save back). */\nexport function loadFileConfig(): YagamiConfig {\n let fromFile: Partial<YagamiConfig> = {};\n try {\n fromFile = JSON.parse(fs.readFileSync(configFilePath(), \"utf8\")) as Partial<YagamiConfig>;\n } catch {\n // no config file yet\n }\n return {\n ...DEFAULT_CONFIG,\n ...fromFile,\n apiKeys: Array.isArray(fromFile.apiKeys) ? fromFile.apiKeys.filter((k) => typeof k === \"string\") : [],\n };\n}\n\n/** File config plus environment overrides. */\nexport function loadConfig(): YagamiConfig {\n const cfg = loadFileConfig();\n const env = process.env;\n if (env[\"YAGAMI_HOST\"]) cfg.host = env[\"YAGAMI_HOST\"];\n if (env[\"YAGAMI_PORT\"] && Number.isFinite(Number(env[\"YAGAMI_PORT\"]))) {\n cfg.port = Number(env[\"YAGAMI_PORT\"]);\n }\n if (env[\"YAGAMI_API_KEY\"] && !cfg.apiKeys.includes(env[\"YAGAMI_API_KEY\"])) {\n cfg.apiKeys.push(env[\"YAGAMI_API_KEY\"]);\n }\n if (env[\"YAGAMI_CLAUDE_PATH\"]) cfg.claudePath = env[\"YAGAMI_CLAUDE_PATH\"];\n if (env[\"YAGAMI_DEFAULT_MODEL\"]) cfg.defaultModel = env[\"YAGAMI_DEFAULT_MODEL\"];\n if (env[\"YAGAMI_PROVIDER\"]) cfg.defaultProvider = env[\"YAGAMI_PROVIDER\"];\n return cfg;\n}\n\nexport function saveConfig(cfg: YagamiConfig): string {\n const dir = yagamiConfigDir();\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n const file = configFilePath();\n fs.writeFileSync(file, `${JSON.stringify(cfg, null, 2)}\\n`, { mode: 0o600 });\n return file;\n}\n\nexport function generateApiKey(): string {\n return `ygm_${randomBytes(24).toString(\"hex\")}`;\n}\n\nexport function maskKey(key: string): string {\n return key.length <= 12 ? key : `${key.slice(0, 12)}…`;\n}\n"],"mappings":"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","names":["path","allIgnored"]}
|
package/dist/cli.js
CHANGED
|
@@ -13,13 +13,13 @@ import {
|
|
|
13
13
|
sessionCachePath,
|
|
14
14
|
startYagami,
|
|
15
15
|
writeServerState
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-GPX47OIO.js";
|
|
17
17
|
import {
|
|
18
18
|
VERSION,
|
|
19
19
|
YagamiEngine,
|
|
20
20
|
createProvider,
|
|
21
21
|
detectProviders
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-2UG5CR5X.js";
|
|
23
23
|
|
|
24
24
|
// src/cli.ts
|
|
25
25
|
import { spawn } from "child_process";
|
|
@@ -28,7 +28,7 @@ import * as path from "path";
|
|
|
28
28
|
import { Command } from "commander";
|
|
29
29
|
var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
30
30
|
var program = new Command();
|
|
31
|
-
program.name("yagami").description("Anthropic-compatible API served by your signed-in
|
|
31
|
+
program.name("yagami").description("Anthropic- and OpenAI-compatible API served by your signed-in coding-agent CLIs").version(VERSION);
|
|
32
32
|
program.command("start", { isDefault: true }).description("start the yagami server").option("-p, --port <port>", "port to listen on").option("-H, --host <host>", "host to bind (default 127.0.0.1)").option("--claude <path>", "path to the claude executable").option("--provider <id>", "default provider for bare model ids (claude, codex, opencode, gemini, \u2026)").option("--cors", "enable permissive CORS (for browser clients)").option("--daemon", "run in the background (managed with `yagami stop`/`yagami status`)").option("--log <file>", "log file for --daemon mode (default ~/.config/yagami/yagami.log)").action(async (opts) => {
|
|
33
33
|
const fileConfig = loadFileConfig();
|
|
34
34
|
let freshKey;
|
|
@@ -78,17 +78,18 @@ program.command("start", { isDefault: true }).description("start the yagami serv
|
|
|
78
78
|
console.log(` config ${configFilePath()}`);
|
|
79
79
|
if (freshKey) {
|
|
80
80
|
console.log(` api key ${freshKey}`);
|
|
81
|
-
console.log(" (newly generated and saved \u2014
|
|
81
|
+
console.log(" (newly generated and saved \u2014 `yagami key` prints it again)");
|
|
82
82
|
} else {
|
|
83
|
-
console.log(` api keys ${running.config.apiKeys.map(maskKey).join(", ")}`);
|
|
83
|
+
console.log(` api keys ${running.config.apiKeys.map(maskKey).join(", ")} (\`yagami key\` prints them in full)`);
|
|
84
84
|
}
|
|
85
85
|
if (!["127.0.0.1", "localhost", "::1"].includes(running.config.host)) {
|
|
86
86
|
console.log(
|
|
87
87
|
` \u26A0 bound to ${running.config.host} \u2014 reachable beyond this machine. Only do this on a network you trust.`
|
|
88
88
|
);
|
|
89
89
|
}
|
|
90
|
-
console.log("\
|
|
91
|
-
console.log(` baseURL
|
|
90
|
+
console.log("\nConnect apps \u2014 either dialect, same key (`yagami key` prints ready-to-paste env exports):");
|
|
91
|
+
console.log(` Anthropic apps baseURL ${running.url} (ANTHROPIC_BASE_URL / ANTHROPIC_API_KEY)`);
|
|
92
|
+
console.log(` OpenAI apps baseURL ${running.url}/v1 (OPENAI_BASE_URL / OPENAI_API_KEY)`);
|
|
92
93
|
} catch (err) {
|
|
93
94
|
console.error(`yagami: ${err instanceof Error ? err.message : String(err)}`);
|
|
94
95
|
process.exitCode = 1;
|
|
@@ -132,8 +133,9 @@ async function startDaemon(opts, freshKey) {
|
|
|
132
133
|
console.log(` log ${logPath}`);
|
|
133
134
|
if (freshKey) {
|
|
134
135
|
console.log(` key ${freshKey}`);
|
|
135
|
-
console.log(" (newly generated and saved \u2014
|
|
136
|
+
console.log(" (newly generated and saved \u2014 `yagami key` prints it again)");
|
|
136
137
|
}
|
|
138
|
+
console.log(" `yagami key` prints the URL, key, and env exports for client apps");
|
|
137
139
|
return;
|
|
138
140
|
}
|
|
139
141
|
await sleep(200);
|
|
@@ -194,6 +196,29 @@ program.command("keygen").description("generate an API key and add it to the con
|
|
|
194
196
|
console.log(key);
|
|
195
197
|
console.error(`saved to ${file} (${cfg.apiKeys.length} key${cfg.apiKeys.length === 1 ? "" : "s"} total)`);
|
|
196
198
|
});
|
|
199
|
+
program.command("key").description("print the server URL, API key, and ready-to-paste env exports for client apps").action(() => {
|
|
200
|
+
const cfg = loadConfig();
|
|
201
|
+
const state = readServerState();
|
|
202
|
+
const live = state !== void 0 && isProcessAlive(state.pid);
|
|
203
|
+
const url = live ? state.url : `http://${cfg.host}:${cfg.port}`;
|
|
204
|
+
if (cfg.apiKeys.length === 0) {
|
|
205
|
+
console.error("no API keys configured \u2014 run `yagami start` (generates one) or `yagami keygen`");
|
|
206
|
+
process.exitCode = 1;
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const key = cfg.apiKeys[cfg.apiKeys.length - 1];
|
|
210
|
+
console.log(`url ${url}${live ? "" : " (server not running \u2014 this is where `yagami start` will listen)"}`);
|
|
211
|
+
console.log(`key ${key}`);
|
|
212
|
+
if (cfg.apiKeys.length > 1) {
|
|
213
|
+
console.log(` (newest of ${cfg.apiKeys.length} keys in ${configFilePath()})`);
|
|
214
|
+
}
|
|
215
|
+
console.log("\nAnthropic-dialect apps:");
|
|
216
|
+
console.log(` export ANTHROPIC_BASE_URL=${url}`);
|
|
217
|
+
console.log(` export ANTHROPIC_API_KEY=${key}`);
|
|
218
|
+
console.log("\nOpenAI-dialect apps:");
|
|
219
|
+
console.log(` export OPENAI_BASE_URL=${url}/v1`);
|
|
220
|
+
console.log(` export OPENAI_API_KEY=${key}`);
|
|
221
|
+
});
|
|
197
222
|
program.command("doctor").description("check which coding-agent CLIs yagami can drive and whether they work").option("--live", "send one real (tiny) completion through the default provider").option("--provider <id>", "provider to use for --live (default: config/claude)").action(async (opts) => {
|
|
198
223
|
let failed = false;
|
|
199
224
|
const cfg = loadConfig();
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { spawn, spawnSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { Command } from \"commander\";\nimport { YagamiEngine } from \"./core/engine.js\";\nimport { ClaudeProvider } from \"./core/providers/claude.js\";\nimport { createProvider, detectProviders } from \"./core/providers/registry.js\";\nimport { startYagami } from \"./server.js\";\nimport {\n clearServerState,\n configFilePath,\n generateApiKey,\n isProcessAlive,\n loadConfig,\n loadFileConfig,\n logFilePath,\n maskKey,\n readServerState,\n saveConfig,\n sessionCachePath,\n writeServerState,\n} from \"./server/config.js\";\nimport { VERSION } from \"./version.js\";\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst program = new Command();\n\nprogram\n .name(\"yagami\")\n .description(\"Anthropic-compatible API served by your signed-in Claude Code CLI\")\n .version(VERSION);\n\ninterface StartFlags {\n port?: string;\n host?: string;\n claude?: string;\n provider?: string;\n cors?: boolean;\n daemon?: boolean;\n log?: string;\n}\n\nprogram\n .command(\"start\", { isDefault: true })\n .description(\"start the yagami server\")\n .option(\"-p, --port <port>\", \"port to listen on\")\n .option(\"-H, --host <host>\", \"host to bind (default 127.0.0.1)\")\n .option(\"--claude <path>\", \"path to the claude executable\")\n .option(\"--provider <id>\", \"default provider for bare model ids (claude, codex, opencode, gemini, …)\")\n .option(\"--cors\", \"enable permissive CORS (for browser clients)\")\n .option(\"--daemon\", \"run in the background (managed with `yagami stop`/`yagami status`)\")\n .option(\"--log <file>\", \"log file for --daemon mode (default ~/.config/yagami/yagami.log)\")\n .action(async (opts: StartFlags) => {\n // First run: generate a key automatically so the endpoint is never open.\n const fileConfig = loadFileConfig();\n let freshKey: string | undefined;\n if (fileConfig.apiKeys.length === 0 && !process.env[\"YAGAMI_API_KEY\"]) {\n freshKey = generateApiKey();\n fileConfig.apiKeys.push(freshKey);\n saveConfig(fileConfig);\n }\n\n if (opts.daemon) {\n await startDaemon(opts, freshKey);\n return;\n }\n\n try {\n const running = await startYagami({\n port: opts.port !== undefined ? Number(opts.port) : undefined,\n host: opts.host,\n claudePath: opts.claude,\n defaultProvider: opts.provider,\n cors: opts.cors,\n });\n\n writeServerState({\n pid: process.pid,\n host: running.config.host,\n port: running.config.port,\n url: running.url,\n startedAt: new Date().toISOString(),\n version: VERSION,\n ...(process.env[\"YAGAMI_LOG_FILE\"] ? { log: process.env[\"YAGAMI_LOG_FILE\"] } : {}),\n });\n const shutdown = () => {\n running.sessionCache.persistNow();\n clearServerState(process.pid);\n void running.close().finally(() => process.exit(0));\n // Don't hang on a stuck in-flight response.\n setTimeout(() => process.exit(0), 3000).unref?.();\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n const engine = running.engine;\n const version = await engine.defaultProvider.version();\n const others = engine.providerIds.filter((id) => id !== engine.defaultProviderId);\n console.log(`yagami v${VERSION}`);\n console.log(` listening ${running.url}`);\n console.log(` provider ${engine.defaultProviderId} — ${engine.executable}${version ? ` (${version})` : \"\"}`);\n console.log(\n ` also ${others.length > 0 ? `${others.join(\", \")} (use model \"<provider>:<model>\")` : \"no other harness CLIs found — see `yagami doctor`\"}`,\n );\n console.log(` config ${configFilePath()}`);\n if (freshKey) {\n console.log(` api key ${freshKey}`);\n console.log(\" (newly generated and saved — copy it now, it is shown in full only once)\");\n } else {\n console.log(` api keys ${running.config.apiKeys.map(maskKey).join(\", \")}`);\n }\n if (![\"127.0.0.1\", \"localhost\", \"::1\"].includes(running.config.host)) {\n console.log(\n ` ⚠ bound to ${running.config.host} — reachable beyond this machine. Only do this on a network you trust.`,\n );\n }\n console.log(\"\\nPoint any Anthropic SDK at it:\");\n console.log(` baseURL: \"${running.url}\" apiKey: <your yagami key>`);\n } catch (err) {\n console.error(`yagami: ${err instanceof Error ? err.message : String(err)}`);\n process.exitCode = 1;\n }\n });\n\nasync function startDaemon(opts: StartFlags, freshKey: string | undefined): Promise<void> {\n const existing = readServerState();\n if (existing && isProcessAlive(existing.pid)) {\n console.error(`yagami is already running (pid ${existing.pid}, ${existing.url}) — \\`yagami stop\\` first`);\n process.exitCode = 1;\n return;\n }\n clearServerState();\n\n const logPath = opts.log ? path.resolve(opts.log) : logFilePath();\n fs.mkdirSync(path.dirname(logPath), { recursive: true });\n const fd = fs.openSync(logPath, \"a\");\n const args = [process.argv[1]!, \"start\"];\n if (opts.port !== undefined) args.push(\"-p\", opts.port);\n if (opts.host !== undefined) args.push(\"-H\", opts.host);\n if (opts.claude !== undefined) args.push(\"--claude\", opts.claude);\n if (opts.provider !== undefined) args.push(\"--provider\", opts.provider);\n if (opts.cors) args.push(\"--cors\");\n\n const child = spawn(process.execPath, args, {\n detached: true,\n stdio: [\"ignore\", fd, fd],\n env: { ...process.env, YAGAMI_LOG_FILE: logPath },\n });\n fs.closeSync(fd);\n let exitCode: number | null | undefined;\n child.on(\"exit\", (code) => {\n exitCode = code;\n });\n child.unref();\n\n const deadline = Date.now() + 15_000;\n while (Date.now() < deadline && exitCode === undefined) {\n const state = readServerState();\n if (state && state.pid === child.pid) {\n console.log(`yagami v${VERSION} running in the background`);\n console.log(` pid ${child.pid}`);\n console.log(` url ${state.url}`);\n console.log(` log ${logPath}`);\n if (freshKey) {\n console.log(` key ${freshKey}`);\n console.log(\" (newly generated and saved — copy it now, it is shown in full only once)\");\n }\n return;\n }\n await sleep(200);\n }\n console.error(\n exitCode !== undefined\n ? `yagami exited immediately (code ${exitCode}) — see ${logPath}`\n : `yagami did not report ready within 15s — see ${logPath}`,\n );\n process.exitCode = 1;\n}\n\nprogram\n .command(\"stop\")\n .description(\"stop a running yagami server\")\n .action(async () => {\n const state = readServerState();\n if (!state || !isProcessAlive(state.pid)) {\n if (state) clearServerState();\n console.log(\"yagami is not running\");\n return;\n }\n process.kill(state.pid, \"SIGTERM\");\n const deadline = Date.now() + 5_000;\n while (Date.now() < deadline) {\n if (!isProcessAlive(state.pid)) {\n clearServerState();\n console.log(`stopped yagami (pid ${state.pid})`);\n return;\n }\n await sleep(100);\n }\n console.error(`yagami (pid ${state.pid}) did not exit within 5s`);\n process.exitCode = 1;\n });\n\nprogram\n .command(\"status\")\n .description(\"show whether yagami is running, plus request/cost totals\")\n .action(async () => {\n const state = readServerState();\n if (!state || !isProcessAlive(state.pid)) {\n if (state) clearServerState();\n console.log(\"yagami is not running\");\n process.exitCode = 1;\n return;\n }\n console.log(`yagami running (pid ${state.pid})`);\n console.log(` url ${state.url}`);\n console.log(` since ${state.startedAt}`);\n if (state.log) console.log(` log ${state.log}`);\n try {\n const res = await fetch(`${state.url}/healthz`, { signal: AbortSignal.timeout(3000) });\n const body = (await res.json()) as {\n version?: string;\n claude?: string;\n requests?: number;\n total_cost_usd?: number;\n };\n console.log(` version ${body.version ?? \"?\"}`);\n console.log(` claude ${body.claude ?? \"?\"}`);\n console.log(` requests ${body.requests ?? 0}`);\n console.log(` cost $${(body.total_cost_usd ?? 0).toFixed(4)} (would-be API cost since start)`);\n } catch {\n console.log(` healthz unreachable — process is alive but ${state.url} is not answering`);\n }\n });\n\nprogram\n .command(\"keygen\")\n .description(\"generate an API key and add it to the config\")\n .action(() => {\n const cfg = loadFileConfig();\n const key = generateApiKey();\n cfg.apiKeys.push(key);\n const file = saveConfig(cfg);\n console.log(key);\n console.error(`saved to ${file} (${cfg.apiKeys.length} key${cfg.apiKeys.length === 1 ? \"\" : \"s\"} total)`);\n });\n\nprogram\n .command(\"doctor\")\n .description(\"check which coding-agent CLIs yagami can drive and whether they work\")\n .option(\"--live\", \"send one real (tiny) completion through the default provider\")\n .option(\"--provider <id>\", \"provider to use for --live (default: config/claude)\")\n .action(async (opts: { live?: boolean; provider?: string }) => {\n let failed = false;\n const cfg = loadConfig();\n const providerConfig = { ...cfg.providers };\n if (cfg.claudePath || cfg.claudeConfigDir) {\n providerConfig[\"claude\"] = {\n ...providerConfig[\"claude\"],\n ...(cfg.claudePath ? { path: cfg.claudePath } : {}),\n ...(cfg.claudeConfigDir ? { configDir: cfg.claudeConfigDir } : {}),\n };\n }\n const defaultProvider = opts.provider ?? cfg.defaultProvider ?? \"claude\";\n\n console.log(`node ${process.version}`);\n console.log(`config ${configFilePath()}${fs.existsSync(configFilePath()) ? \"\" : \" (not created yet)\"}`);\n console.log(`api keys ${cfg.apiKeys.length === 0 ? \"none — run `yagami keygen`\" : cfg.apiKeys.map(maskKey).join(\", \")}`);\n console.log(`bind ${cfg.host}:${cfg.port}`);\n console.log(`sessions ${sessionCachePath()}${fs.existsSync(sessionCachePath()) ? \"\" : \" (empty)\"}`);\n const state = readServerState();\n console.log(\n `server ${state && isProcessAlive(state.pid) ? `running (pid ${state.pid}, ${state.url})` : \"not running\"}`,\n );\n\n console.log(\"\\nproviders (model ids route as \\\"<provider>:<model>\\\"; bare ids go to the default)\");\n const detected = detectProviders(providerConfig);\n const installed = detected.filter((d) => d.installed);\n for (const d of detected) {\n const marker = d.id === defaultProvider ? \"*\" : \" \";\n if (!d.installed) {\n if (presetIsNiche(d.id)) continue; // keep the list readable\n console.log(` ${marker} ${d.id.padEnd(11)} not installed — ${d.installHint}`);\n continue;\n }\n let version: string | undefined;\n try {\n version = await createProvider(d.id, providerConfig[d.id] ?? {}, {}).version();\n } catch (err) {\n version = `✗ ${err instanceof Error ? err.message : String(err)}`;\n }\n console.log(` ${marker} ${d.id.padEnd(11)} ${d.path}${version ? ` (${version})` : \"\"}`);\n }\n const hidden = detected.filter((d) => !d.installed && presetIsNiche(d.id)).length;\n if (hidden > 0) console.log(` … ${hidden} more ACP presets not installed (see README for the full list)`);\n if (!installed.some((d) => d.id === defaultProvider)) {\n failed = true;\n console.log(` ✗ default provider \"${defaultProvider}\" is not installed`);\n }\n\n if (installed.some((d) => d.id === \"claude\")) {\n try {\n const claude = createProvider(\"claude\", providerConfig[\"claude\"] ?? {}, {}) as ClaudeProvider;\n const skew = await claude.versionSkew();\n if (skew) {\n console.log(`\\nagent sdk ${skew.sdkVersion} ↔ claude ${skew.binaryVersion} — ${skew.inSync ? \"in sync\" : `⚠ ${skew.note}`}`);\n }\n } catch {\n // skew check is advisory\n }\n }\n\n if (opts.live && !failed) {\n console.log(`\\nlive check: sending one tiny completion through ${defaultProvider}…`);\n try {\n const engine = new YagamiEngine({ providerConfig, defaultProvider, ...(cfg.defaultModel ? { defaultModel: cfg.defaultModel } : {}) });\n const started = Date.now();\n const result = await engine.complete({\n messages: [{ role: \"user\", content: \"Reply with exactly: pong\" }],\n max_tokens: 32,\n });\n const text = result.response.content\n .filter((b) => b.type === \"text\")\n .map((b) => b[\"text\"])\n .join(\"\");\n console.log(` reply ${JSON.stringify(text)}`);\n console.log(` model ${result.response.model}`);\n console.log(` latency ${((Date.now() - started) / 1000).toFixed(1)}s`);\n if (result.costUsd !== undefined) console.log(` cost $${result.costUsd.toFixed(6)}`);\n } catch (err) {\n failed = true;\n console.log(` ✗ ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n if (failed) process.exitCode = 1;\n });\n\n/** Presets most people won't have; hidden from doctor unless installed. */\nfunction presetIsNiche(id: string): boolean {\n return ![\"claude\", \"codex\", \"opencode\", \"gemini\", \"copilot\", \"cursor\", \"qwen\", \"goose\", \"kimi\"].includes(id);\n}\n\nprogram\n .command(\"models\")\n .description(\"list models across every installed provider (ids are ready to paste into requests)\")\n .option(\"--provider <id>\", \"only this provider\")\n .action(async (opts: { provider?: string }) => {\n const cfg = loadConfig();\n try {\n const engine = new YagamiEngine({\n ...(cfg.providers ? { providerConfig: cfg.providers } : {}),\n ...(cfg.defaultProvider ? { defaultProvider: cfg.defaultProvider } : {}),\n });\n const models = await engine.listModels();\n const byProvider = new Map<string, typeof models>();\n for (const m of models) {\n if (opts.provider && m.provider !== opts.provider) continue;\n if (!m.id.includes(\":\")) continue; // print the qualified form once\n const list = byProvider.get(m.provider ?? \"?\") ?? [];\n list.push(m);\n byProvider.set(m.provider ?? \"?\", list);\n }\n for (const [provider, list] of byProvider) {\n console.log(`${provider}${provider === engine.defaultProviderId ? \" (default — bare ids work too)\" : \"\"}`);\n for (const m of list) {\n console.log(` ${m.id.padEnd(40)} ${m.display_name}${m.resolved_model ? ` → ${m.resolved_model}` : \"\"}`);\n }\n }\n if (byProvider.size === 0) console.log(\"no models reported — run `yagami doctor`\");\n } catch (err) {\n console.error(`yagami: ${err instanceof Error ? err.message : String(err)}`);\n process.exitCode = 1;\n }\n });\n\nawait program.parseAsync(process.argv);\n"],"mappings":"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","names":["resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { spawn, spawnSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { Command } from \"commander\";\nimport { YagamiEngine } from \"./core/engine.js\";\nimport { ClaudeProvider } from \"./core/providers/claude.js\";\nimport { createProvider, detectProviders } from \"./core/providers/registry.js\";\nimport { startYagami } from \"./server.js\";\nimport {\n clearServerState,\n configFilePath,\n generateApiKey,\n isProcessAlive,\n loadConfig,\n loadFileConfig,\n logFilePath,\n maskKey,\n readServerState,\n saveConfig,\n sessionCachePath,\n writeServerState,\n} from \"./server/config.js\";\nimport { VERSION } from \"./version.js\";\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst program = new Command();\n\nprogram\n .name(\"yagami\")\n .description(\"Anthropic- and OpenAI-compatible API served by your signed-in coding-agent CLIs\")\n .version(VERSION);\n\ninterface StartFlags {\n port?: string;\n host?: string;\n claude?: string;\n provider?: string;\n cors?: boolean;\n daemon?: boolean;\n log?: string;\n}\n\nprogram\n .command(\"start\", { isDefault: true })\n .description(\"start the yagami server\")\n .option(\"-p, --port <port>\", \"port to listen on\")\n .option(\"-H, --host <host>\", \"host to bind (default 127.0.0.1)\")\n .option(\"--claude <path>\", \"path to the claude executable\")\n .option(\"--provider <id>\", \"default provider for bare model ids (claude, codex, opencode, gemini, …)\")\n .option(\"--cors\", \"enable permissive CORS (for browser clients)\")\n .option(\"--daemon\", \"run in the background (managed with `yagami stop`/`yagami status`)\")\n .option(\"--log <file>\", \"log file for --daemon mode (default ~/.config/yagami/yagami.log)\")\n .action(async (opts: StartFlags) => {\n // First run: generate a key automatically so the endpoint is never open.\n const fileConfig = loadFileConfig();\n let freshKey: string | undefined;\n if (fileConfig.apiKeys.length === 0 && !process.env[\"YAGAMI_API_KEY\"]) {\n freshKey = generateApiKey();\n fileConfig.apiKeys.push(freshKey);\n saveConfig(fileConfig);\n }\n\n if (opts.daemon) {\n await startDaemon(opts, freshKey);\n return;\n }\n\n try {\n const running = await startYagami({\n port: opts.port !== undefined ? Number(opts.port) : undefined,\n host: opts.host,\n claudePath: opts.claude,\n defaultProvider: opts.provider,\n cors: opts.cors,\n });\n\n writeServerState({\n pid: process.pid,\n host: running.config.host,\n port: running.config.port,\n url: running.url,\n startedAt: new Date().toISOString(),\n version: VERSION,\n ...(process.env[\"YAGAMI_LOG_FILE\"] ? { log: process.env[\"YAGAMI_LOG_FILE\"] } : {}),\n });\n const shutdown = () => {\n running.sessionCache.persistNow();\n clearServerState(process.pid);\n void running.close().finally(() => process.exit(0));\n // Don't hang on a stuck in-flight response.\n setTimeout(() => process.exit(0), 3000).unref?.();\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n const engine = running.engine;\n const version = await engine.defaultProvider.version();\n const others = engine.providerIds.filter((id) => id !== engine.defaultProviderId);\n console.log(`yagami v${VERSION}`);\n console.log(` listening ${running.url}`);\n console.log(` provider ${engine.defaultProviderId} — ${engine.executable}${version ? ` (${version})` : \"\"}`);\n console.log(\n ` also ${others.length > 0 ? `${others.join(\", \")} (use model \"<provider>:<model>\")` : \"no other harness CLIs found — see `yagami doctor`\"}`,\n );\n console.log(` config ${configFilePath()}`);\n if (freshKey) {\n console.log(` api key ${freshKey}`);\n console.log(\" (newly generated and saved — `yagami key` prints it again)\");\n } else {\n console.log(` api keys ${running.config.apiKeys.map(maskKey).join(\", \")} (\\`yagami key\\` prints them in full)`);\n }\n if (![\"127.0.0.1\", \"localhost\", \"::1\"].includes(running.config.host)) {\n console.log(\n ` ⚠ bound to ${running.config.host} — reachable beyond this machine. Only do this on a network you trust.`,\n );\n }\n console.log(\"\\nConnect apps — either dialect, same key (`yagami key` prints ready-to-paste env exports):\");\n console.log(` Anthropic apps baseURL ${running.url} (ANTHROPIC_BASE_URL / ANTHROPIC_API_KEY)`);\n console.log(` OpenAI apps baseURL ${running.url}/v1 (OPENAI_BASE_URL / OPENAI_API_KEY)`);\n } catch (err) {\n console.error(`yagami: ${err instanceof Error ? err.message : String(err)}`);\n process.exitCode = 1;\n }\n });\n\nasync function startDaemon(opts: StartFlags, freshKey: string | undefined): Promise<void> {\n const existing = readServerState();\n if (existing && isProcessAlive(existing.pid)) {\n console.error(`yagami is already running (pid ${existing.pid}, ${existing.url}) — \\`yagami stop\\` first`);\n process.exitCode = 1;\n return;\n }\n clearServerState();\n\n const logPath = opts.log ? path.resolve(opts.log) : logFilePath();\n fs.mkdirSync(path.dirname(logPath), { recursive: true });\n const fd = fs.openSync(logPath, \"a\");\n const args = [process.argv[1]!, \"start\"];\n if (opts.port !== undefined) args.push(\"-p\", opts.port);\n if (opts.host !== undefined) args.push(\"-H\", opts.host);\n if (opts.claude !== undefined) args.push(\"--claude\", opts.claude);\n if (opts.provider !== undefined) args.push(\"--provider\", opts.provider);\n if (opts.cors) args.push(\"--cors\");\n\n const child = spawn(process.execPath, args, {\n detached: true,\n stdio: [\"ignore\", fd, fd],\n env: { ...process.env, YAGAMI_LOG_FILE: logPath },\n });\n fs.closeSync(fd);\n let exitCode: number | null | undefined;\n child.on(\"exit\", (code) => {\n exitCode = code;\n });\n child.unref();\n\n const deadline = Date.now() + 15_000;\n while (Date.now() < deadline && exitCode === undefined) {\n const state = readServerState();\n if (state && state.pid === child.pid) {\n console.log(`yagami v${VERSION} running in the background`);\n console.log(` pid ${child.pid}`);\n console.log(` url ${state.url}`);\n console.log(` log ${logPath}`);\n if (freshKey) {\n console.log(` key ${freshKey}`);\n console.log(\" (newly generated and saved — `yagami key` prints it again)\");\n }\n console.log(\" `yagami key` prints the URL, key, and env exports for client apps\");\n return;\n }\n await sleep(200);\n }\n console.error(\n exitCode !== undefined\n ? `yagami exited immediately (code ${exitCode}) — see ${logPath}`\n : `yagami did not report ready within 15s — see ${logPath}`,\n );\n process.exitCode = 1;\n}\n\nprogram\n .command(\"stop\")\n .description(\"stop a running yagami server\")\n .action(async () => {\n const state = readServerState();\n if (!state || !isProcessAlive(state.pid)) {\n if (state) clearServerState();\n console.log(\"yagami is not running\");\n return;\n }\n process.kill(state.pid, \"SIGTERM\");\n const deadline = Date.now() + 5_000;\n while (Date.now() < deadline) {\n if (!isProcessAlive(state.pid)) {\n clearServerState();\n console.log(`stopped yagami (pid ${state.pid})`);\n return;\n }\n await sleep(100);\n }\n console.error(`yagami (pid ${state.pid}) did not exit within 5s`);\n process.exitCode = 1;\n });\n\nprogram\n .command(\"status\")\n .description(\"show whether yagami is running, plus request/cost totals\")\n .action(async () => {\n const state = readServerState();\n if (!state || !isProcessAlive(state.pid)) {\n if (state) clearServerState();\n console.log(\"yagami is not running\");\n process.exitCode = 1;\n return;\n }\n console.log(`yagami running (pid ${state.pid})`);\n console.log(` url ${state.url}`);\n console.log(` since ${state.startedAt}`);\n if (state.log) console.log(` log ${state.log}`);\n try {\n const res = await fetch(`${state.url}/healthz`, { signal: AbortSignal.timeout(3000) });\n const body = (await res.json()) as {\n version?: string;\n claude?: string;\n requests?: number;\n total_cost_usd?: number;\n };\n console.log(` version ${body.version ?? \"?\"}`);\n console.log(` claude ${body.claude ?? \"?\"}`);\n console.log(` requests ${body.requests ?? 0}`);\n console.log(` cost $${(body.total_cost_usd ?? 0).toFixed(4)} (would-be API cost since start)`);\n } catch {\n console.log(` healthz unreachable — process is alive but ${state.url} is not answering`);\n }\n });\n\nprogram\n .command(\"keygen\")\n .description(\"generate an API key and add it to the config\")\n .action(() => {\n const cfg = loadFileConfig();\n const key = generateApiKey();\n cfg.apiKeys.push(key);\n const file = saveConfig(cfg);\n console.log(key);\n console.error(`saved to ${file} (${cfg.apiKeys.length} key${cfg.apiKeys.length === 1 ? \"\" : \"s\"} total)`);\n });\n\nprogram\n .command(\"key\")\n .description(\"print the server URL, API key, and ready-to-paste env exports for client apps\")\n .action(() => {\n const cfg = loadConfig();\n const state = readServerState();\n const live = state !== undefined && isProcessAlive(state.pid);\n const url = live ? state.url : `http://${cfg.host}:${cfg.port}`;\n if (cfg.apiKeys.length === 0) {\n console.error(\"no API keys configured — run `yagami start` (generates one) or `yagami keygen`\");\n process.exitCode = 1;\n return;\n }\n const key = cfg.apiKeys[cfg.apiKeys.length - 1]!;\n console.log(`url ${url}${live ? \"\" : \" (server not running — this is where `yagami start` will listen)\"}`);\n console.log(`key ${key}`);\n if (cfg.apiKeys.length > 1) {\n console.log(` (newest of ${cfg.apiKeys.length} keys in ${configFilePath()})`);\n }\n console.log(\"\\nAnthropic-dialect apps:\");\n console.log(` export ANTHROPIC_BASE_URL=${url}`);\n console.log(` export ANTHROPIC_API_KEY=${key}`);\n console.log(\"\\nOpenAI-dialect apps:\");\n console.log(` export OPENAI_BASE_URL=${url}/v1`);\n console.log(` export OPENAI_API_KEY=${key}`);\n });\n\nprogram\n .command(\"doctor\")\n .description(\"check which coding-agent CLIs yagami can drive and whether they work\")\n .option(\"--live\", \"send one real (tiny) completion through the default provider\")\n .option(\"--provider <id>\", \"provider to use for --live (default: config/claude)\")\n .action(async (opts: { live?: boolean; provider?: string }) => {\n let failed = false;\n const cfg = loadConfig();\n const providerConfig = { ...cfg.providers };\n if (cfg.claudePath || cfg.claudeConfigDir) {\n providerConfig[\"claude\"] = {\n ...providerConfig[\"claude\"],\n ...(cfg.claudePath ? { path: cfg.claudePath } : {}),\n ...(cfg.claudeConfigDir ? { configDir: cfg.claudeConfigDir } : {}),\n };\n }\n const defaultProvider = opts.provider ?? cfg.defaultProvider ?? \"claude\";\n\n console.log(`node ${process.version}`);\n console.log(`config ${configFilePath()}${fs.existsSync(configFilePath()) ? \"\" : \" (not created yet)\"}`);\n console.log(`api keys ${cfg.apiKeys.length === 0 ? \"none — run `yagami keygen`\" : cfg.apiKeys.map(maskKey).join(\", \")}`);\n console.log(`bind ${cfg.host}:${cfg.port}`);\n console.log(`sessions ${sessionCachePath()}${fs.existsSync(sessionCachePath()) ? \"\" : \" (empty)\"}`);\n const state = readServerState();\n console.log(\n `server ${state && isProcessAlive(state.pid) ? `running (pid ${state.pid}, ${state.url})` : \"not running\"}`,\n );\n\n console.log(\"\\nproviders (model ids route as \\\"<provider>:<model>\\\"; bare ids go to the default)\");\n const detected = detectProviders(providerConfig);\n const installed = detected.filter((d) => d.installed);\n for (const d of detected) {\n const marker = d.id === defaultProvider ? \"*\" : \" \";\n if (!d.installed) {\n if (presetIsNiche(d.id)) continue; // keep the list readable\n console.log(` ${marker} ${d.id.padEnd(11)} not installed — ${d.installHint}`);\n continue;\n }\n let version: string | undefined;\n try {\n version = await createProvider(d.id, providerConfig[d.id] ?? {}, {}).version();\n } catch (err) {\n version = `✗ ${err instanceof Error ? err.message : String(err)}`;\n }\n console.log(` ${marker} ${d.id.padEnd(11)} ${d.path}${version ? ` (${version})` : \"\"}`);\n }\n const hidden = detected.filter((d) => !d.installed && presetIsNiche(d.id)).length;\n if (hidden > 0) console.log(` … ${hidden} more ACP presets not installed (see README for the full list)`);\n if (!installed.some((d) => d.id === defaultProvider)) {\n failed = true;\n console.log(` ✗ default provider \"${defaultProvider}\" is not installed`);\n }\n\n if (installed.some((d) => d.id === \"claude\")) {\n try {\n const claude = createProvider(\"claude\", providerConfig[\"claude\"] ?? {}, {}) as ClaudeProvider;\n const skew = await claude.versionSkew();\n if (skew) {\n console.log(`\\nagent sdk ${skew.sdkVersion} ↔ claude ${skew.binaryVersion} — ${skew.inSync ? \"in sync\" : `⚠ ${skew.note}`}`);\n }\n } catch {\n // skew check is advisory\n }\n }\n\n if (opts.live && !failed) {\n console.log(`\\nlive check: sending one tiny completion through ${defaultProvider}…`);\n try {\n const engine = new YagamiEngine({ providerConfig, defaultProvider, ...(cfg.defaultModel ? { defaultModel: cfg.defaultModel } : {}) });\n const started = Date.now();\n const result = await engine.complete({\n messages: [{ role: \"user\", content: \"Reply with exactly: pong\" }],\n max_tokens: 32,\n });\n const text = result.response.content\n .filter((b) => b.type === \"text\")\n .map((b) => b[\"text\"])\n .join(\"\");\n console.log(` reply ${JSON.stringify(text)}`);\n console.log(` model ${result.response.model}`);\n console.log(` latency ${((Date.now() - started) / 1000).toFixed(1)}s`);\n if (result.costUsd !== undefined) console.log(` cost $${result.costUsd.toFixed(6)}`);\n } catch (err) {\n failed = true;\n console.log(` ✗ ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n if (failed) process.exitCode = 1;\n });\n\n/** Presets most people won't have; hidden from doctor unless installed. */\nfunction presetIsNiche(id: string): boolean {\n return ![\"claude\", \"codex\", \"opencode\", \"gemini\", \"copilot\", \"cursor\", \"qwen\", \"goose\", \"kimi\"].includes(id);\n}\n\nprogram\n .command(\"models\")\n .description(\"list models across every installed provider (ids are ready to paste into requests)\")\n .option(\"--provider <id>\", \"only this provider\")\n .action(async (opts: { provider?: string }) => {\n const cfg = loadConfig();\n try {\n const engine = new YagamiEngine({\n ...(cfg.providers ? { providerConfig: cfg.providers } : {}),\n ...(cfg.defaultProvider ? { defaultProvider: cfg.defaultProvider } : {}),\n });\n const models = await engine.listModels();\n const byProvider = new Map<string, typeof models>();\n for (const m of models) {\n if (opts.provider && m.provider !== opts.provider) continue;\n if (!m.id.includes(\":\")) continue; // print the qualified form once\n const list = byProvider.get(m.provider ?? \"?\") ?? [];\n list.push(m);\n byProvider.set(m.provider ?? \"?\", list);\n }\n for (const [provider, list] of byProvider) {\n console.log(`${provider}${provider === engine.defaultProviderId ? \" (default — bare ids work too)\" : \"\"}`);\n for (const m of list) {\n console.log(` ${m.id.padEnd(40)} ${m.display_name}${m.resolved_model ? ` → ${m.resolved_model}` : \"\"}`);\n }\n }\n if (byProvider.size === 0) console.log(\"no models reported — run `yagami doctor`\");\n } catch (err) {\n console.error(`yagami: ${err instanceof Error ? err.message : String(err)}`);\n process.exitCode = 1;\n }\n });\n\nawait program.parseAsync(process.argv);\n"],"mappings":"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","names":["resolve"]}
|
|
@@ -378,4 +378,23 @@ declare class YagamiEngine {
|
|
|
378
378
|
private attemptStream;
|
|
379
379
|
}
|
|
380
380
|
|
|
381
|
-
|
|
381
|
+
/**
|
|
382
|
+
* The engine-relevant slice of the host's yagami config
|
|
383
|
+
* (~/.config/yagami/config.json + YAGAMI_* env) — what library mode reads so
|
|
384
|
+
* an embedded `Yagami` client automatically matches the `yagami` binary on
|
|
385
|
+
* the same machine: same providers, same paths, same defaults. Server-only
|
|
386
|
+
* fields (host, port, apiKeys) are ignored here on purpose.
|
|
387
|
+
*/
|
|
388
|
+
|
|
389
|
+
declare function yagamiConfigDir(): string;
|
|
390
|
+
/** Engine options derivable from the host machine's yagami config. */
|
|
391
|
+
interface HostEngineConfig {
|
|
392
|
+
defaultProvider?: string;
|
|
393
|
+
defaultModel?: string;
|
|
394
|
+
providerConfig?: Record<string, ProviderConfigEntry>;
|
|
395
|
+
claudePath?: string;
|
|
396
|
+
claudeConfigDir?: string;
|
|
397
|
+
}
|
|
398
|
+
declare function loadHostEngineConfig(): HostEngineConfig;
|
|
399
|
+
|
|
400
|
+
export { ApiError as A, parseModelRef as B, CodexProvider as C, type DetectedProvider as D, type EngineModel as E, presetFor as F, qualifiedModel as G, type HostEngineConfig as H, yagamiConfigDir as I, type LoadedProviders as L, type MessagesRequest as M, type Provider as P, type SseEvent as S, type TurnRequest as T, type Usage as U, YagamiEngine as Y, type MessagesResponse as a, type EngineOptions as b, type ProviderCapabilities as c, type TurnEvent as d, type ApiErrorType as e, type CodexProviderOptions as f, type CodexSandboxMode as g, type CompleteResult as h, type ContentBlock as i, type ContentBlockParam as j, type MessageParam as k, type ModelRef as l, PROVIDER_PRESETS as m, type ProviderConfigEntry as n, type ProviderKind as o, type ProviderPreset as p, SessionCache as q, type SessionCacheOptions as r, type StreamOptions as s, type StreamResultInfo as t, type StreamStart as u, type SystemParam as v, createProvider as w, detectProviders as x, loadHostEngineConfig as y, loadProviders as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,204 @@
|
|
|
1
|
-
import { A as ApiError, P as Provider,
|
|
2
|
-
export {
|
|
1
|
+
import { S as SseEvent, M as MessagesRequest, E as EngineModel, A as ApiError, a as MessagesResponse, Y as YagamiEngine, b as EngineOptions, P as Provider, c as ProviderCapabilities, T as TurnRequest, d as TurnEvent } from './hostConfig-Bzr9JB8R.js';
|
|
2
|
+
export { e as ApiErrorType, C as CodexProvider, f as CodexProviderOptions, g as CodexSandboxMode, h as CompleteResult, i as ContentBlock, j as ContentBlockParam, D as DetectedProvider, H as HostEngineConfig, L as LoadedProviders, k as MessageParam, l as ModelRef, m as PROVIDER_PRESETS, n as ProviderConfigEntry, o as ProviderKind, p as ProviderPreset, q as SessionCache, r as SessionCacheOptions, s as StreamOptions, t as StreamResultInfo, u as StreamStart, v as SystemParam, U as Usage, w as createProvider, x as detectProviders, y as loadHostEngineConfig, z as loadProviders, B as parseModelRef, F as presetFor, G as qualifiedModel, I as yagamiConfigDir } from './hostConfig-Bzr9JB8R.js';
|
|
3
3
|
import { Options, SDKUserMessage, Query, SettingSource, PermissionUpdate, CanUseTool, PermissionResult, SDKMessage } from '@anthropic-ai/claude-agent-sdk';
|
|
4
4
|
export { Options as AgentOptions, CanUseTool, PermissionMode, Query, SDKMessage, SDKUserMessage } from '@anthropic-ai/claude-agent-sdk';
|
|
5
5
|
import { ClientSideConnection, InitializeResponse, SessionNotification, RequestPermissionRequest, RequestPermissionResponse } from '@agentclientprotocol/sdk';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* OpenAI Chat Completions dialect: translation to and from the Anthropic
|
|
9
|
+
* Messages shapes the engine speaks. Pure functions — used by both the HTTP
|
|
10
|
+
* server (`POST /v1/chat/completions`) and the library client
|
|
11
|
+
* (`yagami.chat.completions.create`).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
interface ChatMessageParam {
|
|
15
|
+
role: string;
|
|
16
|
+
content?: string | null | Array<{
|
|
17
|
+
type: string;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}>;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
interface ChatCompletionsRequest {
|
|
23
|
+
model?: string;
|
|
24
|
+
messages: ChatMessageParam[];
|
|
25
|
+
stream?: boolean;
|
|
26
|
+
stream_options?: {
|
|
27
|
+
include_usage?: boolean;
|
|
28
|
+
};
|
|
29
|
+
max_tokens?: number;
|
|
30
|
+
max_completion_tokens?: number;
|
|
31
|
+
temperature?: number;
|
|
32
|
+
top_p?: number;
|
|
33
|
+
stop?: string | string[];
|
|
34
|
+
n?: number;
|
|
35
|
+
reasoning_effort?: string;
|
|
36
|
+
tools?: unknown;
|
|
37
|
+
tool_choice?: unknown;
|
|
38
|
+
functions?: unknown;
|
|
39
|
+
function_call?: unknown;
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}
|
|
42
|
+
interface ChatCompletionChoice {
|
|
43
|
+
index: number;
|
|
44
|
+
message: {
|
|
45
|
+
role: "assistant";
|
|
46
|
+
content: string;
|
|
47
|
+
/** Thinking output (DeepSeek-style extension; no standard OpenAI field exists). */
|
|
48
|
+
reasoning_content?: string;
|
|
49
|
+
refusal: null;
|
|
50
|
+
};
|
|
51
|
+
finish_reason: string;
|
|
52
|
+
logprobs: null;
|
|
53
|
+
}
|
|
54
|
+
interface ChatCompletion {
|
|
55
|
+
id: string;
|
|
56
|
+
object: "chat.completion";
|
|
57
|
+
created: number;
|
|
58
|
+
model: string;
|
|
59
|
+
choices: ChatCompletionChoice[];
|
|
60
|
+
usage: OpenAiUsage;
|
|
61
|
+
}
|
|
62
|
+
interface OpenAiUsage {
|
|
63
|
+
prompt_tokens: number;
|
|
64
|
+
completion_tokens: number;
|
|
65
|
+
total_tokens: number;
|
|
66
|
+
}
|
|
67
|
+
interface ChatCompletionChunk {
|
|
68
|
+
id: string;
|
|
69
|
+
object: "chat.completion.chunk";
|
|
70
|
+
created: number;
|
|
71
|
+
model: string;
|
|
72
|
+
choices: Array<{
|
|
73
|
+
index: number;
|
|
74
|
+
delta: {
|
|
75
|
+
role?: "assistant";
|
|
76
|
+
content?: string;
|
|
77
|
+
reasoning_content?: string;
|
|
78
|
+
};
|
|
79
|
+
finish_reason: string | null;
|
|
80
|
+
}>;
|
|
81
|
+
usage?: OpenAiUsage;
|
|
82
|
+
}
|
|
83
|
+
interface TranslatedChatRequest {
|
|
84
|
+
req: MessagesRequest;
|
|
85
|
+
/** OpenAI params yagami accepted but cannot honor (adds to x-yagami-ignored). */
|
|
86
|
+
extraIgnored: string[];
|
|
87
|
+
/** `stream_options.include_usage` — emit the trailing usage chunk. */
|
|
88
|
+
includeUsage: boolean;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Translate an OpenAI Chat Completions request into the Anthropic Messages
|
|
92
|
+
* request the engine runs. Tool calling is rejected (yagami is
|
|
93
|
+
* completions-only by design); knobs no CLI engine exposes are collected
|
|
94
|
+
* into `extraIgnored` instead of failing the request.
|
|
95
|
+
*/
|
|
96
|
+
declare function chatToMessagesRequest(body: ChatCompletionsRequest): TranslatedChatRequest;
|
|
97
|
+
/** Anthropic Messages response → OpenAI chat.completion. */
|
|
98
|
+
declare function toChatCompletion(resp: MessagesResponse): ChatCompletion;
|
|
99
|
+
/** OpenAI-shaped error body (the OpenAI dialect's counterpart of ApiError.toBody). */
|
|
100
|
+
declare function openAiErrorBody(err: ApiError): {
|
|
101
|
+
error: {
|
|
102
|
+
message: string;
|
|
103
|
+
type: string;
|
|
104
|
+
param: null;
|
|
105
|
+
code: null;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Re-emits an Anthropic SSE event sequence as OpenAI chat.completion.chunk
|
|
110
|
+
* objects. Feed every engine event through `push`; the caller appends the
|
|
111
|
+
* `[DONE]` sentinel (HTTP mode) unless `errored`.
|
|
112
|
+
*/
|
|
113
|
+
declare class ChatChunkTranslator {
|
|
114
|
+
private readonly includeUsage;
|
|
115
|
+
private id;
|
|
116
|
+
private model;
|
|
117
|
+
private created;
|
|
118
|
+
private stopReason;
|
|
119
|
+
private usage;
|
|
120
|
+
/** Set when the engine reported an error mid-stream (no [DONE] after). */
|
|
121
|
+
errored: boolean;
|
|
122
|
+
constructor(includeUsage: boolean);
|
|
123
|
+
private chunk;
|
|
124
|
+
/** Translate one engine SSE event into zero or more OpenAI chunk payloads. */
|
|
125
|
+
push(ev: SseEvent): unknown[];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Model list body served by GET /v1/models: Anthropic fields and OpenAI
|
|
129
|
+
* fields on the same objects, so both SDKs' `models.list()` parse it.
|
|
130
|
+
*/
|
|
131
|
+
declare function modelListBody(models: EngineModel[]): {
|
|
132
|
+
object: "list";
|
|
133
|
+
data: Array<Record<string, unknown>>;
|
|
134
|
+
has_more: false;
|
|
135
|
+
first_id?: string;
|
|
136
|
+
last_id?: string;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* `Yagami` — the zero-config library client. `new Yagami()` needs no URL and
|
|
141
|
+
* no API key: it finds the coding-agent CLIs already installed and signed in
|
|
142
|
+
* on this machine (the same T3-Code trick the server does) and mirrors the
|
|
143
|
+
* Anthropic and OpenAI SDK surfaces on top of them, so an app written
|
|
144
|
+
* against either SDK shape drops in with nothing to configure.
|
|
145
|
+
*
|
|
146
|
+
* By default it also reads the host's yagami config
|
|
147
|
+
* (~/.config/yagami/config.json), so an embedded client and the `yagami`
|
|
148
|
+
* binary on the same machine agree on providers, paths, and defaults.
|
|
149
|
+
*/
|
|
150
|
+
|
|
151
|
+
interface YagamiOptions extends EngineOptions {
|
|
152
|
+
/**
|
|
153
|
+
* Merge the host machine's yagami config (providers, defaults) under any
|
|
154
|
+
* explicit options, so library and binary stay in sync. Default true;
|
|
155
|
+
* ignored when explicit `providers` instances are passed.
|
|
156
|
+
*/
|
|
157
|
+
syncHostConfig?: boolean;
|
|
158
|
+
}
|
|
159
|
+
/** An Anthropic stream event's payload (`message_start`, `content_block_delta`, …). */
|
|
160
|
+
interface MessageStreamEvent {
|
|
161
|
+
type: string;
|
|
162
|
+
[key: string]: unknown;
|
|
163
|
+
}
|
|
164
|
+
interface YagamiMessages {
|
|
165
|
+
/** Anthropic-SDK-shaped: non-stream resolves to the message; `stream: true` yields stream events. */
|
|
166
|
+
create(req: MessagesRequest & {
|
|
167
|
+
stream: true;
|
|
168
|
+
}): AsyncGenerator<MessageStreamEvent, void, undefined>;
|
|
169
|
+
create(req: MessagesRequest & {
|
|
170
|
+
stream?: false | undefined;
|
|
171
|
+
}): Promise<MessagesResponse>;
|
|
172
|
+
/** Always-streaming variant (the SDK's `messages.stream`). */
|
|
173
|
+
stream(req: MessagesRequest): AsyncGenerator<MessageStreamEvent, void, undefined>;
|
|
174
|
+
}
|
|
175
|
+
interface YagamiChatCompletions {
|
|
176
|
+
/** OpenAI-SDK-shaped: non-stream resolves to a chat.completion; `stream: true` yields chunks. */
|
|
177
|
+
create(req: ChatCompletionsRequest & {
|
|
178
|
+
stream: true;
|
|
179
|
+
}): AsyncGenerator<ChatCompletionChunk, void, undefined>;
|
|
180
|
+
create(req: ChatCompletionsRequest & {
|
|
181
|
+
stream?: false | undefined;
|
|
182
|
+
}): Promise<ChatCompletion>;
|
|
183
|
+
}
|
|
184
|
+
declare class Yagami {
|
|
185
|
+
/** The underlying engine, for anything beyond the SDK-shaped surface. */
|
|
186
|
+
readonly engine: YagamiEngine;
|
|
187
|
+
constructor(options?: YagamiOptions);
|
|
188
|
+
readonly messages: YagamiMessages;
|
|
189
|
+
readonly chat: {
|
|
190
|
+
completions: YagamiChatCompletions;
|
|
191
|
+
};
|
|
192
|
+
readonly models: {
|
|
193
|
+
/** Both SDK shapes at once (Anthropic + OpenAI model-list fields). */
|
|
194
|
+
list: () => Promise<ReturnType<typeof modelListBody>>;
|
|
195
|
+
/** The engine's raw model list. */
|
|
196
|
+
raw: () => Promise<EngineModel[]>;
|
|
197
|
+
};
|
|
198
|
+
private streamMessageEvents;
|
|
199
|
+
private streamChatChunks;
|
|
200
|
+
}
|
|
201
|
+
|
|
7
202
|
interface ClaudeSessionOptions {
|
|
8
203
|
/** Path to the `claude` binary. Auto-resolved when omitted. */
|
|
9
204
|
claudePath?: string;
|
|
@@ -323,6 +518,6 @@ declare function resolveExecutable(providerId: string, name: string, installHint
|
|
|
323
518
|
*/
|
|
324
519
|
declare function resolveClaudeExecutable(explicit?: string): string;
|
|
325
520
|
|
|
326
|
-
declare const VERSION = "0.
|
|
521
|
+
declare const VERSION = "0.5.0";
|
|
327
522
|
|
|
328
|
-
export { type AcpConnection, AcpProvider, type AcpProviderOptions, AgentSession, type AgentSessionOptions, ApiError, AuthRequiredError, ClaudeProvider, type ClaudeProviderOptions, type ClaudeSessionOptions, EngineModel, type Parity, PermissionAdapter, type PermissionAdapterOptions, type PermissionDecision, type PermissionHandler, type PermissionRequest, Provider, ProviderCapabilities, ProviderError, ProviderNotInstalledError, TurnEvent, TurnRequest, VERSION, type VersionSkew, YagamiError, claudeCodeSession, findExecutable, resolveClaudeExecutable, resolveExecutable, settingSourcesFor, startAgentSession, toApiError };
|
|
523
|
+
export { type AcpConnection, AcpProvider, type AcpProviderOptions, AgentSession, type AgentSessionOptions, ApiError, AuthRequiredError, ChatChunkTranslator, type ChatCompletion, type ChatCompletionChunk, type ChatCompletionsRequest, type ChatMessageParam, ClaudeProvider, type ClaudeProviderOptions, type ClaudeSessionOptions, EngineModel, EngineOptions, type MessageStreamEvent, MessagesRequest, MessagesResponse, type OpenAiUsage, type Parity, PermissionAdapter, type PermissionAdapterOptions, type PermissionDecision, type PermissionHandler, type PermissionRequest, Provider, ProviderCapabilities, ProviderError, ProviderNotInstalledError, SseEvent, type TranslatedChatRequest, TurnEvent, TurnRequest, VERSION, type VersionSkew, Yagami, type YagamiChatCompletions, YagamiEngine, YagamiError, type YagamiMessages, type YagamiOptions, chatToMessagesRequest, claudeCodeSession, findExecutable, modelListBody, openAiErrorBody, resolveClaudeExecutable, resolveExecutable, settingSourcesFor, startAgentSession, toApiError, toChatCompletion };
|