Merge pull request #490 from alibaba/fix/ts-value-space
fix(ts): `InvokeErrorType` separate confusing value/type space
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { InvokeError, InvokeErrorType } from '@page-agent/llms'
|
import { InvokeError, InvokeErrorTypes } from '@page-agent/llms'
|
||||||
import chalk from 'chalk'
|
import chalk from 'chalk'
|
||||||
import * as z from 'zod/v4'
|
import * as z from 'zod/v4'
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ function validateAction(action: any, tools: Map<string, PageAgentTool>): any {
|
|||||||
if (!tool) {
|
if (!tool) {
|
||||||
const available = Array.from(tools.keys()).join(', ')
|
const available = Array.from(tools.keys()).join(', ')
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.INVALID_TOOL_ARGS,
|
InvokeErrorTypes.INVALID_TOOL_ARGS,
|
||||||
`Unknown action "${toolName}". Available: ${available}`
|
`Unknown action "${toolName}". Available: ${available}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,7 @@ function validateAction(action: any, tools: Map<string, PageAgentTool>): any {
|
|||||||
const result = schema.safeParse(value)
|
const result = schema.safeParse(value)
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.INVALID_TOOL_ARGS,
|
InvokeErrorTypes.INVALID_TOOL_ARGS,
|
||||||
`Invalid input for action "${toolName}": ${z.prettifyError(result.error)}`
|
`Invalid input for action "${toolName}": ${z.prettifyError(result.error)}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
import * as z from 'zod/v4'
|
import * as z from 'zod/v4'
|
||||||
|
|
||||||
import { InvokeError, InvokeErrorType } from './errors'
|
import { InvokeError, InvokeErrorTypes } from './errors'
|
||||||
import type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool } from './types'
|
import type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool } from './types'
|
||||||
import { modelPatch, zodToOpenAITool } from './utils'
|
import { modelPatch, zodToOpenAITool } from './utils'
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ export class OpenAIClient implements LLMClient {
|
|||||||
transformedBody = this.config.transformRequestBody(requestBody)
|
transformedBody = this.config.transformRequestBody(requestBody)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.CONFIG_ERROR,
|
InvokeErrorTypes.CONFIG_ERROR,
|
||||||
`transformRequestBody failed: ${(error as Error).message}`,
|
`transformRequestBody failed: ${(error as Error).message}`,
|
||||||
error
|
error
|
||||||
)
|
)
|
||||||
@@ -73,7 +73,7 @@ export class OpenAIClient implements LLMClient {
|
|||||||
const isAbortError = (error as any)?.name === 'AbortError'
|
const isAbortError = (error as any)?.name === 'AbortError'
|
||||||
const errorMessage = isAbortError ? 'Network request aborted' : 'Network request failed'
|
const errorMessage = isAbortError ? 'Network request aborted' : 'Network request failed'
|
||||||
if (!isAbortError) console.error(error)
|
if (!isAbortError) console.error(error)
|
||||||
throw new InvokeError(InvokeErrorType.NETWORK_ERROR, errorMessage, error)
|
throw new InvokeError(InvokeErrorTypes.NETWORK_ERROR, errorMessage, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Handle HTTP errors
|
// 3. Handle HTTP errors
|
||||||
@@ -84,27 +84,27 @@ export class OpenAIClient implements LLMClient {
|
|||||||
|
|
||||||
if (response.status === 401 || response.status === 403) {
|
if (response.status === 401 || response.status === 403) {
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.AUTH_ERROR,
|
InvokeErrorTypes.AUTH_ERROR,
|
||||||
`Authentication failed: ${errorMessage}`,
|
`Authentication failed: ${errorMessage}`,
|
||||||
errorData
|
errorData
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (response.status === 429) {
|
if (response.status === 429) {
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.RATE_LIMIT,
|
InvokeErrorTypes.RATE_LIMIT,
|
||||||
`Rate limit exceeded: ${errorMessage}`,
|
`Rate limit exceeded: ${errorMessage}`,
|
||||||
errorData
|
errorData
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (response.status >= 500) {
|
if (response.status >= 500) {
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.SERVER_ERROR,
|
InvokeErrorTypes.SERVER_ERROR,
|
||||||
`Server error: ${errorMessage}`,
|
`Server error: ${errorMessage}`,
|
||||||
errorData
|
errorData
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.UNKNOWN,
|
InvokeErrorTypes.UNKNOWN,
|
||||||
`HTTP ${response.status}: ${errorMessage}`,
|
`HTTP ${response.status}: ${errorMessage}`,
|
||||||
errorData
|
errorData
|
||||||
)
|
)
|
||||||
@@ -115,7 +115,7 @@ export class OpenAIClient implements LLMClient {
|
|||||||
|
|
||||||
const choice = data.choices?.[0]
|
const choice = data.choices?.[0]
|
||||||
if (!choice) {
|
if (!choice) {
|
||||||
throw new InvokeError(InvokeErrorType.UNKNOWN, 'No choices in response', data)
|
throw new InvokeError(InvokeErrorTypes.UNKNOWN, 'No choices in response', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check finish_reason
|
// Check finish_reason
|
||||||
@@ -126,21 +126,21 @@ export class OpenAIClient implements LLMClient {
|
|||||||
break
|
break
|
||||||
case 'length':
|
case 'length':
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.CONTEXT_LENGTH,
|
InvokeErrorTypes.CONTEXT_LENGTH,
|
||||||
'Response truncated: max tokens reached',
|
'Response truncated: max tokens reached',
|
||||||
undefined,
|
undefined,
|
||||||
data
|
data
|
||||||
)
|
)
|
||||||
case 'content_filter':
|
case 'content_filter':
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.CONTENT_FILTER,
|
InvokeErrorTypes.CONTENT_FILTER,
|
||||||
'Content filtered by safety system',
|
'Content filtered by safety system',
|
||||||
undefined,
|
undefined,
|
||||||
data
|
data
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.UNKNOWN,
|
InvokeErrorTypes.UNKNOWN,
|
||||||
`Unexpected finish_reason: ${choice.finish_reason}`,
|
`Unexpected finish_reason: ${choice.finish_reason}`,
|
||||||
undefined,
|
undefined,
|
||||||
data
|
data
|
||||||
@@ -155,7 +155,7 @@ export class OpenAIClient implements LLMClient {
|
|||||||
const toolCallName = normalizedChoice?.message?.tool_calls?.[0]?.function?.name
|
const toolCallName = normalizedChoice?.message?.tool_calls?.[0]?.function?.name
|
||||||
if (!toolCallName) {
|
if (!toolCallName) {
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.NO_TOOL_CALL,
|
InvokeErrorTypes.NO_TOOL_CALL,
|
||||||
'No tool call found in response',
|
'No tool call found in response',
|
||||||
undefined,
|
undefined,
|
||||||
data
|
data
|
||||||
@@ -165,7 +165,7 @@ export class OpenAIClient implements LLMClient {
|
|||||||
const tool = tools[toolCallName]
|
const tool = tools[toolCallName]
|
||||||
if (!tool) {
|
if (!tool) {
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.UNKNOWN,
|
InvokeErrorTypes.UNKNOWN,
|
||||||
`Tool "${toolCallName}" not found in tools`,
|
`Tool "${toolCallName}" not found in tools`,
|
||||||
undefined,
|
undefined,
|
||||||
data
|
data
|
||||||
@@ -176,7 +176,7 @@ export class OpenAIClient implements LLMClient {
|
|||||||
const argString = normalizedChoice.message?.tool_calls?.[0]?.function?.arguments
|
const argString = normalizedChoice.message?.tool_calls?.[0]?.function?.arguments
|
||||||
if (!argString) {
|
if (!argString) {
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.INVALID_TOOL_ARGS,
|
InvokeErrorTypes.INVALID_TOOL_ARGS,
|
||||||
'No tool call arguments found',
|
'No tool call arguments found',
|
||||||
undefined,
|
undefined,
|
||||||
data
|
data
|
||||||
@@ -188,7 +188,7 @@ export class OpenAIClient implements LLMClient {
|
|||||||
parsedArgs = JSON.parse(argString)
|
parsedArgs = JSON.parse(argString)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.INVALID_TOOL_ARGS,
|
InvokeErrorTypes.INVALID_TOOL_ARGS,
|
||||||
'Failed to parse tool arguments as JSON',
|
'Failed to parse tool arguments as JSON',
|
||||||
error,
|
error,
|
||||||
data
|
data
|
||||||
@@ -200,7 +200,7 @@ export class OpenAIClient implements LLMClient {
|
|||||||
if (!validation.success) {
|
if (!validation.success) {
|
||||||
console.error(z.prettifyError(validation.error))
|
console.error(z.prettifyError(validation.error))
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.INVALID_TOOL_ARGS,
|
InvokeErrorTypes.INVALID_TOOL_ARGS,
|
||||||
'Tool arguments validation failed',
|
'Tool arguments validation failed',
|
||||||
validation.error,
|
validation.error,
|
||||||
data
|
data
|
||||||
@@ -214,7 +214,7 @@ export class OpenAIClient implements LLMClient {
|
|||||||
toolResult = await tool.execute(toolInput)
|
toolResult = await tool.execute(toolInput)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.TOOL_EXECUTION_ERROR,
|
InvokeErrorTypes.TOOL_EXECUTION_ERROR,
|
||||||
`Tool execution failed: ${(e as Error).message}`,
|
`Tool execution failed: ${(e as Error).message}`,
|
||||||
e,
|
e,
|
||||||
data
|
data
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Error types and error handling for LLM invocations
|
* Error types and error handling for LLM invocations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const InvokeErrorType = {
|
export const InvokeErrorTypes = {
|
||||||
// Retryable
|
// Retryable
|
||||||
NETWORK_ERROR: 'network_error', // Network error, retry
|
NETWORK_ERROR: 'network_error', // Network error, retry
|
||||||
RATE_LIMIT: 'rate_limit', // Rate limit, retry
|
RATE_LIMIT: 'rate_limit', // Rate limit, retry
|
||||||
@@ -20,7 +20,7 @@ export const InvokeErrorType = {
|
|||||||
CONTENT_FILTER: 'content_filter', // Content filtered
|
CONTENT_FILTER: 'content_filter', // Content filtered
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export type InvokeErrorType = (typeof InvokeErrorType)[keyof typeof InvokeErrorType]
|
type InvokeErrorType = (typeof InvokeErrorTypes)[keyof typeof InvokeErrorTypes]
|
||||||
|
|
||||||
export class InvokeError extends Error {
|
export class InvokeError extends Error {
|
||||||
type: InvokeErrorType
|
type: InvokeErrorType
|
||||||
@@ -45,13 +45,13 @@ export class InvokeError extends Error {
|
|||||||
if (isAbortError) return false
|
if (isAbortError) return false
|
||||||
|
|
||||||
const retryableTypes: InvokeErrorType[] = [
|
const retryableTypes: InvokeErrorType[] = [
|
||||||
InvokeErrorType.NETWORK_ERROR,
|
InvokeErrorTypes.NETWORK_ERROR,
|
||||||
InvokeErrorType.RATE_LIMIT,
|
InvokeErrorTypes.RATE_LIMIT,
|
||||||
InvokeErrorType.SERVER_ERROR,
|
InvokeErrorTypes.SERVER_ERROR,
|
||||||
InvokeErrorType.NO_TOOL_CALL,
|
InvokeErrorTypes.NO_TOOL_CALL,
|
||||||
InvokeErrorType.INVALID_TOOL_ARGS,
|
InvokeErrorTypes.INVALID_TOOL_ARGS,
|
||||||
InvokeErrorType.TOOL_EXECUTION_ERROR,
|
InvokeErrorTypes.TOOL_EXECUTION_ERROR,
|
||||||
InvokeErrorType.UNKNOWN,
|
InvokeErrorTypes.UNKNOWN,
|
||||||
]
|
]
|
||||||
return retryableTypes.includes(type)
|
return retryableTypes.includes(type)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { OpenAIClient } from './OpenAIClient'
|
import { OpenAIClient } from './OpenAIClient'
|
||||||
import { DEFAULT_TEMPERATURE, LLM_MAX_RETRIES } from './constants'
|
import { DEFAULT_TEMPERATURE, LLM_MAX_RETRIES } from './constants'
|
||||||
import { InvokeError, InvokeErrorType } from './errors'
|
import { InvokeError, InvokeErrorTypes } from './errors'
|
||||||
import type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool } from './types'
|
import type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool } from './types'
|
||||||
|
|
||||||
export { InvokeError, InvokeErrorType }
|
export { InvokeError, InvokeErrorTypes }
|
||||||
export type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool }
|
export type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool }
|
||||||
|
|
||||||
export function parseLLMConfig(config: LLMConfig): Required<LLMConfig> {
|
export function parseLLMConfig(config: LLMConfig): Required<LLMConfig> {
|
||||||
|
|||||||
Reference in New Issue
Block a user