mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-16 17:01:06 +00:00
docs: update agent docs with mode/permission info, add amp.md
This commit is contained in:
parent
7e1b63a622
commit
e835f2b29b
4 changed files with 317 additions and 14 deletions
|
|
@ -1,253 +0,0 @@
|
|||
# Codex Research
|
||||
|
||||
Research notes on OpenAI Codex's configuration, credential discovery, and runtime behavior based on agent-jj implementation.
|
||||
|
||||
## Overview
|
||||
|
||||
- **Provider**: OpenAI
|
||||
- **Execution Method**: SDK (`@openai/codex-sdk`) or CLI binary
|
||||
- **Session Persistence**: Thread ID (string)
|
||||
- **Import**: Dynamic import to avoid bundling issues
|
||||
- **Binary Location**: `~/.nvm/versions/node/v24.3.0/bin/codex` (npm global install)
|
||||
|
||||
## SDK Architecture
|
||||
|
||||
**The SDK wraps a bundled binary** - it does NOT make direct API calls.
|
||||
|
||||
- The TypeScript SDK includes a pre-compiled Codex binary
|
||||
- When you use the SDK, it spawns this binary as a child process
|
||||
- Communication happens via stdin/stdout using JSONL (JSON Lines) format
|
||||
- The binary itself handles the actual communication with OpenAI's backend services
|
||||
|
||||
Sources: [Codex SDK docs](https://developers.openai.com/codex/sdk/), [GitHub](https://github.com/openai/codex)
|
||||
|
||||
## CLI Usage (Alternative to SDK)
|
||||
|
||||
You can use the `codex` binary directly instead of the SDK:
|
||||
|
||||
### Interactive Mode
|
||||
```bash
|
||||
codex "your prompt here"
|
||||
codex --model o3 "your prompt"
|
||||
```
|
||||
|
||||
### Non-Interactive Mode (`codex exec`)
|
||||
```bash
|
||||
codex exec "your prompt here"
|
||||
codex exec --json "your prompt" # JSONL output
|
||||
codex exec -m o3 "your prompt"
|
||||
codex exec --dangerously-bypass-approvals-and-sandbox "prompt"
|
||||
codex exec resume --last # Resume previous session
|
||||
```
|
||||
|
||||
### Key CLI Flags
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--json` | Print events to stdout as JSONL |
|
||||
| `-m, --model MODEL` | Model to use |
|
||||
| `-s, --sandbox MODE` | `read-only`, `workspace-write`, `danger-full-access` |
|
||||
| `--full-auto` | Auto-approve with workspace-write sandbox |
|
||||
| `--dangerously-bypass-approvals-and-sandbox` | Skip all prompts (dangerous) |
|
||||
| `-C, --cd DIR` | Working directory |
|
||||
| `-o, --output-last-message FILE` | Write final response to file |
|
||||
| `--output-schema FILE` | JSON Schema for structured output |
|
||||
|
||||
### Session Management
|
||||
```bash
|
||||
codex resume # Pick from previous sessions
|
||||
codex resume --last # Resume most recent
|
||||
codex fork --last # Fork most recent session
|
||||
```
|
||||
|
||||
## Credential Discovery
|
||||
|
||||
### Priority Order
|
||||
|
||||
1. User-configured credentials (from `credentials` array)
|
||||
2. Environment variable: `CODEX_API_KEY`
|
||||
3. Environment variable: `OPENAI_API_KEY`
|
||||
4. Bootstrap extraction from config files
|
||||
|
||||
### Config File Location
|
||||
|
||||
| Path | Description |
|
||||
|------|-------------|
|
||||
| `~/.codex/auth.json` | Primary auth config |
|
||||
|
||||
### Auth File Structure
|
||||
|
||||
```json
|
||||
// API Key authentication
|
||||
{
|
||||
"OPENAI_API_KEY": "sk-..."
|
||||
}
|
||||
|
||||
// OAuth authentication
|
||||
{
|
||||
"tokens": {
|
||||
"access_token": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## SDK Usage
|
||||
|
||||
### Client Initialization
|
||||
|
||||
```typescript
|
||||
import { Codex } from "@openai/codex-sdk";
|
||||
|
||||
// With API key
|
||||
const codex = new Codex({ apiKey: "sk-..." });
|
||||
|
||||
// Without API key (uses default auth)
|
||||
const codex = new Codex();
|
||||
```
|
||||
|
||||
Dynamic import is used to avoid bundling the SDK:
|
||||
```typescript
|
||||
const { Codex } = await import("@openai/codex-sdk");
|
||||
```
|
||||
|
||||
### Thread Management
|
||||
|
||||
```typescript
|
||||
// Start new thread
|
||||
const thread = codex.startThread();
|
||||
|
||||
// Resume existing thread
|
||||
const thread = codex.resumeThread(threadId);
|
||||
```
|
||||
|
||||
### Running Prompts
|
||||
|
||||
```typescript
|
||||
const { events } = await thread.runStreamed(prompt);
|
||||
|
||||
for await (const event of events) {
|
||||
// Process events
|
||||
}
|
||||
```
|
||||
|
||||
## Event Types
|
||||
|
||||
| Event Type | Description |
|
||||
|------------|-------------|
|
||||
| `thread.started` | Thread initialized, contains `thread_id` |
|
||||
| `item.completed` | Item finished, check for `agent_message` type |
|
||||
| `turn.failed` | Turn failed with error message |
|
||||
|
||||
### Event Structure
|
||||
|
||||
```typescript
|
||||
// thread.started
|
||||
{
|
||||
type: "thread.started",
|
||||
thread_id: "thread_abc123"
|
||||
}
|
||||
|
||||
// item.completed (agent message)
|
||||
{
|
||||
type: "item.completed",
|
||||
item: {
|
||||
type: "agent_message",
|
||||
text: "Response text"
|
||||
}
|
||||
}
|
||||
|
||||
// turn.failed
|
||||
{
|
||||
type: "turn.failed",
|
||||
error: {
|
||||
message: "Error description"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Response Schema
|
||||
|
||||
```typescript
|
||||
// CodexRunResultSchema
|
||||
type CodexRunResult = string | {
|
||||
result?: string;
|
||||
output?: string;
|
||||
message?: string;
|
||||
// ...additional fields via passthrough
|
||||
};
|
||||
```
|
||||
|
||||
Content is extracted in priority order: `result` > `output` > `message`
|
||||
|
||||
## Thread ID Retrieval
|
||||
|
||||
Thread ID can be obtained from multiple sources:
|
||||
|
||||
1. `thread.started` event's `thread_id` property
|
||||
2. Thread object's `id` getter (after first turn)
|
||||
3. Thread object's `threadId` or `_id` properties (fallbacks)
|
||||
|
||||
```typescript
|
||||
function getThreadId(thread: unknown): string | null {
|
||||
const value = thread as { id?: string; threadId?: string; _id?: string };
|
||||
return value.id ?? value.threadId ?? value._id ?? null;
|
||||
}
|
||||
```
|
||||
|
||||
## Agent Modes
|
||||
|
||||
Modes are implemented via prompt prefixing:
|
||||
|
||||
| Mode | Prompt Prefix |
|
||||
|------|---------------|
|
||||
| `build` | No prefix (default) |
|
||||
| `plan` | `"Make a plan before acting.\n\n"` |
|
||||
| `chat` | `"Answer conversationally.\n\n"` |
|
||||
|
||||
```typescript
|
||||
function withModePrefix(prompt: string, mode: AgentMode): string {
|
||||
if (mode === "plan") {
|
||||
return `Make a plan before acting.\n\n${prompt}`;
|
||||
}
|
||||
if (mode === "chat") {
|
||||
return `Answer conversationally.\n\n${prompt}`;
|
||||
}
|
||||
return prompt;
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
- `turn.failed` events are captured but don't throw
|
||||
- Thread ID is still returned on error for potential resumption
|
||||
- Events iterator may throw after errors - caught and logged
|
||||
|
||||
```typescript
|
||||
interface CodexPromptResult {
|
||||
result: unknown;
|
||||
threadId?: string | null;
|
||||
error?: string; // Set if turn failed
|
||||
}
|
||||
```
|
||||
|
||||
## Conversion to Universal Format
|
||||
|
||||
Codex output is converted via `convertCodexOutput()`:
|
||||
|
||||
1. Parse with `CodexRunResultSchema`
|
||||
2. If result is string, use directly
|
||||
3. Otherwise extract from `result`, `output`, or `message` fields
|
||||
4. Wrap as assistant message entry
|
||||
|
||||
## Session Continuity
|
||||
|
||||
- Thread ID persists across prompts
|
||||
- Use `resumeThread(threadId)` to continue conversation
|
||||
- Thread ID is captured from `thread.started` event or thread object
|
||||
|
||||
## Notes
|
||||
|
||||
- SDK is dynamically imported to reduce bundle size
|
||||
- No explicit timeout (relies on SDK defaults)
|
||||
- Thread ID may not be available until first event
|
||||
- Error messages are preserved for debugging
|
||||
- Working directory is not explicitly set (SDK handles internally)
|
||||
Loading…
Add table
Add a link
Reference in a new issue