UNPKG

@agentproto/driver-agent-cli

Version:

@agentproto/driver-agent-cli — AIP-45 AGENT-CLI.md reference implementation. Multi-protocol runner that loads an AGENT-CLI.md manifest, spawns the binary, and dispatches turns through an ACP / MCP / proprietary arm. ACP arm delegates to @agentproto/acp; e

296 lines (284 loc) • 9.61 kB
export { LEGACY_GATEWAY_MODE_IDS, LEGACY_POSTURE_MODE_IDS, RuntimeConfigError, agentCliFrontmatterSchema, agentCliSupportsHostContextIsolation, applyModelCommand, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createArmSessionControls, createJcodeMapperState, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, hostContextExcludes, inferLegacyModeKind, isLegacyExtractedModeId, isModelSwitchAcknowledgement, mapJcodeEvent, mapMastraEvent, parseModelSwitchCommand, planModePermissionHandler, promptTurn, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers } from './chunk-Y3FGLQ4R.mjs'; /** * @agentproto/driver-agent-cli v0.1.0-alpha * AIP-45 AGENT-CLI.md `defineAgentCli` reference implementation. */ // src/model.ts function datasetPreamble(datasetDir) { return `You have direct read access to the source files under \`${datasetDir}\` (e.g. \`sources/\` raw captures, \`entries/\` refined notes). Use your file-reading tools to consult the primary sources directly when grounding claims \u2014 do not rely only on the excerpts quoted in this prompt.`; } function composePrompt(system, prompt, datasetDir) { const head = datasetDir ? `${datasetPreamble(datasetDir)} ` : ""; return system ? `${head}${system} ${prompt}` : `${head}${prompt}`; } var PROVIDER_KEY_ENV = [ "OPENROUTER_API_KEY", "ANTHROPIC_API_KEY", "OPENAI_API_KEY" ]; function resolveCliEnv(opts) { if (opts.env) return opts.env; const env = {}; for (const k of PROVIDER_KEY_ENV) { const v = process.env[k]; if (v) env[k] = v; } return env; } async function driveTurn(runtime, prompt, opts) { const controller = new AbortController(); const timer = setTimeout( () => controller.abort(), opts.timeoutMs ?? 5 * 60 * 1e3 ); const cwd = opts.cwd ?? opts.datasetDir; const session = await runtime.start({ env: resolveCliEnv(opts), signal: controller.signal, ...cwd ? { cwd } : {} }); try { let text = ""; for await (const evt of session.send({ role: "user", content: prompt })) { if (evt.kind === "text-delta") { text += evt.text; } else if (evt.kind === "error") { throw new Error(`${runtime.definition.id} model: ${evt.error.message}`); } else if (evt.kind === "turn-end") { if (evt.reason !== "completed") throw new Error(`${runtime.definition.id} model: turn ${evt.reason}`); break; } } if (controller.signal.aborted) throw new Error(`${runtime.definition.id} model: timed out`); return text.trim(); } finally { clearTimeout(timer); await session.close(); } } function makeAgentCliModel(runtime, opts = {}) { const run = opts.run ?? ((prompt) => driveTurn(runtime, prompt, opts)); return { async complete({ system, prompt }) { return { result: await run(composePrompt(system, prompt, opts.datasetDir)) }; } }; } // src/continuation/strategies/none.ts var noneStrategy = { id: "none", async acquire(ctx) { return ctx.runtime.start(ctx.startOptions); }, async release(ctx) { await ctx.session.close(); } }; // src/continuation/types.ts function deriveKeyFromScope(scope, turnCtx) { const parts = []; for (const s of scope) { const v = turnCtx[s]; if (v) parts.push(`${s}=${v}`); } return parts.length === 0 ? null : parts.join("|"); } // src/continuation/strategies/pinned-session.ts var DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1e3; var pins = /* @__PURE__ */ new Map(); function clearIdleTimer(entry) { if (entry.idleTimer) { clearTimeout(entry.idleTimer); entry.idleTimer = null; } } function scheduleIdleEviction(key, entry, idleTimeoutMs) { clearIdleTimer(entry); entry.idleTimer = setTimeout(() => { pins.delete(key); entry.session.close().catch((err) => { console.warn( `[pinned-session] idle close failed for ${key}:`, err instanceof Error ? err.message : err ); }); console.log( `[pinned-session] ${key} idle ${idleTimeoutMs / 6e4}m \u2192 closed` ); }, idleTimeoutMs); entry.idleTimer.unref?.(); } function evictPin(key) { const entry = pins.get(key); if (!entry) return; clearIdleTimer(entry); pins.delete(key); entry.session.close().catch((err) => { console.warn( `[pinned-session] evict close failed for ${key}:`, err instanceof Error ? err.message : err ); }); } var pinnedSessionStrategy = { id: "pinned-session", async acquire(ctx) { const tuning = ctx.runtime.definition.continuation?.pinned_session; const scope = tuning?.key_scope ?? ["conversation", "operator"]; const key = deriveKeyFromScope(scope, ctx.turnCtx); const idleTimeoutMs = tuning?.idle_timeout_ms ?? DEFAULT_IDLE_TIMEOUT_MS; if (key === null) { console.warn( `[pinned-session] turnCtx has no fields matching key_scope ${JSON.stringify(scope)}; falling back to per-spawn (no pin).` ); return ctx.runtime.start(ctx.startOptions); } const existing = pins.get(key); if (existing) { clearIdleTimer(existing); return existing.session; } const session = await ctx.runtime.start(ctx.startOptions); const entry = { session, runtime: ctx.runtime, startOptions: ctx.startOptions, idleTimer: null }; pins.set(key, entry); scheduleIdleEviction(key, entry, idleTimeoutMs); return session; }, async release(ctx) { let foundKey = null; for (const [k, e] of pins) { if (e.session === ctx.session) { foundKey = k; break; } } if (!foundKey) { await ctx.session.close(); return; } const entry = pins.get(foundKey); const tuning = entry.runtime.definition.continuation?.pinned_session; const idleTimeoutMs = tuning?.idle_timeout_ms ?? DEFAULT_IDLE_TIMEOUT_MS; if (ctx.outcome.kind === "error" && ctx.outcome.reason === "fatal") { evictPin(foundKey); return; } scheduleIdleEviction(foundKey, entry, idleTimeoutMs); } }; // src/continuation/strategies/transcript.ts var transcriptStrategy = { id: "transcript", async acquire(ctx) { return ctx.runtime.start(ctx.startOptions); }, async release(ctx) { await ctx.session.close(); } }; // src/continuation/strategies/native-resume.ts var _hooks = null; function configureNativeResume(hooks) { _hooks = hooks; } var nativeResumeStrategy = { id: "native-resume", async acquire(ctx) { if (!_hooks) { console.warn( "[native-resume] no hooks registered (call configureNativeResume at boot); falling back to per-spawn \u2014 no continuity." ); return ctx.runtime.start(ctx.startOptions); } const scope = ctx.runtime.definition.continuation?.pinned_session?.key_scope ?? [ "conversation", "operator" ]; const key = deriveKeyFromScope(scope, ctx.turnCtx); if (key === null) { console.warn( `[native-resume] turnCtx has no fields matching key_scope ${JSON.stringify(scope)}; falling back to per-spawn (no resume).` ); return ctx.runtime.start(ctx.startOptions); } const existingId = await _hooks.load(ctx.turnCtx).catch((err) => { console.warn( `[native-resume] load hook failed for ${key}:`, err instanceof Error ? err.message : err ); return void 0; }); let session; let resumed = false; if (existingId) { try { session = await ctx.runtime.start({ ...ctx.startOptions, resumeSessionId: existingId }); resumed = true; } catch (err) { console.warn( `[native-resume] resume failed for ${key} (id=${existingId.slice(0, 12)}\u2026), starting fresh:`, err instanceof Error ? err.message : err ); if (_hooks.forget) { await _hooks.forget(ctx.turnCtx).catch(() => void 0); } session = await ctx.runtime.start(ctx.startOptions); } } else { session = await ctx.runtime.start(ctx.startOptions); } if (!resumed && session.sessionId) { await _hooks.save(ctx.turnCtx, session.sessionId).catch((err) => { console.warn( `[native-resume] save hook failed for ${key}:`, err instanceof Error ? err.message : err ); }); } return session; }, async release(ctx) { await ctx.session.close(); } }; // src/continuation/registry.ts var registry = /* @__PURE__ */ new Map(); function registerContinuationStrategy(strategy) { registry.set(strategy.id, strategy); } function getContinuationStrategy(id) { const s = registry.get(id); if (!s) { throw new Error( `[agent-cli] No continuation strategy registered for id '${id}'. Built-ins: ${Array.from(registry.keys()).join(", ")}.` ); } return s; } function listContinuationStrategies() { return Array.from(registry.keys()); } registerContinuationStrategy(noneStrategy); registerContinuationStrategy(pinnedSessionStrategy); registerContinuationStrategy(transcriptStrategy); registerContinuationStrategy(nativeResumeStrategy); // src/index.ts var SPEC_NAME = "agentcli-interactive/v1"; var SPEC_VERSION = "0.1.0-alpha"; export { PROVIDER_KEY_ENV, SPEC_NAME, SPEC_VERSION, composePrompt, configureNativeResume, datasetPreamble, deriveKeyFromScope, getContinuationStrategy, listContinuationStrategies, makeAgentCliModel, registerContinuationStrategy, resolveCliEnv }; //# sourceMappingURL=index.mjs.map //# sourceMappingURL=index.mjs.map