@@ -10,6 +10,7 @@ import { spawnEnvForAgent } from './env.js';
1010import { probeAgentAuthStatus } from './auth.js' ;
1111import { agentCapabilities } from './capabilities.js' ;
1212import { installMetaForAgent } from './metadata.js' ;
13+ import { resolveAmrOpenCodeExecutable } from './executables.js' ;
1314import { resolveAmrProfile } from '../integrations/vela.js' ;
1415import {
1516 buildAuthDiagnostic ,
@@ -31,6 +32,25 @@ type FetchedRuntimeModels = {
3132 source : RuntimeModelSource ;
3233} ;
3334
35+ export interface DetectedRuntimeVersions {
36+ agentCliVersion ?: string ;
37+ runtimeCompanionName ?: string ;
38+ runtimeCompanionVersion ?: string ;
39+ }
40+
41+ // Detection already pays the bounded `--version` probe cost used by Settings.
42+ // Keep the result as daemon-lifetime provenance so run telemetry can name the
43+ // exact executable family without spawning another process on every turn.
44+ const detectedRuntimeVersions = new Map < string , DetectedRuntimeVersions > ( ) ;
45+
46+ export function getDetectedRuntimeVersions (
47+ agentId : string | null | undefined ,
48+ ) : DetectedRuntimeVersions | null {
49+ if ( ! agentId ) return null ;
50+ const remembered = detectedRuntimeVersions . get ( agentId ) ;
51+ return remembered ? { ...remembered } : null ;
52+ }
53+
3454function configuredEnvForAgent (
3555 configuredEnvByAgent : Record < string , Record < string , string > > ,
3656 agentId : string ,
@@ -153,6 +173,24 @@ async function probeVersionAtPath(
153173 }
154174}
155175
176+ async function probeAmrOpenCodeVersion (
177+ def : RuntimeAgentDef ,
178+ env : NodeJS . ProcessEnv ,
179+ ) : Promise < string | null > {
180+ if ( def . id !== 'amr' ) return null ;
181+ const companion = resolveAmrOpenCodeExecutable ( env ) ;
182+ if ( ! companion ) return null ;
183+ try {
184+ const { stdout } = await execAgentFile ( companion , [ '--version' ] , {
185+ env,
186+ timeout : def . versionProbeTimeoutMs ?? 3000 ,
187+ } ) ;
188+ return String ( stdout ) . trim ( ) . split ( '\n' ) [ 0 ] || null ;
189+ } catch {
190+ return null ;
191+ }
192+ }
193+
156194function unavailableAgent (
157195 def : RuntimeAgentDef ,
158196 diagnostics : AgentDiagnostic [ ] = [ ] ,
@@ -200,6 +238,7 @@ async function probe(
200238 def : RuntimeAgentDef ,
201239 configuredEnv : Record < string , string > = { } ,
202240) : Promise < DetectedAgent > {
241+ detectedRuntimeVersions . delete ( def . id ) ;
203242 // Detection must probe the exact path the runtime will spawn, not just the
204243 // PATH-visible shim. This is load-bearing for Codex under nvm/fnm/mise:
205244 // the discovered `codex` entry is often a `#!/usr/bin/env node` wrapper
@@ -236,16 +275,29 @@ async function probe(
236275 // so a single agent's detection wall is max(help, models, auth) ≈ 5s rather
237276 // than the sum ≈ 15s. `--help` capabilities are cached on `agentCapabilities`
238277 // for buildArgs to consult.
239- const [ caps , modelResult , auth ] = await Promise . all ( [
278+ const [ caps , modelResult , auth , amrOpenCodeVersion ] = await Promise . all ( [
240279 probeCapabilities ( def , launch . launchPath , probeEnv ) ,
241280 fetchModels ( def , launch . launchPath , probeEnv ) ,
242281 probeAgentAuthStatus ( def , launch . launchPath , probeEnv ) ,
282+ probeAmrOpenCodeVersion ( def , probeEnv ) ,
243283 ] ) ;
244284 const surfacedModelResult = withRememberedAmrModels ( def , probeEnv , modelResult ) ;
245285 if ( caps ) {
246286 agentCapabilities . set ( def . id , caps ) ;
247287 }
248288 const authDiagnostic = auth ? buildAuthDiagnostic ( def , auth ) : null ;
289+ const runtimeVersions : DetectedRuntimeVersions = {
290+ ...( outcome . version ? { agentCliVersion : outcome . version } : { } ) ,
291+ ...( amrOpenCodeVersion
292+ ? {
293+ runtimeCompanionName : 'opencode' ,
294+ runtimeCompanionVersion : amrOpenCodeVersion ,
295+ }
296+ : { } ) ,
297+ } ;
298+ if ( Object . keys ( runtimeVersions ) . length > 0 ) {
299+ detectedRuntimeVersions . set ( def . id , runtimeVersions ) ;
300+ }
249301 return {
250302 ...stripFns ( def ) ,
251303 models : surfacedModelResult . models ,
0 commit comments