Files
open-multi-agent/packages/core/tests/errors.test.ts
T
Jack Chen cf6e958711 feat(runner): OMA-owned per-call LLM timeout, uniform across adapters (#344)
Add opt-in AgentConfig.callTimeoutMs bounding a single adapter.chat()
request with a fresh AbortSignal.timeout() merged into each call, so the
per-call bound is uniform across every adapter and composes with the
whole-run timeoutMs. A stalled call surfaces as LLMCallTimeoutError, raised
only when the runner's own deadline fired and the caller's signal did not,
so it stays distinct from a deliberate abort or a real API error.

Applied to both runner-owned chat sites (the agentic loop and
summarize-based context compaction); coordinator and team members inherit
it. mergeAbortSignals moved to utils/abort.ts and shared. Default unset
preserves current behavior exactly.

Closes #336
2026-07-01 14:08:16 +08:00

99 lines
3.5 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { TokenBudgetExceededError, InvalidMessageError, LLMCallTimeoutError } from '../src/errors.js'
describe('TokenBudgetExceededError', () => {
it('sets .name to TokenBudgetExceededError', () => {
const err = new TokenBudgetExceededError('agent-1', 500, 400)
expect(err.name).toBe('TokenBudgetExceededError')
})
it('sets .code to TOKEN_BUDGET_EXCEEDED', () => {
const err = new TokenBudgetExceededError('agent-1', 500, 400)
expect(err.code).toBe('TOKEN_BUDGET_EXCEEDED')
})
it('stores agent, tokensUsed, and budget as readonly properties', () => {
const err = new TokenBudgetExceededError('worker-a', 1234, 1000)
expect(err.agent).toBe('worker-a')
expect(err.tokensUsed).toBe(1234)
expect(err.budget).toBe(1000)
})
it('formats the message with agent name, tokens used, and budget', () => {
const err = new TokenBudgetExceededError('analyst', 750, 500)
expect(err.message).toBe('Agent "analyst" exceeded token budget: 750 tokens used (budget: 500)')
})
it('is an instance of TokenBudgetExceededError', () => {
const err = new TokenBudgetExceededError('b', 1, 2)
expect(err).toBeInstanceOf(TokenBudgetExceededError)
})
it('is an instance of Error (extends built-in Error)', () => {
const err = new TokenBudgetExceededError('b', 1, 2)
expect(err).toBeInstanceOf(Error)
})
})
describe('InvalidMessageError', () => {
it('sets .name to InvalidMessageError', () => {
const err = new InvalidMessageError('bad content')
expect(err.name).toBe('InvalidMessageError')
})
it('sets .code to INVALID_MESSAGE', () => {
const err = new InvalidMessageError('some reason')
expect(err.code).toBe('INVALID_MESSAGE')
})
it('uses the constructor argument as the message', () => {
const err = new InvalidMessageError('content must be a ContentBlock[]')
expect(err.message).toBe('content must be a ContentBlock[]')
})
it('is an instance of InvalidMessageError', () => {
const err = new InvalidMessageError('test')
expect(err).toBeInstanceOf(InvalidMessageError)
})
it('is an instance of Error (extends built-in Error)', () => {
const err = new InvalidMessageError('test')
expect(err).toBeInstanceOf(Error)
})
})
describe('LLMCallTimeoutError', () => {
it('sets .name to LLMCallTimeoutError', () => {
const err = new LLMCallTimeoutError(30_000, 'agent-1')
expect(err.name).toBe('LLMCallTimeoutError')
})
it('sets .code to LLM_CALL_TIMEOUT', () => {
const err = new LLMCallTimeoutError(30_000, 'agent-1')
expect(err.code).toBe('LLM_CALL_TIMEOUT')
})
it('stores timeoutMs and agent as readonly properties', () => {
const err = new LLMCallTimeoutError(15_000, 'worker-a')
expect(err.timeoutMs).toBe(15_000)
expect(err.agent).toBe('worker-a')
})
it('formats the message with agent name and timeout', () => {
const err = new LLMCallTimeoutError(20_000, 'analyst')
expect(err.message).toBe('Agent "analyst" LLM call exceeded per-call timeout of 20000ms')
})
it('omits the agent name from the message when unknown', () => {
const err = new LLMCallTimeoutError(20_000)
expect(err.agent).toBeUndefined()
expect(err.message).toBe('LLM call exceeded per-call timeout of 20000ms')
})
it('is an instance of LLMCallTimeoutError and Error', () => {
const err = new LLMCallTimeoutError(1000, 'b')
expect(err).toBeInstanceOf(LLMCallTimeoutError)
expect(err).toBeInstanceOf(Error)
})
})