De-hardcode orchestrator and interaction agent names (#748)
This commit was merged in pull request #748.
This commit is contained in:
@@ -189,6 +189,36 @@ describe('fleet roster parsing', () => {
|
||||
expect(getRosterAgent(roster, 'canary-pi').runtime).toBe('pi');
|
||||
});
|
||||
|
||||
it('accepts optional agent alias and provider metadata without requiring them', async () => {
|
||||
cleanup = await tempDir();
|
||||
const rosterPath = join(cleanup, 'roster.yaml');
|
||||
await writeFile(
|
||||
rosterPath,
|
||||
[
|
||||
'version: 1',
|
||||
'transport: tmux',
|
||||
'agents:',
|
||||
' - name: interaction',
|
||||
' alias: Friday',
|
||||
' provider: openai-codex',
|
||||
' runtime: pi',
|
||||
' - name: worker0',
|
||||
' runtime: codex',
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
const roster = await loadFleetRoster(rosterPath);
|
||||
|
||||
expect(getRosterAgent(roster, 'interaction')).toMatchObject({
|
||||
name: 'interaction',
|
||||
alias: 'Friday',
|
||||
provider: 'openai-codex',
|
||||
});
|
||||
expect(getRosterAgent(roster, 'worker0')).toMatchObject({ name: 'worker0' });
|
||||
expect(getRosterAgent(roster, 'worker0').alias).toBeUndefined();
|
||||
expect(getRosterAgent(roster, 'worker0').provider).toBeUndefined();
|
||||
});
|
||||
|
||||
it('socketArgs: named socket → -L <name>; empty → no -L (default socket)', () => {
|
||||
expect(socketArgs('mosaic-fleet')).toEqual(['-L', 'mosaic-fleet']);
|
||||
expect(socketArgs('')).toEqual([]);
|
||||
@@ -1872,7 +1902,61 @@ describe('fleet ps — tenant and host', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('fleet ps — JSON output shape (FR-6)', () => {
|
||||
describe('fleet ps — aliases and JSON output shape (FR-6)', () => {
|
||||
it('shows an agent alias in table output and falls back to name when absent', async () => {
|
||||
const home = await mkdtemp(join(tmpdir(), 'mosaic-fleet-'));
|
||||
const rosterPath = join(home, 'fleet', 'roster.yaml');
|
||||
await mkdir(join(home, 'fleet'), { recursive: true });
|
||||
await writeFile(
|
||||
rosterPath,
|
||||
[
|
||||
'version: 1',
|
||||
'transport: tmux',
|
||||
'agents:',
|
||||
' - name: interaction',
|
||||
' alias: Friday',
|
||||
' runtime: pi',
|
||||
' - name: worker0',
|
||||
' runtime: codex',
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
const runner: CommandRunner = async (command, args) => {
|
||||
const fullArgs = [command, ...args].join(' ');
|
||||
if (fullArgs.includes('list-sessions')) {
|
||||
return { stdout: 'interaction\nworker0\n', stderr: '', exitCode: 0 };
|
||||
}
|
||||
return {
|
||||
stdout: fullArgs.includes('systemctl')
|
||||
? 'ActiveState=active\nSubState=running\nUnitFileState=enabled\n'
|
||||
: '12345 pi 0 0 0 0\n',
|
||||
stderr: '',
|
||||
exitCode: 0,
|
||||
};
|
||||
};
|
||||
|
||||
const lines: string[] = [];
|
||||
const origLog = console.log;
|
||||
console.log = (msg: string) => {
|
||||
lines.push(msg);
|
||||
};
|
||||
|
||||
const program = new Command();
|
||||
program.exitOverride();
|
||||
registerFleetCommand(program, { runner, mosaicHome: home });
|
||||
|
||||
try {
|
||||
await program.parseAsync(['node', 'mosaic', 'fleet', 'ps']);
|
||||
} finally {
|
||||
console.log = origLog;
|
||||
await rm(home, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
const output = lines.join('\n');
|
||||
expect(output).toContain('Friday');
|
||||
expect(output).toContain('worker0');
|
||||
});
|
||||
|
||||
it('produces --json records including tenant_id and host for each agent', async () => {
|
||||
const home = await mkdtemp(join(tmpdir(), 'mosaic-fleet-'));
|
||||
const rosterPath = join(home, 'fleet', 'roster.yaml');
|
||||
|
||||
@@ -81,6 +81,8 @@ interface RawFleetRoster {
|
||||
runtimes?: Record<string, { reset_command?: unknown; resetCommand?: unknown }>;
|
||||
agents?: Array<{
|
||||
name?: unknown;
|
||||
alias?: unknown;
|
||||
provider?: unknown;
|
||||
runtime?: unknown;
|
||||
class?: unknown;
|
||||
working_directory?: unknown;
|
||||
@@ -102,6 +104,8 @@ interface RawFleetRoster {
|
||||
|
||||
export interface FleetAgent {
|
||||
name: string;
|
||||
alias?: string;
|
||||
provider?: string;
|
||||
runtime: string;
|
||||
className: string;
|
||||
workingDirectory?: string;
|
||||
@@ -1074,6 +1078,7 @@ export interface HeartbeatInfo {
|
||||
|
||||
export interface AgentPsRow {
|
||||
name: string;
|
||||
alias?: string;
|
||||
tenant_id: string;
|
||||
host: string;
|
||||
runtime: string;
|
||||
@@ -1755,6 +1760,7 @@ export function registerFleetCommand(program: Command, deps: FleetCommandDeps =
|
||||
|
||||
rows.push({
|
||||
name: agent.name,
|
||||
alias: agent.alias,
|
||||
tenant_id,
|
||||
host,
|
||||
runtime: agent.runtime,
|
||||
@@ -1888,7 +1894,7 @@ export function registerFleetCommand(program: Command, deps: FleetCommandDeps =
|
||||
|
||||
console.log(
|
||||
[
|
||||
row.name.padEnd(18),
|
||||
(row.alias ?? row.name).padEnd(18),
|
||||
row.tenant_id.padEnd(12),
|
||||
row.host.padEnd(12),
|
||||
row.runtime.padEnd(10),
|
||||
@@ -2494,6 +2500,8 @@ function normalizeAgent(raw: NonNullable<RawFleetRoster['agents']>[number]): Fle
|
||||
assertObject(raw, 'Fleet roster agent');
|
||||
assertKnownKeys(raw, 'Fleet roster agent', [
|
||||
'name',
|
||||
'alias',
|
||||
'provider',
|
||||
'runtime',
|
||||
'class',
|
||||
'working_directory',
|
||||
@@ -2525,6 +2533,8 @@ function normalizeAgent(raw: NonNullable<RawFleetRoster['agents']>[number]): Fle
|
||||
}
|
||||
return {
|
||||
name,
|
||||
alias: optionalString(raw.alias, `Fleet roster agent "${name}" alias`),
|
||||
provider: optionalString(raw.provider, `Fleet roster agent "${name}" provider`),
|
||||
runtime,
|
||||
className: stringValue(raw.class, 'worker', `Fleet roster agent "${name}" class`),
|
||||
workingDirectory: optionalString(
|
||||
@@ -2827,6 +2837,12 @@ export function serializeRosterToYaml(roster: FleetRoster): string {
|
||||
runtime: agent.runtime,
|
||||
class: agent.className,
|
||||
};
|
||||
if (agent.alias !== undefined) {
|
||||
raw['alias'] = agent.alias;
|
||||
}
|
||||
if (agent.provider !== undefined) {
|
||||
raw['provider'] = agent.provider;
|
||||
}
|
||||
if (agent.workingDirectory !== undefined) {
|
||||
raw['working_directory'] = agent.workingDirectory;
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ function readFleetToolPolicyBlock(policy: string | undefined): string {
|
||||
'',
|
||||
'Permitted: authorized conversation, status, retrieval, and safe diagnostics.',
|
||||
'Denied by default: coding/general orchestration claims, direct fleet control, destructive actions, and credential access.',
|
||||
'Delegate Mos-owned work through the authorized handoff boundary.',
|
||||
'Delegate orchestrator-owned work through the authorized handoff boundary.',
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user