blob: ec2c5e40cb603dbd088ed81eb759c8951750908e [file]
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { ClientCapabilityChannel } from '../client/client-capability-channel.js';
import type { ClientCapabilityProvider } from '../client/client-capability.js';
test('Client Capability channel closes a provider after its final registration is released', async () => {
let closeCalls = 0;
const replacements: string[] = [];
const provider: ClientCapabilityProvider = {
offers: () => [
{
offerId: 'fixture',
version: '0',
affinity: 'call',
label: 'Fixture',
tools: [
{
serverId: 'fixture',
name: 'inspect',
inputSchema: { type: 'object' },
},
],
},
],
call: async () => ({ content: [] }),
close: () => {
closeCalls += 1;
},
};
const channel = new ClientCapabilityChannel({
write: async () => undefined,
replace: async (input) => {
assert.equal(Object.hasOwn(input, 'services'), false);
replacements.push(input.registrationId);
return { registrationId: input.registrationId, revision: replacements.length };
},
unregister: async (input) => ({
registrationId: input.registrationId,
revision: replacements.length + 1,
}),
onFailure: (error) => {
throw error;
},
});
await channel.replace(provider, 1_000);
await channel.replace(provider, 1_000);
const [firstRegistrationId, secondRegistrationId] = replacements;
assert.ok(firstRegistrationId);
assert.ok(secondRegistrationId);
channel.accept({
kind: 'client.capability.registration_release',
registrationId: firstRegistrationId,
});
assert.equal(closeCalls, 0);
await channel.unregister(1_000);
channel.accept({
kind: 'client.capability.registration_release',
registrationId: secondRegistrationId,
});
assert.equal(closeCalls, 1);
channel.close(new Error('test complete'));
assert.equal(closeCalls, 1);
});
test('Client Capability channel runs a self-described Host service through admission', async () => {
let registrationId = '';
let accepted = false;
const written: unknown[] = [];
let channel!: ClientCapabilityChannel;
const provider: ClientCapabilityProvider = {
offers: () => [],
services: () => [{ serviceId: 'vendor_service', version: '1' }],
callService: async (frame, options) => {
assert.equal(frame.method, 'present');
assert.equal(accepted, false);
await options.accept();
accepted = true;
return { kind: 'presented' };
},
};
channel = new ClientCapabilityChannel({
write: async (frame) => {
written.push(frame);
if (frame.kind === 'client.capability.accepted') {
queueMicrotask(() =>
channel.accept({
kind: 'client.capability.admitted',
invocationId: frame.invocationId,
}),
);
}
},
replace: async (input) => {
registrationId = input.registrationId;
return { registrationId, revision: 1 };
},
unregister: async (input) => ({ registrationId: input.registrationId, revision: 2 }),
onFailure: (error) => {
throw error;
},
});
await channel.replace(provider, 1_000);
channel.accept({
kind: 'client.capability.service_call',
invocationId: 'service_invocation',
registrationId,
serviceId: 'vendor_service',
version: '1',
method: 'present',
input: {},
});
await new Promise((resolve) => setImmediate(resolve));
assert.equal(accepted, true);
assert.deepEqual(written, [
{ kind: 'client.capability.accepted', invocationId: 'service_invocation' },
{
kind: 'client.capability.result',
invocationId: 'service_invocation',
result: { content: [], structuredContent: { kind: 'presented' } },
},
]);
channel.close(new Error('test complete'));
});