import { requestJSON } from './http-client.mjs';
try {
const model = process.env.API_MODEL;
const policy = process.env.API_TOOL_POLICY || 'forced';
if (!model?.trim() || !['auto', 'required', 'forced', 'none'].includes(policy)) throw new Error('Invalid configuration.');
const tools = [{ type: 'function', function: {
name: 'get_stock', description: 'Read stock from the local demonstration catalog.', strict: true,
parameters: { type: 'object', properties: { sku: { type: 'string', enum: ['NOTEBOOK'] } },
required: ['sku'], additionalProperties: false },
} }];
const messages = [{ role: 'user', content: 'How many NOTEBOOK items are available? Use get_stock if permitted; otherwise say the stock is unknown.' }];
let completed = false;
let callCount = 0;
for (let round = 0; round < 2; round++) {
const toolChoice = round === 1 ? 'none' : policy === 'forced'
? { type: 'function', function: { name: 'get_stock' } } : policy;
const result = await requestJSON('/v1/chat/completions', {
model, messages, tools, tool_choice: toolChoice, parallel_tool_calls: false,
});
const choice = result.choices?.[0];
const message = choice?.message;
if (!Array.isArray(result.choices) || result.choices.length !== 1 || choice?.index !== 0
|| message?.role !== 'assistant' || message.refusal != null || message.function_call != null) {
throw new Error('Invalid assistant result.');
}
const calls = message.tool_calls ?? [];
if (!Array.isArray(calls) || calls.length > 1) throw new Error('Expected at most one call.');
if (!calls.length) {
if ((round === 0 && ['required', 'forced'].includes(policy)) || choice.finish_reason !== 'stop'
|| typeof message.content !== 'string' || !message.content.trim()) throw new Error('Missing final answer or required call.');
console.log(JSON.stringify({ answer: message.content, tool_calls: callCount }));
completed = true;
break;
}
if (round !== 0 || policy === 'none' || choice.finish_reason !== 'tool_calls') throw new Error('Tool policy violated.');
const call = calls[0];
if (call?.type !== 'function' || typeof call.id !== 'string' || !call.id.trim()
|| call.function?.name !== 'get_stock' || typeof call.function.arguments !== 'string'
|| call.function.arguments.length > 4096) throw new Error('Invalid tool call.');
const args = JSON.parse(call.function.arguments);
if (!args || Array.isArray(args) || Object.keys(args).length !== 1 || args.sku !== 'NOTEBOOK') {
throw new Error('Invalid catalog arguments.');
}
// Only this read-only fixture is executable. Preserve the original assistant message for replay.
messages.push(message, { role: 'tool', tool_call_id: call.id, content: JSON.stringify({ sku: args.sku, available: 8 }) });
callCount++;
}
if (!completed) throw new Error('No final answer within the example budget.');
} catch {
console.error('Tool policy example failed. Check model support, call policy, arguments, and completion. No automatic retry.');
process.exitCode = 1;
}