@brainpilot/web 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/assets/index-Br55rkHb.css +1 -0
  2. package/dist/assets/index-CeUzk-ej.js +445 -0
  3. package/dist/index.html +2 -2
  4. package/package.json +5 -2
  5. package/src/__tests__/agentsReducer.test.ts +67 -0
  6. package/src/__tests__/api.test.ts +118 -0
  7. package/src/__tests__/chatScrollMemory.test.ts +49 -0
  8. package/src/__tests__/demoConversation.test.ts +73 -0
  9. package/src/__tests__/demoReset.test.ts +24 -0
  10. package/src/__tests__/runningToast.test.ts +29 -0
  11. package/src/__tests__/tokenUsage.test.ts +48 -0
  12. package/src/__tests__/toolDisplay.test.ts +55 -0
  13. package/src/__tests__/traceReducer.test.ts +62 -0
  14. package/src/components/chat/MessageStream.tsx +97 -56
  15. package/src/components/chat/PromptComposer.tsx +120 -29
  16. package/src/components/chat/chatScrollMemory.ts +49 -0
  17. package/src/components/demo/DemoView.tsx +91 -29
  18. package/src/components/demo/TraceNodeModal.tsx +6 -2
  19. package/src/components/demo/demoBundle.ts +7 -2
  20. package/src/components/demo/demoReset.ts +16 -0
  21. package/src/components/session/AgentNetwork.tsx +68 -75
  22. package/src/components/session/AgentTraceViews.tsx +35 -70
  23. package/src/components/session/AnalyticsTab.tsx +58 -224
  24. package/src/components/session/TraceGraphView.tsx +36 -30
  25. package/src/components/session/TraceNodeDetail.tsx +61 -24
  26. package/src/components/session/agentNetworkShared.ts +10 -0
  27. package/src/components/session/traceLayout.ts +32 -0
  28. package/src/components/settings/SettingsDialog.tsx +19 -1
  29. package/src/components/shell/DesktopShell.tsx +39 -14
  30. package/src/components/sidebar/Sidebar.tsx +6 -2
  31. package/src/contexts/SSEContext.tsx +90 -1
  32. package/src/contexts/SessionContext.tsx +354 -43
  33. package/src/contexts/agentsReducer.ts +49 -0
  34. package/src/contexts/runningToast.ts +33 -0
  35. package/src/contexts/traceReducer.ts +62 -0
  36. package/src/contexts/turnTimer.test.ts +97 -0
  37. package/src/contexts/turnTimer.ts +108 -0
  38. package/src/contexts/useTurnTimer.ts +104 -0
  39. package/src/contracts/backend.ts +53 -2
  40. package/src/i18n/messages/analytics.ts +16 -6
  41. package/src/i18n/messages/chat.ts +26 -4
  42. package/src/i18n/messages/contexts.ts +2 -0
  43. package/src/i18n/messages/network.ts +13 -9
  44. package/src/i18n/messages/profile.ts +4 -0
  45. package/src/i18n/messages/settings.ts +4 -0
  46. package/src/i18n/messages/trace.ts +69 -17
  47. package/src/mocks/backend.ts +7 -0
  48. package/src/styles/global.css +204 -55
  49. package/src/utils/api.ts +105 -8
  50. package/src/utils/toolDisplay.ts +74 -0
  51. package/dist/assets/index-C-8G4D4j.js +0 -448
  52. package/dist/assets/index-C501m5OS.css +0 -1
@@ -12,8 +12,9 @@ export default defineMessages(
12
12
  "network.legend.dormant": "休眠",
13
13
  "network.legend.error": "错误",
14
14
  "network.legend.delegate": "委派",
15
- "network.legend.result": "结果",
16
- "network.legend.counter": "{live}/{total} 在线 · {running} 运行中 · {edges} 条连线 · {msgs} 条消息",
15
+ "network.legend.result": "结果",
16
+ "network.legend.counter": "{live} 个参与 · {running} 运行中 · {edges} 条连线 · {msgs} 条消息",
17
+ "network.available.summary": "{count} 个可用但未参与的 Agent",
17
18
 
18
19
  // Aria labels
19
20
  "network.aria.legend": "网络图例",
@@ -47,9 +48,10 @@ export default defineMessages(
47
48
  "network.detail.responsibility": "职责",
48
49
  "network.detail.status": "状态",
49
50
  "network.detail.state": "状态",
50
- "network.detail.currentTask": "当前任务",
51
- "network.detail.idleWaiting": "空闲 — 等待指令",
52
- "network.detail.notSpawnedByPrincipal": "尚未由 Principal 创建",
51
+ "network.detail.currentTask": "当前任务",
52
+ "network.detail.idleWaiting": "空闲 — 等待指令",
53
+ "network.detail.runningTask": "正在处理任务",
54
+ "network.detail.notSpawnedByPrincipal": "尚未由 Principal 创建",
53
55
  "network.detail.updated": "更新于",
54
56
  "network.detail.communication": "通信",
55
57
  "network.detail.commCount": "{sent} 已发送 · {received} 已接收",
@@ -107,7 +109,8 @@ export default defineMessages(
107
109
  "network.legend.error": "error",
108
110
  "network.legend.delegate": "delegate",
109
111
  "network.legend.result": "result",
110
- "network.legend.counter": "{live}/{total} live · {running} running · {edges} edges · {msgs} msgs",
112
+ "network.legend.counter": "{live} active · {running} running · {edges} links · {msgs} messages",
113
+ "network.available.summary": "{count} available agents not used",
111
114
 
112
115
  "network.aria.legend": "Network legend",
113
116
  "network.aria.viewport": "Agent collaboration network",
@@ -136,9 +139,10 @@ export default defineMessages(
136
139
  "network.detail.responsibility": "Responsibility",
137
140
  "network.detail.status": "Status",
138
141
  "network.detail.state": "State",
139
- "network.detail.currentTask": "Current task",
140
- "network.detail.idleWaiting": "Idle — waiting for instructions",
141
- "network.detail.notSpawnedByPrincipal": "Not yet spawned by Principal",
142
+ "network.detail.currentTask": "Current task",
143
+ "network.detail.idleWaiting": "Idle — waiting for instructions",
144
+ "network.detail.runningTask": "Working on the task",
145
+ "network.detail.notSpawnedByPrincipal": "Not yet spawned by Principal",
142
146
  "network.detail.updated": "Updated",
143
147
  "network.detail.communication": "Communication",
144
148
  "network.detail.commCount": "{sent} sent · {received} received",
@@ -14,6 +14,8 @@ export default defineMessages(
14
14
  "profile.engineer.desc": "将科学意图转化为可运行的代码,管理环境、数据管线、统计计算与可视化,并保证可复现性。",
15
15
  "profile.writer.role": "科学写作 · 报告",
16
16
  "profile.writer.desc": "将研究发现转化为清晰、严谨的论文、文档与报告,并针对受众进行调整。",
17
+ "profile.auditor.role": "稽核 · 杜撰检测",
18
+ "profile.auditor.desc": "在主研究员交付前,依据会话的真实执行记录(Bash 输出、文件写入、轨迹图、信箱)逐条核验报告中的数字、文件路径与外部引用,标记无证据支撑的杜撰主张。仅核对“主张是否有证据”,不评判科学正确性;为顾问角色,最终由主研究员决定是否采纳。",
17
19
  "profile.user.role": "人类用户",
18
20
  "profile.user.desc": "通过聊天提示驱动会话的人类研究者。",
19
21
  "profile.default.role": "专家 · 领域 Agent",
@@ -32,6 +34,8 @@ export default defineMessages(
32
34
  "profile.engineer.desc": "Translates scientific intent into working code, manages environments, data pipelines, statistical computation and visualization with reproducibility guarantees.",
33
35
  "profile.writer.role": "Scientific writing · Reporting",
34
36
  "profile.writer.desc": "Transforms research findings into clear, rigorous papers, documentation and reports tailored to the audience.",
37
+ "profile.auditor.role": "Audit · Fabrication detection",
38
+ "profile.auditor.desc": "Before the principal delivers its final report, cross-checks every numeric claim, file path and external citation against the session's actual execution record (Bash output, file writes, the Graph of Trace, the mailbox) and flags fabricated claims with no supporting evidence. Judges only whether claims match evidence, not scientific correctness; advisory — the principal makes the final call.",
35
39
  "profile.user.role": "Human user",
36
40
  "profile.user.desc": "The human researcher driving the session through chat prompts.",
37
41
  "profile.default.role": "Expert · Domain agent",
@@ -65,6 +65,8 @@ export default defineMessages(
65
65
  "settings.providerForm.close": "关闭服务商表单",
66
66
  "settings.providerForm.name": "服务商名称",
67
67
  "settings.providerForm.baseUrl": "基础 URL",
68
+ "settings.providerForm.protocol": "协议",
69
+ "settings.providerForm.protocolAria": "提供商协议",
68
70
  "settings.providerForm.apiKey": "API 密钥",
69
71
  "settings.providerForm.apiKeyKeep": "(留空则保持不变)",
70
72
  "settings.providerForm.hideKey": "隐藏 API 密钥",
@@ -153,6 +155,8 @@ export default defineMessages(
153
155
  "settings.providerForm.close": "Close provider form",
154
156
  "settings.providerForm.name": "Provider name",
155
157
  "settings.providerForm.baseUrl": "Base URL",
158
+ "settings.providerForm.protocol": "Protocol",
159
+ "settings.providerForm.protocolAria": "Provider protocol",
156
160
  "settings.providerForm.apiKey": "API key",
157
161
  "settings.providerForm.apiKeyKeep": "(leave blank to keep current)",
158
162
  "settings.providerForm.hideKey": "Hide API key",
@@ -12,11 +12,26 @@ export default defineMessages(
12
12
  "trace.title": "Trace",
13
13
  "trace.loadFailed": "加载 Trace 失败",
14
14
  "trace.aria.layoutDir": "Trace 布局方向",
15
- "trace.aria.refreshControls": "Trace 刷新控制",
16
- "trace.aria.refresh": "刷新 Trace",
17
- "trace.autoRefreshTitle": "每 3 秒自动刷新 Trace",
18
- "trace.live": "实时",
19
- "trace.emptyNoSession": "创建或选择会话后,这里会显示任务分解和 Agent 协作轨迹。",
15
+ "trace.aria.refreshControls": "Trace 刷新控制",
16
+ "trace.aria.refresh": "刷新 Trace",
17
+ "trace.layout.horizontal": "横向",
18
+ "trace.layout.vertical": "纵向",
19
+ "trace.liveTitle": "Trace 随事件实时更新",
20
+ "trace.live": "实时",
21
+ "trace.node.auto": "自动捕获",
22
+ "trace.node.autoTitle": "由系统在回合结束时自动记录(非 Agent 主动调用)",
23
+ "trace.node.noneSelected": "尚未选择 Trace 节点。",
24
+ "trace.node.parentFallback": "上游任务",
25
+ "trace.node.tools": "{count} 个工具",
26
+ "trace.node.artifacts": "{count} 个产物",
27
+ "trace.node.dependencies": "依赖关系",
28
+ "trace.node.toolCalls": "工具调用",
29
+ "trace.node.error": "错误",
30
+ "trace.node.artifactsTitle": "产物",
31
+ "trace.node.timeline": "时间线",
32
+ "trace.node.created": "创建",
33
+ "trace.node.children": "后续任务",
34
+ "trace.emptyNoSession": "创建或选择会话后,这里会显示任务分解和 Agent 协作轨迹。",
20
35
  "trace.untitled": "未命名会话",
21
36
  "trace.focus": "聚焦:{focus}",
22
37
  "trace.nodes": "{visible}/{total} 个节点",
@@ -39,10 +54,21 @@ export default defineMessages(
39
54
  "trace.aria.pause": "暂停回放",
40
55
  "trace.aria.play": "开始回放",
41
56
  "trace.aria.playbackProgress": "回放进度",
42
- "trace.status.done": "完成",
43
- "trace.status.running": "进行中",
44
- },
45
- {
57
+ "trace.status.done": "完成",
58
+ "trace.status.running": "进行中",
59
+ "trace.kind.task": "任务",
60
+ "trace.kind.trace": "轨迹",
61
+ "trace.kind.action": "行动",
62
+ "trace.kind.observation": "观察",
63
+ "trace.kind.decision": "决策",
64
+ "trace.kind.milestone": "里程碑",
65
+ "trace.kind.validation": "验证",
66
+ "trace.kind.audit": "审计",
67
+ "trace.kind.writing": "写作",
68
+ "trace.kind.research": "研究",
69
+ "trace.kind.step": "步骤",
70
+ },
71
+ {
46
72
  "trace.agents.eyebrow": "Live agent network",
47
73
  "trace.agents.title": "Agents",
48
74
  "trace.agents.emptyNoSession": "Once you create or select a session, the agents involved in the current task and the message flow between them will appear here.",
@@ -51,11 +77,26 @@ export default defineMessages(
51
77
  "trace.title": "Trace",
52
78
  "trace.loadFailed": "Failed to load trace",
53
79
  "trace.aria.layoutDir": "Trace layout direction",
54
- "trace.aria.refreshControls": "Trace refresh controls",
55
- "trace.aria.refresh": "Refresh trace",
56
- "trace.autoRefreshTitle": "Refresh trace automatically every 3 seconds",
57
- "trace.live": "Live",
58
- "trace.emptyNoSession": "Once you create or select a session, the task breakdown and agent collaboration trace will appear here.",
80
+ "trace.aria.refreshControls": "Trace refresh controls",
81
+ "trace.aria.refresh": "Refresh trace",
82
+ "trace.layout.horizontal": "Horizontal",
83
+ "trace.layout.vertical": "Vertical",
84
+ "trace.liveTitle": "Trace updates live as events arrive",
85
+ "trace.live": "Live",
86
+ "trace.node.auto": "Auto-captured",
87
+ "trace.node.autoTitle": "Recorded automatically at turn end by the system (not an explicit agent call)",
88
+ "trace.node.noneSelected": "No trace node selected.",
89
+ "trace.node.parentFallback": "Upstream task",
90
+ "trace.node.tools": "{count} tools",
91
+ "trace.node.artifacts": "{count} artifacts",
92
+ "trace.node.dependencies": "Dependencies",
93
+ "trace.node.toolCalls": "Tool calls",
94
+ "trace.node.error": "Error",
95
+ "trace.node.artifactsTitle": "Artifacts",
96
+ "trace.node.timeline": "Timeline",
97
+ "trace.node.created": "Created",
98
+ "trace.node.children": "Next tasks",
99
+ "trace.emptyNoSession": "Once you create or select a session, the task breakdown and agent collaboration trace will appear here.",
59
100
  "trace.untitled": "Untitled session",
60
101
  "trace.focus": "Focus: {focus}",
61
102
  "trace.nodes": "{visible}/{total} nodes",
@@ -78,7 +119,18 @@ export default defineMessages(
78
119
  "trace.aria.pause": "Pause playback",
79
120
  "trace.aria.play": "Play playback",
80
121
  "trace.aria.playbackProgress": "Playback progress",
81
- "trace.status.done": "done",
82
- "trace.status.running": "running",
83
- },
122
+ "trace.status.done": "done",
123
+ "trace.status.running": "running",
124
+ "trace.kind.task": "Task",
125
+ "trace.kind.trace": "Trace",
126
+ "trace.kind.action": "Action",
127
+ "trace.kind.observation": "Observation",
128
+ "trace.kind.decision": "Decision",
129
+ "trace.kind.milestone": "Milestone",
130
+ "trace.kind.validation": "Validation",
131
+ "trace.kind.audit": "Audit",
132
+ "trace.kind.writing": "Writing",
133
+ "trace.kind.research": "Research",
134
+ "trace.kind.step": "Step",
135
+ },
84
136
  );
@@ -73,6 +73,9 @@ let mockProviders: ProviderProfile[] = [
73
73
  id: "provider-anthropic",
74
74
  name: "Anthropic",
75
75
  baseUrl: "https://api.anthropic.com",
76
+ api: "anthropic-messages",
77
+ adapter: "anthropic",
78
+ isShared: false,
76
79
  models: ["claude-sonnet-4-6", "claude-opus-4-6", "claude-haiku-4-5-20251001"],
77
80
  icon: "sparkles",
78
81
  iconColor: "#111111",
@@ -502,6 +505,9 @@ export const mockBackend = {
502
505
  id: crypto.randomUUID(),
503
506
  name: data.name,
504
507
  baseUrl: data.baseUrl,
508
+ api: data.api ?? "anthropic-messages",
509
+ adapter: data.adapter ?? "auto",
510
+ isShared: false,
505
511
  models: data.models || [],
506
512
  icon: data.icon || "circle",
507
513
  iconColor: data.iconColor || "#111111",
@@ -529,6 +535,7 @@ export const mockBackend = {
529
535
  ...profile,
530
536
  ...(data.name !== undefined ? { name: data.name } : {}),
531
537
  ...(data.baseUrl !== undefined ? { baseUrl: data.baseUrl } : {}),
538
+ ...(data.api !== undefined ? { api: data.api } : {}),
532
539
  ...(data.models !== undefined ? { models: data.models } : {}),
533
540
  ...(data.icon !== undefined ? { icon: data.icon } : {}),
534
541
  ...(data.iconColor !== undefined ? { iconColor: data.iconColor } : {}),
@@ -669,6 +669,15 @@ button {
669
669
  outline: none;
670
670
  }
671
671
 
672
+ /* #104: icon-only nav — square buttons, no horizontal text weight. The label
673
+ lives in a .sr-only span so the accessible name is preserved. */
674
+ .workspace-view-tabs--icon-only button {
675
+ width: 28px;
676
+ justify-content: center;
677
+ gap: 0;
678
+ padding: 0;
679
+ }
680
+
672
681
  .session-title {
673
682
  display: flex;
674
683
  min-width: 0;
@@ -691,9 +700,10 @@ button {
691
700
  white-space: nowrap;
692
701
  }
693
702
 
703
+ /* #105: id demoted to muted secondary metadata beside the real title. */
694
704
  .session-title__id {
695
- color: var(--color-text-muted);
696
- font-size: 12px;
705
+ color: var(--color-text-subtle);
706
+ font-size: 11px;
697
707
  font-family: var(--font-mono);
698
708
  }
699
709
 
@@ -858,44 +868,24 @@ button {
858
868
  border-radius: 0;
859
869
  }
860
870
 
861
- .trace-live-toggle {
871
+ /* #79: trace is live-by-SSE — a static "Live" indicator, not a poll toggle. */
872
+ .trace-live-indicator {
862
873
  display: inline-flex;
863
874
  height: 28px;
864
875
  align-items: center;
865
876
  gap: 6px;
866
- border: 0;
867
- background: transparent;
868
- color: var(--color-text-muted);
877
+ color: var(--color-text);
869
878
  padding: 0 9px;
870
879
  font-size: 12px;
871
880
  }
872
881
 
873
- .trace-live-toggle span {
882
+ .trace-live-indicator span {
874
883
  width: 7px;
875
884
  height: 7px;
876
885
  border-radius: 999px;
877
- background: var(--color-text-subtle);
878
- }
879
-
880
- .trace-live-toggle.is-active {
881
- color: var(--color-text);
882
- }
883
-
884
- .trace-live-toggle.is-active span {
885
886
  background: var(--color-success);
886
887
  }
887
888
 
888
- .trace-live-toggle:hover:not(:disabled),
889
- .trace-live-toggle:focus-visible {
890
- background: var(--color-hover);
891
- color: var(--color-text);
892
- outline: none;
893
- }
894
-
895
- .trace-live-toggle:disabled {
896
- opacity: 0.5;
897
- }
898
-
899
889
  .agent-grid {
900
890
  display: grid;
901
891
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
@@ -1168,8 +1158,8 @@ button {
1168
1158
 
1169
1159
  .trace-edge path {
1170
1160
  fill: none;
1171
- stroke: var(--color-border-strong);
1172
- stroke-width: 1.35;
1161
+ stroke: color-mix(in srgb, var(--color-accent) 55%, var(--color-border-strong));
1162
+ stroke-width: 2;
1173
1163
  marker-end: url("#trace-arrow");
1174
1164
  }
1175
1165
 
@@ -1182,6 +1172,10 @@ button {
1182
1172
  stroke: var(--color-success);
1183
1173
  }
1184
1174
 
1175
+ .trace-edge--follows path {
1176
+ stroke: color-mix(in srgb, var(--color-accent) 50%, var(--color-border-strong));
1177
+ }
1178
+
1185
1179
  .trace-edge-label rect {
1186
1180
  fill: var(--color-surface-raised);
1187
1181
  stroke: var(--color-border-strong);
@@ -1199,7 +1193,7 @@ button {
1199
1193
  }
1200
1194
 
1201
1195
  #trace-arrow path {
1202
- fill: var(--color-border-strong);
1196
+ fill: color-mix(in srgb, var(--color-accent) 55%, var(--color-border-strong));
1203
1197
  }
1204
1198
 
1205
1199
  .trace-map-node {
@@ -1512,6 +1506,13 @@ button {
1512
1506
  font-size: 11px;
1513
1507
  }
1514
1508
 
1509
+ /* #79: auto-captured (hook-driven) trace nodes get a distinct badge. */
1510
+ .trace-detail__badges span.trace-detail__badge--auto {
1511
+ border-color: color-mix(in srgb, var(--color-success) 45%, var(--color-border));
1512
+ background: color-mix(in srgb, var(--color-success) 14%, transparent);
1513
+ color: var(--color-success);
1514
+ }
1515
+
1515
1516
  .trace-detail__section {
1516
1517
  display: grid;
1517
1518
  gap: 8px;
@@ -1622,6 +1623,37 @@ button {
1622
1623
  white-space: nowrap;
1623
1624
  }
1624
1625
 
1626
+ .trace-detail__children {
1627
+ display: flex;
1628
+ flex-wrap: wrap;
1629
+ gap: 5px;
1630
+ overflow: visible !important;
1631
+ white-space: normal !important;
1632
+ }
1633
+
1634
+ .trace-detail__children button {
1635
+ display: inline-flex;
1636
+ min-width: 0;
1637
+ max-width: 100%;
1638
+ height: 24px;
1639
+ align-items: center;
1640
+ border: 1px solid var(--color-border);
1641
+ border-radius: 999px;
1642
+ background: var(--color-surface-soft);
1643
+ color: var(--color-text-muted);
1644
+ padding: 0 8px;
1645
+ font: inherit;
1646
+ font-size: 11px;
1647
+ }
1648
+
1649
+ .trace-detail__children button:hover,
1650
+ .trace-detail__children button:focus-visible {
1651
+ border-color: var(--color-border-strong);
1652
+ background: var(--color-hover);
1653
+ color: var(--color-text);
1654
+ outline: none;
1655
+ }
1656
+
1625
1657
  .prompt-home__inner {
1626
1658
  display: grid;
1627
1659
  width: min(var(--composer-width), 100%);
@@ -1700,6 +1732,48 @@ button {
1700
1732
  gap: 4px;
1701
1733
  }
1702
1734
 
1735
+ /* #47: uploaded-file chips shown between the input and the toolbar. */
1736
+ .composer__attachments {
1737
+ display: flex;
1738
+ flex-wrap: wrap;
1739
+ gap: 6px;
1740
+ padding: 0 8px 4px;
1741
+ }
1742
+ .composer__chip {
1743
+ display: inline-flex;
1744
+ align-items: center;
1745
+ gap: 4px;
1746
+ max-width: 220px;
1747
+ padding: 2px 6px 2px 8px;
1748
+ border-radius: 999px;
1749
+ font-size: 12px;
1750
+ line-height: 1.4;
1751
+ background: var(--surface-2, rgba(127, 127, 127, 0.12));
1752
+ color: var(--text-2, inherit);
1753
+ }
1754
+ .composer__chip--pending {
1755
+ opacity: 0.7;
1756
+ }
1757
+ .composer__chip-name {
1758
+ overflow: hidden;
1759
+ text-overflow: ellipsis;
1760
+ white-space: nowrap;
1761
+ }
1762
+ .composer__chip-remove {
1763
+ display: inline-flex;
1764
+ align-items: center;
1765
+ justify-content: center;
1766
+ padding: 0;
1767
+ border: 0;
1768
+ background: transparent;
1769
+ color: inherit;
1770
+ cursor: pointer;
1771
+ opacity: 0.6;
1772
+ }
1773
+ .composer__chip-remove:hover {
1774
+ opacity: 1;
1775
+ }
1776
+
1703
1777
  .toolbar-select {
1704
1778
  padding: 0 8px;
1705
1779
  font-size: 13px;
@@ -2173,34 +2247,31 @@ button {
2173
2247
  }
2174
2248
 
2175
2249
  .message-row--live .message-row__body::after {
2176
- content: "";
2177
- position: absolute;
2178
- inset: 0;
2179
- pointer-events: none;
2180
- border-radius: var(--radius-md);
2181
- background: linear-gradient(
2182
- 100deg,
2183
- transparent 30%,
2184
- color-mix(in srgb, var(--color-info) 22%, transparent) 50%,
2185
- transparent 70%
2186
- );
2187
- background-size: 220% 100%;
2188
- animation: textSweep 1.4s linear infinite;
2250
+ content: none;
2189
2251
  }
2190
2252
 
2191
- @keyframes textSweep {
2192
- from {
2193
- background-position: 160% 0;
2194
- }
2195
- to {
2196
- background-position: -60% 0;
2197
- }
2253
+ .message-row__content {
2254
+ display: grid;
2255
+ min-width: 0;
2256
+ gap: 2px;
2198
2257
  }
2199
2258
 
2200
- @media (prefers-reduced-motion: reduce) {
2201
- .message-row--live .message-row__body::after {
2202
- animation: none;
2203
- background: none;
2259
+ .message-row__content--pending .message-card__content {
2260
+ color: var(--color-text-muted);
2261
+ }
2262
+
2263
+ .message-row__streaming-cursor {
2264
+ display: inline-block;
2265
+ width: 7px;
2266
+ height: 15px;
2267
+ border-radius: 2px;
2268
+ background: var(--color-info);
2269
+ opacity: 0.82;
2270
+ }
2271
+
2272
+ @media (prefers-reduced-motion: no-preference) {
2273
+ .message-row__streaming-cursor {
2274
+ animation: pulse 1.1s infinite;
2204
2275
  }
2205
2276
  }
2206
2277
 
@@ -2725,7 +2796,13 @@ button {
2725
2796
  background: var(--color-surface-soft);
2726
2797
  border: 1px solid var(--color-border);
2727
2798
  border-radius: 4px;
2728
- padding: 1px 4px;
2799
+ /* em-based padding scales with the (0.92em) code font; box-decoration-break
2800
+ keeps the border/radius/background intact on every fragment when an inline
2801
+ code span wraps across lines, instead of slicing into vertically-overflowing
2802
+ boxes that overlap adjacent lines (#130). */
2803
+ padding: 0.1em 0.35em;
2804
+ -webkit-box-decoration-break: clone;
2805
+ box-decoration-break: clone;
2729
2806
  }
2730
2807
 
2731
2808
  .message-card__content pre {
@@ -2865,6 +2942,22 @@ button {
2865
2942
  font-size: 12px;
2866
2943
  }
2867
2944
 
2945
+ /* #84: label each tool payload as Args / Result so the two stacked <pre>
2946
+ blocks are distinguishable. Label is intentionally low-weight — it's a
2947
+ separator signal, not a heading. */
2948
+ .activity-step__io {
2949
+ display: grid;
2950
+ gap: 4px;
2951
+ }
2952
+
2953
+ .activity-step__io-label {
2954
+ color: var(--color-text-muted);
2955
+ font-size: 11px;
2956
+ padding-left: 2px;
2957
+ text-transform: uppercase;
2958
+ letter-spacing: 0.04em;
2959
+ }
2960
+
2868
2961
  .terminal-input {
2869
2962
  display: grid;
2870
2963
  grid-template-columns: auto minmax(0, 1fr);
@@ -5097,6 +5190,52 @@ button {
5097
5190
  font-size: 11px;
5098
5191
  }
5099
5192
 
5193
+ .agent-network__available {
5194
+ border: 1px solid var(--color-border);
5195
+ border-radius: var(--radius-sm);
5196
+ background: var(--color-surface);
5197
+ color: var(--color-text-muted);
5198
+ padding: 7px 10px;
5199
+ font-size: 11px;
5200
+ }
5201
+
5202
+ .agent-network__available summary {
5203
+ cursor: pointer;
5204
+ list-style: none;
5205
+ }
5206
+
5207
+ .agent-network__available summary::-webkit-details-marker {
5208
+ display: none;
5209
+ }
5210
+
5211
+ .agent-network__available summary::before {
5212
+ content: ">";
5213
+ display: inline-block;
5214
+ margin-right: 6px;
5215
+ color: var(--color-text-subtle);
5216
+ transition: transform var(--ease-standard);
5217
+ }
5218
+
5219
+ .agent-network__available[open] summary::before {
5220
+ transform: rotate(90deg);
5221
+ }
5222
+
5223
+ .agent-network__available ul {
5224
+ display: flex;
5225
+ flex-wrap: wrap;
5226
+ gap: 5px;
5227
+ margin: 8px 0 0;
5228
+ padding: 0;
5229
+ list-style: none;
5230
+ }
5231
+
5232
+ .agent-network__available li {
5233
+ border: 1px dashed var(--color-border-strong);
5234
+ border-radius: 999px;
5235
+ color: var(--color-text-subtle);
5236
+ padding: 2px 7px;
5237
+ }
5238
+
5100
5239
  .agent-network__legend-dot {
5101
5240
  display: inline-block;
5102
5241
  width: 8px;
@@ -6395,6 +6534,17 @@ button {
6395
6534
  .agent-analytics__chart-title svg {
6396
6535
  color: var(--color-text-subtle);
6397
6536
  }
6537
+ .agent-analytics__token-total {
6538
+ font-size: 22px;
6539
+ font-weight: 700;
6540
+ color: var(--color-text);
6541
+ margin: 2px 0 8px;
6542
+ }
6543
+ .agent-analytics__token-total-label {
6544
+ font-size: 12px;
6545
+ font-weight: 500;
6546
+ color: var(--color-text-muted);
6547
+ }
6398
6548
  .agent-analytics__svg {
6399
6549
  width: 100%;
6400
6550
  height: auto;
@@ -7426,4 +7576,3 @@ button {
7426
7576
  .demo-right { border-bottom: 1px solid var(--color-border); }
7427
7577
  .demo-landing__cards { grid-template-columns: 1fr; }
7428
7578
  }
7429
-