Skip to main content
Glama
demo_multi_source.py12.2 kB
#!/usr/bin/env python3 """多端混合 GUI 测试 Demo。 测试 shared/gui 模块在多端模式下的表现: - 显示来源标签 [GEMINI] [CODEX] [CLAUDE] - 侧边栏按来源分组 - 混合事件流按时间排序 这模拟 cli-agent-mcp 的最密集使用场景。 Usage: python tests/gui/demo_multi_source.py """ from __future__ import annotations import random import sys import threading import time from pathlib import Path # 添加 shared 到路径 SHARED_DIR = Path(__file__).parent.parent.parent / "shared" sys.path.insert(0, str(SHARED_DIR)) from gui import LiveViewer def generate_mixed_events() -> list[dict]: """生成混合多端事件流。 模拟并发场景:多个 session 交错产生事件。 """ gemini_session = "gemini-abc12345" codex_session = "019b25ad-271b-7d93" claude_session = "claude-xyz78901" events = [ # === 各端会话开始 === { "category": "lifecycle", "lifecycle_type": "session_start", "session_id": gemini_session, "model": "gemini-2.0-flash", "source": "gemini", "timestamp": "2025-12-16T10:30:00.000Z", }, { "category": "lifecycle", "lifecycle_type": "session_start", "session_id": codex_session, "source": "codex", "timestamp": "2025-12-16T10:30:00.100Z", }, { "category": "lifecycle", "lifecycle_type": "session_start", "session_id": claude_session, "model": "claude-opus-4-5-20251101", "source": "claude", "timestamp": "2025-12-16T10:30:00.200Z", }, # === 用户输入(各端) === { "category": "message", "content_type": "text", "role": "user", "text": "[Gemini] Write a fibonacci function", "source": "gemini", "session_id": gemini_session, "timestamp": "2025-12-16T10:30:01.000Z", }, { "category": "message", "content_type": "text", "role": "user", "text": "[Codex] List all Python files in the project", "source": "codex", "session_id": codex_session, "timestamp": "2025-12-16T10:30:01.100Z", }, { "category": "message", "content_type": "text", "role": "user", "text": "[Claude] Explain the codebase architecture", "source": "claude", "session_id": claude_session, "timestamp": "2025-12-16T10:30:01.200Z", }, # === 思考过程交错 === { "category": "message", "content_type": "reasoning", "role": "assistant", "text": "**Analyzing fibonacci requirements**\nI need to implement an efficient fibonacci function...", "source": "codex", "session_id": codex_session, "timestamp": "2025-12-16T10:30:02.000Z", }, { "category": "message", "content_type": "reasoning", "role": "assistant", "text": "Let me think about the codebase structure first...", "source": "claude", "session_id": claude_session, "timestamp": "2025-12-16T10:30:02.100Z", }, # === 工具调用交错 === { "category": "operation", "operation_type": "file", "name": "write_file", "operation_id": "gemini-tool-001", "status": "running", "input": '{"path": "fib.py"}', "source": "gemini", "session_id": gemini_session, "timestamp": "2025-12-16T10:30:03.000Z", }, { "category": "operation", "operation_type": "command", "name": "shell", "operation_id": "codex-cmd-001", "status": "running", "input": "find . -name '*.py'", "source": "codex", "session_id": codex_session, "timestamp": "2025-12-16T10:30:03.100Z", }, { "category": "operation", "operation_type": "tool", "name": "Read", "operation_id": "claude-toolu-001", "status": "running", "input": '{"file_path": "/src/main.py"}', "source": "claude", "session_id": claude_session, "timestamp": "2025-12-16T10:30:03.200Z", }, # === 工具结果交错 === { "category": "operation", "operation_type": "file", "name": "write_file", "operation_id": "gemini-tool-001", "status": "success", "output": "File written: fib.py", "source": "gemini", "session_id": gemini_session, "timestamp": "2025-12-16T10:30:04.000Z", }, { "category": "operation", "operation_type": "command", "name": "shell", "operation_id": "codex-cmd-001", "status": "success", "output": "./src/main.py\n./src/utils.py\n./tests/test_main.py", "metadata": {"exit_code": 0}, "source": "codex", "session_id": codex_session, "timestamp": "2025-12-16T10:30:04.100Z", }, { "category": "operation", "operation_type": "tool", "name": "Read", "operation_id": "claude-toolu-001", "status": "success", "output": "def main():\n print('Hello World')\n\nif __name__ == '__main__':\n main()", "source": "claude", "session_id": claude_session, "timestamp": "2025-12-16T10:30:04.200Z", }, # === 助手回复交错 === { "category": "message", "content_type": "text", "role": "assistant", "text": "I've created the fibonacci function in fib.py with memoization.", "source": "gemini", "session_id": gemini_session, "timestamp": "2025-12-16T10:30:05.000Z", }, { "category": "message", "content_type": "text", "role": "assistant", "text": "Found 3 Python files in the project:\n- src/main.py\n- src/utils.py\n- tests/test_main.py", "source": "codex", "session_id": codex_session, "timestamp": "2025-12-16T10:30:05.100Z", }, { "category": "message", "content_type": "text", "role": "assistant", "text": "The codebase has a simple structure with a main entry point in src/main.py.", "source": "claude", "session_id": claude_session, "timestamp": "2025-12-16T10:30:05.200Z", }, # === MCP 调用示例 === { "category": "operation", "operation_type": "mcp", "name": "mcp__tavily__search", "operation_id": "claude-mcp-001", "status": "running", "input": '{"query": "Python best practices"}', "source": "claude", "session_id": claude_session, "timestamp": "2025-12-16T10:30:06.000Z", }, { "category": "operation", "operation_type": "mcp", "name": "mcp__tavily__search", "operation_id": "claude-mcp-001", "status": "success", "output": "Found 10 results about Python best practices...", "source": "claude", "session_id": claude_session, "timestamp": "2025-12-16T10:30:07.000Z", }, # === 会话结束 === { "category": "lifecycle", "lifecycle_type": "session_end", "session_id": gemini_session, "status": "success", "stats": { "total_tokens": 250, "duration_ms": 7000, "tool_calls": 1, }, "source": "gemini", "timestamp": "2025-12-16T10:30:08.000Z", }, { "category": "lifecycle", "lifecycle_type": "turn_end", "session_id": codex_session, "status": "success", "stats": { "input_tokens": 150, "output_tokens": 200, }, "source": "codex", "timestamp": "2025-12-16T10:30:08.100Z", }, { "category": "lifecycle", "lifecycle_type": "session_end", "session_id": claude_session, "status": "success", "stats": { "duration_ms": 8200, "total_cost_usd": 0.30612, "input_tokens": 500, "output_tokens": 300, }, "source": "claude", "timestamp": "2025-12-16T10:30:08.200Z", }, ] return events def generate_stress_test_events(count: int = 50) -> list[dict]: """生成压力测试事件。 模拟高频事件流(用于测试性能和滚动)。 """ sources = ["gemini", "codex", "claude"] sessions = { "gemini": "stress-gemini-001", "codex": "stress-codex-001", "claude": "stress-claude-001", } events = [] # 会话开始 for src in sources: events.append({ "category": "lifecycle", "lifecycle_type": "session_start", "session_id": sessions[src], "source": src, }) # 随机事件 for i in range(count): src = random.choice(sources) event_type = random.choice(["message", "operation"]) if event_type == "message": events.append({ "category": "message", "content_type": random.choice(["text", "reasoning"]), "role": "assistant", "text": f"[{src.upper()}] Event #{i}: " + "Sample text. " * random.randint(1, 5), "source": src, "session_id": sessions[src], }) else: op_type = random.choice(["command", "file", "tool", "mcp"]) events.append({ "category": "operation", "operation_type": op_type, "name": f"{op_type}_operation", "operation_id": f"op-{i}", "status": random.choice(["running", "success", "success", "success"]), "input": f"input for {op_type}", "output": f"output #{i}" if random.random() > 0.3 else "", "source": src, "session_id": sessions[src], }) return events def run_demo(stress_test: bool = False) -> None: """运行多端 Demo。""" print("Starting CLI Agent Live Output (Multi Source Mode)") print("Features:") print(" - Source labels: [GEMINI] [CODEX] [CLAUDE]") print(" - Sidebar: Sessions grouped by source") print(" - Mixed event stream") print() if stress_test: events = generate_stress_test_events(100) print("Running stress test with 100 random events...") interval = 0.05 else: events = generate_mixed_events() print("Pushing mixed events with 0.3s interval...") interval = 0.3 # 创建查看器(多端模式) viewer = LiveViewer( title="CLI Agent Live Output", multi_source_mode=True, # 多端模式! ) # 启动事件推送线程 def push_events(): time.sleep(1) # 等待窗口加载 for event in events: viewer.push_event(event) time.sleep(interval) print(f"All {len(events)} events pushed!") threading.Thread(target=push_events, daemon=True).start() # 启动查看器(阻塞) viewer.start(blocking=True) def main(): stress_test = "--stress" in sys.argv or "-s" in sys.argv run_demo(stress_test=stress_test) if __name__ == "__main__": main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/shiharuharu/cli-agent-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server