Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 78 additions & 1 deletion packages/cli/src/__tests__/acp-agent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,43 @@ describe('Maka ACP agent', () => {
assert.deepEqual(lists, [{ cwd: '/workspace' }]);
});

test('routes official SDK set-config requests through the Session registry', async () => {
const configurationRequests: unknown[] = [];
await client({ name: 'test-client' }).connectWith(
createMakaAcpAgent({
version: '0.2.0',
sessionRegistry: fakeSessionRegistry({ configurationRequests }),
}),
async (agent) => {
assert.deepEqual(
await agent.request(methods.agent.session.setConfigOption, {
sessionId: 'session-1',
configId: 'collaboration_mode',
value: 'plan',
}),
{
configOptions: [
{
type: 'select',
id: 'collaboration_mode',
name: 'Collaboration mode',
category: 'mode',
currentValue: 'plan',
options: [
{ value: 'agent', name: 'Agent' },
{ value: 'plan', name: 'Plan' },
],
},
],
},
);
},
);
assert.deepEqual(configurationRequests, [
{ sessionId: 'session-1', configId: 'collaboration_mode', value: 'plan' },
]);
});

test('does not implement or advertise session/close', async () => {
await client({ name: 'test-client' }).connectWith(
createMakaAcpAgent({ version: '0.2.0', sessionRegistry: fakeSessionRegistry() }),
Expand All @@ -87,6 +124,26 @@ describe('Maka ACP agent', () => {
);
});

test('does not implement session/set_mode', async () => {
await client({ name: 'test-client' }).connectWith(
createMakaAcpAgent({ version: '0.2.0', sessionRegistry: fakeSessionRegistry() }),
async (agent) => {
await assert.rejects(
agent.request(methods.agent.session.setMode, {
sessionId: 'session-1',
modeId: 'plan',
}),
(error: unknown) => {
assert.ok(error instanceof RequestError);
assert.equal(error.code, -32601);
assert.deepEqual(error.data, { method: 'session/set_mode' });
return true;
},
);
},
);
});

test('selects v1 when the client requests an unsupported lower or higher version', async () => {
for (const protocolVersion of [0, 2]) {
await client({ name: 'test-client' }).connectWith(
Expand All @@ -100,7 +157,9 @@ describe('Maka ACP agent', () => {
});
});

function fakeSessionRegistry(observations: { creates?: unknown[]; lists?: unknown[] } = {}) {
function fakeSessionRegistry(
observations: { creates?: unknown[]; lists?: unknown[]; configurationRequests?: unknown[] } = {},
) {
return {
create: async (params: unknown) => {
observations.creates?.push(params);
Expand All @@ -119,5 +178,23 @@ function fakeSessionRegistry(observations: { creates?: unknown[]; lists?: unknow
],
};
},
setConfigOption: async (params: unknown) => {
observations.configurationRequests?.push(params);
return {
configOptions: [
{
type: 'select' as const,
id: 'collaboration_mode',
name: 'Collaboration mode',
category: 'mode',
currentValue: 'plan',
options: [
{ value: 'agent', name: 'Agent' },
{ value: 'plan', name: 'Plan' },
],
},
],
};
},
};
}
54 changes: 54 additions & 0 deletions packages/cli/src/__tests__/acp-child-process-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ import {
type ClientConnection,
type ClientContext,
} from '@agentclientprotocol/sdk';
import type { ThinkingLevel } from '@maka/core/model-thinking';
import {
startExecutionRuntimeHostService,
type RuntimeHostKernel,
} from '@maka/runtime-host/server';
import { openInteractiveRuntimePolicyStoresForWrite } from '@maka/storage/runtime-policy-stores';
import { resolveStorageRoot, tryAcquireInteractiveRootOwner } from '@maka/storage/root-authority';
import { STORAGE_ROOT_MARKER_FILE } from '@maka/storage/root-authority';
import { deriveMakaDataRoots, resolveMakaClientDataRoot } from '../workspace-root.js';

Expand All @@ -42,6 +45,10 @@ const DEFAULT_TIMEOUT_MS = 15_000;
export interface AcpChildProcessHarnessOptions {
readonly timeoutMs?: number;
readonly startRuntimeHost?: boolean;
readonly model?: {
readonly id: string;
readonly thinkingLevels: readonly ThinkingLevel[];
};
}

export interface AcpChildProcessExit {
Expand Down Expand Up @@ -289,6 +296,7 @@ export async function startAcpChildProcessHarness(
let rootCleanupFollowsHostStartup = false;
try {
await mkdir(workspaceRoot, { recursive: true });
if (options.model) await seedModelConnection(workspaceRoot, options.model);
if (options.startRuntimeHost) {
hostStartup = startExecutionRuntimeHostService({ rootPath: workspaceRoot });
try {
Expand Down Expand Up @@ -341,6 +349,52 @@ export async function startAcpChildProcessHarness(
}
}

async function seedModelConnection(
rootPath: string,
model: NonNullable<AcpChildProcessHarnessOptions['model']>,
): Promise<void> {
const capability = await resolveStorageRoot({ path: rootPath, kind: 'interactive' });
const owner = await tryAcquireInteractiveRootOwner(capability);
if (!owner) throw new Error('Unable to acquire ACP model fixture root');
try {
const policy = await openInteractiveRuntimePolicyStoresForWrite(owner.lease);
const created = await policy.connectionCatalog.create({
expectedCatalogRevision: 0,
connection: {
slug: 'acp-fixture-model',
name: 'ACP fixture model',
providerType: 'openai-compatible',
baseUrl: 'https://acp-model.invalid/v1',
enabled: true,
enabledModelIds: [model.id],
relayModelProfiles: {
[model.id]: { thinkingLevels: model.thinkingLevels },
},
},
});
if (created.kind !== 'committed') throw new Error('ACP model fixture did not commit');
const connection = created.snapshot.connections[0];
if (!connection) throw new Error('ACP model fixture connection was not persisted');
const credential = await policy.credentialVault.set({
locator: {
scope: 'connection',
connectionId: connection.connectionId,
kind: 'api_key',
},
expected: null,
secret: 'acp-fixture-key',
});
if (credential.kind !== 'committed') throw new Error('ACP model fixture key did not commit');
const defaulted = await policy.connectionCatalog.setDefaultTarget({
expectedCatalogRevision: created.snapshot.revision,
target: { connectionId: connection.connectionId, modelId: model.id },
});
if (defaulted.kind !== 'committed') throw new Error('ACP model fixture was not selected');
} finally {
await owner.close();
}
}

export async function withAcpChildProcessHarness<T>(
operation: (harness: AcpChildProcessHarness) => Promise<T> | T,
options: AcpChildProcessHarnessOptions = {},
Expand Down
91 changes: 91 additions & 0 deletions packages/cli/src/__tests__/acp-child-process.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,27 @@ describe('Maka ACP child process', () => {
cwd: harness.workspaceRoot,
mcpServers: [],
});
assert.deepEqual(
(first.configOptions ?? []).map((option) => [option.id, option.currentValue]),
[
['permission_mode', 'ask'],
['collaboration_mode', 'agent'],
['orchestration_mode', 'default'],
],
);
const configured = await context.request(methods.agent.session.setConfigOption, {
sessionId: first.sessionId,
configId: 'collaboration_mode',
value: 'plan',
});
assert.deepEqual(
(configured.configOptions ?? []).map((option) => [option.id, option.currentValue]),
[
['permission_mode', 'ask'],
['collaboration_mode', 'plan'],
['orchestration_mode', 'default'],
],
);
const second = await context.request(methods.agent.session.new, {
cwd: harness.workspaceRoot,
mcpServers: [],
Expand Down Expand Up @@ -198,6 +219,76 @@ describe('Maka ACP child process', () => {
);
});

test('configures every advertised option for a reasoning model through a real Runtime Host', {
timeout: 30_000,
}, async () => {
await withAcpChildProcessHarness(
async (harness) => {
await harness.withClient(async ({ context }) => {
await context.request(methods.agent.initialize, { protocolVersion: 1 });
const created = await context.request(methods.agent.session.new, {
cwd: harness.workspaceRoot,
mcpServers: [],
});
assert.deepEqual(
(created.configOptions ?? []).map(({ id, currentValue }) => [id, currentValue]),
[
['permission_mode', 'ask'],
['thinking_level', 'default'],
['collaboration_mode', 'agent'],
['orchestration_mode', 'default'],
],
);
const permission = created.configOptions?.find(({ id }) => id === 'permission_mode');
assert.ok(permission?.type === 'select');
assert.deepEqual(
permission.options.flatMap((option) => ('value' in option ? [option.value] : [])),
['ask', 'bypass'],
);
const thinking = created.configOptions?.find(({ id }) => id === 'thinking_level');
assert.ok(thinking?.type === 'select');
assert.deepEqual(
thinking.options.flatMap((option) => ('value' in option ? [option.value] : [])),
['default', 'low', 'high'],
);

let configuredOptions = created.configOptions;
for (const [configId, value] of [
['permission_mode', 'bypass'],
['thinking_level', 'high'],
['collaboration_mode', 'plan'],
['orchestration_mode', 'swarm'],
] as const) {
configuredOptions = (
await context.request(methods.agent.session.setConfigOption, {
sessionId: created.sessionId,
configId,
value,
})
).configOptions;
}
assert.deepEqual(
(configuredOptions ?? []).map(({ id, currentValue }) => [id, currentValue]),
[
['permission_mode', 'bypass'],
['thinking_level', 'high'],
['collaboration_mode', 'plan'],
['orchestration_mode', 'swarm'],
],
);
});

await harness.closeStdin();
assert.deepEqual(await harness.waitForExit(), { code: 0, signal: null });
assert.equal(harness.stderr, '');
},
{
startRuntimeHost: true,
model: { id: 'relay-reasoner', thinkingLevels: ['low', 'high'] },
},
);
});

test('creates more than sixteen Sessions without attaching on a real Runtime Host', {
timeout: 30_000,
}, async () => {
Expand Down
Loading