personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 393 lines 16 kB view raw view rendered
1# Cortex API and Eventing 2 3The Cortex system manages AI talent execution through the Callosum message bus with file-based persistence. It acts as a process manager for talent instances, receiving requests via Callosum and writing execution events to both JSONL files (for persistence) and the message bus (for real-time distribution). 4 5For details on the Callosum protocol and message format, see [CALLOSUM.md](CALLOSUM.md). 6 7## Architecture 8 9### Event Flow 101. **Request Creation**: Client calls `cortex_request()` which broadcasts to Callosum (`tract="cortex"`, `event="request"`) 112. **Request Reception**: Cortex receives message via Callosum callback and creates `<name>/<timestamp>_active.jsonl` 123. **Talent Spawning**: Cortex spawns a talent process via `python -m think.talents` with merged configuration 134. **Event Emission**: Talents write JSON events to stdout (captured by Cortex) 145. **Event Distribution**: Cortex appends events to JSONL file AND broadcasts to Callosum 156. **Agent Completion**: Cortex renames file to `<name>/<timestamp>.jsonl` when agent finishes 16 17### Key Components 18- **Message Bus Integration**: Cortex connects to Callosum to receive requests and broadcast events 19- **Process Management**: Spawns talent subprocesses (both tool talents and generators) 20- **Configuration Delegation**: Passes raw requests to `python -m think.talents`, which handles all config loading, validation, and hydration 21- **Event Capture**: Monitors agent stdout/stderr and appends to JSONL files 22- **Dual Event Distribution**: Events go to both persistent files and real-time message bus 23- **NDJSON Input Mode**: Agent processes accept newline-delimited JSON via stdin containing the full merged configuration 24 25### File States 26- `<name>/<timestamp>_active.jsonl`: Talent currently executing (Cortex is appending events) 27- `<name>/<timestamp>.jsonl`: Talent completed (contains full event history) 28 29**Note**: Files provide persistence and historical record, while Callosum provides real-time event distribution to all interested services. 30 31## Request Format 32 33Requests are created via `cortex_request()` from `think.cortex_client`, which broadcasts to Callosum. The request message follows this format: 34 35```json 36{ 37 "event": "request", 38 "ts": 1234567890123, // Required: millisecond timestamp (must match use_id in filename) 39 "prompt": "Analyze this code for security issues", // Required for talents (not generators) 40 "name": "default", // Optional: talent name from talent/*.md 41 "provider": "openai", // Optional: override provider (openai, google, anthropic) 42 "max_output_tokens": 8192, // Optional: maximum response tokens 43 "thinking_budget": 10000, // Optional: thinking token budget (ignored by OpenAI) 44 "session_id": "sess-abc123", // Optional: CLI session ID for continuation 45 "chat_id": "1234567890122", // Optional: chat ID for reverse lookup 46 "facet": "my-project", // Optional: project context 47 "output": "md", // Optional: output format ("md" or "json"), writes to talents/ 48 "day": "20250109", // Optional: YYYYMMDD format, defaults to current day 49 "env": { // Optional: environment variables for subprocess 50 "API_KEY": "secret", 51 "DEBUG": "true" 52 } 53} 54``` 55 56The model is automatically resolved based on the talent context (`talent.{source}.{name}`) 57and the configured tier in `journal.json`. Provider can optionally be overridden at 58request time, which will resolve the appropriate model for that provider at the same tier. 59 60## Generator Request Format 61 62Generators are spawned via Cortex when a request has an `output` field but no `tools` field. They produce analysis output (markdown or JSON) from clustered transcripts. 63 64```json 65{ 66 "event": "request", 67 "ts": 1234567890123, // Required: millisecond timestamp 68 "name": "activity", // Required: generator name from talent/*.md 69 "day": "20250109", // Required: day in YYYYMMDD format 70 "output": "md", // Required: output format ("md" or "json") 71 "segment": "120000_300", // Optional: single segment key (HHMMSS_duration) 72 "span": ["120000_300", "120500_300"], // Optional: list of sequential segment keys 73 "output_path": "/path/to/file.md", // Optional: override output location 74 "refresh": false, // Optional: regenerate even if output exists 75 "provider": "google", // Optional: AI provider override 76 "model": "gemini-2.0-flash" // Optional: model override 77} 78``` 79 80### Generator Events 81 82Generators emit the same event types as talents: 83- `start` - When generation begins 84- `finish` - On completion, with `result` containing generated content 85- `error` - On failure 86 87The `finish` event may include a `skipped` field when generation is skipped: 88- `"no_input"` - Insufficient transcript content to analyze 89- `"disabled"` - Generator is marked as disabled in frontmatter 90 91### Conversation Continuations 92 93All providers (Anthropic, OpenAI, Google) support continuing conversations via CLI 94session resumption. Include a `session_id` field in the request with the CLI session 95ID from a previous talent's finish event. The provider CLI tool resumes the conversation 96internally using its native session management (e.g., `claude --resume`, `codex exec resume`). 97 98Chats are locked to their original provider — continuations must use the same provider 99that started the conversation. The `chat_id` field enables reverse lookup from an 100talent back to its parent chat. 101 102## Agent Event Format 103 104All subsequent lines are JSON objects with `event` and millisecond `ts` fields. The `ts` field is automatically added by Cortex if not provided by the provider. Additionally, Cortex automatically adds an `use_id` field (matching the timestamp component in the filename) to all events for tracking purposes. 105 106### request 107The initial spawn request (first line of file, written by client). 108```json 109{ 110 "event": "request", 111 "ts": 1234567890123, 112 "use_id": "1234567890123", 113 "prompt": "User's task or question", 114 "provider": "openai", 115 "name": "default", 116 "output": "md", 117 "day": "20250109" 118} 119``` 120 121### start 122Emitted when a talent run begins. 123```json 124{ 125 "event": "start", 126 "ts": 1234567890123, 127 "use_id": "1234567890123", 128 "name": "default", 129 "model": "gpt-4o", 130 "session_id": "sess-abc", 131 "chat_id": "1234567890122" 132} 133``` 134 135### tool_start 136Emitted when a tool execution begins. 137```json 138{ 139 "event": "tool_start", 140 "ts": 1234567890123, 141 "use_id": "1234567890123", 142 "tool": "search_journal", 143 "args": {"query": "search terms", "limit": 10}, 144 "call_id": "search_journal-1" 145} 146``` 147 148### tool_end 149Emitted when a tool execution completes. 150```json 151{ 152 "event": "tool_end", 153 "ts": 1234567890123, 154 "use_id": "1234567890123", 155 "tool": "search_journal", 156 "args": {"query": "search terms"}, 157 "result": ["result", "array", "or", "object"], 158 "call_id": "search_journal-1" 159} 160``` 161 162### thinking 163Emitted when the model produces reasoning/thinking content (model-dependent, primarily o1 models). 164```json 165{ 166 "event": "thinking", 167 "ts": 1234567890123, 168 "use_id": "1234567890123", 169 "summary": "Model's internal reasoning about the task...", 170 "model": "o1-mini" 171} 172``` 173 174### talent_updated 175Emitted when control is handed off to a different agent (multi-agent scenarios). 176```json 177{ 178 "event": "talent_updated", 179 "ts": 1234567890123, 180 "use_id": "1234567890123", 181 "agent": "SpecializedAgent" 182} 183``` 184 185### finish 186Emitted when the talent run completes successfully. 187```json 188{ 189 "event": "finish", 190 "ts": 1234567890123, 191 "use_id": "1234567890123", 192 "result": "Final response text to the owner" 193} 194``` 195 196### error 197Emitted when an error occurs during execution. 198```json 199{ 200 "event": "error", 201 "ts": 1234567890123, 202 "use_id": "1234567890123", 203 "error": "Error message", 204 "trace": "Full stack trace..." 205} 206``` 207 208### info 209Emitted when non-JSON output is captured from agent stdout. 210```json 211{ 212 "event": "info", 213 "ts": 1234567890123, 214 "use_id": "1234567890123", 215 "message": "Non-JSON output line from agent" 216} 217``` 218 219## Tool Call Tracking 220 221Tool events use `call_id` to pair `tool_start` and `tool_end` events. This allows tracking: 222- Which tools are currently running 223- Tool execution duration 224- Tool inputs and outputs 225- Concurrent tool executions 226 227The frontend uses this to show real-time status updates as tools execute, changing from "running..." to "✓" when complete. 228 229## Agent Output 230 231When an agent completes successfully, its result can be automatically written to a file. This uses the same output path logic as generators. 232 233- Include an `output` field in the agent's frontmatter with the format ("md" or "json") 234- Output path is derived from agent name + format + schedule: 235 - Daily agents: `YYYYMMDD/talents/{name}.{ext}` 236 - Segment agents: `YYYYMMDD/{segment}/{name}.{ext}` 237- Writing occurs before completion 238- Write failures are logged but don't interrupt the agent flow 239- Commonly used for scheduled agents that generate daily reports 240 241## Talent Configuration 242 243Talents use configurations stored in the `talent/` directory. Each talent is a `.md` file containing: 244- JSON frontmatter with metadata and configuration 245- The talent-specific prompt and instructions in the content 246 247When spawning a talent: 2481. Cortex passes the raw request to `python -m think.talents` via stdin (NDJSON format) 2492. The talent process (`think/talents.py`) handles all config loading via `prepare_config()`: 250 - Loads talent configuration using `get_talent()` from `think/talent.py` 251 - Merges request parameters with talent defaults 252 - Resolves provider and model based on context 2533. The agent validates the config via `validate_config()` before execution 2544. Instructions are built with three components: 255 - `system_instruction`: `journal.md` (shared base prompt, cacheable) 256 - `extra_context`: Runtime context (facets, generators list, datetime) 257 - `user_instruction`: The agent's `.md` file content 258 259Agents define specialized behaviors and facet expertise. Available agents can be discovered using `get_talent_configs(type="cogitate")` or by listing files in the `talent/` directory. 260 261### Agent Configuration Options 262 263The JSON frontmatter for an agent can include: 264- `max_tokens`: Maximum response token limit 265- `schedule`: Scheduling configuration for automated execution 266 - `"daily"`: Run automatically at midnight each day 267- `priority`: Execution order for scheduled prompts (integer, **required** for scheduled prompts) 268 - Lower numbers run first (e.g., priority 10 runs before priority 40) 269 - See [THINK.md](THINK.md#unified-priority-execution) for priority bands 270- `multi_facet`: Boolean flag for facet-aware agents (default: false) 271 - When true, the agent is spawned once for each **active** facet (see Multi-Facet Agents section) 272 - Each instance receives a facet-specific prompt with the facet name 273 - Useful for creating per-facet reports, newsletters, or analyses 274- `always`: Override active facet detection for multi-facet agents (default: false) 275 - When true, agent runs for all non-muted facets regardless of activity 276- `env`: Environment variables to set for the agent subprocess (object) 277 - Keys are variable names, values are coerced to strings 278 - Request-level `env` overrides agent defaults 279 - Note: `SOLSTONE_JOURNAL` is inherited by Cortex from the managed wrapper / test fixture / sandbox env, and child processes inherit it through `os.environ` 280 281### Model Resolution 282 283Models are resolved automatically based on context and tier: 2841. Each talent config has a context pattern: `talent.{source}.{name}` (e.g., `talent.system.default`) 2852. The context determines the tier (pro/flash/lite) from `journal.json` or system defaults 2863. The tier + provider determines the actual model to use 287 288This allows controlling model selection via tier configuration rather than hardcoding models: 289```json 290{ 291 "providers": { 292 "contexts": { 293 "talent.system.default": {"tier": 1}, 294 "talent.*": {"tier": 2} 295 } 296 } 297} 298``` 299 300## Agent Providers 301 302The system supports multiple AI providers, each implementing the same event interface: 303 304- **OpenAI** (`think/providers/openai.py`): GPT models with OpenAI Agents SDK 305- **Google** (`think/providers/google.py`): Gemini models with Google AI SDK 306- **Anthropic** (`think/providers/anthropic.py`): Claude models with Anthropic SDK 307 308All providers: 309- Emit JSON events to stdout (one per line) 310- Are spawned as subprocesses by Cortex 311- Use consistent event structures across providers 312- Process events are written to stdout for Cortex to capture 313 314## Scheduled Agents and Generators 315 316Both agents and generators support scheduling via `sol think`. Agents have `"schedule": "daily"` and generators have `"schedule": "segment"` or `"schedule": "daily"`. 317 318### Execution Order 319Scheduled items run in priority order (lower numbers first): 3201. Items are sorted by their `priority` field (required for all scheduled prompts) 3212. Items with the same priority run in parallel, then think waits for completion 3223. After each generator completes, incremental indexing runs for its output 323 324**Priority bands (recommended):** 325- **10-30**: Generators (content-producing prompts) 326- **40-60**: Analysis agents 327- **90+**: Late-stage agents 328- **99**: Fun/optional prompts 329 330### Multi-Facet Agents 331When an agent has `"multi_facet": true`: 3321. The agent is spawned once for each **active** facet 3332. Each instance receives a prompt including the facet name 3343. The agent should call `get_facet(facet_name)` to load facet context 3354. This enables per-facet reports, newsletters, and analyses 336 337#### Daily Multi-Facet Agents 338 339**Active Facet Detection**: By default, daily multi-facet agents only run for facets that had activity the previous day. `think/facets.py:get_active_facets()` determines activity by scanning segment-level `facets.json` files from the previous day, not facet event files. This prevents unnecessary agent runs for inactive facets. 340 341To force an agent to run for all facets regardless of activity, set `"always": true`: 342 343```json 344{ 345 "title": "Facet Newsletter Generator", 346 "schedule": "daily", 347 "priority": 10, 348 "multi_facet": true 349} 350``` 351 352```json 353{ 354 "title": "Facet Auditor", 355 "schedule": "daily", 356 "multi_facet": true, 357 "always": true 358} 359``` 360 361#### Segment Multi-Facet Agents 362 363Segment agents can also be multi-facet. Active facets are determined from the `facets.json` output written by the facets generator (priority 90) during segment processing. 364 365```json 366{ 367 "title": "Facet Activity Tracker", 368 "schedule": "segment", 369 "multi_facet": true 370} 371``` 372 373The facets generator outputs an array of detected facets for each segment: 374```json 375[ 376 {"facet": "work", "activity": "Code review", "level": "high"}, 377 {"facet": "personal", "activity": "Email check", "level": "low"} 378] 379``` 380 381Multi-facet segment agents spawn once per non-muted facet in this array. Muted facets are filtered out, consistent with daily agent behavior. If no enabled facets are detected (empty array, missing file, or all facets muted), the agent simply doesn't spawn for that segment. 382 383**Note**: The `"always"` flag is not supported for segment agents since facet detection is inherent to the segment content. 384 385## Process Management 386 387The `sol supervisor` command provides process management for the Cortex ecosystem: 388- Starts and monitors the Cortex file watcher service 389- Handles process restarts on failure 390- Monitors system health indicators 391- Triggers `sol think` at midnight for daily processing (generators + agents) 392 393This is distinct from agent lifecycle management, which Cortex handles internally through file state transitions.