Spaces:
Sleeping
Sleeping
File size: 7,448 Bytes
116524e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | # Data Model: OpenClaw Integration
**Feature**: 001-openclaw-integration | **Date**: 2026-02-27
## Pipeline Steps
### LoadTracesStep (`ace/steps/load_traces.py`)
Generic step that reads a trace file from disk and puts raw content on `ctx.trace`.
| Attribute | Value |
|-----------|-------|
| `requires` | `frozenset({"sample"})` β `sample` is the file path (`str \| Path`) |
| `provides` | `frozenset({"trace"})` β raw file content (type depends on file format) |
**Behaviour**: Reads the file at `ctx.sample`, parses JSONL lines into `list[dict]`, places on `ctx.trace`. Skips unparseable lines gracefully.
### OpenClawToTraceStep (`ace/integrations/openclaw/to_trace.py`)
OpenClaw-specific step that converts raw JSONL events into a structured trace dict, preserving chronological order of queries, thinking, and tool uses.
| Attribute | Value |
|-----------|-------|
| `requires` | `frozenset({"trace"})` β raw `list[dict]` from LoadTracesStep |
| `provides` | `frozenset({"trace"})` β structured trace dict for ReflectStep |
**Behaviour**: Walks events in order, extracts message content items (text, thinking, toolCall, toolResult) preserving full content without truncation. Produces a trace dict with `{question, reasoning, answer, skill_ids, feedback, ground_truth}`. Transformation logic TBD (user will define separately).
## Entities
### SessionEvent
A single line from an OpenClaw JSONL transcript file.
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | `str` | yes | Event type: `"session"`, `"message"`, `"thinking_level_change"`, `"custom"` |
| `id` | `str` | yes | Unique event identifier |
| `parentId` | `str \| None` | no | Parent event ID for threading |
| `timestamp` | `str` | yes | ISO 8601 timestamp |
| `message` | `MessagePayload \| None` | no | Present when `type == "message"` |
| `version` | `int \| None` | no | Present when `type == "session"` |
| `cwd` | `str \| None` | no | Working directory (session events only) |
| `thinkingLevel` | `str \| None` | no | Present when `type == "thinking_level_change"` |
| `data` | `dict \| None` | no | Present when `type == "custom"` |
### MessagePayload
The `message` field within a `SessionEvent` of type `"message"`.
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `role` | `str` | yes | `"user"`, `"assistant"`, or `"toolResult"` |
| `content` | `list[ContentItem]` | yes | Array of content items |
| `api` | `str \| None` | no | API used (e.g., `"openai-completions"`) |
| `provider` | `str \| None` | no | Provider name (e.g., `"litellm"`) |
| `model` | `str \| None` | no | Model identifier |
| `usage` | `UsageInfo \| None` | no | Token/cost tracking |
| `stopReason` | `str \| None` | no | Why generation stopped |
| `timestamp` | `int \| None` | no | Unix timestamp (ms) |
### ContentItem
An individual content block within a message's content array.
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | `str` | yes | `"text"`, `"thinking"`, `"toolCall"`, `"toolResult"` |
| `text` | `str \| None` | no | Present when `type == "text"` |
| `thinking` | `str \| None` | no | Present when `type == "thinking"` |
| `id` | `str \| None` | no | Tool call ID (toolCall) |
| `name` | `str \| None` | no | Tool name (toolCall) |
| `arguments` | `dict \| None` | no | Tool arguments (toolCall) |
| `toolCallId` | `str \| None` | no | Matching call ID (toolResult) |
| `content` | `list[dict] \| None` | no | Result content (toolResult) |
### Trace (dict)
The structured representation placed on `ctx.trace` by `OpenClawToTraceStep`. This is a plain dict matching the TraceAnalyser's raw trace interface.
| Key | Type | Required | Description |
|-----|------|----------|-------------|
| `question` | `str` | yes | First user message in the session |
| `reasoning` | `str` | yes | Full chronological conversation: user messages, assistant responses, thinking (full), tool calls (full), tool results (full) |
| `answer` | `str` | yes | Last assistant text response |
| `skill_ids` | `list[str]` | yes | Always `[]` (no prior skills applied) |
| `feedback` | `str` | yes | Summary string (e.g., "Session completed with N tool calls") |
| `ground_truth` | `None` | yes | Always `None` (no ground truth for open-ended sessions) |
### Skillbook (existing)
Reused from `ace.core.skillbook.Skillbook`. No changes needed.
| Field | Type | Description |
|-------|------|-------------|
| `skills` | `dict[str, Skill]` | ID β Skill mapping |
| `sections` | `dict[str, list[str]]` | Section β skill IDs |
| `next_id` | `int` | Counter for new skill IDs |
| `similarity_decisions` | `dict` | Deduplication cache |
### Skill (existing)
Reused from `ace.core.skillbook.Skill`. No changes needed.
| Field | Type | Description |
|-------|------|-------------|
| `id` | `str` | Format: `{section}-{5-digit-counter}` |
| `section` | `str` | Category/domain |
| `content` | `str` | Strategy description |
| `justification` | `str` | Why this strategy is valuable |
| `evidence` | `str` | Source session evidence |
| `helpful` | `int` | Positive vote count |
| `harmful` | `int` | Negative vote count |
| `neutral` | `int` | Neutral vote count |
| `created_at` | `str` | ISO 8601 timestamp |
| `updated_at` | `str` | ISO 8601 timestamp |
| `status` | `str` | `"active"` or `"invalid"` |
### ProcessedLog
Plain text file tracking which sessions have been processed.
| Aspect | Detail |
|--------|--------|
| **Path** | `~/.openclaw/ace_processed.txt` |
| **Format** | Newline-delimited session filenames (sorted) |
| **Example** | `b3db607f-7ae8-4089-b806-44800e961672.jsonl\nc4ef912a-...jsonl\n` |
## Relationships
```text
LoadTracesStep:
ctx.sample (file path) β read JSONL β ctx.trace (list[dict] raw events)
OpenClawToTraceStep:
ctx.trace (list[dict] raw events) β convert β ctx.trace (structured trace dict)
Pipeline composition:
LoadTracesStep β OpenClawToTraceStep β ReflectStep β TagStep β UpdateStep β ApplyStep
SessionEvent (JSONL line)
βββ contains β MessagePayload
βββ contains β ContentItem[]
βββ text β user messages / assistant responses (full)
βββ thinking β reasoning content (full, no truncation)
βββ toolCall β tool invocation data (full)
βββ toolResult β tool output data (full)
Skillbook β save_to_file() β ace_skillbook.json
Skillbook β wrap_skillbook_context() β sync_to_agents_md() β AGENTS.md
Session filenames β ProcessedLog (ace_processed.txt)
```
## Validation Rules
1. **LoadTracesStep**: Skips unparseable JSONL lines. Returns empty list for empty/missing files.
2. **SessionEvent**: Events with `type != "message"` are skipped by OpenClawToTraceStep.
3. **MessagePayload**: Messages must have `role` in `{"user", "assistant"}` and non-empty `content` array.
4. **ContentItem**: Unknown `type` values are silently skipped.
5. **Trace**: Must have non-empty `question` (at least one user message). Sessions with no user messages produce `None` from OpenClawToTraceStep.
6. **No truncation**: Thinking content, tool call arguments, and tool results are all preserved in full per clarifications.
|