Class: Chocomint::Server
- Inherits:
-
Object
- Object
- Chocomint::Server
- Includes:
- EditArchiveHandlers, 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 EditArchiveHandlers
EditArchiveHandlers::MAX_ARCHIVE_ENTRIES, EditArchiveHandlers::MAX_BZIP2_INPUT_BYTES
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::CHAT_HISTORY_LIMIT, EditHandlers::COMPACT_INPUT_LIMIT, EditHandlers::EDIT_HTML_TEMPLATE, EditHandlers::EXCLUDED_TREE_DIRS, EditHandlers::MAX_DIR_ENTRIES, EditHandlers::MEDIA_KINDS, EditHandlers::MEDIA_KIND_BY_EXT, EditHandlers::RAW_CONTENT_TYPES, EditHandlers::TARGET_SUMMARY_LIMIT
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, config: nil) ⇒ Server
constructor
planner: Planner インスタンス (run(request, expectations:) -> Planner::Result)。 edit UI 用に PathGuard / base_dir / vendor / console 情報も受け取る (任意)。 chat_client: 会話 (ツール不要の質問) を判定・応答する ChatClient (任意)。 未指定なら /edit チャットは従来どおり全指示を Planner に流す。 config: Config インスタンス (任意)。渡すと /edit のモデル切り替え (POST /edit/model) で Planner / chat_client を再構築できるようになる。.
-
#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 EditArchiveHandlers
#accumulate_top_level, #archive?, #archive_kind, #build_result, #bunzip2, #find_eocd, #gunzip, #gzip_uncompressed_size, #handle_edit_archive, #inspect_archive, #inspect_single_compressed, #inspect_tar, #inspect_zip, #normalize_entry_name, #zip_central_directory, #zip_decode_name
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_dir, #handle_edit_file, #handle_edit_fs_delete, #handle_edit_fs_mkdir, #handle_edit_fs_rename, #handle_edit_fs_touch, #handle_edit_model, #handle_edit_models, #handle_edit_raw, #handle_edit_save, #handle_edit_static, #humanize_chat_error, #list_dir_entries, #media_content_type, #media_kind, #normalize_fs_path, #ollama_model_names, #parse_byte_range, #parse_chat_history, #rebuild_llm!, #relative_root, #result_field, #run_chat_stream, #serve_edit_static, #serve_raw_file, #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, config: nil) ⇒ Server
planner: Planner インスタンス (run(request, expectations:) -> Planner::Result)。 edit UI 用に PathGuard / base_dir / vendor / console 情報も受け取る (任意)。 chat_client: 会話 (ツール不要の質問) を判定・応答する ChatClient (任意)。 未指定なら /edit チャットは従来どおり全指示を Planner に流す。 config: Config インスタンス (任意)。渡すと /edit のモデル切り替え (POST /edit/model) で Planner / chat_client を再構築できるようになる。
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/chocomint/server.rb', line 32 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, config: nil) @planner = planner @chat_client = chat_client @config = config @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]
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/chocomint/server.rb', line 107 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]
130 131 132 133 134 |
# File 'lib/chocomint/server.rb', line 130 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
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 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/chocomint/server.rb', line 55 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/dir") { |req, res| handle_edit_dir(req, res) } server.mount_proc("/edit/file") { |req, res| handle_edit_file(req, res) } server.mount_proc("/edit/raw") { |req, res| handle_edit_raw(req, res) } server.mount_proc("/edit/archive") { |req, res| handle_edit_archive(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/models") { |req, res| handle_edit_models(req, res) } server.mount_proc("/edit/model") { |req, res| handle_edit_model(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 |