Skip to content

Commit 7eb24c5

Browse files
alban bertoliniclaude
andcommitted
fix(ai-proxy): use proper AI error classes instead of generic Error
- ForestIntegrationClient.checkConnection(): Error β†’ AIBadRequestError - assertResponseOk(): Error β†’ AIToolUnprocessableError - Add CLAUDE.md with error handling guidelines Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2ce5c0c commit 7eb24c5

3 files changed

Lines changed: 26 additions & 3 deletions

File tree

β€Žpackages/ai-proxy/CLAUDE.mdβ€Ž

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# @forestadmin/ai-proxy
2+
3+
## Overview
4+
5+
This package is used by both the Forest Admin agent (`@forestadmin/agent`) and the Forest Admin server. Both consumers bind AI error classes to HTTP status codes via their error middleware.
6+
7+
## Error Handling
8+
9+
All errors thrown in this package must extend an AI error class from `src/errors.ts`, never `new Error(...)` directly.
10+
11+
Both the agent and the Forest Admin server map error classes to HTTP status codes. A bare `Error` will result in a generic 500 instead of the correct status.
12+
13+
Choose the right error class based on context:
14+
- `AIBadRequestError` β€” invalid config, bad input from caller
15+
- `AIToolUnprocessableError` β€” tool invocation failed at runtime (e.g. Zendesk API returned an error)
16+
- `McpConnectionError` β€” MCP server connection validation failed
17+
- `AINotFoundError` / `AIToolNotFoundError` β€” resource or tool not found
18+
- `AIProviderError` β€” AI provider call failed
19+
20+
See `src/errors.ts` for the full list.

β€Žpackages/ai-proxy/src/forest-integration-client.tsβ€Ž

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type RemoteTool from './remote-tool';
22
import type { ToolProvider } from './tool-provider';
33
import type { Logger } from '@forestadmin/datasource-toolkit';
44

5+
import { AIBadRequestError } from './errors';
56
import getZendeskTools, { type ZendeskConfig } from './integrations/zendesk/tools';
67
import { validateZendeskConfig } from './integrations/zendesk/utils';
78

@@ -54,7 +55,7 @@ export default class ForestIntegrationClient implements ToolProvider {
5455
case 'Zendesk':
5556
return validateZendeskConfig(config as ZendeskConfig);
5657
default:
57-
throw new Error(`Unsupported integration: ${integrationName}`);
58+
throw new AIBadRequestError(`Unsupported integration: ${integrationName}`);
5859
}
5960
}),
6061
);

β€Žpackages/ai-proxy/src/integrations/zendesk/utils.tsβ€Ž

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { ZendeskConfig } from './tools';
22

3-
import { McpConnectionError } from '../../errors';
3+
import { AIToolUnprocessableError, McpConnectionError } from '../../errors';
44

55
export function getZendeskConfig(config: ZendeskConfig) {
66
const baseUrl = `https://${config.subdomain}.zendesk.com/api/v2`;
@@ -24,7 +24,9 @@ export async function assertResponseOk(response: Response, action: string) {
2424
// Response body is not JSON
2525
}
2626

27-
throw new Error(`Zendesk ${action} failed (${response.status}): ${errorMessage}`);
27+
throw new AIToolUnprocessableError(
28+
`Zendesk ${action} failed (${response.status}): ${errorMessage}`,
29+
);
2830
}
2931
}
3032

0 commit comments

Comments
Β (0)