Coverage for src\agents_sdk_models\gen_agent.py: 99%

1 from __future__ import annotations

2

3"""GenAgent — AgentPipeline as a Step for Flow workflows.

4

5 GenAgentはAgentPipelineをStepとして使用するためのクラスです。

6これにより、AgentPipelineをFlowワークフロー内で直接使用できます。

7"""

8

9 import asyncio

10 from typing import Any, Callable, List, Dict, Optional, Type

11 from concurrent.futures import ThreadPoolExecutor

12

13 from .step import Step

14 from .context import Context

15 from .pipeline import AgentPipeline, EvaluationResult

16

17

18 class GenAgent(Step):

19 """

20 Step implementation that wraps AgentPipeline functionality

21 AgentPipeline機能をラップするStep実装

22

23 This class allows using AgentPipeline directly as a Step in Flow workflows,

24 providing generation, evaluation, and retry capabilities within a workflow context.

25 このクラスはAgentPipelineをFlowワークフロー内で直接Stepとして使用できるようにし、

26 ワークフローコンテキスト内で生成、評価、リトライ機能を提供します。

27 """

28

29 def __init__(

30 self,

31 name: str,

32 generation_instructions: str,

33 evaluation_instructions: Optional[str] = None,

34 *,

35 input_guardrails: Optional[list] = None,

36 output_guardrails: Optional[list] = None,

37 output_model: Optional[Type[Any]] = None,

38 model: str | None = None,

39 evaluation_model: str | None = None,

40 generation_tools: Optional[list] = None,

41 evaluation_tools: Optional[list] = None,

42 routing_func: Optional[Callable[[Any], Any]] = None,

43 session_history: Optional[list] = None,

44 history_size: int = 10,

45 threshold: int = 85,

46 retries: int = 3,

47 improvement_callback: Optional[Callable[[Any, EvaluationResult], None]] = None,

48 dynamic_prompt: Optional[Callable[[str], str]] = None,

49 retry_comment_importance: Optional[list[str]] = None,

50 locale: str = "en",

51 next_step: Optional[str] = None,

52 store_result_key: Optional[str] = None,

53 ) -> None:

54 """

55 Initialize GenAgent with AgentPipeline configuration

56 AgentPipeline設定でGenAgentを初期化する

57

58 Args:

59 name: Step name / ステップ名

60 generation_instructions: System prompt for generation / 生成用システムプロンプト

61 evaluation_instructions: System prompt for evaluation / 評価用システムプロンプト

62 input_guardrails: Guardrails for generation / 生成用ガードレール

63 output_guardrails: Guardrails for evaluation / 評価用ガードレール

64 output_model: Model for output formatting / 出力フォーマット用モデル

65 model: LLM model name / LLMモデル名

66 evaluation_model: Optional LLM model name for evaluation / 評価用LLMモデル名（任意）

67 generation_tools: Tools for generation / 生成用ツール

68 evaluation_tools: Tools for evaluation / 評価用ツール

69 routing_func: Function for output routing / 出力ルーティング用関数

70 session_history: Session history / セッション履歴

71 history_size: Size of history to keep / 保持する履歴サイズ

72 threshold: Evaluation score threshold / 評価スコア閾値

73 retries: Number of retry attempts / リトライ試行回数

74 improvement_callback: Callback for improvement suggestions / 改善提案用コールバック

75 dynamic_prompt: Optional function to dynamically build prompt / 動的プロンプト生成関数（任意）

76 retry_comment_importance: Importance levels of comments to include on retry / リトライ時コメント重要度レベル

77 locale: Language code for localized messages / ローカライズメッセージ用言語コード

78 next_step: Next step after pipeline execution / パイプライン実行後の次ステップ

79 store_result_key: Key to store result in context shared_state / コンテキスト共有状態に結果を格納するキー

80 """

81 # Initialize Step base class

82 # Step基底クラスを初期化

83 super().__init__(name)

84

85 # Store flow-specific configuration

86 # フロー固有の設定を保存

87 self.next_step = next_step

88 self.store_result_key = store_result_key or f"{name}_result"

89

90 # Create internal AgentPipeline instance

91 # 内部AgentPipelineインスタンスを作成

92 self.pipeline = AgentPipeline(

93 name=f"{name}_pipeline",

94 generation_instructions=generation_instructions,

95 evaluation_instructions=evaluation_instructions,

96 input_guardrails=input_guardrails,

97 output_guardrails=output_guardrails,

98 output_model=output_model,

99 model=model,

100 evaluation_model=evaluation_model,

101 generation_tools=generation_tools,

102 evaluation_tools=evaluation_tools,

103 routing_func=routing_func,

104 session_history=session_history,

105 history_size=history_size,

106 threshold=threshold,

107 retries=retries,

108 improvement_callback=improvement_callback,

109 dynamic_prompt=dynamic_prompt,

110 retry_comment_importance=retry_comment_importance,

111 locale=locale,

112 )

113

114 async def run(self, user_input: Optional[str], ctx: Context) -> Context:

115 """

116 Execute GenAgent step using AgentPipeline

117 AgentPipelineを使用してGenAgentステップを実行する

118

119 Args:

120 user_input: User input for the pipeline / パイプライン用ユーザー入力

121 ctx: Current workflow context / 現在のワークフローコンテキスト

122

123 Returns:

124 Context: Updated context with pipeline results / パイプライン結果付き更新済みコンテキスト

125 """

126 # English: Update step information in context

127 # 日本語: コンテキストのステップ情報を更新

128 ctx.update_step_info(self.name)

129

130 try:

131 # English: Determine input text for pipeline

132 # 日本語: パイプライン用入力テキストを決定

133 input_text = user_input or ctx.last_user_input or ""

134

135 if not input_text:

136 # English: If no input available, add system message and continue

137 # 日本語: 入力がない場合、システムメッセージを追加して続行

138 ctx.add_system_message(f"GenAgent {self.name}: No input available, skipping pipeline execution")

139 result = None

140 else:

141 # English: Execute pipeline in thread pool to handle sync methods

142 # 日本語: 同期メソッドを処理するためにスレッドプールでパイプラインを実行

143 loop = asyncio.get_event_loop()

144 with ThreadPoolExecutor() as executor:

145 future = loop.run_in_executor(executor, self.pipeline.run, input_text)

146 result = await future

147

148 # English: Store result in context

149 # 日本語: 結果をコンテキストに保存

150 if result is not None:

151 # English: Store in shared state for other steps to access

152 # 日本語: 他のステップがアクセスできるよう共有状態に保存

153 ctx.shared_state[self.store_result_key] = result

154 ctx.prev_outputs[self.name] = result

155

156 # English: Add result as assistant message

157 # 日本語: 結果をアシスタントメッセージとして追加

158 ctx.add_assistant_message(str(result))

159

160 # English: Add success system message

161 # 日本語: 成功システムメッセージを追加

162 ctx.add_system_message(f"GenAgent {self.name}: Pipeline executed successfully")

163 else:

164 # English: Handle case where pipeline returned None (evaluation failed)

165 # 日本語: パイプラインがNoneを返した場合（評価失敗）を処理

166 ctx.shared_state[self.store_result_key] = None

167 ctx.prev_outputs[self.name] = None

168

169 # English: Add failure system message

170 # 日本語: 失敗システムメッセージを追加

171 ctx.add_system_message(f"GenAgent {self.name}: Pipeline execution failed (evaluation threshold not met)")

172

173 except Exception as e:

174 # English: Handle execution errors

175 # 日本語: 実行エラーを処理

176 error_msg = f"GenAgent {self.name} execution error: {str(e)}"

177 ctx.add_system_message(error_msg)

178 ctx.shared_state[self.store_result_key] = None

179 ctx.prev_outputs[self.name] = None

180

181 # English: Log error for debugging

182 # 日本語: デバッグ用エラーログ

183 print(f"🚨 {error_msg}")

184

185 # English: Set next step if specified

186 # 日本語: 指定されている場合は次ステップを設定

187 if self.next_step:

188 ctx.goto(self.next_step)

189

190 return ctx

191

192 def get_pipeline_history(self) -> List[Dict[str, str]]:

193 """

194 Get the internal pipeline history

195 内部パイプライン履歴を取得する

196

197 Returns:

198 List[Dict[str, str]]: Pipeline history / パイプライン履歴

199 """

200 return self.pipeline._pipeline_history

201

202 def get_session_history(self) -> Optional[List[str]]:

203 """

204 Get the session history

205 セッション履歴を取得する

206

207 Returns:

208 Optional[List[str]]: Session history / セッション履歴

209 """

210 return self.pipeline.session_history

211

212 def update_instructions(

213 self,

214 generation_instructions: Optional[str] = None,

215 evaluation_instructions: Optional[str] = None

216 ) -> None:

217 """

218 Update pipeline instructions

219 パイプライン指示を更新する

220

221 Args:

222 generation_instructions: New generation instructions / 新しい生成指示

223 evaluation_instructions: New evaluation instructions / 新しい評価指示

224 """

225 if generation_instructions is not None:

226 self.pipeline.generation_instructions = generation_instructions.strip()

227 # English: Update the agent instructions

228 # 日本語: エージェント指示を更新

229 self.pipeline.gen_agent.instructions = generation_instructions.strip()

230

231 if evaluation_instructions is not None:

232 self.pipeline.evaluation_instructions = evaluation_instructions.strip() if evaluation_instructions else None

233 # English: Update evaluation agent if it exists

234 # 日本語: 評価エージェントが存在する場合は更新

235 if self.pipeline.eval_agent and evaluation_instructions:

236 self.pipeline.eval_agent.instructions = evaluation_instructions.strip()

237

238 def clear_history(self) -> None:

239 """

240 Clear both pipeline and session history

241 パイプライン履歴とセッション履歴の両方をクリア

242 """

243 self.pipeline._pipeline_history.clear()

244 if self.pipeline.session_history:

245 self.pipeline.session_history.clear()

246

247 def set_threshold(self, threshold: int) -> None:

248 """

249 Update evaluation threshold

250 評価閾値を更新する

251

252 Args:

253 threshold: New threshold value (0-100) / 新しい閾値（0-100）

254 """

255 if 0 <= threshold <= 100:

256 self.pipeline.threshold = threshold

257 else:

258 raise ValueError("Threshold must be between 0 and 100")

259

260 def __str__(self) -> str:

261 return f"GenAgent({self.name}, model={self.pipeline.model})"

262

263 def __repr__(self) -> str:

264 return self.__str__()

265

266

267# Utility function for creating GenAgent with common configurations

268# 共通設定でGenAgentを作成するユーティリティ関数

269

270 def create_simple_gen_agent(

271 name: str,

272 instructions: str,

273 model: Optional[str] = None,

274 next_step: Optional[str] = None,

275 threshold: int = 85,

276 retries: int = 3

277) -> GenAgent:

278 """

279 Create a simple GenAgent with basic configuration

280 基本設定でシンプルなGenAgentを作成

281

282 Args:

283 name: Agent name / エージェント名

284 instructions: Generation instructions / 生成指示

285 model: LLM model name / LLMモデル名

286 next_step: Next step after execution / 実行後の次ステップ

287 threshold: Evaluation threshold / 評価閾値

288 retries: Number of retries / リトライ回数

289

290 Returns:

291 GenAgent: Configured GenAgent instance / 設定済みGenAgentインスタンス

292 """

293 return GenAgent(

294 name=name,

295 generation_instructions=instructions,

296 evaluation_instructions=None, # No evaluation for simple agent

297 model=model,

298 next_step=next_step,

299 threshold=threshold,

300 retries=retries

301 )

302

303

304 def create_evaluated_gen_agent(

305 name: str,

306 generation_instructions: str,

307 evaluation_instructions: str,

308 model: Optional[str] = None,

309 evaluation_model: Optional[str] = None,

310 next_step: Optional[str] = None,

311 threshold: int = 85,

312 retries: int = 3

313) -> GenAgent:

314 """

315 Create a GenAgent with both generation and evaluation

316 生成と評価の両方を持つGenAgentを作成

317

318 Args:

319 name: Agent name / エージェント名

320 generation_instructions: Generation instructions / 生成指示

321 evaluation_instructions: Evaluation instructions / 評価指示

322 model: LLM model name / LLMモデル名

323 evaluation_model: Evaluation model name / 評価モデル名

324 next_step: Next step after execution / 実行後の次ステップ

325 threshold: Evaluation threshold / 評価閾値

326 retries: Number of retries / リトライ回数

327

328 Returns:

329 GenAgent: Configured GenAgent instance / 設定済みGenAgentインスタンス

330 """

331 return GenAgent(

332 name=name,

333 generation_instructions=generation_instructions,

334 evaluation_instructions=evaluation_instructions,

335 model=model,

336 evaluation_model=evaluation_model,

337 next_step=next_step,

338 threshold=threshold,

339 retries=retries

340 )