process-gpt-agent-sdk 0.3.19__py3-none-any.whl → 0.4.0__py3-none-any.whl

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.

Potentially problematic release.


This version of process-gpt-agent-sdk might be problematic. Click here for more details.

@@ -2,64 +2,91 @@ import os
2
2
  import logging
3
3
  import traceback
4
4
  from typing import Any, Dict, Optional, List
5
- from typing import Iterable, Union
6
- from openai import AsyncOpenAI
5
+ from llm_factory import create_llm
7
6
 
8
7
 
9
8
  logger = logging.getLogger(__name__)
10
9
 
11
10
 
12
11
  # ─────────────────────────────
13
- # Lazy Singleton OpenAI Client
12
+ # Lazy Singleton LLM Client
14
13
  # ─────────────────────────────
15
- _client: Optional["AsyncOpenAI"] = None # type: ignore[name-defined]
16
-
17
- def _require_env(name: str, default: Optional[str] = None) -> str:
18
- v = os.getenv(name, default if default is not None else "")
19
- if not v:
20
- raise RuntimeError(f"Missing required environment variable: {name}")
21
- return v
22
-
23
- def get_client() -> "AsyncOpenAI": # type: ignore[name-defined]
14
+ _client = None
15
+ _global_agent_model = None
16
+
17
+ def set_agent_model(agent: Optional[Dict[str, Any]]) -> None:
18
+ """첫 번째 에이전트의 모델을 글로벌 변수에 설정합니다."""
19
+ global _global_agent_model
20
+
21
+ if agent:
22
+ model = agent.get("model")
23
+ if model:
24
+ # "openai/gpt-4o" 형식을 파싱하여 provider와 model 분리
25
+ if "/" in model:
26
+ provider, model_name = model.split("/", 1)
27
+ _global_agent_model = {"provider": provider, "model": model_name}
28
+ logger.info("🤖 글로벌 에이전트 모델 설정: %s/%s", provider, model_name)
29
+ else:
30
+ # 벤더사명이 없으면 모델명만 저장
31
+ _global_agent_model = {"provider": None, "model": model}
32
+ logger.info("🤖 글로벌 에이전트 모델 설정: %s", model)
33
+ else:
34
+ _global_agent_model = None
35
+ logger.info("🤖 에이전트에 모델 정보가 없음")
36
+ else:
37
+ _global_agent_model = None
38
+ logger.info("🤖 에이전트가 없음")
39
+
40
+ def get_agent_model() -> Optional[str]:
41
+ """글로벌 에이전트 모델 정보를 반환합니다."""
42
+ return _global_agent_model
43
+
44
+ def get_client():
24
45
  global _client
25
46
  if _client is not None:
26
47
  return _client
27
- if AsyncOpenAI is None:
28
- raise RuntimeError("OpenAI SDK (async) is not available")
29
- base_url = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
30
- api_key = _require_env("OPENAI_API_KEY", "")
31
- _client = AsyncOpenAI(base_url=base_url, api_key=api_key)
48
+
49
+ # 글로벌 에이전트 모델로 클라이언트 생성
50
+ agent_model = get_agent_model()
51
+ if agent_model:
52
+ provider = agent_model["provider"]
53
+ model_name = agent_model["model"]
54
+
55
+ if provider:
56
+ # 벤더사가 있으면 provider와 model 모두 전달
57
+ _client = create_llm(provider=provider, model=model_name, temperature=0)
58
+ logger.info("🤖 글로벌 에이전트 모델로 LLM 클라이언트 초기화: %s/%s", provider, model_name)
59
+ else:
60
+ # 벤더사가 없으면 model만 전달
61
+ _client = create_llm(model=model_name, temperature=0)
62
+ logger.info("🤖 글로벌 에이전트 모델로 LLM 클라이언트 초기화: %s", model_name)
63
+ else:
64
+ _client = create_llm(model="gpt-4.1-mini", temperature=0)
65
+ logger.info("🔧 기본 모델로 LLM 클라이언트 초기화: gpt-4.1-mini")
32
66
  return _client
33
67
 
34
68
  # ─────────────────────────────
35
69
  # 공통 LLM 호출 유틸
36
70
  # ─────────────────────────────
37
- async def _llm_request(system: str, user: str, model_env: str, default_model: str) -> str:
38
- model_name = os.getenv(model_env, default_model)
39
- logger.info("📡 LLM 요청 전송 (모델: %s)", model_name)
40
-
41
- client = get_client()
42
- # responses API (신규)
43
- resp = await client.responses.create(
44
- model=model_name,
45
- input=[
46
- {"role": "system", "content": system},
47
- {"role": "user", "content": user},
48
- ],
49
- )
50
-
51
- # 다양한 SDK 출력 구조 호환
52
- text: Optional[str] = None
53
- try:
54
- text = getattr(resp, "output_text", None) # 최신 필드
55
- except Exception:
56
- text = None
57
-
58
- if not text and hasattr(resp, "choices") and resp.choices: # 구 구조 호환
59
- choice0 = resp.choices[0]
60
- text = getattr(getattr(choice0, "message", None), "content", None)
61
-
62
- if not text:
71
+ async def _llm_request(system: str, user: str) -> str:
72
+ logger.info("📡 LLM 요청 전송")
73
+
74
+ model = get_client()
75
+
76
+ # llm_factory를 사용한 LLM 호출
77
+ messages = [
78
+ {"role": "system", "content": system},
79
+ {"role": "user", "content": user},
80
+ ]
81
+
82
+ response = await model.ainvoke(messages)
83
+
84
+ # 응답에서 텍스트 추출
85
+ if hasattr(response, 'content'):
86
+ text = response.content
87
+ elif isinstance(response, str):
88
+ text = response
89
+ else:
63
90
  raise RuntimeError("No text in LLM response")
64
91
 
65
92
  return text.strip()
@@ -68,12 +95,8 @@ async def _llm_request(system: str, user: str, model_env: str, default_model: st
68
95
  # 공개 API
69
96
  # ─────────────────────────────
70
97
  async def summarize_error_to_user(exc: Exception, meta: Dict[str, Any]) -> str:
71
- """
72
- 예외 정보를 바탕으로 사용자 친화적인 5줄 요약을 생성.
73
- - 모델: gpt-4.1-nano (환경변수 ERROR_SUMMARY_MODEL로 재정의 가능)
74
- - 폴백: 없음 (LLM 실패 시 예외를 상위로 전파)
75
- """
76
- logger.info("🔍 오류 컨텍스트 분석 시작")
98
+ """예외 정보를 바탕으로 사용자 친화적인 5줄 요약을 생성."""
99
+ logger.info("\n\n🔍 오류 컨텍스트 분석 시작")
77
100
 
78
101
  err_text = f"{type(exc).__name__}: {str(exc)}"
79
102
 
@@ -109,20 +132,15 @@ async def summarize_error_to_user(exc: Exception, meta: Dict[str, Any]) -> str:
109
132
  )
110
133
 
111
134
  try:
112
- text = await _llm_request(system, user, "ERROR_SUMMARY_MODEL", "gpt-4.1-nano")
135
+ text = await _llm_request(system, user)
113
136
  logger.info("✅ LLM 오류 요약 생성 완료")
114
137
  return text
115
138
  except Exception as e:
116
139
  logger.warning("⚠️ LLM 오류 요약 생성 실패: %s", e, exc_info=True)
117
- # 폴백 없이 상위 전파
118
140
  raise
119
141
 
120
142
  async def summarize_feedback(feedback_data: List[dict], content_data: dict = {}) -> str:
121
- """
122
- 피드백과 결과물을 바탕으로 통합된 피드백 요약을 생성.
123
- - 모델: gpt-4.1-nano (환경변수 FEEDBACK_SUMMARY_MODEL로 재정의 가능)
124
- - 폴백: 없음 (LLM 실패 시 예외를 상위로 전파)
125
- """
143
+ """피드백과 결과물을 바탕으로 통합된 피드백 요약을 생성."""
126
144
  logger.info(
127
145
  "🔍 피드백 요약 처리 시작 | 피드백: %s, 결과물: %s자",
128
146
  feedback_data, content_data)
@@ -131,12 +149,11 @@ async def summarize_feedback(feedback_data: List[dict], content_data: dict = {})
131
149
  user_prompt = _create_feedback_summary_prompt(feedback_data, content_data)
132
150
 
133
151
  try:
134
- text = await _llm_request(system_prompt, user_prompt, "FEEDBACK_SUMMARY_MODEL", "gpt-4.1-nano")
152
+ text = await _llm_request(system_prompt, user_prompt)
135
153
  logger.info("✅ LLM 피드백 요약 생성 완료")
136
154
  return text
137
155
  except Exception as e:
138
156
  logger.error("❌ LLM 피드백 요약 생성 실패: %s", e, exc_info=True)
139
- # 폴백 없이 상위 전파
140
157
  raise
141
158
 
142
159
  # ─────────────────────────────
@@ -166,6 +183,7 @@ def _create_feedback_summary_prompt(feedback_data: List[dict], content_data: dic
166
183
  - 구체적이고 실행 가능한 개선사항 제시
167
184
  - **자연스럽고 통합된 하나의 완전한 피드백으로 작성**
168
185
  - 최대 1000자까지 허용하여 상세히 작성
186
+ - 만약 전달된 피드백 내용이 1000자 미만일 경우 요약하지 않고 하나의 문맥으로 그대로 반환
169
187
 
170
188
  **중요한 상황별 처리:**
171
189
  - 결과물 품질에 대한 불만 → **품질 개선** 요구