Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
52a6c9020This file is pinned to the selected release. Download the original to open it in your design tool.
import { afterEach, describe, expect, it } from 'vitest'
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { assignmentMatches, classifyGridAssignment, probeGridAssignment, readOpencodeGridAssignment, readPiGridAssignment } from './gridAssignment.js'
import { buildGridEngineLaunch, gridCapableEngines, type GridLaunchOverride } from './gridLaunch.js'
import type { AgentEngine } from '../engines/types.js'
import { clearProcessEnvCache, parsePsEnviron } from './processEnv.js'
const NETWORK_ID = 'grid-3378218621364f16'
const RELAY = `https://grid.autonomous.ai/${NETWORK_ID}/relay`
const RELAY_V1 = `${RELAY}/v1`
const OVERRIDE: GridLaunchOverride = {
networkId: NETWORK_ID,
networkName: 'autonomous.ai',
baseUrl: RELAY_V1,
apiKey: 'gridkey-secret',
model: 'GLM-4.7-Flash',
}
/** The same launch with the grid's web tools wired in — see `gridLaunch`'s MCP section. */
const WITH_MCP: GridLaunchOverride = {
...OVERRIDE,
mcpUrl: 'https://api-grid.autonomous.ai/v1/grid/web-mcp/',
}
describe('classifyGridAssignment', () => {
it('reads back what every supported engine was actually launched with', () => {
// The point of the round trip: the probe and the launcher must use the SAME knob per engine, or
// an agent that IS on a grid reports as being on none and gets pointlessly restarted.
for (const engine of gridCapableEngines()) {
// Pi and OpenCode keep their endpoint in a file rather than in the process, so they
// round-trip through their own probes below — this one only covers what a process carries.
if (engine === 'pi' || engine === 'opencode') continue
const built = buildGridEngineLaunch(engine, OVERRIDE, { hermesSystemManaged: false })
expect(built.ok).toBe(true)
if (!built.ok) continue
const assignment = classifyGridAssignment(engine, built.launch.env, built.launch.args.join(' '))
expect(assignment, engine).not.toBeNull()
expect(assignment?.baseUrl, engine).toContain(NETWORK_ID)
expect(assignment?.model, engine).toBe('GLM-4.7-Flash')
}
})
it('never carries the credential out of the process', () => {
for (const engine of gridCapableEngines()) {
if (engine === 'pi' || engine === 'opencode') continue
const built = buildGridEngineLaunch(engine, OVERRIDE, { hermesSystemManaged: false })
if (!built.ok) continue
const assignment = classifyGridAssignment(engine, built.launch.env, built.launch.args.join(' '))
expect(JSON.stringify(assignment), engine).not.toContain('gridkey-secret')
}
})
it('leaves an agent the user pointed somewhere else alone', () => {
// Offering to "move" these away from where they were deliberately sent would be the app
// overruling a choice it did not make.
expect(classifyGridAssignment('claude', { ANTHROPIC_BASE_URL: 'https://openrouter.ai/api' })).toBeNull()
expect(classifyGridAssignment('opencode', { OPENAI_BASE_URL: 'http://localhost:8080/v1' })).toBeNull()
expect(classifyGridAssignment('claude', {})).toBeNull()
expect(classifyGridAssignment('claude', { ANTHROPIC_BASE_URL: ' ' })).toBeNull()
expect(classifyGridAssignment('claude', { ANTHROPIC_BASE_URL: 'not a url' })).toBeNull()
})
it('reads Codex off its argv, where its endpoint actually lives', () => {
const args = `codex -c model_provider="grid" -c model_providers.grid.base_url="${RELAY_V1}" -m GLM-4.7-Flash`
expect(classifyGridAssignment('codex', { GRID_API_KEY: 'gridkey-secret' }, args))
.toEqual({ baseUrl: RELAY_V1, model: 'GLM-4.7-Flash' })
// Its environment alone says nothing — reading only env would report every codex agent as free.
expect(classifyGridAssignment('codex', { GRID_API_KEY: 'gridkey-secret' })).toBeNull()
})
it('reads Grok\'s argv model, and reports the router as no model at all', () => {
const env = { GROK_MODELS_BASE_URL: RELAY_V1, GRID_API_KEY: 'gridkey-secret' }
expect(classifyGridAssignment('grok', env, 'grok -m DeepSeek-V4-Flash-0731'))
.toEqual({ baseUrl: RELAY_V1, model: 'DeepSeek-V4-Flash-0731' })
// ⚠️ Grok ALWAYS carries `-m`, unlike codex: its grid credential rides on a declared model block,
// so "let the grid route" is spelled `-m Auto` rather than by omitting the flag. Reporting that id
// verbatim would print `Auto` where the app prints its own Auto row from null, and
// `assignmentMatches` would compare 'Auto' against null and call every routed agent misplaced,
// forever — the same trap opencode's reader documents.
expect(classifyGridAssignment('grok', env, 'grok -m Auto'))
.toEqual({ baseUrl: RELAY_V1, model: null })
})
it('does not confuse one engine\'s knob for another\'s', () => {
// A grok agent whose OPENAI_BASE_URL happens to be set by the user's shell is not on a grid.
expect(classifyGridAssignment('grok', { OPENAI_BASE_URL: RELAY_V1 })).toBeNull()
expect(classifyGridAssignment('copilot', { ANTHROPIC_BASE_URL: RELAY })).toBeNull()
})
it('reads a real macOS `ps eww` line, which is how this actually arrives', () => {
const line = `/Users/u/.local/bin/claude --resume abc ANTHROPIC_BASE_URL=${RELAY}`
+ ' ANTHROPIC_AUTH_TOKEN=gridkey-secret ANTHROPIC_MODEL=GLM-4.7-Flash HOME=/Users/u'
expect(classifyGridAssignment('claude', parsePsEnviron(line)))
.toEqual({ baseUrl: RELAY, model: 'GLM-4.7-Flash' })
})
it('has no answer for an engine that cannot be on a grid at all', () => {
expect(classifyGridAssignment('cursor', { ANTHROPIC_BASE_URL: RELAY })).toBeNull()
})
})
describe('Pi, whose endpoint lives in a file', () => {
const dirs: string[] = []
afterEach(() => {
clearProcessEnvCache()
for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true })
})
/** Writes the launch's own config files where the probe will look for them. */
function materialize(): { dir: string; args: string } {
const built = buildGridEngineLaunch('pi', OVERRIDE, { hermesSystemManaged: false })
if (!built.ok) throw new Error(built.detail)
const dir = mkdtempSync(join(tmpdir(), 'pi-grid-'))
dirs.push(dir)
for (const file of built.launch.configDir!.files) writeFileSync(join(dir, file.name), file.content)
return { dir, args: `pi ${built.launch.args.join(' ')}` }
}
it('round-trips: what the launcher wrote is what the probe reads back', async () => {
const { dir, args } = materialize()
// Parsed from a real macOS `ps eww` line — argv first, then the environment — so the shape the
// probe is handed at runtime is the shape under test.
const env = parsePsEnviron(`${args} PI_CODING_AGENT_DIR=${dir} GRID_API_KEY=gridkey-secret`)
await expect(readPiGridAssignment(env, args)).resolves.toEqual({
baseUrl: RELAY_V1,
model: 'GLM-4.7-Flash',
})
await expect(readPiGridAssignment(env, args)).resolves.toSatisfy(
(a: { baseUrl: string; model: string | null }) => assignmentMatches(a, NETWORK_ID, 'GLM-4.7-Flash'),
)
})
it('a config directory that is gone reads as unknown, not as fine', async () => {
const { dir, args } = materialize()
const env = parsePsEnviron(`${args} PI_CODING_AGENT_DIR=${dir}`)
rmSync(dir, { recursive: true, force: true })
// Nothing to read → null → the app offers a move rather than claiming the agent is in place.
await expect(readPiGridAssignment(env, args)).resolves.toBeNull()
})
it('reads nothing when the pane was never given a config directory', async () => {
const { args } = materialize()
await expect(readPiGridAssignment({}, args)).resolves.toBeNull()
})
it('will not call a provider pointed somewhere else a grid', async () => {
const { dir, args } = materialize()
writeFileSync(join(dir, 'models.json'), JSON.stringify({
providers: { grid: { baseUrl: 'https://api.openai.com/v1' } },
}))
const env = parsePsEnviron(`${args} PI_CODING_AGENT_DIR=${dir}`)
await expect(readPiGridAssignment(env, args)).resolves.toBeNull()
})
})
describe('assignmentMatches', () => {
const assignment = { baseUrl: RELAY, model: 'GLM-4.7-Flash' }
it('matches the grid and the model the user picked', () => {
expect(assignmentMatches(assignment, NETWORK_ID, 'GLM-4.7-Flash')).toBe(true)
})
it('does not match a different grid, or the same grid on a different model', () => {
expect(assignmentMatches(assignment, 'grid-e3b210eacc5b4cdf', 'GLM-4.7-Flash')).toBe(false)
expect(assignmentMatches(assignment, NETWORK_ID, 'DeepSeek-V4-Flash-0731')).toBe(false)
expect(assignmentMatches(assignment, NETWORK_ID, null)).toBe(false)
})
it('treats an unknown assignment as not matching, never as fine', () => {
// The whole point: "we could not tell" must cost a needless move offer, never a silent claim that
// an agent is already where the user asked for.
expect(assignmentMatches(null, NETWORK_ID, null)).toBe(false)
expect(assignmentMatches(undefined, NETWORK_ID, null)).toBe(false)
})
it('matches an unpinned model only against an unpinned choice', () => {
const unpinned = { baseUrl: RELAY, model: null }
expect(assignmentMatches(unpinned, NETWORK_ID, null)).toBe(true)
expect(assignmentMatches(unpinned, NETWORK_ID, 'GLM-4.7-Flash')).toBe(false)
})
})
describe('readOpencodeGridAssignment', () => {
const dirs: string[] = []
afterEach(() => {
for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true })
})
// OpenCode's endpoint lives in the config file this daemon wrote, not in a variable. Two
// regressions are pinned here:
// * listing opencode under BASE_URL_VAR while its endpoint had moved made every opencode agent
// report "own login" while the grid answered correctly underneath;
// * reading the model out of argv made the app's pill flicker between the model and "own login"
// while the agent was answering, because a live process may rewrite its command line.
const RELAY = 'https://grid.autonomous.ai/grid-3378218621364f16/relay/v1'
const write = (body: unknown): string => {
const dir = mkdtempSync(join(tmpdir(), 'harness-opencode-cfg-'))
dirs.push(dir)
const path = join(dir, 'opencode.json')
writeFileSync(path, JSON.stringify(body))
return path
}
const config = (baseURL: string, models: string[] = ['DeepSeek-V4-Flash-0731']) => ({
provider: {
'autonomous-ai': {
npm: '@ai-sdk/openai-compatible',
options: { baseURL },
models: Object.fromEntries(models.map((m) => [m, { name: m }])),
},
},
})
it('round-trips the config the LAUNCHER writes, not one written by hand', async () => {
// The strongest form of this test: build the real launch, write its real files where the probe
// will look, and read them back. A spec that hand-writes the config proves only that two
// hand-written shapes agree.
const built = buildGridEngineLaunch('opencode', OVERRIDE, { hermesSystemManaged: false })
if (!built.ok) throw new Error(built.detail)
const dir = mkdtempSync(join(tmpdir(), 'opencode-grid-'))
dirs.push(dir)
for (const file of built.launch.configDir!.files) {
writeFileSync(join(dir, file.name), file.content)
}
const assignment = await readOpencodeGridAssignment({
[built.launch.configDir!.envVar]: join(dir, built.launch.configDir!.pointAt!),
})
expect(assignment).not.toBeNull()
expect(assignment!.baseUrl).toContain(NETWORK_ID)
expect(assignment!.model).toBe(OVERRIDE.model)
// And the credential never leaves the process, exactly as for every other engine.
expect(JSON.stringify(assignment)).not.toContain('gridkey-secret')
})
it('reports the router as NO model, the way every other engine does', async () => {
// OpenCode is the only engine whose provider block must name something, so a launch with no
// model picked writes the relay's router id there. Letting that id back out would be the app's
// own "Auto" under a second name: the header would print the raw id, and `assignmentMatches`
// would compare it against null and call every such agent mis-targeted forever.
const path = write(config(RELAY, ['Auto']))
await expect(readOpencodeGridAssignment({ OPENCODE_CONFIG: path }))
.resolves.toEqual({ baseUrl: RELAY, model: null })
})
it('answers the same whatever the engine has done to its command line', async () => {
// The flicker: argv is a live process's to rewrite, so nothing here may depend on it.
const path = write(config(RELAY))
const expected = { baseUrl: RELAY, model: 'DeepSeek-V4-Flash-0731' }
await expect(readOpencodeGridAssignment({ OPENCODE_CONFIG: path })).resolves.toEqual(expected)
})
it('answers null for an endpoint that is not a relay', async () => {
const path = write(config('https://api.openai.com/v1'))
await expect(readOpencodeGridAssignment({ OPENCODE_CONFIG: path })).resolves.toBeNull()
})
it('answers null for a file this launch did not write', async () => {
// A user's own config can carry several providers; guessing which one an engine would pick
// would report an agent as being on a grid it is not on.
const path = write({
provider: {
'autonomous-ai': { options: { baseURL: RELAY }, models: { a: {} } },
other: { options: { baseURL: RELAY } },
},
})
await expect(readOpencodeGridAssignment({ OPENCODE_CONFIG: path })).resolves.toBeNull()
})
it('answers null when the provider names more than one model', async () => {
// Then the file cannot say which one is live, and a guess would be reported as a measurement.
const path = write(config(RELAY, ['DeepSeek-V4-Flash-0731', 'Auto']))
await expect(readOpencodeGridAssignment({ OPENCODE_CONFIG: path })).resolves.toBeNull()
})
it('answers null rather than throwing when the file is gone or unreadable', async () => {
await expect(readOpencodeGridAssignment({ OPENCODE_CONFIG: '/nonexistent/opencode.json' }))
.resolves.toBeNull()
await expect(readOpencodeGridAssignment({})).resolves.toBeNull()
})
})
describe('a failed read is not a finding', () => {
// The flicker this pins: the app's grid pill swapped between an agent's model and "own login" for
// the length of every turn. Each probe whose `ps` did not answer in time reported "on no grid",
// the registry wrote that over a known-good assignment, and the next successful probe put it back.
//
// The distinction is the fix, not the failure rate. A read can fail for reasons this code will
// never enumerate — a busy machine, a 2s timeout, a process caught mid-exec — and none of them are
// evidence about where an agent is pointed.
const DEAD_PID = 2 ** 31 - 1
it('answers undefined when the environment cannot be read at all', async () => {
clearProcessEnvCache()
await expect(probeGridAssignment(
{ pid: DEAD_PID, executable: 'opencode', startMarker: 'Mon Jan 1 00:00:00 2035' },
'opencode',
)).resolves.toBeUndefined()
})
it('is distinguishable from a read that found no grid', () => {
// Same call shape, opposite meaning: this one looked and there was nothing.
expect(classifyGridAssignment('claude', { PATH: '/usr/bin' })).toBeNull()
// `null == undefined` is true, so only a strict check tells these apart — which is exactly what
// `openProcessAgent` and `updateProcessIdentity` do.
expect(classifyGridAssignment('claude', { PATH: '/usr/bin' })).not.toBeUndefined()
})
})
describe('web tools do not disturb the probe', () => {
// Wiring MCP adds argv to Codex and a key to OpenCode's config file, and both are things the probe
// parses. An agent that IS on a grid reporting as being on none gets pointlessly restarted, so the
// round trips above are repeated against the shape a launch with web tools produces.
const dirs: string[] = []
afterEach(() => {
for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true })
})
const classify = (engine: AgentEngine, override: GridLaunchOverride) => {
const built = buildGridEngineLaunch(engine, override, { hermesSystemManaged: false })
if (!built.ok) throw new Error(`${engine}: ${built.detail}`)
return classifyGridAssignment(engine, built.launch.env, built.launch.args.join(' '))
}
it('reads a process back identically with the MCP argv in the way', () => {
for (const engine of gridCapableEngines()) {
if (engine === 'pi' || engine === 'opencode') continue
// Compared against the same engine launched WITHOUT web tools rather than a literal, so this
// states the invariant — wiring MCP changes nothing the probe reads — in a form that survives
// an engine changing which URL shape it wants.
expect(classify(engine, WITH_MCP), engine).toEqual(classify(engine, OVERRIDE))
expect(classify(engine, WITH_MCP)?.model, engine).toBe('GLM-4.7-Flash')
}
})
it('never reads the control plane as the place an agent is running', () => {
// Codex is the one at risk: its endpoint comes out of argv, which now also carries
// `mcp_servers.harness.url=…`. Reading that as the endpoint would report an agent as running on
// the control plane, and the app would offer to move it off a grid it is already on.
expect(classify('codex', WITH_MCP)?.baseUrl).toBe(RELAY_V1)
})
it("reads OpenCode's config back with the server declared beside the provider", async () => {
const built = buildGridEngineLaunch('opencode', WITH_MCP, { hermesSystemManaged: false })
if (!built.ok) throw new Error(built.detail)
const dir = mkdtempSync(join(tmpdir(), 'opencode-grid-mcp-'))
dirs.push(dir)
for (const file of built.launch.configDir!.files) {
writeFileSync(join(dir, file.name), file.content)
}
const assignment = await readOpencodeGridAssignment({
[built.launch.configDir!.envVar]: join(dir, built.launch.configDir!.pointAt!),
})
expect(assignment).toEqual({ baseUrl: RELAY_V1, model: 'GLM-4.7-Flash' })
})
})