| 106 | * modes — `mode` only affects the `messages` array and which markers |
| 107 | * appear. */ |
| 108 | export function projectContext( |
| 109 | entries: ReadonlyArray<WireEntry>, |
| 110 | mode: 'model' | 'full' = 'model', |
| 111 | ): ContextProjection { |
| 112 | let messages: ProjectedMessage[] = []; |
| 113 | const usage: UsageTotals = { |
| 114 | byScope: { session: { ...ZERO }, turn: { ...ZERO } }, |
| 115 | byModel: {}, |
| 116 | }; |
| 117 | const config: ConfigSnapshot = {}; |
| 118 | let permissionMode: PermissionMode | null = null; |
| 119 | let planActive = false; |
| 120 | let planId: string | undefined; |
| 121 | let contextTokens = 0; |
| 122 | let goal: GoalSnapshot | null = null; |
| 123 | let swarm: { active: boolean; trigger?: string } = { active: false }; |
| 124 | let microCutoff = 0; |
| 125 | // Maps step.uuid → the assistant ProjectedMessage that step is filling in. |
| 126 | // Cleared on context.clear / context.apply_compaction. |
| 127 | let openSteps = new Map<string, ProjectedMessage>(); |
| 128 | |
| 129 | for (const entry of entries) { |
| 130 | const rec = entry.data; |
| 131 | switch (rec.type) { |
| 132 | case 'context.append_message': |
| 133 | messages.push({ |
| 134 | lineNo: entry.lineNo, |
| 135 | time: rec.time, |
| 136 | source: 'append_message', |
| 137 | message: rec.message, |
| 138 | toolStepUuids: [], |
| 139 | }); |
| 140 | break; |
| 141 | case 'context.append_loop_event': { |
| 142 | const ev = rec.event; |
| 143 | if (ev.type === 'step.begin') { |
| 144 | const message: ContextMessage = { |
| 145 | role: 'assistant', |
| 146 | content: [], |
| 147 | toolCalls: [], |
| 148 | }; |
| 149 | const projected: ProjectedMessage = { |
| 150 | lineNo: entry.lineNo, |
| 151 | time: rec.time, |
| 152 | source: 'append_message', |
| 153 | message, |
| 154 | toolStepUuids: [ev.uuid], |
| 155 | }; |
| 156 | messages.push(projected); |
| 157 | openSteps.set(ev.uuid, projected); |
| 158 | } else if (ev.type === 'content.part') { |
| 159 | const projected = openSteps.get(ev.stepUuid); |
| 160 | if (projected !== undefined) { |
| 161 | (projected.message.content as ContentPart[]).push(ev.part); |
| 162 | } |
| 163 | } else if (ev.type === 'tool.call') { |
| 164 | const projected = openSteps.get(ev.stepUuid); |
| 165 | if (projected !== undefined) { |