MCPcopy Create free account
hub / github.com/agentforce314/clawcodex / update_progress_from_message

Function update_progress_from_message

src/tasks/progress.py:123–190  ·  view source on GitHub ↗

Fold one assistant message into the tracker. Mirrors ``updateProgressFromMessage`` in ``LocalAgentTask.tsx:68-96``. Updates token counts (per the cumulative-vs-per-turn split), pushes one ``ToolActivity`` per non-blacklisted ``tool_use`` block, and drops the oldest activity on cap-5

(
    tracker: ProgressTracker,
    message: "AssistantMessage",
    *,
    resolve_activity_description: ActivityDescriptionResolver | None = None,
)

Source from the content-addressed store, hash-verified

121
122
123def update_progress_from_message(
124 tracker: ProgressTracker,
125 message: "AssistantMessage",
126 *,
127 resolve_activity_description: ActivityDescriptionResolver | None = None,
128) -> None:
129 """Fold one assistant message into the tracker.
130
131 Mirrors ``updateProgressFromMessage`` in ``LocalAgentTask.tsx:68-96``.
132 Updates token counts (per the cumulative-vs-per-turn split), pushes
133 one ``ToolActivity`` per non-blacklisted ``tool_use`` block, and
134 drops the oldest activity on cap-5 overflow.
135
136 Tolerant of missing/partial usage payloads — ``message.usage`` is
137 ``dict[str, Any] | None`` per ``src.types.messages``, and a stub
138 test message that omits it is a no-op for token accounting.
139 """
140 # Local imports defer the cycle: ``progress`` doesn't need to know
141 # about message types at module load.
142 from src.types.content_blocks import ToolUseBlock
143 from src.types.messages import AssistantMessage
144
145 if not isinstance(message, AssistantMessage):
146 return
147
148 usage = message.usage if isinstance(message.usage, dict) else None
149 if usage is not None:
150 # Cumulative-per-call inputs: include cache read/creation token
151 # counts so the total matches what the API billed for.
152 input_tokens = int(usage.get("input_tokens", 0) or 0)
153 cache_creation = int(usage.get("cache_creation_input_tokens", 0) or 0)
154 cache_read = int(usage.get("cache_read_input_tokens", 0) or 0)
155 tracker.latest_input_tokens = input_tokens + cache_creation + cache_read
156
157 tracker.cumulative_output_tokens += int(usage.get("output_tokens", 0) or 0)
158
159 content = message.content
160 if not isinstance(content, list):
161 return
162
163 for block in content:
164 if not isinstance(block, ToolUseBlock):
165 continue
166 tracker.tool_use_count += 1
167 if block.name in _PREVIEW_BLACKLIST:
168 # Counted in tool_use_count (chapter does the same) but
169 # omitted from the preview ring.
170 continue
171 block_input = getattr(block, "input", None)
172 if not isinstance(block_input, dict):
173 block_input = {}
174 description: str | None = None
175 if resolve_activity_description is not None:
176 try:
177 description = resolve_activity_description(block.name, block_input)
178 except Exception:
179 # A resolver bug must not poison the tracker.
180 description = None

Calls 3

ToolActivityClass · 0.85
getMethod · 0.45
appendMethod · 0.45