Module: AgentHarness::Providers::CodexModelDiscovery
- Included in:
- Codex
- Defined in:
- lib/agent_harness/providers/codex_model_discovery.rb
Overview
Runs the interactive protocol beside the CLI, including for executors that only expose execute (Docker/remote transports). Codex's npm installation already requires Node. No shell, host credentials, or host CLI is used.
Constant Summary collapse
- SCRIPT =
"const { spawn } = require('node:child_process');\nconst child = spawn(process.argv[1], ['app-server', '--listen', 'stdio://'], {stdio: ['pipe', 'pipe', 'pipe']});\nlet buffer = '', bytes = 0, page = 0, done = false;\nconst models = [], cursors = new Set();\nconst send = value => child.stdin.write(JSON.stringify(value) + '\\n');\nconst finish = (code, value) => {\n if (done) return;\n done = true;\n clearTimeout(timer);\n if (value) process.stdout.write(JSON.stringify(value) + '\\n');\n process.exitCode = code;\n child.stdin.end();\n child.kill('SIGTERM');\n setTimeout(() => child.kill('SIGKILL'), 250).unref();\n};\nconst timer = setTimeout(() => finish(1), Number(process.argv[2]));\nchild.on('error', () => finish(1));\nchild.stdin.on('error', () => finish(1));\nchild.stderr.on('data', () => {});\nchild.on('close', () => { if (!done) finish(1); });\nchild.stdout.on('data', chunk => {\n bytes += chunk.length;\n if (bytes > 1048576) return finish(1);\n buffer += chunk.toString();\n let end;\n while (!done && (end = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0, end); buffer = buffer.slice(end + 1);\n let msg; try { msg = JSON.parse(line); } catch { continue; }\n if (msg.id !== 1 && msg.id !== 2) continue;\n if (msg.error) return finish(0, {id: 2, error: msg.error});\n if (msg.id === 1) {\n send({method: 'initialized', params: {}});\n send({id: 2, method: 'model/list', params: {limit: 100}});\n } else {\n if (!Array.isArray(msg.result?.data)) return finish(1);\n models.push(...msg.result.data);\n const cursor = msg.result.nextCursor;\n if (!cursor) return finish(0, {id: 2, result: {data: models}});\n if (++page >= 10 || cursors.has(cursor)) return finish(1);\n cursors.add(cursor);\n send({id: 2, method: 'model/list', params: {limit: 100, cursor}});\n }\n }\n});\nsend({id: 1, method: 'initialize', params: {clientInfo: {name: 'agent-harness', version: '1.0.0'}}});\n"
Instance Method Summary collapse
-
#discover_available_models(env:, timeout: 15) ⇒ Object
Fresh account-local discovery.
Instance Method Details
#discover_available_models(env:, timeout: 15) ⇒ Object
Fresh account-local discovery. The caller owns selection policy and must still smoke-test its selected model; model/list is not execution proof.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/agent_harness/providers/codex_model_discovery.rb', line 59 def discover_available_models(env:, timeout: 15) result = execute_model_discovery(env: env, timeout: timeout) return unavailable_model_discovery(:app_server_failed) unless result.success? response = parse_app_server_response(result.stdout, 2) return unavailable_model_discovery(:model_list_missing_response) unless response return unavailable_model_discovery(:model_list_error) if response["error"] entries = Array(response.dig("result", "data")).filter_map { |entry| normalize_model_entry(entry) } .reject { |entry| entry[:hidden] }.uniq { |entry| entry[:id] } return unavailable_model_discovery(:no_compatible_model) if entries.empty? preferred = entries.find { |entry| entry[:is_default] } || entries.first self.class::ModelDiscovery.new(status: :available, models: entries, recommended_model_id: preferred[:id], source: :codex_app_server_model_list) rescue TimeoutError unavailable_model_discovery(:app_server_timeout) end |