@kaiban/sdk 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -19
- package/dist/cjs/index.js +21 -0
- package/dist/cjs/lib/client.js +54 -0
- package/dist/cjs/lib/http/HttpClient.js +243 -0
- package/dist/cjs/lib/http/errors.js +143 -0
- package/dist/cjs/lib/http/types.js +2 -0
- package/dist/cjs/lib/resources/ActivitiesClient.js +164 -0
- package/dist/cjs/lib/resources/AgentsClient.js +196 -0
- package/dist/cjs/lib/resources/BoardsClient.js +78 -0
- package/dist/cjs/lib/resources/CardsClient.js +352 -0
- package/dist/cjs/lib/resources/ExternalChannelsClient.js +78 -0
- package/dist/cjs/lib/resources/ModelCost.js +87 -0
- package/dist/cjs/lib/resources/ResourcesClient.js +78 -0
- package/dist/cjs/lib/resources/TeamsClient.js +96 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/test/helpers/mockFetch.js +27 -0
- package/dist/cjs/types/entities/a2a-dataparts.js +17 -0
- package/dist/cjs/types/entities/activities.js +76 -0
- package/dist/cjs/types/entities/agent.js +28 -0
- package/dist/cjs/types/entities/board.js +2 -0
- package/dist/cjs/types/entities/card.js +29 -0
- package/dist/cjs/types/entities/costs.js +2 -0
- package/dist/cjs/types/entities/external-channel.js +19 -0
- package/dist/cjs/types/entities/index.js +25 -0
- package/dist/cjs/types/entities/resource.js +10 -0
- package/dist/cjs/types/entities/shared.js +3 -0
- package/dist/cjs/types/entities/team.js +2 -0
- package/dist/cjs/types/entities.js +17 -0
- package/dist/cjs/types/responses.js +2 -0
- package/dist/esm/index.js +5 -0
- package/dist/{lib → esm/lib}/client.js +9 -9
- package/dist/{lib → esm/lib}/http/HttpClient.js +1 -1
- package/dist/{lib → esm/lib}/resources/CardsClient.js +1 -1
- package/dist/esm/types/entities/a2a-dataparts.js +14 -0
- package/dist/esm/types/entities/index.js +9 -0
- package/dist/esm/types/entities.js +1 -0
- package/dist/esm/types/requests.js +19 -0
- package/dist/types/types/entities/a2a-dataparts.d.ts +202 -0
- package/package.json +16 -7
- package/dist/index.js +0 -5
- package/dist/types/entities/a2a-dataparts.d.ts +0 -11
- package/dist/types/entities/a2a-dataparts.js +0 -3
- package/dist/types/entities/index.js +0 -9
- package/dist/types/entities.js +0 -1
- /package/dist/{types → cjs/types}/requests.js +0 -0
- /package/dist/{lib → esm/lib}/http/errors.js +0 -0
- /package/dist/{lib → esm/lib}/http/types.js +0 -0
- /package/dist/{lib → esm/lib}/resources/ActivitiesClient.js +0 -0
- /package/dist/{lib → esm/lib}/resources/AgentsClient.js +0 -0
- /package/dist/{lib → esm/lib}/resources/BoardsClient.js +0 -0
- /package/dist/{lib → esm/lib}/resources/ExternalChannelsClient.js +0 -0
- /package/dist/{lib → esm/lib}/resources/ModelCost.js +0 -0
- /package/dist/{lib → esm/lib}/resources/ResourcesClient.js +0 -0
- /package/dist/{lib → esm/lib}/resources/TeamsClient.js +0 -0
- /package/dist/{test → esm/test}/helpers/mockFetch.js +0 -0
- /package/dist/{types → esm/types}/entities/activities.js +0 -0
- /package/dist/{types → esm/types}/entities/agent.js +0 -0
- /package/dist/{types → esm/types}/entities/board.js +0 -0
- /package/dist/{types → esm/types}/entities/card.js +0 -0
- /package/dist/{types → esm/types}/entities/costs.js +0 -0
- /package/dist/{types → esm/types}/entities/external-channel.js +0 -0
- /package/dist/{types → esm/types}/entities/resource.js +0 -0
- /package/dist/{types → esm/types}/entities/shared.js +0 -0
- /package/dist/{types → esm/types}/entities/team.js +0 -0
- /package/dist/{types → esm/types}/responses.js +0 -0
- /package/dist/{index.d.ts → types/index.d.ts} +0 -0
- /package/dist/{lib → types/lib}/client.d.ts +0 -0
- /package/dist/{lib → types/lib}/http/HttpClient.d.ts +0 -0
- /package/dist/{lib → types/lib}/http/errors.d.ts +0 -0
- /package/dist/{lib → types/lib}/http/types.d.ts +0 -0
- /package/dist/{lib → types/lib}/resources/ActivitiesClient.d.ts +0 -0
- /package/dist/{lib → types/lib}/resources/AgentsClient.d.ts +0 -0
- /package/dist/{lib → types/lib}/resources/BoardsClient.d.ts +0 -0
- /package/dist/{lib → types/lib}/resources/CardsClient.d.ts +0 -0
- /package/dist/{lib → types/lib}/resources/ExternalChannelsClient.d.ts +0 -0
- /package/dist/{lib → types/lib}/resources/ModelCost.d.ts +0 -0
- /package/dist/{lib → types/lib}/resources/ResourcesClient.d.ts +0 -0
- /package/dist/{lib → types/lib}/resources/TeamsClient.d.ts +0 -0
- /package/dist/{test → types/test}/helpers/mockFetch.d.ts +0 -0
- /package/dist/types/{entities → types/entities}/activities.d.ts +0 -0
- /package/dist/types/{entities → types/entities}/agent.d.ts +0 -0
- /package/dist/types/{entities → types/entities}/board.d.ts +0 -0
- /package/dist/types/{entities → types/entities}/card.d.ts +0 -0
- /package/dist/types/{entities → types/entities}/costs.d.ts +0 -0
- /package/dist/types/{entities → types/entities}/external-channel.d.ts +0 -0
- /package/dist/types/{entities → types/entities}/index.d.ts +0 -0
- /package/dist/types/{entities → types/entities}/resource.d.ts +0 -0
- /package/dist/types/{entities → types/entities}/shared.d.ts +0 -0
- /package/dist/types/{entities → types/entities}/team.d.ts +0 -0
- /package/dist/types/{entities.d.ts → types/entities.d.ts} +0 -0
- /package/dist/types/{requests.d.ts → types/requests.d.ts} +0 -0
- /package/dist/types/{responses.d.ts → types/responses.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npm install @kaiban/sdk
|
|
|
14
14
|
import { createKaibanClient } from '@kaiban/sdk';
|
|
15
15
|
|
|
16
16
|
const client = createKaibanClient({
|
|
17
|
-
tenant: '
|
|
17
|
+
tenant: 'your-tenant',
|
|
18
18
|
token: process.env.KAIBAN_TOKEN,
|
|
19
19
|
});
|
|
20
20
|
|
|
@@ -22,11 +22,12 @@ const result = await client.agents.list({ limit: 10 });
|
|
|
22
22
|
console.log(result.data); // Array of agents
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
## Auth and
|
|
25
|
+
## Auth and Tenancy
|
|
26
26
|
|
|
27
27
|
- Uses `Authorization: Bearer <token>` automatically when provided
|
|
28
|
-
- Sends `x-tenant` with the configured tenant
|
|
28
|
+
- Sends `x-tenant` header with the configured tenant
|
|
29
29
|
- Default base URL: `https://{tenant}.kaiban.io`
|
|
30
|
+
- Custom base URL can be configured via `baseUrl` option
|
|
30
31
|
|
|
31
32
|
## Resources
|
|
32
33
|
|
|
@@ -41,13 +42,14 @@ The SDK provides clients for the following API resources:
|
|
|
41
42
|
- **boards**: `list`, `listAll`, `get`
|
|
42
43
|
- **resources**: `list`, `listAll`, `get`
|
|
43
44
|
- **external_channels**: `list`, `listAll`, `get`
|
|
45
|
+
- **costs**: `calculateCosts` (offline utility for model cost calculations)
|
|
44
46
|
|
|
45
47
|
### Pagination
|
|
46
48
|
|
|
47
49
|
All `list` methods return paginated results with cursor-based navigation:
|
|
48
50
|
|
|
49
51
|
```ts
|
|
50
|
-
import { type Paginated, type Agent, type ListParams } from '@kaiban/sdk';
|
|
52
|
+
import { type Paginated, type Agent, type Card, type ListParams } from '@kaiban/sdk';
|
|
51
53
|
|
|
52
54
|
// Basic pagination
|
|
53
55
|
const params: ListParams = {
|
|
@@ -76,6 +78,13 @@ if (result.pagination.prev_cursor) {
|
|
|
76
78
|
before: result.pagination.prev_cursor,
|
|
77
79
|
});
|
|
78
80
|
}
|
|
81
|
+
|
|
82
|
+
// Filter cards by metadata (cards only)
|
|
83
|
+
const cardsResult: Paginated<Card> = await client.cards.list({
|
|
84
|
+
limit: 20,
|
|
85
|
+
metadata: { thread_id: 'thread-123', user_id: 'user-456' },
|
|
86
|
+
});
|
|
87
|
+
// This becomes: ?metadata.thread_id=thread-123&metadata.user_id=user-456
|
|
79
88
|
```
|
|
80
89
|
|
|
81
90
|
All `listAll` methods return async generators that automatically handle pagination:
|
|
@@ -91,13 +100,19 @@ for await (const agent of client.agents.listAll({ limit: 100 })) {
|
|
|
91
100
|
|
|
92
101
|
All types are published and re-exported from `@kaiban/sdk`. Available types include:
|
|
93
102
|
|
|
94
|
-
- **Entities**: `Agent`, `Card`, `Activity`, `Team`, `Board`, `Resource`, `ExternalChannel`
|
|
95
|
-
- **
|
|
96
|
-
- **
|
|
97
|
-
- **Actors & Changes**: `ActivityActor`, `ActivityChange`
|
|
103
|
+
- **Entities**: `Agent`, `Card`, `Activity`, `Team`, `Board`, `Resource`, `ExternalChannel`, `TeamMember`, `Column`
|
|
104
|
+
- **Agent Types**: `AgentFeedback`, `AgentSupervisorFeedback`, `AgentType`, `AgentStatus`, `AgentFeedbackStatus`, `AgentFeedbackType`, `AgentFeedbackEvaluation`
|
|
105
|
+
- **Activity Types**: `ActivityCreate`, `ActivityActor`, `ActivityChange`, `ActivityType`
|
|
98
106
|
- **Card Types**: `CardStatus`, `CardPart`
|
|
99
|
-
- **
|
|
100
|
-
- **
|
|
107
|
+
- **Board Types**: `Column`
|
|
108
|
+
- **Resource Types**: `ResourceStatus`
|
|
109
|
+
- **External Channel Types**: `ExternalChannelType`, `ExternalChannelStatus`, `ExternalChannelPriority`
|
|
110
|
+
- **Cost Types**: `ModelCostInput`, `ModelCostOutput`
|
|
111
|
+
- **A2A Data Parts**: `A2ADataPartType`, `ToolCallStartPart`, `ToolCallArgsPart`, `ToolCallEndPart`, `ToolCallResultPart`, `TaskInfoMessagePart`, `TaskStepOutputPart`, `UserEvaluationPart`, `UserThreadFeedbackPart`, `UserCloseThreadPart`, `GenerateReportPart`, `KaibanActivityPart`, `AgentStatusPart`
|
|
112
|
+
- **Request/Response**: `ListParams`, `Paginated`, `PaginationMeta`
|
|
113
|
+
- **Configuration**: `KaibanClientConfig`, `RequestOptions`
|
|
114
|
+
- **Shared Types**: `ISODate`
|
|
115
|
+
- **Error classes**: `HttpError`, `ApiError`, `BadRequestError`, `ValidationError`, `UnauthorizedError`, `ForbiddenError`, `NotFoundError`, `ConflictError`, `RateLimitError`, `UnavailableError`, `ServerError`, `TimeoutError`, `AbortedError`
|
|
101
116
|
|
|
102
117
|
### Example: Using Types
|
|
103
118
|
|
|
@@ -207,21 +222,36 @@ import { createKaibanClient, type KaibanClientConfig } from '@kaiban/sdk';
|
|
|
207
222
|
const config: KaibanClientConfig = {
|
|
208
223
|
tenant: 'your-tenant', // Required: Your tenant identifier
|
|
209
224
|
token: 'your-api-token', // Required: Your API authentication token
|
|
210
|
-
baseUrl: 'https://custom-host', // Optional: Custom API base URL
|
|
225
|
+
baseUrl: 'https://custom-host', // Optional: Custom API base URL (default: https://{tenant}.kaiban.io)
|
|
211
226
|
timeoutMs: 30000, // Optional: Request timeout in milliseconds (default: 30000)
|
|
212
227
|
retry: {
|
|
213
228
|
// Optional: Retry configuration
|
|
214
229
|
maxAttempts: 3, // Maximum number of retry attempts (default: 3)
|
|
215
|
-
backoffMs: 1000, // Initial backoff delay (default: 1000)
|
|
216
|
-
maxBackoffMs: 30000, // Maximum backoff delay (default: 30000)
|
|
230
|
+
backoffMs: 1000, // Initial backoff delay in ms (default: 1000)
|
|
231
|
+
maxBackoffMs: 30000, // Maximum backoff delay in ms (default: 30000)
|
|
217
232
|
jitter: true, // Add randomness to backoff (default: true)
|
|
233
|
+
retryOn: [429, 502, 503, 504], // Optional: HTTP status codes to retry on
|
|
234
|
+
retryMethods: ['GET', 'PUT', 'DELETE'], // Optional: HTTP methods to retry
|
|
235
|
+
},
|
|
236
|
+
fetch: globalThis.fetch, // Optional: Custom fetch implementation
|
|
237
|
+
onRequest: ({ method, url, init }) => {
|
|
238
|
+
// Optional: Hook called before each request
|
|
239
|
+
console.log(`Making ${method} request to ${url}`);
|
|
240
|
+
},
|
|
241
|
+
onResponse: ({ status, url, response }) => {
|
|
242
|
+
// Optional: Hook called after each response
|
|
243
|
+
console.log(`Received ${status} from ${url}`);
|
|
218
244
|
},
|
|
219
245
|
};
|
|
220
246
|
|
|
221
247
|
const client = createKaibanClient(config);
|
|
248
|
+
|
|
249
|
+
// You can also update the token dynamically after client creation
|
|
250
|
+
client.setToken('new-token'); // Set a new token
|
|
251
|
+
client.setToken(); // Clear the token
|
|
222
252
|
```
|
|
223
253
|
|
|
224
|
-
## Per-call
|
|
254
|
+
## Per-call Options
|
|
225
255
|
|
|
226
256
|
All resource methods accept an optional `RequestOptions` parameter for per-call overrides:
|
|
227
257
|
|
|
@@ -242,29 +272,70 @@ await client.cards.list({ limit: 20 }, options);
|
|
|
242
272
|
await client.agents.get('agent-123', options);
|
|
243
273
|
```
|
|
244
274
|
|
|
245
|
-
## Error
|
|
275
|
+
## Error Handling
|
|
246
276
|
|
|
247
|
-
The SDK provides typed error classes for different HTTP status codes:
|
|
277
|
+
The SDK provides typed error classes for different HTTP status codes and network errors:
|
|
248
278
|
|
|
249
279
|
```ts
|
|
250
|
-
import {
|
|
280
|
+
import {
|
|
281
|
+
createKaibanClient,
|
|
282
|
+
ApiError,
|
|
283
|
+
NotFoundError,
|
|
284
|
+
BadRequestError,
|
|
285
|
+
ValidationError,
|
|
286
|
+
UnauthorizedError,
|
|
287
|
+
RateLimitError,
|
|
288
|
+
TimeoutError,
|
|
289
|
+
AbortedError,
|
|
290
|
+
} from '@kaiban/sdk';
|
|
291
|
+
|
|
292
|
+
const client = createKaibanClient({
|
|
293
|
+
tenant: 'your-tenant',
|
|
294
|
+
token: process.env.KAIBAN_TOKEN!,
|
|
295
|
+
});
|
|
251
296
|
|
|
252
297
|
try {
|
|
253
298
|
await client.cards.get('non-existent-id');
|
|
254
299
|
} catch (err) {
|
|
255
300
|
if (err instanceof NotFoundError) {
|
|
256
301
|
console.error('Card not found:', err.message);
|
|
302
|
+
console.error('Error code:', err.code); // Optional error code from API
|
|
303
|
+
} else if (err instanceof ValidationError) {
|
|
304
|
+
console.error('Validation failed:', err.message);
|
|
305
|
+
console.error('Details:', err.details); // Additional error details from API
|
|
257
306
|
} else if (err instanceof BadRequestError) {
|
|
258
307
|
console.error('Invalid request:', err.message);
|
|
308
|
+
} else if (err instanceof UnauthorizedError) {
|
|
309
|
+
console.error('Authentication required:', err.message);
|
|
310
|
+
} else if (err instanceof RateLimitError) {
|
|
311
|
+
console.error('Rate limit exceeded:', err.message);
|
|
312
|
+
} else if (err instanceof TimeoutError) {
|
|
313
|
+
console.error('Request timed out');
|
|
314
|
+
} else if (err instanceof AbortedError) {
|
|
315
|
+
console.error('Request was cancelled');
|
|
259
316
|
} else if (err instanceof ApiError) {
|
|
260
|
-
console.error('API error:', err.
|
|
317
|
+
console.error('API error:', err.message);
|
|
261
318
|
} else {
|
|
262
319
|
console.error('Unexpected error:', err);
|
|
263
320
|
}
|
|
264
321
|
}
|
|
265
322
|
```
|
|
266
323
|
|
|
267
|
-
Available
|
|
324
|
+
### Available Error Classes
|
|
325
|
+
|
|
326
|
+
- **`ApiError`**: Base class for all API errors (includes `code`, `message`, `details` properties)
|
|
327
|
+
- **`BadRequestError`**: 400 - Invalid request format or parameters
|
|
328
|
+
- **`ValidationError`**: 422 - Request validation failed
|
|
329
|
+
- **`UnauthorizedError`**: 401 - Authentication required or failed
|
|
330
|
+
- **`ForbiddenError`**: 403 - Insufficient permissions
|
|
331
|
+
- **`NotFoundError`**: 404 - Resource not found
|
|
332
|
+
- **`ConflictError`**: 409 - Resource conflict
|
|
333
|
+
- **`RateLimitError`**: 429 - Too many requests
|
|
334
|
+
- **`UnavailableError`**: 502, 503, 504 - Service temporarily unavailable
|
|
335
|
+
- **`ServerError`**: 500 or other server errors
|
|
336
|
+
- **`TimeoutError`**: Request exceeded configured timeout
|
|
337
|
+
- **`AbortedError`**: Request was cancelled via AbortSignal
|
|
338
|
+
- **`HttpError`**: Low-level HTTP error (includes `status`, `url`, `body` properties)
|
|
268
339
|
|
|
269
340
|
## Examples by resource
|
|
270
341
|
|
|
@@ -519,3 +590,55 @@ for await (const channel of client.external_channels.listAll()) {
|
|
|
519
590
|
// Get a specific channel
|
|
520
591
|
const channel = await client.external_channels.get('channel-123');
|
|
521
592
|
```
|
|
593
|
+
|
|
594
|
+
### Model Costs
|
|
595
|
+
|
|
596
|
+
The `costs` client provides an offline utility to calculate costs for LLM usage based on token counts:
|
|
597
|
+
|
|
598
|
+
```ts
|
|
599
|
+
import { type ModelCostInput } from '@kaiban/sdk';
|
|
600
|
+
|
|
601
|
+
// Calculate costs for multiple model usages
|
|
602
|
+
const usages: ModelCostInput[] = [
|
|
603
|
+
{
|
|
604
|
+
model: 'gpt-4o',
|
|
605
|
+
inputTokens: 1500,
|
|
606
|
+
outputTokens: 500,
|
|
607
|
+
reasoningTokens: 200, // Optional: reasoning tokens for models that support it
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
model: 'gpt-4o-mini',
|
|
611
|
+
inputTokens: 3000,
|
|
612
|
+
outputTokens: 1000,
|
|
613
|
+
},
|
|
614
|
+
];
|
|
615
|
+
|
|
616
|
+
const result = client.costs.calculateCosts(usages);
|
|
617
|
+
|
|
618
|
+
console.log('Total cost:', result.totalCost); // Total cost in dollars
|
|
619
|
+
console.log('Total tokens:', result.totalTokens); // Total tokens used
|
|
620
|
+
|
|
621
|
+
// Get detailed costs per model
|
|
622
|
+
result.costsByModel.forEach((modelCost) => {
|
|
623
|
+
console.log(`Model: ${modelCost.model}`);
|
|
624
|
+
console.log(` Input tokens: ${modelCost.inputTokens}`);
|
|
625
|
+
console.log(` Output tokens: ${modelCost.outputTokens}`);
|
|
626
|
+
console.log(` Reasoning tokens: ${modelCost.reasoningTokens}`);
|
|
627
|
+
console.log(` Charged output tokens: ${modelCost.chargedOutputTokens}`); // output + reasoning
|
|
628
|
+
console.log(` Total tokens: ${modelCost.totalTokens}`);
|
|
629
|
+
console.log(` Input cost: $${modelCost.inputCost.toFixed(6)}`);
|
|
630
|
+
console.log(` Output cost: $${modelCost.outputCost.toFixed(6)}`);
|
|
631
|
+
console.log(` Total cost: $${modelCost.totalCost.toFixed(6)}`);
|
|
632
|
+
});
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
Supported models and their pricing (per 1M tokens):
|
|
636
|
+
|
|
637
|
+
- **gpt-4o**: $5.00 input, $20.00 output
|
|
638
|
+
- **gpt-4o-mini**: $0.60 input, $2.40 output
|
|
639
|
+
- **gpt-5**: $1.50 input, $10.00 output
|
|
640
|
+
- **gpt-5-mini**: $0.25 input, $2.00 output
|
|
641
|
+
- **gpt-5-nano**: $0.05 input, $0.40 output
|
|
642
|
+
- **text-embedding-3-small**: $0.02 input, $0.00 output
|
|
643
|
+
|
|
644
|
+
**Note:** Reasoning tokens (when provided) are billed as output tokens.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./lib/client"), exports);
|
|
18
|
+
__exportStar(require("./lib/http/errors"), exports);
|
|
19
|
+
__exportStar(require("./lib/http/types"), exports);
|
|
20
|
+
__exportStar(require("./types/entities"), exports);
|
|
21
|
+
__exportStar(require("./types/responses"), exports);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createKaibanClient = createKaibanClient;
|
|
4
|
+
const HttpClient_1 = require("./http/HttpClient");
|
|
5
|
+
const ActivitiesClient_1 = require("./resources/ActivitiesClient");
|
|
6
|
+
const AgentsClient_1 = require("./resources/AgentsClient");
|
|
7
|
+
const BoardsClient_1 = require("./resources/BoardsClient");
|
|
8
|
+
const CardsClient_1 = require("./resources/CardsClient");
|
|
9
|
+
const ExternalChannelsClient_1 = require("./resources/ExternalChannelsClient");
|
|
10
|
+
const ModelCost_1 = require("./resources/ModelCost");
|
|
11
|
+
const ResourcesClient_1 = require("./resources/ResourcesClient");
|
|
12
|
+
const TeamsClient_1 = require("./resources/TeamsClient");
|
|
13
|
+
/**
|
|
14
|
+
* Create a Kaiban SDK client instance
|
|
15
|
+
*
|
|
16
|
+
* @param config - Client configuration object
|
|
17
|
+
* @param config.tenant - The tenant identifier for your Kaiban instance
|
|
18
|
+
* @param config.token - Optional bearer token for authentication
|
|
19
|
+
* @param config.baseUrl - Optional custom base URL for the API
|
|
20
|
+
* @param config.maxRetries - Optional maximum number of request retries (default: 3)
|
|
21
|
+
* @param config.timeout - Optional request timeout in milliseconds (default: 30000)
|
|
22
|
+
*
|
|
23
|
+
* @returns A configured Kaiban client instance
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import { createKaibanClient } from 'kaiban-sdk';
|
|
28
|
+
*
|
|
29
|
+
* const client = createKaibanClient({
|
|
30
|
+
* tenant: 'my-tenant',
|
|
31
|
+
* token: 'my-auth-token',
|
|
32
|
+
* baseUrl: 'https://api.kaiban.ai'
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // List all agents
|
|
36
|
+
* const agents = await client.agents.list();
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @category Client
|
|
40
|
+
*/
|
|
41
|
+
function createKaibanClient(config) {
|
|
42
|
+
const http = new HttpClient_1.HttpClient(config);
|
|
43
|
+
return {
|
|
44
|
+
setToken: (t) => http.setToken(t),
|
|
45
|
+
agents: new AgentsClient_1.AgentsClient(http),
|
|
46
|
+
cards: new CardsClient_1.CardsClient(http),
|
|
47
|
+
activities: new ActivitiesClient_1.ActivitiesClient(http),
|
|
48
|
+
teams: new TeamsClient_1.TeamsClient(http),
|
|
49
|
+
boards: new BoardsClient_1.BoardsClient(http),
|
|
50
|
+
resources: new ResourcesClient_1.ResourcesClient(http),
|
|
51
|
+
external_channels: new ExternalChannelsClient_1.ExternalChannelsClient(http),
|
|
52
|
+
costs: new ModelCost_1.ModelCost(),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpClient = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
function buildQuery(query) {
|
|
6
|
+
if (!query)
|
|
7
|
+
return '';
|
|
8
|
+
const params = new URLSearchParams();
|
|
9
|
+
for (const [k, v] of Object.entries(query)) {
|
|
10
|
+
if (v !== undefined && v !== null)
|
|
11
|
+
params.append(k, String(v));
|
|
12
|
+
}
|
|
13
|
+
const qs = params.toString();
|
|
14
|
+
return qs ? `?${qs}` : '';
|
|
15
|
+
}
|
|
16
|
+
function sleep(ms) {
|
|
17
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
18
|
+
}
|
|
19
|
+
class HttpClient {
|
|
20
|
+
constructor(config) {
|
|
21
|
+
const defaultRetry = {
|
|
22
|
+
maxAttempts: 3,
|
|
23
|
+
backoffMs: 250,
|
|
24
|
+
maxBackoffMs: 4000,
|
|
25
|
+
jitter: true,
|
|
26
|
+
retryOn: [429, 500, 502, 503, 504],
|
|
27
|
+
retryMethods: ['GET', 'PUT', 'DELETE'],
|
|
28
|
+
};
|
|
29
|
+
const baseUrl = config.baseUrl || `https://${config.tenant}.kaiban.io/api`;
|
|
30
|
+
this.config = {
|
|
31
|
+
tenant: config.tenant,
|
|
32
|
+
token: config.token,
|
|
33
|
+
baseUrl,
|
|
34
|
+
timeoutMs: config.timeoutMs ?? 30000,
|
|
35
|
+
retry: {
|
|
36
|
+
...defaultRetry,
|
|
37
|
+
...(config.retry || {}),
|
|
38
|
+
retryOn: [
|
|
39
|
+
...(Array.isArray((config.retry || {}).retryOn)
|
|
40
|
+
? (config.retry || {}).retryOn
|
|
41
|
+
: defaultRetry.retryOn),
|
|
42
|
+
],
|
|
43
|
+
retryMethods: [
|
|
44
|
+
...(Array.isArray((config.retry || {}).retryMethods)
|
|
45
|
+
? (config.retry || {}).retryMethods
|
|
46
|
+
: defaultRetry.retryMethods),
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
fetch: config.fetch || fetch,
|
|
50
|
+
onRequest: config.onRequest || (() => { }),
|
|
51
|
+
onResponse: config.onResponse || (() => { }),
|
|
52
|
+
};
|
|
53
|
+
this._token = config.token;
|
|
54
|
+
// Normalize retry config with required fields for internal use
|
|
55
|
+
const r = this.config.retry;
|
|
56
|
+
this.retryCfg = {
|
|
57
|
+
maxAttempts: r.maxAttempts ?? defaultRetry.maxAttempts,
|
|
58
|
+
backoffMs: r.backoffMs ?? defaultRetry.backoffMs,
|
|
59
|
+
maxBackoffMs: r.maxBackoffMs ?? defaultRetry.maxBackoffMs,
|
|
60
|
+
jitter: r.jitter ?? defaultRetry.jitter,
|
|
61
|
+
retryOn: Array.isArray(r.retryOn) ? r.retryOn : defaultRetry.retryOn,
|
|
62
|
+
retryMethods: Array.isArray(r.retryMethods) ? r.retryMethods : defaultRetry.retryMethods,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
setToken(token) {
|
|
66
|
+
this._token = token;
|
|
67
|
+
}
|
|
68
|
+
async attempt(fn, retryCfg) {
|
|
69
|
+
const { maxAttempts = 3, backoffMs = 250, maxBackoffMs = 4000, jitter = true } = retryCfg;
|
|
70
|
+
let attempt = 0;
|
|
71
|
+
let delay = backoffMs;
|
|
72
|
+
while (true) {
|
|
73
|
+
try {
|
|
74
|
+
return await fn();
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
attempt++;
|
|
78
|
+
if (attempt >= maxAttempts)
|
|
79
|
+
throw err;
|
|
80
|
+
const wait = jitter ? Math.min(maxBackoffMs, delay * (1 + Math.random())) : delay;
|
|
81
|
+
await sleep(wait);
|
|
82
|
+
delay = Math.min(maxBackoffMs, delay * 2);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async request(method, path, body, options) {
|
|
87
|
+
const normalizedPath = path.startsWith('/v1') ? path : `/v1${path}`;
|
|
88
|
+
const url = `${this.config.baseUrl}${normalizedPath}${buildQuery(options?.query)}`;
|
|
89
|
+
const headers = {
|
|
90
|
+
'content-type': 'application/json',
|
|
91
|
+
'x-tenant': this.config.tenant,
|
|
92
|
+
...(this._token ? { authorization: `Bearer ${this._token}` } : {}),
|
|
93
|
+
...(options?.headers || {}),
|
|
94
|
+
};
|
|
95
|
+
// Compose abort signals: user-provided and timeout
|
|
96
|
+
const combinedController = new AbortController();
|
|
97
|
+
const userSignal = options?.signal;
|
|
98
|
+
let timedOut = false;
|
|
99
|
+
const timeout = setTimeout(() => {
|
|
100
|
+
timedOut = true;
|
|
101
|
+
combinedController.abort();
|
|
102
|
+
}, options?.timeoutMs ?? this.config.timeoutMs);
|
|
103
|
+
const onUserAbort = () => combinedController.abort();
|
|
104
|
+
if (userSignal) {
|
|
105
|
+
if (userSignal.aborted) {
|
|
106
|
+
// propagate immediately
|
|
107
|
+
combinedController.abort();
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
userSignal.addEventListener('abort', onUserAbort);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const init = {
|
|
114
|
+
method,
|
|
115
|
+
headers,
|
|
116
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
117
|
+
signal: combinedController.signal,
|
|
118
|
+
};
|
|
119
|
+
this.config.onRequest({ method, url, init });
|
|
120
|
+
const doFetch = async () => {
|
|
121
|
+
try {
|
|
122
|
+
const res = await this.config.fetch(url, init);
|
|
123
|
+
this.config.onResponse({ status: res.status, url, response: res });
|
|
124
|
+
let parsed;
|
|
125
|
+
const contentType = res.headers.get('content-type') || '';
|
|
126
|
+
if (contentType.includes('application/json')) {
|
|
127
|
+
try {
|
|
128
|
+
parsed = await res.json();
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
parsed = undefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
parsed = await res.text();
|
|
136
|
+
}
|
|
137
|
+
if (!res.ok) {
|
|
138
|
+
throw (0, errors_1.mapHttpToSdkError)(res.status, parsed);
|
|
139
|
+
}
|
|
140
|
+
return parsed;
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
if (isAbortError(e)) {
|
|
144
|
+
if (timedOut)
|
|
145
|
+
throw new errors_1.TimeoutError();
|
|
146
|
+
throw new errors_1.AbortedError();
|
|
147
|
+
}
|
|
148
|
+
throw e;
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
clearTimeout(timeout);
|
|
152
|
+
if (userSignal)
|
|
153
|
+
userSignal.removeEventListener('abort', onUserAbort);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const retryCfg = mergeRetryConfig(this.retryCfg, options?.retry);
|
|
157
|
+
const shouldRetry = (err) => {
|
|
158
|
+
const methodUpper = method.toUpperCase();
|
|
159
|
+
const retryableByMethod = retryCfg.retryMethods?.includes(methodUpper);
|
|
160
|
+
if (!retryableByMethod)
|
|
161
|
+
return false;
|
|
162
|
+
if (err instanceof errors_1.TimeoutError)
|
|
163
|
+
return true;
|
|
164
|
+
// Retry on known transient SDK errors
|
|
165
|
+
if (err instanceof errors_1.RateLimitError)
|
|
166
|
+
return retryCfg.retryOn?.includes(429) ?? false;
|
|
167
|
+
if (err instanceof errors_1.UnavailableError)
|
|
168
|
+
return retryCfg.retryOn?.some((c) => c === 502 || c === 503 || c === 504) ?? false;
|
|
169
|
+
if (err instanceof errors_1.ServerError)
|
|
170
|
+
return retryCfg.retryOn?.includes(500) ?? false;
|
|
171
|
+
return false;
|
|
172
|
+
};
|
|
173
|
+
return await this.attempt(async () => {
|
|
174
|
+
try {
|
|
175
|
+
return await doFetch();
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
if (shouldRetry(err))
|
|
179
|
+
throw err;
|
|
180
|
+
throw err;
|
|
181
|
+
}
|
|
182
|
+
}, retryCfg);
|
|
183
|
+
}
|
|
184
|
+
get(path, options) {
|
|
185
|
+
return this.request('GET', path, undefined, options);
|
|
186
|
+
}
|
|
187
|
+
post(path, body, options) {
|
|
188
|
+
return this.request('POST', path, body, options);
|
|
189
|
+
}
|
|
190
|
+
put(path, body, options) {
|
|
191
|
+
return this.request('PUT', path, body, options);
|
|
192
|
+
}
|
|
193
|
+
delete(path, options) {
|
|
194
|
+
return this.request('DELETE', path, undefined, options);
|
|
195
|
+
}
|
|
196
|
+
list(path, listParams, options) {
|
|
197
|
+
const queryParams = {};
|
|
198
|
+
if (listParams) {
|
|
199
|
+
// Handle pagination
|
|
200
|
+
if (listParams.limit)
|
|
201
|
+
queryParams.limit = listParams.limit;
|
|
202
|
+
if (listParams.before)
|
|
203
|
+
queryParams.before = listParams.before;
|
|
204
|
+
if (listParams.after)
|
|
205
|
+
queryParams.after = listParams.after;
|
|
206
|
+
// Handle sorting (already a string)
|
|
207
|
+
if (listParams.order_by)
|
|
208
|
+
queryParams.order_by = listParams.order_by;
|
|
209
|
+
// Handle filters
|
|
210
|
+
if (listParams.filters) {
|
|
211
|
+
Object.entries(listParams.filters).forEach(([key, value]) => {
|
|
212
|
+
queryParams[key] = value;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
// Handle metadata filters for cards
|
|
216
|
+
if (listParams.metadata) {
|
|
217
|
+
Object.entries(listParams.metadata).forEach(([key, value]) => {
|
|
218
|
+
queryParams[`metadata.${key}`] = value;
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return this.request('GET', path, undefined, { ...options, query: queryParams });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
exports.HttpClient = HttpClient;
|
|
226
|
+
function isAbortError(e) {
|
|
227
|
+
if (!e)
|
|
228
|
+
return false;
|
|
229
|
+
const anyErr = e;
|
|
230
|
+
return anyErr && anyErr.name === 'AbortError';
|
|
231
|
+
}
|
|
232
|
+
function mergeRetryConfig(base, override) {
|
|
233
|
+
if (!override)
|
|
234
|
+
return base;
|
|
235
|
+
return {
|
|
236
|
+
maxAttempts: override.maxAttempts ?? base.maxAttempts,
|
|
237
|
+
backoffMs: override.backoffMs ?? base.backoffMs,
|
|
238
|
+
maxBackoffMs: override.maxBackoffMs ?? base.maxBackoffMs,
|
|
239
|
+
jitter: override.jitter ?? base.jitter,
|
|
240
|
+
retryOn: override.retryOn ? [...override.retryOn] : base.retryOn,
|
|
241
|
+
retryMethods: override.retryMethods ? [...override.retryMethods] : base.retryMethods,
|
|
242
|
+
};
|
|
243
|
+
}
|