Class: Chocomint::Server
- Inherits:
-
Object
- Object
- Chocomint::Server
- Includes:
- EditGitHandlers, EditHandlers
- Defined in:
- lib/chocomint/server.rb
Overview
監督完結型の Anthropic Messages API 互換プロキシサーバー。
POST /v1/messages でユーザー要求を受け取り、Orchestrator に委譲して ツール実行・機械検証・意味検証・再試行・監査ログまで完結させ、 保証済みの結果を Anthropic 形式のレスポンスとして返す。
通常の LLM API との違い: 「提案」ではなく「実行が保証された結果」を返す。
Constant Summary collapse
- PORT_FALLBACK_RANGE =
指定ポートが使用中なら、この範囲内で連番の空きポートを探す (0 なら無制限に探索しない)。
20- PAGE_SIZE =
100
Constants included from EditGitHandlers
EditGitHandlers::GIT_NOT_FOUND
Constants included from EditHandlers
EditHandlers::ANSI_ESCAPE, EditHandlers::ASSET_CONTENT_TYPES, EditHandlers::BINARY_SNIFF_BYTES, EditHandlers::CHAT_CONTEXT_LIMIT, EditHandlers::COMPACT_INPUT_LIMIT, EditHandlers::EDIT_HTML_TEMPLATE, EditHandlers::EXCLUDED_TREE_DIRS, EditHandlers::MAX_LISTED_FILES, EditHandlers::TARGET_SUMMARY_LIMIT, EditHandlers::TOOL_LABELS
Instance Method Summary collapse
-
#initialize(planner, host: "127.0.0.1", port: 9210, logger: $stderr, sqlite_path: nil, path_guard: nil, base_dir: Dir.pwd, max_file_bytes: 10_485_760, ws_port: nil, ws_token: nil, chat_client: nil) ⇒ Server
constructor
planner: Planner インスタンス (run(request, expectations:) -> Planner::Result)。 edit UI 用に PathGuard / base_dir / vendor / console 情報も受け取る (任意)。 chat_client: 会話 (ツール不要の質問) を判定・応答する ChatClient (任意)。 未指定なら /edit チャットは従来どおり全指示を Planner に流す。.
-
#process(body_hash) ⇒ Object
テスト・組み込み用: Rack 非依存で 1 リクエストを処理する純粋関数。 body_hash(パース済み) -> [status, response_hash].
-
#render_logs(rows, total: nil, page: 0, trace_id: nil) ⇒ Object
監査ログをブラウザ表示するための HTML を組み立てる純粋関数。 rows: SqliteLogger#recent 相当の Hash 配列(当該ページ分) total: 全件数(trace_id 指定時はその trace の件数) page: 現在のページ(0 始まり) trace_id: フィルタ中の trace_id(無ければ nil) -> [status, content_type, body].
- #start ⇒ Object
Methods included from EditGitHandlers
#discard_paths, #git_body_paths, #git_capture, #git_current_branch, #git_remote_url, #git_repo?, #git_run, #git_tracked?, #handle_edit_git_branches, #handle_edit_git_checkout, #handle_edit_git_commit, #handle_edit_git_discard, #handle_edit_git_init, #handle_edit_git_push, #handle_edit_git_remote_set, #handle_edit_git_stage, #handle_edit_git_stage_all, #handle_edit_git_status, #handle_edit_git_unstage, #handle_edit_git_unstage_all, #normalize_path, #parse_git_status, #push_target_missing?, #require_git_repo!, #same_path?, #unstage_paths, #with_git
Methods included from EditHandlers
#binary_content?, #build_chat_request, #chat_file_context, #chat_instruction?, #console_ws_config, #deep_scrub, #edit_chat_reply, #edit_chat_result, #edit_html, #edit_json, #edit_method_guard, #edit_root, #fs_body_path, #handle_edit, #handle_edit_asset, #handle_edit_chat, #handle_edit_chat_stream, #handle_edit_compact, #handle_edit_file, #handle_edit_files, #handle_edit_fs_delete, #handle_edit_fs_mkdir, #handle_edit_fs_rename, #handle_edit_fs_touch, #handle_edit_save, #handle_edit_static, #humanize_chat_error, #list_workspace_empty_dirs, #list_workspace_files, #normalize_fs_path, #relative_root, #result_field, #run_chat_stream, #serve_edit_static, #strip_ansi, #tool_label, #tool_output_text, #tool_target_summary, #with_fs
Constructor Details
#initialize(planner, host: "127.0.0.1", port: 9210, logger: $stderr, sqlite_path: nil, path_guard: nil, base_dir: Dir.pwd, max_file_bytes: 10_485_760, ws_port: nil, ws_token: nil, chat_client: nil) ⇒ Server
planner: Planner インスタンス (run(request, expectations:) -> Planner::Result)。 edit UI 用に PathGuard / base_dir / vendor / console 情報も受け取る (任意)。 chat_client: 会話 (ツール不要の質問) を判定・応答する ChatClient (任意)。 未指定なら /edit チャットは従来どおり全指示を Planner に流す。
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/chocomint/server.rb', line 28 def initialize(planner, host: "127.0.0.1", port: 9210, logger: $stderr, sqlite_path: nil, path_guard: nil, base_dir: Dir.pwd, max_file_bytes: 10_485_760, ws_port: nil, ws_token: nil, chat_client: nil) @planner = planner @chat_client = chat_client @host = host @port = port @logger = logger @sqlite_path = sqlite_path @path_guard = path_guard @base_dir = base_dir @max_file_bytes = max_file_bytes @ws_port = ws_port @ws_token = ws_token @vendor_dir = File.("../../public/vendor", __dir__) @edit_static_dir = File.("../../public/edit", __dir__) end |
Instance Method Details
#process(body_hash) ⇒ Object
テスト・組み込み用: Rack 非依存で 1 リクエストを処理する純粋関数。 body_hash(パース済み) -> [status, response_hash]
97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/chocomint/server.rb', line 97 def process(body_hash) request = extract_request(body_hash) return [400, error_body("invalid_request_error", "no user message found")] if request.nil? expectations = body_hash["expectations"] || body_hash.dig("metadata", "expectations") result = @planner.run(request, expectations: expectations) [200, success_body(result)] rescue Chocomint::InvalidProposalError, Chocomint::UnknownToolError => e [422, error_body("invalid_request_error", e.)] rescue Chocomint::RetryLimitExceededError => e [502, error_body("execution_failed", e.)] rescue Chocomint::Error => e [500, error_body("api_error", e.)] end |
#render_logs(rows, total: nil, page: 0, trace_id: nil) ⇒ Object
監査ログをブラウザ表示するための HTML を組み立てる純粋関数。 rows: SqliteLogger#recent 相当の Hash 配列(当該ページ分) total: 全件数(trace_id 指定時はその trace の件数) page: 現在のページ(0 始まり) trace_id: フィルタ中の trace_id(無ければ nil) -> [status, content_type, body]
120 121 122 123 124 |
# File 'lib/chocomint/server.rb', line 120 def render_logs(rows, total: nil, page: 0, trace_id: nil) total ||= rows.size [200, "text/html; charset=utf-8", logs_html(rows, total: total, page: page, trace_id: trace_id)] end |
#start ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/chocomint/server.rb', line 50 def start server = bind_server_with_fallback server.mount_proc("/v1/messages") { |req, res| (req, res) } server.mount_proc("/health") { |_req, res| ok_json(res, { "status" => "ok" }) } server.mount_proc("/logs") { |req, res| handle_logs(req, res) } server.mount_proc("/logs/detail") { |req, res| handle_log_detail(req, res) } server.mount_proc("/logs/llm") { |req, res| handle_llm_logs(req, res) } # AI エディタ (/edit)。PathGuard が注入されているときのみ有効化する。 if @path_guard server.mount_proc("/edit") { |req, res| handle_edit(req, res) } server.mount_proc("/edit/assets") { |req, res| handle_edit_asset(req, res) } server.mount_proc("/edit/static") { |req, res| handle_edit_static(req, res) } server.mount_proc("/edit/files") { |req, res| handle_edit_files(req, res) } server.mount_proc("/edit/file") { |req, res| handle_edit_file(req, res) } server.mount_proc("/edit/save") { |req, res| handle_edit_save(req, res) } server.mount_proc("/edit/chat") { |req, res| handle_edit_chat(req, res) } server.mount_proc("/edit/compact") { |req, res| handle_edit_compact(req, res) } # ファイル操作 (右クリックメニュー): 削除 / 名前変更 / 追加。 server.mount_proc("/edit/fs/delete") { |req, res| handle_edit_fs_delete(req, res) } server.mount_proc("/edit/fs/rename") { |req, res| handle_edit_fs_rename(req, res) } server.mount_proc("/edit/fs/mkdir") { |req, res| handle_edit_fs_mkdir(req, res) } server.mount_proc("/edit/fs/touch") { |req, res| handle_edit_fs_touch(req, res) } # Git 操作 (ステータスバー / WORKING DIRECTORY パネル)。 server.mount_proc("/edit/git/status") { |req, res| handle_edit_git_status(req, res) } server.mount_proc("/edit/git/init") { |req, res| handle_edit_git_init(req, res) } server.mount_proc("/edit/git/stage") { |req, res| handle_edit_git_stage(req, res) } server.mount_proc("/edit/git/unstage") { |req, res| handle_edit_git_unstage(req, res) } server.mount_proc("/edit/git/stage_all") { |req, res| handle_edit_git_stage_all(req, res) } server.mount_proc("/edit/git/unstage_all") { |req, res| handle_edit_git_unstage_all(req, res) } server.mount_proc("/edit/git/discard") { |req, res| handle_edit_git_discard(req, res) } server.mount_proc("/edit/git/commit") { |req, res| handle_edit_git_commit(req, res) } server.mount_proc("/edit/git/push") { |req, res| handle_edit_git_push(req, res) } server.mount_proc("/edit/git/remote") { |req, res| handle_edit_git_remote_set(req, res) } server.mount_proc("/edit/git/branches") { |req, res| handle_edit_git_branches(req, res) } server.mount_proc("/edit/git/checkout") { |req, res| handle_edit_git_checkout(req, res) } end trap("INT") { server.shutdown } @logger.puts("chocomint proxy listening on http://#{@host}:#{@port}/v1/messages") @logger.puts("chocomint editor available at http://#{@host}:#{@port}/edit") if @path_guard server.start end |