Class: Chocomint::LLM::PrimaryClient
- Inherits:
-
Object
- Object
- Chocomint::LLM::PrimaryClient
- Defined in:
- lib/chocomint/llm/primary_client.rb
Overview
主 LLM にツール提案をさせる (DESIGN §5 Step1)。 tool_use ブロックを優先し、無ければテキストから JSON を抽出する (LLM 出力形式に依存しない堅牢性: DESIGN Goals)。
Constant Summary collapse
- WORKSPACE_RULES =
共通の作業ルール (パス・workspace の扱い)。両プロンプトで共有する。
<<~PROMPT.strip パスを指定するツールでは、必ず作業ディレクトリからの相対パス (例: workspace/foo.txt) を 使ってください。/workspace や /home/user/workspace のような絶対パスは許可されません。 run_command / bash / powershell の作業ディレクトリはプロジェクトルートです。 成果物は必ず workspace/ 配下に作ってください。uv など出力先ディレクトリを取るコマンドは 必ず --directory workspace/... のように workspace 配下を明示してください (例: run_command uv init --directory workspace/myproj)。 最新情報や外部ドキュメントの参照が必要な場合は fetch_url ツールを使ってください。 PROMPT
- FINISH_TOOL =
完了宣言用の疑似ツール。実際には実行されず、Planner がループ終了の合図として使う。
"finish"- FINISH_TOOL_DEFINITION =
{ "name" => FINISH_TOOL, "description" => "ユーザー要求がすべて達成され、もう実行すべきツールが残っていないときに呼ぶ。", "input_schema" => { "type" => "object", "properties" => { "reason" => { "type" => "string", "description" => "完了と判断した理由 (任意)" }, "message" => { "type" => "string", "description" => "ユーザーへ伝える最終メッセージ (任意)" } } } }.freeze
Class Method Summary collapse
-
.environment_prompt ⇒ Object
実行環境 (現在日時・OS・シェル) の説明。ローカルモデルが「今日の日付」や 「どの OS 上で動いているか」を誤解しないよう、システムプロンプトに毎回埋め込む。 シェルは PowerShell を優先させる (Windows ネイティブ環境のため)。.
-
.host_os_description ⇒ Object
RbConfig の host_os を人間可読な OS 名に整える。.
-
.step_system_prompt ⇒ Object
マルチステップの逐次実行を促すシステムプロンプト。 1 回の応答で「次に実行すべき 1 ツール」だけを選ばせ、 やることが残っていなければ finish ツールで完了を宣言させる。.
- .system_prompt ⇒ Object
Instance Method Summary collapse
-
#initialize(base_client:, tool_definitions:) ⇒ PrimaryClient
constructor
A new instance of PrimaryClient.
-
#propose(request, feedback: nil, trace_id: nil) ⇒ Object
戻り値: { "tool" => name, "arguments" => Hash } feedback: 初回〜前回までの全試行履歴 (再提案時に引数を変えさせるため / DESIGN §6)。 [{ attempt:, proposal:, error: }, ...] 形式。旧来の単一 Hash も許容する。.
-
#propose_step(request, done_steps = [], trace_id: nil) ⇒ Object
マルチステップ用: これまで完了したステップを踏まえ、次に実行すべき 1 ツールを提案する。 完了していれば tool="finish" を返す (Planner がループ終了に使う)。 戻り値: { "tool" => name, "arguments" => Hash } done_steps: [{ tool:, arguments:, result: }, ...] 形式の完了済みステップ列。.
Constructor Details
#initialize(base_client:, tool_definitions:) ⇒ PrimaryClient
Returns a new instance of PrimaryClient.
93 94 95 96 |
# File 'lib/chocomint/llm/primary_client.rb', line 93 def initialize(base_client:, tool_definitions:) @client = base_client @tool_definitions = tool_definitions end |
Class Method Details
.environment_prompt ⇒ Object
実行環境 (現在日時・OS・シェル) の説明。ローカルモデルが「今日の日付」や 「どの OS 上で動いているか」を誤解しないよう、システムプロンプトに毎回埋め込む。 シェルは PowerShell を優先させる (Windows ネイティブ環境のため)。
15 16 17 18 19 20 21 22 23 24 |
# File 'lib/chocomint/llm/primary_client.rb', line 15 def self.environment_prompt <<~ENV.strip 実行環境: - 現在日時: #{Time.now.strftime('%Y-%m-%d %H:%M:%S %Z')} - OS: #{host_os_description} - シェル: PowerShell (pwsh) を優先して使うこと。 コマンド実行が必要な場合は、原則として powershell ツール (または run_command) を使い、 PowerShell の構文で書いてください。bash 固有の構文は避けてください。 ENV end |
.host_os_description ⇒ Object
RbConfig の host_os を人間可読な OS 名に整える。
27 28 29 30 31 32 33 34 35 |
# File 'lib/chocomint/llm/primary_client.rb', line 27 def self.host_os_description host = RbConfig::CONFIG["host_os"] case host when /mswin|mingw|cygwin/ then "Windows (#{host})" when /darwin/ then "macOS (#{host})" when /linux/ then "Linux (#{host})" else host.to_s end end |
.step_system_prompt ⇒ Object
マルチステップの逐次実行を促すシステムプロンプト。 1 回の応答で「次に実行すべき 1 ツール」だけを選ばせ、 やることが残っていなければ finish ツールで完了を宣言させる。
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/chocomint/llm/primary_client.rb', line 63 def self.step_system_prompt <<~PROMPT あなたはユーザー要求を達成するために、ツールを 1 つずつ順番に実行していくアシスタントです。 これまでに完了したステップの一覧が与えられます。それを踏まえ、 「次に実行すべきツールを 1 つだけ」選び、その引数を決めてください。 ユーザー要求がすべて満たされ、もう実行すべきことが残っていない場合は、 finish ツールを呼び出して完了を宣言してください (それ以外のツールは呼ばないこと)。 まだ残作業がある場合は finish を呼ばず、次に必要なツールを 1 つだけ呼んでください。 #{environment_prompt} #{WORKSPACE_RULES} PROMPT end |
.system_prompt ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/chocomint/llm/primary_client.rb', line 48 def self.system_prompt <<~PROMPT あなたはツール実行を提案するアシスタントです。 ユーザー要求を満たすために呼び出すべきツールを 1 つだけ選び、 その引数を決めてください。ツールを使って応答してください。 #{environment_prompt} #{WORKSPACE_RULES} PROMPT end |
Instance Method Details
#propose(request, feedback: nil, trace_id: nil) ⇒ Object
戻り値: { "tool" => name, "arguments" => Hash } feedback: 初回〜前回までの全試行履歴 (再提案時に引数を変えさせるため / DESIGN §6)。 [{ attempt:, proposal:, error: }, ...] 形式。旧来の単一 Hash も許容する。
123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/chocomint/llm/primary_client.rb', line 123 def propose(request, feedback: nil, trace_id: nil) response = @client.( system: self.class.system_prompt, tools: @tool_definitions, messages: (request, feedback), trace_id: trace_id ) from_tool_use(response) || from_text(response) || raise(InvalidProposalError, "proposal contains no valid tool call") end |
#propose_step(request, done_steps = [], trace_id: nil) ⇒ Object
マルチステップ用: これまで完了したステップを踏まえ、次に実行すべき 1 ツールを提案する。 完了していれば tool="finish" を返す (Planner がループ終了に使う)。 戻り値: { "tool" => name, "arguments" => Hash } done_steps: [{ tool:, arguments:, result: }, ...] 形式の完了済みステップ列。
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/chocomint/llm/primary_client.rb', line 102 def propose_step(request, done_steps = [], trace_id: nil) response = @client.( system: self.class.step_system_prompt, tools: @tool_definitions + [FINISH_TOOL_DEFINITION], messages: (request, done_steps), trace_id: trace_id ) # ツール提案があればそれを優先。無ければモデルの自然文応答を「finish + メッセージ」 # として扱う。天気の問い合わせで場所を聞き返すなど、モデルがツールではなく # テキストで応答するのは正当なので、これを失敗にせずユーザーへ返す (聞き返し対応)。 # ここでは JSON 抽出の失敗を致命エラーにしない (strict: false)。自然文に壊れた # JSON 断片が混じっていても、聞き返し (from_text_reply) にフォールバックさせる。 from_tool_use(response) || from_text(response, strict: false) || from_text_reply(response) || raise(InvalidProposalError, "step proposal contains no valid tool call") end |