Skip to content

Commit 3d419c0

Browse files
SonAIengineclaude
andcommitted
fix(ci): ruff lint + format 누적 에러 78개 해결
- examples/xgen_workflow_gateway.py: SyntaxError 수정 (**kwargs 뒤 일반 param) - ruff --fix로 36개 자동 수정 (F401 unused-import, F541 f-string, I001 imports) - E402: pytest.importorskip 패턴에 # noqa: E402 추가 (5개) - F841 unused-var 5개 + F811 중복 함수 1개 정리 - E501 line-too-long: 라이브러리 코드는 줄바꿈, test fixture는 file-level noqa - ruff format 적용 (16개 파일, deterministic 재포매팅) CI lint job이 5개 commit 동안 누적 fail 상태였음 — 이번 README 변경 PR이 그 사실을 표면화. test job은 정상 통과해 왔음. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e58e622 commit 3d419c0

20 files changed

Lines changed: 798 additions & 343 deletions

benchmarks/run_competitive.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import argparse
1616
import json
1717
import time
18-
from dataclasses import dataclass, field
18+
from dataclasses import dataclass
1919
from datetime import datetime, timezone
2020

2121
from benchmarks.config import DATASET_REGISTRY
@@ -214,7 +214,10 @@ def print_comparison(
214214
def main() -> None:
215215
parser = argparse.ArgumentParser(description="Competitive retrieval benchmark")
216216
parser.add_argument(
217-
"--datasets", "-d", nargs="+", default=None,
217+
"--datasets",
218+
"-d",
219+
nargs="+",
220+
default=None,
218221
help="Datasets to benchmark (default: all non-legacy)",
219222
)
220223
parser.add_argument("--top-k", type=int, default=5)
@@ -223,20 +226,15 @@ def main() -> None:
223226
parser.add_argument("--save", action="store_true", help="Save results as JSON")
224227
args = parser.parse_args()
225228

226-
dataset_names = args.datasets or [
227-
k for k, v in DATASET_REGISTRY.items() if not v.get("legacy")
228-
]
229+
dataset_names = args.datasets or [k for k, v in DATASET_REGISTRY.items() if not v.get("legacy")]
229230

230-
active_strategies = [
231-
s for s in STRATEGIES
232-
if not (args.no_embedding and s.embedding)
233-
]
231+
active_strategies = [s for s in STRATEGIES if not (args.no_embedding and s.embedding)]
234232

235-
print(f"\n Competitive Retrieval Benchmark")
233+
print("\n Competitive Retrieval Benchmark")
236234
print(f" Strategies: {len(active_strategies)}")
237235
print(f" Datasets: {len(dataset_names)}")
238236
if any(s.embedding for s in active_strategies):
239-
print(f" Embedding: ollama/qwen3-embedding:0.6b")
237+
print(" Embedding: ollama/qwen3-embedding:0.6b")
240238
print()
241239

242240
all_results: dict[str, dict[str, StrategyResult]] = {}
@@ -257,15 +255,21 @@ def main() -> None:
257255
for strategy in active_strategies:
258256
print(f" → {strategy.label}...", end="", flush=True)
259257
result = run_strategy(
260-
tg_base, strategy, gt["queries"],
261-
top_k=args.top_k, verbose=args.verbose,
258+
tg_base,
259+
strategy,
260+
gt["queries"],
261+
top_k=args.top_k,
262+
verbose=args.verbose,
262263
)
263264
ds_results[strategy.name] = result
264265
print(f" Recall={result.recall_5:.1%} MRR={result.mrr:.3f}")
265266

266267
print_comparison(
267-
gt["name"], gt.get("tool_count", len(tg_base.tools)),
268-
len(gt["queries"]), ds_results, active_strategies,
268+
gt["name"],
269+
gt.get("tool_count", len(tg_base.tools)),
270+
len(gt["queries"]),
271+
ds_results,
272+
active_strategies,
269273
)
270274
all_results[ds_name] = ds_results
271275

examples/test_bonsai_tool_calling.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
2. OpenAI function calling format (tools parameter)
66
3. graph-tool-call retrieve + LLM 조합
77
"""
8+
# ruff: noqa: E501
89

910
from __future__ import annotations
1011

@@ -128,9 +129,9 @@ def chat(messages: list[dict], tools: list[dict] | None = None, **kwargs) -> dic
128129

129130

130131
def print_header(title: str) -> None:
131-
print(f"\n{'='*60}")
132+
print(f"\n{'=' * 60}")
132133
print(f" {title}")
133-
print(f"{'='*60}")
134+
print(f"{'=' * 60}")
134135

135136

136137
def print_result(label: str, passed: bool, detail: str = "") -> None:
@@ -143,6 +144,7 @@ def print_result(label: str, passed: bool, detail: str = "") -> None:
143144

144145
# ── TEST 1: SearchLLM 통합 ──────────────────────────────────────────
145146

147+
146148
def test_search_llm():
147149
"""graph-tool-call의 OpenAICompatibleSearchLLM으로 query expansion 테스트."""
148150
print_header("TEST 1: SearchLLM Query Expansion & Intent Decomposition")
@@ -195,6 +197,7 @@ def test_search_llm():
195197

196198
# ── TEST 2: OpenAI Function Calling ─────────────────────────────────
197199

200+
198201
def test_function_calling():
199202
"""직접 tool calling format으로 호출하여 도구 선택 능력 테스트."""
200203
print_header("TEST 2: OpenAI Function Calling Format")
@@ -256,7 +259,11 @@ def test_function_calling():
256259
func_name = called.get("function", {}).get("name", "")
257260
func_args_raw = called.get("function", {}).get("arguments", "{}")
258261
try:
259-
func_args = json.loads(func_args_raw) if isinstance(func_args_raw, str) else func_args_raw
262+
func_args = (
263+
json.loads(func_args_raw)
264+
if isinstance(func_args_raw, str)
265+
else func_args_raw
266+
)
260267
except json.JSONDecodeError:
261268
func_args = {}
262269

@@ -283,6 +290,7 @@ def test_function_calling():
283290

284291
# ── TEST 3: graph-tool-call retrieve + LLM 조합 ─────────────────────
285292

293+
286294
def test_retrieve_with_llm():
287295
"""ToolGraph retrieve 후 LLM에게 도구 선택시키는 end-to-end 테스트."""
288296
print_header("TEST 3: ToolGraph Retrieve + LLM Tool Selection (E2E)")
@@ -344,7 +352,11 @@ def test_retrieve_with_llm():
344352
func_name = tool_calls[0].get("function", {}).get("name", "")
345353
func_args_raw = tool_calls[0].get("function", {}).get("arguments", "{}")
346354
try:
347-
func_args = json.loads(func_args_raw) if isinstance(func_args_raw, str) else func_args_raw
355+
func_args = (
356+
json.loads(func_args_raw)
357+
if isinstance(func_args_raw, str)
358+
else func_args_raw
359+
)
348360
except json.JSONDecodeError:
349361
func_args = {}
350362
passed = func_name == tc["expected_tool"]
@@ -388,6 +400,6 @@ def test_retrieve_with_llm():
388400
except Exception as e:
389401
print(f" [!] Test 3 failed: {e}")
390402

391-
print(f"\n{'='*60}")
403+
print(f"\n{'=' * 60}")
392404
print(" Done!")
393-
print(f"{'='*60}\n")
405+
print(f"{'=' * 60}\n")

examples/xgen_workflow_agent.py

Lines changed: 74 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,19 @@ def upload_file(file_path: str, bucket: str) -> str:
101101
@tool
102102
def query_database(sql: str) -> str:
103103
"""Execute a SQL query on the analytics database."""
104-
return f"Query result: 42 rows"
104+
return "Query result: 42 rows"
105105

106106
all_tools = [
107-
search_products, get_order_detail, cancel_order, create_refund,
108-
send_notification, get_user_profile, update_inventory,
109-
generate_report, upload_file, query_database,
107+
search_products,
108+
get_order_detail,
109+
cancel_order,
110+
create_refund,
111+
send_notification,
112+
get_user_profile,
113+
update_inventory,
114+
generate_report,
115+
upload_file,
116+
query_database,
110117
]
111118

112119
# -- 핵심: filter_tools 적용 (2줄) --
@@ -199,11 +206,10 @@ def send_notification(user_id: str, message: str) -> str:
199206
"""Send push notification to a user."""
200207
return f"Sent to {user_id}"
201208

202-
all_tools = [search_products, get_order_detail, cancel_order,
203-
create_refund, send_notification]
209+
# 데모용 tool 정의 (실제 적용 코드는 아래 print 블록 참고)
210+
_ = [search_products, get_order_detail, cancel_order, create_refund, send_notification]
204211

205212
# -- 핵심: create_agent 교체 --
206-
from graph_tool_call.langchain import create_agent as create_filtered_agent
207213

208214
# query_mode="message": 기본값, 추가 LLM 호출 없음 (빠름)
209215
# query_mode="llm": 대화 컨텍스트에서 검색 쿼리 생성 (멀티턴 강함)
@@ -284,27 +290,70 @@ def pattern_c_gateway():
284290
tools (50~500개) → create_gateway_tools() → 2개 meta-tool → agent_core
285291
"""
286292
import json
287-
from langchain_core.tools import tool
288293

289294
# -- 시뮬레이션: DB에서 가져온 사용자 등록 tool 50개 --
290295
tools = []
291296
tool_categories = {
292-
"order": ["create_order", "get_order", "cancel_order", "update_order", "list_orders",
293-
"get_order_status", "track_shipment", "confirm_delivery", "return_order",
294-
"exchange_order"],
295-
"product": ["search_products", "get_product", "create_product", "update_product",
296-
"delete_product", "get_product_reviews", "add_product_review",
297-
"get_product_inventory", "update_price", "get_categories"],
298-
"user": ["get_user", "create_user", "update_user", "delete_user", "list_users",
299-
"get_user_orders", "get_user_wishlist", "add_to_wishlist",
300-
"get_user_notifications", "update_preferences"],
301-
"payment": ["process_payment", "create_refund", "get_payment_status",
302-
"list_transactions", "get_invoice", "send_receipt",
303-
"validate_coupon", "apply_discount", "get_billing_info",
304-
"update_payment_method"],
305-
"admin": ["generate_report", "get_analytics", "export_data", "import_data",
306-
"get_system_status", "clear_cache", "send_notification",
307-
"create_announcement", "get_audit_log", "manage_permissions"],
297+
"order": [
298+
"create_order",
299+
"get_order",
300+
"cancel_order",
301+
"update_order",
302+
"list_orders",
303+
"get_order_status",
304+
"track_shipment",
305+
"confirm_delivery",
306+
"return_order",
307+
"exchange_order",
308+
],
309+
"product": [
310+
"search_products",
311+
"get_product",
312+
"create_product",
313+
"update_product",
314+
"delete_product",
315+
"get_product_reviews",
316+
"add_product_review",
317+
"get_product_inventory",
318+
"update_price",
319+
"get_categories",
320+
],
321+
"user": [
322+
"get_user",
323+
"create_user",
324+
"update_user",
325+
"delete_user",
326+
"list_users",
327+
"get_user_orders",
328+
"get_user_wishlist",
329+
"add_to_wishlist",
330+
"get_user_notifications",
331+
"update_preferences",
332+
],
333+
"payment": [
334+
"process_payment",
335+
"create_refund",
336+
"get_payment_status",
337+
"list_transactions",
338+
"get_invoice",
339+
"send_receipt",
340+
"validate_coupon",
341+
"apply_discount",
342+
"get_billing_info",
343+
"update_payment_method",
344+
],
345+
"admin": [
346+
"generate_report",
347+
"get_analytics",
348+
"export_data",
349+
"import_data",
350+
"get_system_status",
351+
"clear_cache",
352+
"send_notification",
353+
"create_announcement",
354+
"get_audit_log",
355+
"manage_permissions",
356+
],
308357
}
309358

310359
for category, tool_names in tool_categories.items():
@@ -410,7 +459,7 @@ def bonus_multiturn_scenario():
410459
top_name = results[0].name if results else "없음"
411460
match = "✓" if top_name == s["expected"] else "✗"
412461

413-
print(f"{s['turn']}: \"{s['message']}\"")
462+
print(f'{s["turn"]}: "{s["message"]}"')
414463
print(f" → message 모드 Top-1: {top_name} {match}")
415464
if "note" in s:
416465
print(f" ※ {s['note']}")

examples/xgen_workflow_gateway.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
import asyncio
2525
import json
2626

27-
2827
# =====================================================================
2928
# 방법 1: MCP 서버에서 tool 수집 → gateway
3029
# =====================================================================
3130
# 실제 MCP 서버(Slack, GitHub, Jira 등)에서 tool을 가져와서
3231
# gateway 2개로 축약하는 패턴. xgen-workflow 실 적용 코드와 동일.
3332

33+
3434
async def example_mcp_gateway():
3535
"""MCP 서버에서 tool 수집 후 gateway agent 구성."""
3636
from langchain_openai import ChatOpenAI
@@ -66,8 +66,9 @@ async def example_mcp_gateway():
6666
# MCP tool → LangChain StructuredTool 변환
6767
for t in response.tools:
6868
from langchain_core.tools import StructuredTool
69+
6970
tool = StructuredTool.from_function(
70-
func=lambda **kwargs, _s=session, _n=t.name: asyncio.run(
71+
func=lambda _s=session, _n=t.name, **kwargs: asyncio.run(
7172
_s.call_tool(_n, kwargs)
7273
),
7374
name=t.name,
@@ -97,14 +98,14 @@ async def example_mcp_gateway():
9798
# Swagger/OpenAPI에서 tool을 자동 생성하고 gateway에 넣는 패턴.
9899
# 사내 API가 OpenAPI spec으로 문서화되어 있을 때 유용.
99100

101+
100102
def example_openapi_gateway():
101103
"""OpenAPI spec에서 tool 생성 후 gateway agent 구성."""
102104
from langchain_openai import ChatOpenAI
103105
from langgraph.prebuilt import create_react_agent
104106

105107
from graph_tool_call import ToolGraph
106108
from graph_tool_call.langchain import create_gateway_tools
107-
from graph_tool_call.langchain.tools import tool_schema_to_openai_function
108109

109110
# ── 1. OpenAPI spec에서 ToolGraph 구축 ───────────────────────
110111
# URL 또는 파일 경로 모두 가능
@@ -127,12 +128,15 @@ def example_openapi_gateway():
127128
def make_fn(tool_schema=schema):
128129
def fn(**kwargs):
129130
req = build_request(tool_schema, kwargs)
130-
return json.dumps({
131-
"method": req.method,
132-
"url": req.url,
133-
"body": req.body,
134-
"note": "실제 환경에서는 requests.request()로 호출",
135-
})
131+
return json.dumps(
132+
{
133+
"method": req.method,
134+
"url": req.url,
135+
"body": req.body,
136+
"note": "실제 환경에서는 requests.request()로 호출",
137+
}
138+
)
139+
136140
return fn
137141

138142
tool = StructuredTool.from_function(
@@ -163,6 +167,7 @@ def fn(**kwargs):
163167
# 이미 LangChain tool이 있는 프로젝트에서 gateway 또는 filter를
164168
# 한 줄로 적용하는 패턴. 기존 코드 변경 최소화.
165169

170+
166171
def example_langchain_integration():
167172
"""기존 LangChain tool에 gateway/filter 적용."""
168173
from langchain_community.tools import DuckDuckGoSearchRun
@@ -214,8 +219,14 @@ def send_slack_message(channel: str, message: str) -> str:
214219
return json.dumps({"ok": True, "channel": channel})
215220

216221
all_tools = [
217-
search, get_weather, send_email, create_calendar_event,
218-
list_files, read_file, query_database, create_jira_issue,
222+
search,
223+
get_weather,
224+
send_email,
225+
create_calendar_event,
226+
list_files,
227+
read_file,
228+
query_database,
229+
create_jira_issue,
219230
send_slack_message,
220231
]
221232
print(f" 기존 tool {len(all_tools)}개")

0 commit comments

Comments
 (0)