Skip to content

Commit ae48a08

Browse files
authored
feat: give codex system prompt via personality (#1482)
## Problem The Codex adapter was not receiving custom instructions/system prompts, and token usage tracking was incomplete, limiting its ability to follow user-specific guidance and provide accurate usage metrics during task execution. ## Changes - Added `instructions` parameter to `TaskExecutionOptions` and `CodexProcessOptions` interfaces - Modified the Codex spawn logic to pass instructions as a configuration parameter with proper escaping for backslashes and quotes - Moved system prompt building earlier in the agent service to make it available during initial connection setup - Enhanced token usage tracking in the Codex adapter to accumulate usage across prompts and emit turn completion notifications - Updated the Codex client to track per-message token usage including cached read/write tokens - Added proper usage accumulation in session state for comprehensive token tracking ## How did you test this? I wont lie, i didnt test this more than a quick test prompt. trust the agents bro
1 parent 2b755fe commit ae48a08

6 files changed

Lines changed: 76 additions & 22 deletions

File tree

apps/code/src/main/services/agent/service.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -601,11 +601,18 @@ When creating pull requests, add the following footer at the end of the PR descr
601601
});
602602

603603
try {
604+
const systemPrompt = this.buildSystemPrompt(
605+
credentials,
606+
taskId,
607+
customInstructions,
608+
);
609+
604610
const acpConnection = await agent.run(taskId, taskRunId, {
605611
adapter,
606612
gatewayUrl: proxyUrl,
607613
codexBinaryPath: adapter === "codex" ? getCodexBinaryPath() : undefined,
608614
model,
615+
instructions: adapter === "codex" ? systemPrompt.append : undefined,
609616
processCallbacks: {
610617
onProcessSpawned: (info) => {
611618
this.processTracking.register(
@@ -711,12 +718,6 @@ When creating pull requests, add the following footer at the end of the PR descr
711718
}
712719
}
713720

714-
const systemPrompt = this.buildSystemPrompt(
715-
credentials,
716-
taskId,
717-
customInstructions,
718-
);
719-
720721
// Both adapters implement unstable_resumeSession:
721722
// - Claude: delegates to SDK's resumeSession with JSONL hydration
722723
// - Codex: delegates to codex-acp's loadSession internally
@@ -747,11 +748,6 @@ When creating pull requests, add the following footer at the end of the PR descr
747748
taskRunId,
748749
});
749750
}
750-
const systemPrompt = this.buildSystemPrompt(
751-
credentials,
752-
taskId,
753-
customInstructions,
754-
);
755751
const newSessionResponse = await connection.newSession({
756752
cwd: repoPath,
757753
mcpServers,

packages/agent/src/adapters/codex/codex-agent.ts

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -282,18 +282,49 @@ export class CodexAcpAgent extends BaseAcpAgent {
282282

283283
const response = await this.codexConnection.prompt(params);
284284

285-
// Emit PostHog usage notification
286-
if (this.sessionState?.taskRunId && response.usage) {
287-
await this.client.extNotification("_posthog/usage_update", {
285+
if (this.sessionState && response.usage) {
286+
// Accumulate token usage from the prompt response
287+
this.sessionState.accumulatedUsage.inputTokens +=
288+
response.usage.inputTokens ?? 0;
289+
this.sessionState.accumulatedUsage.outputTokens +=
290+
response.usage.outputTokens ?? 0;
291+
this.sessionState.accumulatedUsage.cachedReadTokens +=
292+
response.usage.cachedReadTokens ?? 0;
293+
this.sessionState.accumulatedUsage.cachedWriteTokens +=
294+
response.usage.cachedWriteTokens ?? 0;
295+
}
296+
297+
if (this.sessionState?.taskRunId) {
298+
const { accumulatedUsage } = this.sessionState;
299+
300+
await this.client.extNotification(POSTHOG_NOTIFICATIONS.TURN_COMPLETE, {
288301
sessionId: params.sessionId,
289-
used: {
290-
inputTokens: response.usage.inputTokens ?? 0,
291-
outputTokens: response.usage.outputTokens ?? 0,
292-
cachedReadTokens: response.usage.cachedReadTokens ?? 0,
293-
cachedWriteTokens: response.usage.cachedWriteTokens ?? 0,
302+
stopReason: response.stopReason ?? "end_turn",
303+
usage: {
304+
inputTokens: accumulatedUsage.inputTokens,
305+
outputTokens: accumulatedUsage.outputTokens,
306+
cachedReadTokens: accumulatedUsage.cachedReadTokens,
307+
cachedWriteTokens: accumulatedUsage.cachedWriteTokens,
308+
totalTokens:
309+
accumulatedUsage.inputTokens +
310+
accumulatedUsage.outputTokens +
311+
accumulatedUsage.cachedReadTokens +
312+
accumulatedUsage.cachedWriteTokens,
294313
},
295-
cost: null,
296314
});
315+
316+
if (response.usage) {
317+
await this.client.extNotification("_posthog/usage_update", {
318+
sessionId: params.sessionId,
319+
used: {
320+
inputTokens: response.usage.inputTokens ?? 0,
321+
outputTokens: response.usage.outputTokens ?? 0,
322+
cachedReadTokens: response.usage.cachedReadTokens ?? 0,
323+
cachedWriteTokens: response.usage.cachedWriteTokens ?? 0,
324+
},
325+
cost: null,
326+
});
327+
}
297328
}
298329

299330
return response;

packages/agent/src/adapters/codex/codex-client.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,34 @@ export function createCodexClient(
6060
},
6161

6262
async sessionUpdate(params: SessionNotification): Promise<void> {
63-
// Parse usage data from session updates
6463
const update = params.update as Record<string, unknown> | undefined;
6564
if (update?.sessionUpdate === "usage_update") {
6665
const used = update.used as number | undefined;
6766
const size = update.size as number | undefined;
6867
if (used !== undefined) sessionState.contextUsed = used;
6968
if (size !== undefined) sessionState.contextSize = size;
69+
70+
// Accumulate per-message token usage when available
71+
const inputTokens = update.inputTokens as number | undefined;
72+
const outputTokens = update.outputTokens as number | undefined;
73+
if (inputTokens !== undefined) {
74+
sessionState.accumulatedUsage.inputTokens += inputTokens;
75+
}
76+
if (outputTokens !== undefined) {
77+
sessionState.accumulatedUsage.outputTokens += outputTokens;
78+
}
79+
const cachedRead = update.cachedReadTokens as number | undefined;
80+
const cachedWrite = update.cachedWriteTokens as number | undefined;
81+
if (cachedRead !== undefined) {
82+
sessionState.accumulatedUsage.cachedReadTokens += cachedRead;
83+
}
84+
if (cachedWrite !== undefined) {
85+
sessionState.accumulatedUsage.cachedWriteTokens += cachedWrite;
86+
}
87+
7088
callbacks?.onUsageUpdate?.(update);
7189
}
7290

73-
// Forward to upstream client
7491
await upstreamClient.sessionUpdate(params);
7592
},
7693

packages/agent/src/adapters/codex/spawn.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export interface CodexProcessOptions {
1010
apiBaseUrl?: string;
1111
apiKey?: string;
1212
model?: string;
13+
instructions?: string;
1314
binaryPath?: string;
1415
logger?: Logger;
1516
processCallbacks?: ProcessSpawnedCallback;
@@ -42,6 +43,13 @@ function buildConfigArgs(options: CodexProcessOptions): string[] {
4243
args.push("-c", `model="${options.model}"`);
4344
}
4445

46+
if (options.instructions) {
47+
const escaped = options.instructions
48+
.replace(/\\/g, "\\\\")
49+
.replace(/"/g, '\\"');
50+
args.push("-c", `instructions="${escaped}"`);
51+
}
52+
4553
return args;
4654
}
4755

packages/agent/src/agent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export class Agent {
131131
apiKey: gatewayConfig.apiKey,
132132
binaryPath: options.codexBinaryPath,
133133
model: sanitizedModel,
134+
instructions: options.instructions,
134135
}
135136
: undefined,
136137
});

packages/agent/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ export interface TaskExecutionOptions {
112112
model?: string;
113113
gatewayUrl?: string;
114114
codexBinaryPath?: string;
115+
instructions?: string;
115116
processCallbacks?: ProcessSpawnedCallback;
116117
}
117118

0 commit comments

Comments
 (0)