| |
| from __future__ import annotations |
|
|
| import argparse |
| import asyncio |
| import os |
| import re |
| import io |
| import contextlib |
| from typing import Optional |
|
|
| from dataflow_agent.state import DFRequest, DFState |
| from dataflow_agent.workflow.wf_pipeline_write import create_operator_write_graph |
| from dataflow_agent.utils import get_project_root |
|
|
| PROJDIR = get_project_root() |
|
|
| def parse_args(): |
| p = argparse.ArgumentParser(description="Run operator flow: match -> write -> (optional debug loop)") |
| p.add_argument('--chat-api-url', default='http://123.129.219.111:3000/v1/', help='LLM Chat API base') |
| p.add_argument('--model', default='gpt-4o', help='LLM model name') |
| p.add_argument('--language', default='en', help='Prompt output language') |
| p.add_argument('--target', required=True, help='User requirement / purpose for new operator') |
| p.add_argument('--category', default='Default', help='Operator category for matching (fallback if no classifier)') |
| p.add_argument('--output', default='', help='Optional path to write generated operator code') |
| p.add_argument('--json-file', default='', help='Path to test jsonl file used in debug run') |
| p.add_argument('--need-debug', action='store_true', help='Enable debug loop for executing and fixing the operator') |
| p.add_argument('--max-debug-rounds', type=int, default=3, help='Max debug rounds when --need-debug is set') |
| return p.parse_args() |
|
|
|
|
| """ |
| Entry script for operator write workflow. |
| Only keeps CLI parsing, DFState creation, and running the workflow graph. |
| Graph construction and node/tool definitions live in workflow/wf_pipeline_write.py |
| """ |
|
|
|
|
| async def main(): |
| args = parse_args() |
|
|
| from dataflow.cli_funcs.paths import DataFlowPath |
|
|
| req = DFRequest( |
| language=args.language, |
| chat_api_url=args.chat_api_url, |
| api_key=os.getenv("DF_API_KEY", "sk-dummy"), |
| model=args.model, |
| target=args.target, |
| need_debug=bool(args.need_debug), |
| max_debug_rounds=int(args.max_debug_rounds), |
| |
| json_file=(args.json_file or f"{PROJDIR}/tests/test.jsonl"), |
| ) |
| state = DFState(request=req, messages=[]) |
| if args.output: |
| state.temp_data["pipeline_file_path"] = args.output |
| |
| if args.category: |
| state.temp_data["category"] = args.category |
|
|
| |
| state.temp_data["round"] = 0 |
|
|
| graph = create_operator_write_graph().build() |
| |
| |
| recursion_limit = 4 + 5 * int(args.max_debug_rounds) + 5 |
| final_state: DFState = await graph.ainvoke(state, config={"recursion_limit": recursion_limit}) |
|
|
| |
| print("==== Match Operator Result ====") |
| try: |
| if isinstance(final_state, dict): |
| matched = final_state.get("matched_ops") |
| if not matched: |
| matched = ( |
| final_state.get("agent_results", {}) |
| .get("match_operator", {}) |
| .get("results", {}) |
| .get("match_operators", []) |
| ) |
| else: |
| matched = getattr(final_state, "matched_ops", []) |
| if not matched and hasattr(final_state, "agent_results"): |
| matched = ( |
| final_state.agent_results.get("match_operator", {}) |
| .get("results", {}) |
| .get("match_operators", []) |
| ) |
| print("Matched ops:", matched or []) |
| except Exception: |
| print("Matched ops: <unavailable>") |
|
|
| print("\n==== Writer Result ====") |
| try: |
| |
| if isinstance(final_state, dict): |
| code_str = ( |
| final_state.get("temp_data", {}).get("pipeline_code", "") |
| or final_state.get("draft_operator_code", "") |
| or final_state.get("agent_results", {}).get("write_the_operator", {}).get("results", {}).get("code", "") |
| ) |
| if not code_str: |
| fp = final_state.get("temp_data", {}).get("pipeline_file_path") |
| if fp: |
| from pathlib import Path |
| p = Path(fp) |
| try: |
| if p.exists(): |
| code_str = p.read_text(encoding="utf-8") |
| except Exception: |
| pass |
| else: |
| code_str = ( |
| getattr(final_state, "temp_data", {}).get("pipeline_code", "") |
| or getattr(final_state, "draft_operator_code", "") |
| or getattr(getattr(final_state, "agent_results", {}), "get", lambda *_: {})("write_the_operator", {}).get("results", {}).get("code", "") |
| ) |
| if not code_str: |
| fp = getattr(final_state, "temp_data", {}).get("pipeline_file_path") |
| if fp: |
| from pathlib import Path |
| p = Path(fp) |
| try: |
| if p.exists(): |
| code_str = p.read_text(encoding="utf-8") |
| except Exception: |
| pass |
| except Exception: |
| code_str = "" |
| print(f"Code length: {len(code_str)}") |
| if args.output: |
| print(f"Saved to: {args.output}") |
| else: |
| |
| preview = (code_str or "")[:1000] |
| print("Code preview:\n", preview) |
|
|
| |
| |
|
|
| |
| |
| |
| if isinstance(final_state, dict): |
| exec_res = final_state.get("execution_result", {}) or {} |
| if not exec_res or ("success" not in exec_res): |
| exec_res = final_state.get("agent_results", {}).get("operator_executor", {}).get("results", {}) or exec_res |
| else: |
| exec_res = getattr(final_state, "execution_result", {}) or {} |
| if (not exec_res or ("success" not in exec_res)) and hasattr(final_state, "agent_results"): |
| exec_res = final_state.agent_results.get("operator_executor", {}).get("results", {}) or exec_res |
| success = bool(exec_res.get("success")) |
| print("\n==== Execution Result (instantiate) ====") |
| print("Success:", success) |
| if not success: |
| stderr = (exec_res.get("stderr") or exec_res.get("traceback") or "") |
| print("stderr preview:\n", (stderr or "")[:500]) |
|
|
| |
| try: |
| dbg = None |
| if isinstance(final_state, dict): |
| dbg = (final_state.get("temp_data") or {}).get("debug_runtime") |
| else: |
| dbg = getattr(final_state, "temp_data", {}).get("debug_runtime") |
| if dbg: |
| print("\n==== Debug Runtime Preview ==== ") |
| ik = dbg.get("input_key") |
| ak = dbg.get("available_keys") |
| print("input_key:", ik) |
| if ak: |
| print("available_keys:", ak) |
| stdout_pv = (dbg.get("stdout") or "")[:1000] |
| stderr_pv = (dbg.get("stderr") or "")[:1000] |
| if stdout_pv: |
| print("[debug stdout]\n", stdout_pv) |
| if stderr_pv: |
| print("[debug stderr]\n", stderr_pv) |
| except Exception: |
| pass |
|
|
|
|
| if __name__ == "__main__": |
| asyncio.run(main()) |
|
|