Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions core/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ export {TrajectoryThoughtPruningCompactor} from './context/trajectory_thought_pr
export type {TrajectoryThoughtPruningCompactorOptions} from './context/trajectory_thought_pruning_compactor.js';
export {TruncatingContextCompactor} from './context/truncating_context_compactor.js';
export type {TruncatingContextCompactorOptions} from './context/truncating_context_compactor.js';
export {AlreadyExistsError} from './errors/already_exists_error.js';
export {InputValidationError} from './errors/input_validation_error.js';
export {NotFoundError} from './errors/not_found_error.js';
export {SessionNotFoundError} from './errors/session_not_found_error.js';
export {
ToolErrorType,
ToolExecutionError,
} from './errors/tool_execution_error.js';
export {isCompactedEvent, isScratchpadEvent} from './events/compacted_event.js';
export type {CompactedEvent} from './events/compacted_event.js';
export {
Expand Down
18 changes: 18 additions & 0 deletions core/src/errors/already_exists_error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Represents an error that occurs when an entity already exists.
*/
export class AlreadyExistsError extends Error {
/**
* @param message An optional custom message to describe the error.
*/
constructor(message = 'The resource already exists.') {
super(message);
this.name = 'AlreadyExistsError';
}
}
18 changes: 18 additions & 0 deletions core/src/errors/input_validation_error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Represents an error raised when user input fails validation.
*/
export class InputValidationError extends Error {
/**
* @param message A message describing why the input is invalid.
*/
constructor(message = 'Invalid input.') {
super(message);
this.name = 'InputValidationError';
}
}
18 changes: 18 additions & 0 deletions core/src/errors/not_found_error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Represents an error that occurs when an entity is not found.
*/
export class NotFoundError extends Error {
/**
* @param message An optional custom message to describe the error.
*/
constructor(message = 'The requested item was not found.') {
super(message);
this.name = 'NotFoundError';
}
}
18 changes: 18 additions & 0 deletions core/src/errors/session_not_found_error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Raised when a session cannot be found.
*/
export class SessionNotFoundError extends Error {
/**
* @param message An optional custom message to describe the error.
*/
constructor(message = 'Session not found.') {
super(message);
this.name = 'SessionNotFoundError';
}
}
43 changes: 43 additions & 0 deletions core/src/errors/tool_execution_error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* HTTP error types conforming to OpenTelemetry semantics.
*
* The string values populate the `error.type` span attribute, so they are
* observable outside the process and must stay identical to the adk-python
* `ToolErrorType` members.
*/
export enum ToolErrorType {
BAD_REQUEST = 'BAD_REQUEST',
UNAUTHORIZED = 'UNAUTHORIZED',
FORBIDDEN = 'FORBIDDEN',
NOT_FOUND = 'NOT_FOUND',
REQUEST_TIMEOUT = 'REQUEST_TIMEOUT',
INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR',
BAD_GATEWAY = 'BAD_GATEWAY',
SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',
GATEWAY_TIMEOUT = 'GATEWAY_TIMEOUT',
}

/**
* Represents an error that occurs during the execution of a tool.
*/
export class ToolExecutionError extends Error {
/**
* @param message A message describing the error.
* @param errorType The semantic error type (e.g.
* {@link ToolErrorType.REQUEST_TIMEOUT} or `'500'`). Used to populate the
* `error.type` span attribute in OpenTelemetry traces.
*/
constructor(
message: string,
readonly errorType?: ToolErrorType | string,
) {
super(message);
this.name = 'ToolExecutionError';
}
}
46 changes: 46 additions & 0 deletions core/test/errors/already_exists_error_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {AlreadyExistsError, NotFoundError} from '@google/adk';
import {describe, expect, it} from 'vitest';

describe('AlreadyExistsError', () => {
it('defaults the message when none is supplied', () => {
expect(new AlreadyExistsError().message).toBe(
'The resource already exists.',
);
expect(new AlreadyExistsError(undefined).message).toBe(
'The resource already exists.',
);
});

it('stores a supplied message verbatim', () => {
expect(new AlreadyExistsError('Session 42 already exists.').message).toBe(
'Session 42 already exists.',
);
expect(new AlreadyExistsError('').message).toBe('');
});

it('sets name', () => {
expect(new AlreadyExistsError().name).toBe('AlreadyExistsError');
});

it('is an instance of itself and of Error', () => {
const error = new AlreadyExistsError();
expect(error).toBeInstanceOf(AlreadyExistsError);
expect(error).toBeInstanceOf(Error);
});

it('is not an instance of a sibling error class', () => {
expect(new AlreadyExistsError()).not.toBeInstanceOf(NotFoundError);
});

it('can be thrown and caught by type', () => {
expect(() => {
throw new AlreadyExistsError('boom');
}).toThrow(AlreadyExistsError);
});
});
42 changes: 42 additions & 0 deletions core/test/errors/input_validation_error_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {InputValidationError, NotFoundError} from '@google/adk';
import {describe, expect, it} from 'vitest';

describe('InputValidationError', () => {
it('defaults the message when none is supplied', () => {
expect(new InputValidationError().message).toBe('Invalid input.');
expect(new InputValidationError(undefined).message).toBe('Invalid input.');
});

it('stores a supplied message verbatim', () => {
expect(new InputValidationError('appName is required.').message).toBe(
'appName is required.',
);
expect(new InputValidationError('').message).toBe('');
});

it('sets name', () => {
expect(new InputValidationError().name).toBe('InputValidationError');
});

it('is an instance of itself and of Error', () => {
const error = new InputValidationError();
expect(error).toBeInstanceOf(InputValidationError);
expect(error).toBeInstanceOf(Error);
});

it('is not an instance of a sibling error class', () => {
expect(new InputValidationError()).not.toBeInstanceOf(NotFoundError);
});

it('can be thrown and caught by type', () => {
expect(() => {
throw new InputValidationError('boom');
}).toThrow(InputValidationError);
});
});
50 changes: 50 additions & 0 deletions core/test/errors/not_found_error_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {NotFoundError, SessionNotFoundError} from '@google/adk';
import {describe, expect, it} from 'vitest';

describe('NotFoundError', () => {
it('defaults the message when none is supplied', () => {
expect(new NotFoundError().message).toBe(
'The requested item was not found.',
);
expect(new NotFoundError(undefined).message).toBe(
'The requested item was not found.',
);
});

it('stores a supplied message verbatim', () => {
expect(new NotFoundError('No eval set foo.').message).toBe(
'No eval set foo.',
);
// An empty string is a supplied argument, so it must not fall back to the
// default: only `undefined` triggers a default parameter.
expect(new NotFoundError('').message).toBe('');
// No sanitisation: `$` replacement patterns are stored as written.
expect(new NotFoundError("a $& b $' c").message).toBe("a $& b $' c");
});

it('sets name', () => {
expect(new NotFoundError().name).toBe('NotFoundError');
});

it('is an instance of itself and of Error', () => {
const error = new NotFoundError();
expect(error).toBeInstanceOf(NotFoundError);
expect(error).toBeInstanceOf(Error);
});

it('is not an instance of a sibling error class', () => {
expect(new NotFoundError()).not.toBeInstanceOf(SessionNotFoundError);
});

it('can be thrown and caught by type', () => {
expect(() => {
throw new NotFoundError('boom');
}).toThrow(NotFoundError);
});
});
47 changes: 47 additions & 0 deletions core/test/errors/session_not_found_error_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {NotFoundError, SessionNotFoundError} from '@google/adk';
import {describe, expect, it} from 'vitest';

describe('SessionNotFoundError', () => {
it('defaults the message when none is supplied', () => {
expect(new SessionNotFoundError().message).toBe('Session not found.');
expect(new SessionNotFoundError(undefined).message).toBe(
'Session not found.',
);
});

it('stores a supplied message verbatim', () => {
expect(new SessionNotFoundError('No session 42.').message).toBe(
'No session 42.',
);
expect(new SessionNotFoundError('').message).toBe('');
});

it('sets name', () => {
expect(new SessionNotFoundError().name).toBe('SessionNotFoundError');
});

it('is an instance of itself and of Error', () => {
const error = new SessionNotFoundError();
expect(error).toBeInstanceOf(SessionNotFoundError);
expect(error).toBeInstanceOf(Error);
});

it('is not an instance of a sibling error class', () => {
// The hierarchy is flat: SessionNotFoundError must not extend
// NotFoundError, or `catch (e) { if (e instanceof NotFoundError) }` would
// start swallowing session lookups it does not swallow in adk-python.
expect(new SessionNotFoundError()).not.toBeInstanceOf(NotFoundError);
});

it('can be thrown and caught by type', () => {
expect(() => {
throw new SessionNotFoundError('boom');
}).toThrow(SessionNotFoundError);
});
});
Loading
Loading