(options: CompleteOptions)
| 90 | * }); |
| 91 | */ |
| 92 | export async function complete(options: CompleteOptions): Promise<LLMResult> { |
| 93 | const { |
| 94 | prompt, |
| 95 | system, |
| 96 | maxTokens = 100, |
| 97 | model = 'fast', |
| 98 | operationName = 'llm-complete', |
| 99 | } = options; |
| 100 | |
| 101 | const modelId = ModelConfig[model]; |
| 102 | const startTime = Date.now(); |
| 103 | |
| 104 | const response = await withRetry( |
| 105 | async () => { |
| 106 | return getClient().messages.create({ |
| 107 | model: modelId, |
| 108 | max_tokens: maxTokens, |
| 109 | ...(system && { system }), |
| 110 | messages: [{ role: 'user', content: prompt }], |
| 111 | }); |
| 112 | }, |
| 113 | { maxRetries: 3, initialDelayMs: 1000 }, |
| 114 | operationName |
| 115 | ); |
| 116 | |
| 117 | const latencyMs = Date.now() - startTime; |
| 118 | |
| 119 | if (!response.content || response.content.length === 0) { |
| 120 | throw new Error('Empty response from LLM'); |
| 121 | } |
| 122 | const content = response.content[0]; |
| 123 | |
| 124 | if (content.type !== 'text') { |
| 125 | throw new Error('Unexpected response type from LLM'); |
| 126 | } |
| 127 | |
| 128 | return { |
| 129 | text: content.text.trim(), |
| 130 | model: modelId, |
| 131 | inputTokens: response.usage?.input_tokens, |
| 132 | outputTokens: response.usage?.output_tokens, |
| 133 | latencyMs, |
| 134 | }; |
| 135 | } |
| 136 | |
| 137 | /** |
| 138 | * Options for yes/no classification |
no test coverage detected