guantao 1 день назад
Родитель
Сommit
42a10d6ae2

+ 17 - 4
agent/llm/claude_code_oauth.py

@@ -189,9 +189,10 @@ def create_claude_code_oauth_llm_call(model: str = "claude-sonnet-4-5"):
                     if isinstance(msg, AssistantMessage):
                     if isinstance(msg, AssistantMessage):
                         for block in msg.content:
                         for block in msg.content:
                             if hasattr(block, "thinking"):
                             if hasattr(block, "thinking"):
-                                _emit(f"[think] {block.thinking}")
+                                # thinking 内容太多,跳过
+                                continue
                             elif isinstance(block, TextBlock):
                             elif isinstance(block, TextBlock):
-                                _emit(f"[text]  {block.text}")
+                                _emit(f"[text] {block.text}")
                                 text_parts.append(block.text)
                                 text_parts.append(block.text)
                             elif hasattr(block, "name") and hasattr(block, "input"):
                             elif hasattr(block, "name") and hasattr(block, "input"):
                                 _emit(f"[tool_use] {block.name}({block.input})")
                                 _emit(f"[tool_use] {block.name}({block.input})")
@@ -223,8 +224,20 @@ def create_claude_code_oauth_llm_call(model: str = "claude-sonnet-4-5"):
                         if info_status and info_status != "allowed":
                         if info_status and info_status != "allowed":
                             rate_limit_signal = f"status={info_status!r}"
                             rate_limit_signal = f"status={info_status!r}"
                     else:
                     else:
-                        # SystemMessage 或其他未知类型
-                        _emit(f"[{msg_type}] {msg!r}")
+                        # SystemMessage 简化为关键字段;其他未知类型 fallback
+                        if msg_type == "SystemMessage":
+                            data = getattr(msg, "data", {}) or {}
+                            subtype = getattr(msg, "subtype", "?")
+                            if subtype == "init":
+                                _emit(
+                                    f"[init] model={data.get('model')!r} "
+                                    f"apiKeySource={data.get('apiKeySource')!r} "
+                                    f"session={data.get('session_id', '')[:8]}"
+                                )
+                            else:
+                                _emit(f"[system] subtype={subtype}")
+                        else:
+                            _emit(f"[{msg_type}] {msg!r}")
         except ClaudeSDKError as e:
         except ClaudeSDKError as e:
             stderr_tail = "\n".join(stderr_lines[-20:])
             stderr_tail = "\n".join(stderr_lines[-20:])
             raise RuntimeError(
             raise RuntimeError(

+ 4 - 6
examples/process_pipeline/run_pipeline.py

@@ -765,13 +765,11 @@ async def main():
         # 使用 Claude SDK (CLAUDE_CODE_KEY/URL 或 ANTHROPIC_API_KEY/BASE_URL)
         # 使用 Claude SDK (CLAUDE_CODE_KEY/URL 或 ANTHROPIC_API_KEY/BASE_URL)
         claude_model = "claude-sonnet-4-6"
         claude_model = "claude-sonnet-4-6"
         print(f"✅ Using Claude SDK with model: {claude_model}")
         print(f"✅ Using Claude SDK with model: {claude_model}")
-        print(f"   API Key: {os.getenv('CLAUDE_CODE_KEY', 'N/A')[:20]}...")
-        print(f"   Base URL: {os.getenv('CLAUDE_CODE_URL', os.getenv('ANTHROPIC_BASE_URL', 'https://api.anthropic.com'))}")
-        claude_llm_call = create_claude_llm_call(model=claude_model)
-        # workflow 单独走 Claude Agent SDK(OAuth / Max 订阅)
+        # 所有环节走 Claude Agent SDK(OAuth / Max 订阅)
         from agent.llm.claude_code_oauth import create_claude_code_oauth_llm_call
         from agent.llm.claude_code_oauth import create_claude_code_oauth_llm_call
-        workflow_llm_call = create_claude_code_oauth_llm_call(model=claude_model)
-        print(f"✅ Workflow extraction will use Claude Agent SDK (OAuth/Max subscription)")
+        claude_llm_call = create_claude_code_oauth_llm_call(model=claude_model)
+        workflow_llm_call = claude_llm_call
+        print(f"✅ All Claude operations will use Claude Agent SDK (OAuth/Max subscription)")
     else:
     else:
         # 使用 OpenRouter 代理的 GPT-5.4(支持结构化输出 strict mode)
         # 使用 OpenRouter 代理的 GPT-5.4(支持结构化输出 strict mode)
         claude_model = "openai/gpt-5.4"
         claude_model = "openai/gpt-5.4"

+ 1 - 1
examples/process_pipeline/script/extract_workflow.py

@@ -191,7 +191,7 @@ async def extract_workflow_from_case(
 请严格按照上述格式输出JSON,不要包含其他内容。"""
 请严格按照上述格式输出JSON,不要包含其他内容。"""
 
 
     if images:
     if images:
-        image_urls = [img for img in images[:9] if isinstance(img, str) and img.startswith("http")]
+        image_urls = [img for img in images[:30] if isinstance(img, str) and img.startswith("http")]
         if image_urls:
         if image_urls:
             content_array = [{"type": "text", "text": prompt}]
             content_array = [{"type": "text", "text": prompt}]
             for url in image_urls:
             for url in image_urls:

+ 3 - 3
examples/process_pipeline/ui/app.js

@@ -1230,7 +1230,7 @@ async function fetchRequirementData(index) {
 
 
         const clusterData = window.dataCache[index].cluster;
         const clusterData = window.dataCache[index].cluster;
 
 
-        const oldActiveWorkflowTab = jsonBlueprint.querySelector('.sub-tab-btn.active')?.dataset?.target || 'sub-tab-workflow-cluster';
+        const oldActiveWorkflowTab = jsonBlueprint.querySelector('.sub-tab-btn.active')?.dataset?.target || 'sub-tab-workflow-cases';
 
 
         const workflowCasesHtml = renderAggregatedPerCaseData(casesList, 'workflow');
         const workflowCasesHtml = renderAggregatedPerCaseData(casesList, 'workflow');
         let bpHtml = `<div id="container-workflow">`;
         let bpHtml = `<div id="container-workflow">`;
@@ -3073,8 +3073,8 @@ window.triggerSingleCaseRerun = async function (step, caseIndex) {
             case_index: caseIndex
             case_index: caseIndex
         };
         };
 
 
-        // Use Claude SDK if it's checked in the UI
-        const cbClaudeSdk = document.getElementById('cb-use-claude-sdk');
+        // Use global Claude SDK checkbox if it's checked in the UI
+        const cbClaudeSdk = document.getElementById('check-claude-sdk');
         if (cbClaudeSdk) {
         if (cbClaudeSdk) {
             payload.use_claude_sdk = cbClaudeSdk.checked;
             payload.use_claude_sdk = cbClaudeSdk.checked;
         }
         }

+ 6 - 6
examples/process_pipeline/ui/index.html

@@ -149,6 +149,11 @@
                 <!-- Search Input -->
                 <!-- Search Input -->
                 <input type="text" class="search-input" placeholder="搜索标题 / 能力 / 工序 / 关键词" style="padding: 6px 12px; border: 1px solid #e2e8f0; border-radius: 8px; font-size: 0.85rem; outline: none; min-width: 220px; margin-right: 15px;">
                 <input type="text" class="search-input" placeholder="搜索标题 / 能力 / 工序 / 关键词" style="padding: 6px 12px; border: 1px solid #e2e8f0; border-radius: 8px; font-size: 0.85rem; outline: none; min-width: 220px; margin-right: 15px;">
                 
                 
+                <label style="display: flex; align-items: center; cursor: pointer; gap: 4px; margin-right: 15px;">
+                    <input type="checkbox" id="check-claude-sdk" checked>
+                    <span style="font-size: 0.85rem; color: var(--text-muted);">使用 Anthropic SDK (Max)</span>
+                </label>
+
                 <button class="btn btn-secondary btn-small" id="btn-refresh-data" title="局部刷新当前数据,保持页面位置">🔄 刷新数据</button>
                 <button class="btn btn-secondary btn-small" id="btn-refresh-data" title="局部刷新当前数据,保持页面位置">🔄 刷新数据</button>
                 <button class="btn btn-secondary btn-small" id="btn-toggle-memo" title="切换需求笔记面板">📝 笔记</button>
                 <button class="btn btn-secondary btn-small" id="btn-toggle-memo" title="切换需求笔记面板">📝 笔记</button>
                 <button class="btn btn-primary btn-small" id="btn-open-run-modal">🚀 运行流水线</button>
                 <button class="btn btn-primary btn-small" id="btn-open-run-modal">🚀 运行流水线</button>
@@ -301,12 +306,7 @@
                     <label>平台列表 (用逗号分隔)</label>
                     <label>平台列表 (用逗号分隔)</label>
                     <input type="text" id="input-platforms" value="xhs,gzh,zhihu,x" class="glass-input">
                     <input type="text" id="input-platforms" value="xhs,gzh,zhihu,x" class="glass-input">
                 </div>
                 </div>
-                <label class="form-group"
-                    style="flex-direction: row; align-items: center; cursor: pointer; justify-content: flex-start; gap: 10px;">
-                    <input type="checkbox" id="check-claude-sdk">
-                    <span>使用 Anthropic SDK 核心调用大模型</span>
-                </label>
-            </div>
+                </div>
             <div class="modal-footer">
             <div class="modal-footer">
                 <button class="btn btn-secondary" id="btn-cancel-run">取消</button>
                 <button class="btn btn-secondary" id="btn-cancel-run">取消</button>
                 <button class="btn btn-primary" id="btn-confirm-run">执行</button>
                 <button class="btn btn-primary" id="btn-confirm-run">执行</button>

+ 0 - 27
scratch/check_case35.py

@@ -1,27 +0,0 @@
-import json
-
-with open(r"C:\Users\11304\gitlab\cybertogether\Agent\examples\process_pipeline\output\112\case.json", "r", encoding="utf-8") as f:
-    data = json.load(f)
-
-case_35 = next((c for c in data.get("cases", []) if c.get("index") == 35), None)
-if not case_35:
-    print("case 35 NOT FOUND")
-else:
-    wf = case_35.get("workflow")
-    fr = case_35.get("capability") or case_35.get("fragments") or []
-    print("title:", (case_35.get("title") or "")[:50])
-    print("workflow exists:", wf is not None)
-    if wf:
-        steps = wf.get("steps", [])
-        print("steps count:", len(steps))
-        for s in steps:
-            order = s.get("order")
-            phase = s.get("phase")
-            body_present = bool(s.get("body"))
-            print(f"  step {order}: phase={phase} body_present={body_present}")
-    print("fragments count:", len(fr))
-    for f in fr:
-        fid = f.get("fragment_id")
-        action = f.get("action")
-        ref = (f.get("workflow_step_ref") or {}).get("step_id")
-        print(f"  {fid}: action={action} ref={ref}")

+ 0 - 41
scratch/test_claude_sdk.py

@@ -1,41 +0,0 @@
-"""
-最小化的 Claude Agent SDK 调用示例。
-
-前置条件:
-  1) pip install claude-agent-sdk
-  2) 终端里已经跑过 `claude` 并登录(OAuth token 已存在 ~/.claude/)
-  3) 不要设 ANTHROPIC_API_KEY 环境变量,否则会走 API 计费而不是订阅额度
-
-运行:
-  python scratch/test_claude_sdk.py
-"""
-
-import anyio
-import os
-
-from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, TextBlock
-
-
-async def main() -> None:
-    if os.environ.get("ANTHROPIC_API_KEY"):
-        print("[warn] 检测到 ANTHROPIC_API_KEY,将走 API 计费而非订阅额度。")
-        print("       想用终端登录态请先 `Remove-Item Env:ANTHROPIC_API_KEY`。\n")
-
-    options = ClaudeAgentOptions(
-        system_prompt="You are a concise assistant. Reply in Chinese.",
-        max_turns=1,
-        allowed_tools=[],
-    )
-
-    prompt = "用一句话告诉我:1+1 等于几?"
-    print(f">>> 提问: {prompt}\n")
-
-    async for message in query(prompt=prompt, options=options):
-        if isinstance(message, AssistantMessage):
-            for block in message.content:
-                if isinstance(block, TextBlock):
-                    print(f"<<< 回答: {block.text}")
-
-
-if __name__ == "__main__":
-    anyio.run(main)