Repository: microsoft/TypeChat
File: typescript/src/model.ts (TypeScript)

Code before:
    };
    return model;

    async function complete(prompt: string | PromptSection[]) {
        let retryCount = 0;
        const retryMaxAttempts = model.retryMaxAttempts ?? 3;
        const retryPauseMs = model.retryPauseMs ?? 1000;
        const messages = typeof prompt === "string" ? [{ role: "user", content: prompt }] : prompt;
        while (true) {
            const options = {
                method: "POST",
                body: JSON.stringify({
                    ...defaultParams,
                    messages,
                    temperature: 0,
                    n: 1
                }),
                headers: {
                    "content-type": "application/json",
                    ...headers
                }
            }
            const response = await fetch(url, options);
            if (response.ok) {
                const json = await response.json() as { choices: { message: PromptSection }[] };
                if (typeof json.choices[0].message.content  === 'string') {
                    return success(json.choices[0].message.content ?? "");
                } else {
                    return error(`REST API unexpected response format :  ${JSON.stringify(json.choices[0].message.content)}`);
                }
            }
            if (!isTransientHttpError(response.status) || retryCount >= retryMaxAttempts) {
                return error(`REST API error ${response.status}: ${response.statusText}`);
            }
            await sleep(retryPauseMs);
            retryCount++;
        }
    }
}

/**
 * Returns true of the given HTTP status code represents a transient error.
 */
function isTransientHttpError(code: number): boolean {
    switch (code) {
        case 429: // TooManyRequests
        case 500: // InternalServerError
        case 502: // BadGateway
        case 503: // ServiceUnavailable
        case 504: // GatewayTimeout
            return true;

Review comment (suggestion):
```suggestion
                if (typeof json.choices[0].message.content === "string") {
```

Code after:
    };
    return model;

    async function complete(prompt: string | PromptSection[]) {
        let retryCount = 0;
        const retryMaxAttempts = model.retryMaxAttempts ?? 3;
        const retryPauseMs = model.retryPauseMs ?? 1000;
        const messages = typeof prompt === "string" ? [{ role: "user", content: prompt }] : prompt;
        while (true) {
            const options = {
                method: "POST",
                body: JSON.stringify({
                    ...defaultParams,
                    messages,
                    temperature: 0,
                    n: 1
                }),
                headers: {
                    "content-type": "application/json",
                    ...headers
                }
            }
            const response = await fetch(url, options);
            if (response.ok) {
                const json = await response.json() as { choices: { message: PromptSection }[] };
                if (typeof json.choices[0].message.content === "string") {
                    return success(json.choices[0].message.content ?? "");
                } else {
                    return error(`REST API unexpected response format: ${JSON.stringify(json.choices[0].message.content)}`);
                }
            }
            if (!isTransientHttpError(response.status) || retryCount >= retryMaxAttempts) {
                return error(`REST API error ${response.status}: ${response.statusText}`);
            }
            await sleep(retryPauseMs);
            retryCount++;
        }
    }
}

/**
 * Returns true of the given HTTP status code represents a transient error.
 */
function isTransientHttpError(code: number): boolean {
    switch (code) {
        case 429: // TooManyRequests
        case 500: // InternalServerError
        case 502: // BadGateway
        case 503: // ServiceUnavailable
        case 504: // GatewayTimeout
            return true;