mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 18:03:50 +00:00
Finalize OpenAI Codex compatibility (#737)
- align Codex Responses provider with Pi static instructions - simplify Codex request/stream handling and cleanup exports - keep legacy OpenCode Codex prompt for testing until Pi prompt is allowlisted
This commit is contained in:
parent
3ed0d1bde7
commit
6484ae279d
17 changed files with 613 additions and 1779 deletions
|
|
@ -1,5 +1,4 @@
|
|||
import type { AgentState, AgentTool } from "@mariozechner/pi-agent-core";
|
||||
import { buildCodexPiBridge, getCodexInstructions } from "@mariozechner/pi-ai";
|
||||
import type { AgentState } from "@mariozechner/pi-agent-core";
|
||||
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||
import { basename, join } from "path";
|
||||
import { APP_NAME, getExportTemplateDir } from "../../config.js";
|
||||
|
|
@ -36,37 +35,6 @@ export interface ExportOptions {
|
|||
toolRenderer?: ToolHtmlRenderer;
|
||||
}
|
||||
|
||||
/** Info about Codex injection to show inline with model_change entries */
|
||||
interface CodexInjectionInfo {
|
||||
/** Codex instructions text */
|
||||
instructions: string;
|
||||
/** Bridge text (tool list) */
|
||||
bridge: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Codex injection info for display inline with model_change entries.
|
||||
*/
|
||||
async function buildCodexInjectionInfo(tools?: AgentTool[]): Promise<CodexInjectionInfo | undefined> {
|
||||
// Try to get cached instructions for default model family
|
||||
let instructions: string | null = null;
|
||||
try {
|
||||
instructions = getCodexInstructions();
|
||||
} catch {
|
||||
// Cache miss - that's fine
|
||||
}
|
||||
|
||||
const bridgeText = buildCodexPiBridge(tools);
|
||||
|
||||
const instructionsText =
|
||||
instructions || "(Codex instructions not cached. Run a Codex request to populate the local cache.)";
|
||||
|
||||
return {
|
||||
instructions: instructionsText,
|
||||
bridge: bridgeText,
|
||||
};
|
||||
}
|
||||
|
||||
/** Parse a color string to RGB values. Supports hex (#RRGGBB) and rgb(r,g,b) formats. */
|
||||
function parseColor(color: string): { r: number; g: number; b: number } | undefined {
|
||||
const hexMatch = color.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);
|
||||
|
|
@ -160,8 +128,6 @@ interface SessionData {
|
|||
entries: ReturnType<SessionManager["getEntries"]>;
|
||||
leafId: string | null;
|
||||
systemPrompt?: string;
|
||||
/** Info for rendering Codex injection inline with model_change entries */
|
||||
codexInjectionInfo?: CodexInjectionInfo;
|
||||
tools?: { name: string; description: string }[];
|
||||
/** Pre-rendered HTML for custom tool calls/results, keyed by tool call ID */
|
||||
renderedTools?: Record<string, RenderedToolHtml>;
|
||||
|
|
@ -287,7 +253,6 @@ export async function exportSessionToHtml(
|
|||
entries,
|
||||
leafId: sm.getLeafId(),
|
||||
systemPrompt: state?.systemPrompt,
|
||||
codexInjectionInfo: await buildCodexInjectionInfo(state?.tools),
|
||||
tools: state?.tools?.map((t) => ({ name: t.name, description: t.description })),
|
||||
renderedTools,
|
||||
};
|
||||
|
|
@ -322,7 +287,6 @@ export async function exportFromFile(inputPath: string, options?: ExportOptions
|
|||
entries: sm.getEntries(),
|
||||
leafId: sm.getLeafId(),
|
||||
systemPrompt: undefined,
|
||||
codexInjectionInfo: await buildCodexInjectionInfo(undefined),
|
||||
tools: undefined,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -512,39 +512,6 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.codex-bridge-toggle {
|
||||
color: var(--muted);
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.codex-bridge-toggle:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.codex-bridge-content {
|
||||
display: none;
|
||||
margin-top: 8px;
|
||||
padding: 8px;
|
||||
background: var(--exportCardBg);
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.codex-bridge-content pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.model-change.show-bridge .codex-bridge-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Compaction / Branch Summary - matches customMessage colors from TUI */
|
||||
.compaction {
|
||||
background: var(--customMessageBg);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
const data = JSON.parse(new TextDecoder('utf-8').decode(bytes));
|
||||
const { header, entries, leafId: defaultLeafId, systemPrompt, codexInjectionInfo, tools, renderedTools } = data;
|
||||
const { header, entries, leafId: defaultLeafId, systemPrompt, tools, renderedTools } = data;
|
||||
|
||||
// ============================================================
|
||||
// URL PARAMETER HANDLING
|
||||
|
|
@ -1117,17 +1117,7 @@
|
|||
}
|
||||
|
||||
if (entry.type === 'model_change') {
|
||||
let html = `<div class="model-change" id="${entryId}">${tsHtml}Switched to model: <span class="model-name">${escapeHtml(entry.provider)}/${escapeHtml(entry.modelId)}</span>`;
|
||||
|
||||
// Show expandable bridge prompt info when switching to openai-codex
|
||||
if (entry.provider === 'openai-codex' && codexInjectionInfo) {
|
||||
const fullContent = `# Codex Instructions\n${codexInjectionInfo.instructions}\n\n# Codex-Pi Bridge\n${codexInjectionInfo.bridge}`;
|
||||
html += ` <span class="codex-bridge-toggle" onclick="event.stopPropagation(); this.parentElement.classList.toggle('show-bridge')">[bridge prompt]</span>`;
|
||||
html += `<div class="codex-bridge-content"><pre>${escapeHtml(fullContent)}</pre></div>`;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
return html;
|
||||
return `<div class="model-change" id="${entryId}">${tsHtml}Switched to model: <span class="model-name">${escapeHtml(entry.provider)}/${escapeHtml(entry.modelId)}</span></div>`;
|
||||
}
|
||||
|
||||
if (entry.type === 'compaction') {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
* System prompt construction and project context loading
|
||||
*/
|
||||
|
||||
import { PI_STATIC_INSTRUCTIONS } from "@mariozechner/pi-ai";
|
||||
import chalk from "chalk";
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import { join, resolve } from "path";
|
||||
import { getAgentDir, getDocsPath, getExamplesPath, getReadmePath } from "../config.js";
|
||||
import { getAgentDir, getReadmePath } from "../config.js";
|
||||
import type { SkillsSettings } from "./settings-manager.js";
|
||||
import { formatSkillsForPrompt, loadSkills, type Skill } from "./skills.js";
|
||||
import type { ToolName } from "./tools/index.js";
|
||||
|
|
@ -135,6 +136,17 @@ export interface BuildSystemPromptOptions {
|
|||
skills?: Skill[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Pi installation path for documentation references.
|
||||
* This resolves the pi-internal:// scheme used in the static instructions.
|
||||
*/
|
||||
function getPiPath(): string {
|
||||
// getReadmePath returns something like /path/to/pi/README.md
|
||||
// We want the parent directory
|
||||
const readmePath = getReadmePath();
|
||||
return resolve(readmePath, "..");
|
||||
}
|
||||
|
||||
/** Build the system prompt with tools, guidelines, and context */
|
||||
export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {
|
||||
const {
|
||||
|
|
@ -173,6 +185,7 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
|
|||
providedSkills ??
|
||||
(skillsSettings?.enabled !== false ? loadSkills({ ...skillsSettings, cwd: resolvedCwd, agentDir }).skills : []);
|
||||
|
||||
// Handle custom prompt (full replacement)
|
||||
if (resolvedCustomPrompt) {
|
||||
let prompt = resolvedCustomPrompt;
|
||||
|
||||
|
|
@ -202,11 +215,6 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
|
|||
return prompt;
|
||||
}
|
||||
|
||||
// Get absolute paths to documentation and examples
|
||||
const readmePath = getReadmePath();
|
||||
const docsPath = getDocsPath();
|
||||
const examplesPath = getExamplesPath();
|
||||
|
||||
// Build tools list based on selected tools
|
||||
const tools = selectedTools || (["read", "bash", "edit", "write"] as ToolName[]);
|
||||
const toolsList = tools.length > 0 ? tools.map((t) => `- ${t}: ${toolDescriptions[t]}`).join("\n") : "(none)";
|
||||
|
|
@ -264,7 +272,12 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
|
|||
|
||||
const guidelines = guidelinesList.map((g) => `- ${g}`).join("\n");
|
||||
|
||||
let prompt = `You are an expert coding assistant. You help users with coding tasks by reading files, executing commands, editing code, and writing new files.
|
||||
// Build prompt with static prefix + dynamic parts
|
||||
const piPath = getPiPath();
|
||||
|
||||
let prompt = `${PI_STATIC_INSTRUCTIONS}
|
||||
Pi path:
|
||||
pi-internal:// refers to paths in ${piPath}
|
||||
|
||||
Available tools:
|
||||
${toolsList}
|
||||
|
|
@ -272,14 +285,7 @@ ${toolsList}
|
|||
In addition to the tools above, you may have access to other custom tools depending on the project.
|
||||
|
||||
Guidelines:
|
||||
${guidelines}
|
||||
|
||||
Documentation:
|
||||
- Main documentation: ${readmePath}
|
||||
- Additional docs: ${docsPath}
|
||||
- Examples: ${examplesPath} (extensions, custom tools, SDK)
|
||||
- When asked to create: custom models/providers (README.md), extensions (docs/extensions.md, examples/extensions/), themes (docs/theme.md), skills (docs/skills.md), TUI components (docs/tui.md - has copy-paste patterns)
|
||||
- Always read the doc, examples, AND follow .md cross-references before implementing`;
|
||||
${guidelines}`;
|
||||
|
||||
if (appendSection) {
|
||||
prompt += appendSection;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue