File size: 4,177 Bytes
4e23b01 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | /**
* Scenario: runtime validation at Klient wire-contract boundaries.
*
* Exercises the session-creation and plugin-manifest schemas directly with no
* external collaborators. Run with `pnpm --filter @moonshot-ai/klient exec
* vitest run test/contract.test.ts`.
*/
import { describe, expect, it } from 'vitest';
import { pluginManifestSchema } from '../src/contract/global/plugins.js';
import { mcpServerAuthFlowHandleSchema } from '../src/contract/global/mcpManagement.js';
import { createSessionOptionsSchema } from '../src/contract/session/lifecycle.js';
import { promptPayloadSchema } from '../src/contract/agent/schemas.js';
type McpTimeoutField = 'startupTimeoutMs' | 'toolTimeoutMs';
const timeoutCases = [
{
surface: 'plugin manifests',
parse: (field: McpTimeoutField, value: number) =>
pluginManifestSchema.safeParse({
name: 'example',
mcpServers: {
example: { transport: 'stdio', command: 'node', [field]: value },
},
}),
},
].flatMap(({ surface, parse }) => [
{ surface, field: 'startupTimeoutMs' as const, parse },
{ surface, field: 'toolTimeoutMs' as const, parse },
]);
describe('MCP timeout contract validation', () => {
it.each(timeoutCases)('accepts the maximum $field for $surface', ({ field, parse }) => {
expect(parse(field, 2_147_483_647).success).toBe(true);
});
it.each(timeoutCases)('rejects an above-maximum $field for $surface', ({ field, parse }) => {
expect(parse(field, 2_147_483_648).success).toBe(false);
});
it('session creation options accept ephemeral mcpServers', () => {
const parsed = createSessionOptionsSchema.safeParse({
workDir: '/tmp/example',
mcpServers: {
stdioExample: { transport: 'stdio', command: 'node', args: ['server.mjs'] },
httpExample: { transport: 'http', url: 'https://example.com/mcp', headers: { a: 'b' } },
sseExample: { transport: 'sse', url: 'https://example.com/sse' },
},
});
expect(parsed.success).toBe(true);
expect(parsed.data?.mcpServers?.['stdioExample']).toEqual({
transport: 'stdio',
command: 'node',
args: ['server.mjs'],
});
});
it('session creation options preserve the per-server deferred field', () => {
const parsed = createSessionOptionsSchema.safeParse({
workDir: '/tmp/example',
mcpServers: {
stdioExample: { transport: 'stdio', command: 'node', deferred: false },
httpExample: { transport: 'http', url: 'https://example.com/mcp', deferred: true },
sseExample: { transport: 'sse', url: 'https://example.com/sse' },
},
});
expect(parsed.success).toBe(true);
expect(parsed.data?.mcpServers?.['stdioExample']).toEqual({
transport: 'stdio',
command: 'node',
deferred: false,
});
expect(parsed.data?.mcpServers?.['httpExample']).toEqual({
transport: 'http',
url: 'https://example.com/mcp',
deferred: true,
});
expect(parsed.data?.mcpServers?.['sseExample']).toEqual({
transport: 'sse',
url: 'https://example.com/sse',
});
});
it('session creation options reject malformed mcpServers entries', () => {
const parsed = createSessionOptionsSchema.safeParse({
workDir: '/tmp/example',
mcpServers: {
example: { transport: 'http', url: 'not-a-url' },
},
});
expect(parsed.success).toBe(false);
});
it('completeAuth timeoutMs accepts the setTimeout maximum and rejects above it', () => {
expect(
mcpServerAuthFlowHandleSchema.safeParse({ flowId: 'flow-1', timeoutMs: 2_147_483_647 })
.success,
).toBe(true);
expect(
mcpServerAuthFlowHandleSchema.safeParse({ flowId: 'flow-1', timeoutMs: 2_147_483_648 })
.success,
).toBe(false);
});
});
describe('prompt contract validation', () => {
it('rejects an empty caller-chosen promptId', () => {
expect(promptPayloadSchema.safeParse({ input: [], promptId: '' }).success).toBe(false);
});
it('accepts a non-empty caller-chosen promptId', () => {
expect(promptPayloadSchema.safeParse({ input: [], promptId: 'submission-1' }).success).toBe(true);
});
});
|