Callbacks that render live tool-call progress inside a st.status container.
| 42 | |
| 43 | |
| 44 | class StreamlitProgress: |
| 45 | """Callbacks that render live tool-call progress inside a st.status container.""" |
| 46 | |
| 47 | def __init__(self, container): |
| 48 | self.status = container |
| 49 | self.tool_count = 0 |
| 50 | self.steps = [] # saved into message history |
| 51 | |
| 52 | def on_thinking(self): |
| 53 | self.status.update(label="Thinking...", state="running") |
| 54 | |
| 55 | def on_reasoning(self, text: str): |
| 56 | if text: |
| 57 | self.status.write(f"_{text}_") |
| 58 | self.steps.append({"label": "Reasoning", "detail": text}) |
| 59 | |
| 60 | def on_tool_start(self, tool_name: str, tool_args: dict): |
| 61 | self.tool_count += 1 |
| 62 | label = TOOL_LABELS.get(tool_name, tool_name) |
| 63 | self.status.update(label=f"{label}...", state="running") |
| 64 | |
| 65 | def on_tool_end(self, tool_name: str, result: str, success: bool = True): |
| 66 | label = TOOL_LABELS.get(tool_name, tool_name) |
| 67 | marker = "OK" if success else "FAIL" |
| 68 | preview = _summarize_result(tool_name, result) |
| 69 | self.status.write(f"[{marker}] **{label}** — {preview}") |
| 70 | self.steps.append({"label": label, "detail": f"[{marker}] {preview}"}) |
| 71 | |
| 72 | def on_approval_skipped(self, tool_name: str, tool_args: dict): |
| 73 | label = TOOL_LABELS.get(tool_name, tool_name) |
| 74 | self.status.write(f"[BLOCKED] **{label}** — requires your approval") |
| 75 | self.steps.append({"label": label, "detail": "[BLOCKED] requires approval"}) |
| 76 | |
| 77 | def complete(self): |
| 78 | n = self.tool_count |
| 79 | if n: |
| 80 | self.status.update( |
| 81 | label=f"Done — {n} tool{'s' if n != 1 else ''} used", |
| 82 | state="complete", expanded=False, |
| 83 | ) |
| 84 | else: |
| 85 | self.status.update(label="Done", state="complete", expanded=False) |
| 86 | |
| 87 | def error(self, msg: str): |
| 88 | self.status.update(label="Error", state="error") |
| 89 | self.status.write(f"Error: {msg}") |
| 90 | |
| 91 | |
| 92 | def _summarize_result(tool_name: str, result: str) -> str: |