Skip to content

Commit eaff9c9

Browse files
committed
fix(providers): forward systemPromptFile through ACP and detect hermes runtime
ACP has no dedicated system-message channel, so our daemon-generated agent work protocol (claim/review lifecycle, identity, trailer) was never reaching hermes — it only saw the raw task description. Now we read the systemPromptFile and send it as a separate text block ahead of the task context in the first `session/prompt` call. Also register hermes in the runtime detector so `ak identity` and related commands work when invoked from inside a hermes agent session, and make `ak identity` fail fast when no runtime can be detected instead of silently falling back to a "default" bucket.
1 parent f0bd425 commit eaff9c9

3 files changed

Lines changed: 22 additions & 6 deletions

File tree

packages/cli/src/agent/runtime.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const RUNTIMES: Record<string, RuntimeSpec> = {
1111
codex: { envVar: "CODEX_CI", commandPattern: /(^|\/)codex(\s|$)/ },
1212
gemini: { envVar: "GEMINI_CLI", commandPattern: /(^|\/)gemini(\s|$)/ },
1313
copilot: { envVar: "COPILOT_CLI", commandPattern: /(^|\/)copilot(\s|$)/ },
14+
hermes: { envVar: "HERMES_INTERACTIVE", commandPattern: /(^|\/)hermes(\s|$)/ },
1415
};
1516

1617
export function detectRuntime(): string | null {

packages/cli/src/index.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,15 @@ program
233233
.description("Show agent identity for the current runtime")
234234
.action(() => {
235235
const runtime = detectRuntime();
236-
const runtimeKey = runtime ?? "default";
237-
const identity = loadIdentity(runtimeKey);
236+
if (!runtime) {
237+
console.error("No supported agent runtime found. Run this command from inside an agent runtime.");
238+
process.exit(1);
239+
}
240+
const identity = loadIdentity(runtime);
238241
if (!identity) {
239242
console.error(
240243
[
241-
`No identity found for runtime "${runtimeKey}".`,
244+
`No identity found for runtime "${runtime}".`,
242245
"",
243246
"Create one explicitly with:",
244247
" ak identity create --username <username> [--name <name>]",
@@ -250,7 +253,7 @@ program
250253
);
251254
process.exit(1);
252255
}
253-
console.log(`Runtime: ${runtimeKey}`);
256+
console.log(`Runtime: ${runtime}`);
254257
console.log(`Agent ID: ${identity.agent_id}`);
255258
console.log(`Name: ${identity.name}`);
256259
console.log(`Fingerprint: ${identity.fingerprint}`);

packages/cli/src/providers/acp.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
import { type ChildProcess, spawn } from "node:child_process";
19+
import { readFileSync } from "node:fs";
1920
import { Readable, Writable } from "node:stream";
2021
import { ToolName } from "@agent-kanban/shared";
2122
import {
@@ -77,7 +78,8 @@ async function acpExecute(config: AcpRuntimeConfig, opts: ExecuteOpts): Promise<
7778
await conn.initialize({ protocolVersion: PROTOCOL_VERSION, clientCapabilities: {} });
7879

7980
const sessionId = await openSession(conn, opts);
80-
const promptDone = runPromptLoop(conn, sessionId, opts.taskContext, queue, mapState, runtimeState, logger);
81+
const systemPrompt = opts.systemPromptFile ? readFileSync(opts.systemPromptFile, "utf-8") : undefined;
82+
const promptDone = runPromptLoop(conn, sessionId, opts.taskContext, systemPrompt, queue, mapState, runtimeState, logger);
8183

8284
proc.once("exit", (code) => {
8385
if (!runtimeState.aborted && code !== 0 && !queue.done) {
@@ -125,15 +127,25 @@ async function runPromptLoop(
125127
conn: ClientSideConnection,
126128
sessionId: string,
127129
taskContext: string,
130+
systemPrompt: string | undefined,
128131
queue: EventQueue,
129132
mapState: MapState,
130133
runtime: RuntimeState,
131134
logger: ReturnType<typeof createLogger>,
132135
): Promise<void> {
136+
// ACP has no dedicated system-message channel; combine the daemon's agent
137+
// work protocol with the task context so the agent gets claim/review
138+
// lifecycle instructions before the task description.
139+
const prompt = systemPrompt
140+
? [
141+
{ type: "text" as const, text: systemPrompt },
142+
{ type: "text" as const, text: taskContext },
143+
]
144+
: [{ type: "text" as const, text: taskContext }];
133145
try {
134146
const resp: PromptResponse = await conn.prompt({
135147
sessionId,
136-
prompt: [{ type: "text", text: taskContext }],
148+
prompt,
137149
});
138150
// If abort() has already taken the wheel, let it drive finalization.
139151
if (runtime.aborted) return;

0 commit comments

Comments
 (0)