@cobbl-ai/sdk 0.1.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/dist/index.js ADDED
@@ -0,0 +1,236 @@
1
+ 'use strict';
2
+
3
+ // src/errors.ts
4
+ var CobblError = class _CobblError extends Error {
5
+ constructor(message, code, details) {
6
+ super(message);
7
+ this.name = "CobblError";
8
+ this.code = code;
9
+ this.details = details;
10
+ if (Error.captureStackTrace) {
11
+ Error.captureStackTrace(this, _CobblError);
12
+ }
13
+ }
14
+ /**
15
+ * Check if an error is a CobblError
16
+ */
17
+ static isCobblError(error) {
18
+ return error instanceof _CobblError;
19
+ }
20
+ /**
21
+ * Convert error to JSON-serializable object
22
+ */
23
+ toJSON() {
24
+ return {
25
+ name: this.name,
26
+ message: this.message,
27
+ code: this.code,
28
+ details: this.details
29
+ };
30
+ }
31
+ };
32
+
33
+ // src/client.ts
34
+ var REQUEST_TIMEOUT_MS = 3e4;
35
+ var CobblClient = class {
36
+ /**
37
+ * Initialize the Cobbl SDK client
38
+ *
39
+ * @param config - Configuration object
40
+ * @param config.apiKey - Your Cobbl API key
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const client = new CobblClient({
45
+ * apiKey: process.env.COBBL_API_KEY
46
+ * })
47
+ * ```
48
+ */
49
+ constructor(config) {
50
+ if (!config.apiKey || config.apiKey.trim().length === 0) {
51
+ throw new CobblError("API key is required", "INVALID_CONFIG");
52
+ }
53
+ this.apiKey = config.apiKey;
54
+ }
55
+ /**
56
+ * Execute a prompt with the given input variables
57
+ *
58
+ * @param promptSlug - The unique slug identifier for the prompt
59
+ * @param input - Input variables to populate the prompt template
60
+ * @returns Promise containing the prompt execution results
61
+ *
62
+ * @throws {CobblError} When the request fails or API returns an error
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * const result = await client.runPrompt('sales_summary', {
67
+ * topic: 'Q4 Results',
68
+ * tone: 'friendly',
69
+ * audience: 'investors'
70
+ * })
71
+ *
72
+ * console.log(result.output) // AI-generated response
73
+ * console.log(result.runId) // Save this to link feedback later
74
+ * ```
75
+ */
76
+ async runPrompt(promptSlug, input) {
77
+ if (!promptSlug || promptSlug.trim().length === 0) {
78
+ throw new CobblError("promptSlug is required", "INVALID_REQUEST");
79
+ }
80
+ try {
81
+ const response = await this.makeRequest("/prompt/run", {
82
+ method: "POST",
83
+ body: JSON.stringify({
84
+ promptSlug: promptSlug.trim(),
85
+ input
86
+ })
87
+ });
88
+ if (!response.ok) {
89
+ await this.handleErrorResponse(response);
90
+ }
91
+ const data = await response.json();
92
+ return {
93
+ runId: data.runId,
94
+ output: data.output,
95
+ tokenUsage: data.tokenUsage,
96
+ renderedPrompt: data.renderedPrompt,
97
+ promptVersion: data.promptVersion
98
+ };
99
+ } catch (error) {
100
+ if (error instanceof CobblError) {
101
+ throw error;
102
+ }
103
+ throw new CobblError(
104
+ `Failed to run prompt: ${error instanceof Error ? error.message : "Unknown error"}`,
105
+ "NETWORK_ERROR"
106
+ );
107
+ }
108
+ }
109
+ /**
110
+ * Submit user feedback for a prompt run
111
+ *
112
+ * @param feedback - Feedback submission data
113
+ * @param feedback.runId - The run ID from a previous runPrompt call
114
+ * @param feedback.helpful - Whether the output was helpful ('helpful' or 'not_helpful')
115
+ * @param feedback.userFeedback - Detailed feedback message from the user
116
+ * @returns Promise containing the created feedback ID
117
+ *
118
+ * @throws {CobblError} When the request fails or API returns an error
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * await client.submitFeedback({
123
+ * runId: result.runId,
124
+ * helpful: 'not_helpful',
125
+ * userFeedback: 'The response was too formal and lengthy'
126
+ * })
127
+ * ```
128
+ */
129
+ async submitFeedback(feedback) {
130
+ if (!feedback.runId || feedback.runId.trim().length === 0) {
131
+ throw new CobblError("runId is required", "INVALID_REQUEST");
132
+ }
133
+ if (!feedback.userFeedback || feedback.userFeedback.trim().length === 0) {
134
+ throw new CobblError("userFeedback is required", "INVALID_REQUEST");
135
+ }
136
+ if (!feedback.helpful || !["helpful", "not_helpful"].includes(feedback.helpful)) {
137
+ throw new CobblError(
138
+ 'helpful must be either "helpful" or "not_helpful"',
139
+ "INVALID_REQUEST"
140
+ );
141
+ }
142
+ try {
143
+ const response = await this.makeRequest("/feedback", {
144
+ method: "POST",
145
+ body: JSON.stringify({
146
+ runId: feedback.runId.trim(),
147
+ helpful: feedback.helpful,
148
+ userFeedback: feedback.userFeedback.trim()
149
+ })
150
+ });
151
+ if (!response.ok) {
152
+ await this.handleErrorResponse(response);
153
+ }
154
+ const data = await response.json();
155
+ return {
156
+ feedbackId: data.feedbackId,
157
+ message: data.message
158
+ };
159
+ } catch (error) {
160
+ if (error instanceof CobblError) {
161
+ throw error;
162
+ }
163
+ throw new CobblError(
164
+ `Failed to submit feedback: ${error instanceof Error ? error.message : "Unknown error"}`,
165
+ "NETWORK_ERROR"
166
+ );
167
+ }
168
+ }
169
+ /**
170
+ * Make an HTTP request to the Cobbl API
171
+ * @private
172
+ */
173
+ async makeRequest(path, options) {
174
+ const baseUrl = process.env.COBBL_API_URL || "https://api.cobbl.ai";
175
+ const url = `${baseUrl}${path}`;
176
+ const controller = new AbortController();
177
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
178
+ try {
179
+ const response = await fetch(url, {
180
+ ...options,
181
+ headers: {
182
+ "Content-Type": "application/json",
183
+ Authorization: `Bearer ${this.apiKey}`,
184
+ ...options.headers
185
+ },
186
+ signal: controller.signal
187
+ });
188
+ return response;
189
+ } finally {
190
+ clearTimeout(timeoutId);
191
+ }
192
+ }
193
+ /**
194
+ * Handle error responses from the API
195
+ * @private
196
+ */
197
+ async handleErrorResponse(response) {
198
+ let errorData;
199
+ try {
200
+ errorData = await response.json();
201
+ } catch {
202
+ throw new CobblError(
203
+ `HTTP ${response.status}: ${response.statusText}`,
204
+ "API_ERROR",
205
+ { status: response.status }
206
+ );
207
+ }
208
+ const message = errorData.error || errorData.message || "Unknown error";
209
+ const details = errorData.details;
210
+ switch (response.status) {
211
+ case 400:
212
+ throw new CobblError(message, "INVALID_REQUEST", details);
213
+ case 401:
214
+ throw new CobblError(message, "UNAUTHORIZED", details);
215
+ case 404:
216
+ throw new CobblError(message, "NOT_FOUND", details);
217
+ case 429:
218
+ throw new CobblError(message, "RATE_LIMIT_EXCEEDED", details);
219
+ case 500:
220
+ case 502:
221
+ case 503:
222
+ case 504:
223
+ throw new CobblError(message, "SERVER_ERROR", details);
224
+ default:
225
+ throw new CobblError(message, "API_ERROR", {
226
+ status: response.status,
227
+ ...details
228
+ });
229
+ }
230
+ }
231
+ };
232
+
233
+ exports.CobblClient = CobblClient;
234
+ exports.CobblError = CobblError;
235
+ //# sourceMappingURL=index.js.map
236
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Error types that can be thrown by the Cobbl SDK\n */\nexport type CobblErrorCode =\n | 'INVALID_CONFIG'\n | 'INVALID_REQUEST'\n | 'UNAUTHORIZED'\n | 'NOT_FOUND'\n | 'RATE_LIMIT_EXCEEDED'\n | 'SERVER_ERROR'\n | 'NETWORK_ERROR'\n | 'API_ERROR'\n\n/**\n * Custom error class for Cobbl SDK errors\n *\n * @example\n * ```typescript\n * try {\n * await client.runPrompt('my-prompt', { topic: 'test' })\n * } catch (error) {\n * if (error instanceof CobblError) {\n * console.error(`Error [${error.code}]: ${error.message}`)\n * console.error('Details:', error.details)\n * }\n * }\n * ```\n */\nexport class CobblError extends Error {\n /**\n * Error code indicating the type of error\n */\n public readonly code: CobblErrorCode\n\n /**\n * Additional details about the error (e.g., missing variables, validation issues)\n */\n public readonly details?: unknown\n\n constructor(message: string, code: CobblErrorCode, details?: unknown) {\n super(message)\n this.name = 'CobblError'\n this.code = code\n this.details = details\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CobblError)\n }\n }\n\n /**\n * Check if an error is a CobblError\n */\n static isCobblError(error: unknown): error is CobblError {\n return error instanceof CobblError\n }\n\n /**\n * Convert error to JSON-serializable object\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n details: this.details,\n }\n }\n}\n","/**\n * CobblClient - SDK for the Cobbl platform\n *\n * Provides methods to run prompts and submit feedback to the Cobbl API.\n */\n\nimport type { PromptInput, PromptVersionClient } from '@prompti/shared'\nimport type {\n RunPromptResponse,\n SubmitFeedbackResponse,\n CobblConfig,\n TokenUsage,\n FeedbackSubmission,\n} from './types'\nimport { CobblError } from './errors'\n\nconst REQUEST_TIMEOUT_MS = 30_000\n\nexport class CobblClient {\n private readonly apiKey: string\n\n /**\n * Initialize the Cobbl SDK client\n *\n * @param config - Configuration object\n * @param config.apiKey - Your Cobbl API key\n *\n * @example\n * ```typescript\n * const client = new CobblClient({\n * apiKey: process.env.COBBL_API_KEY\n * })\n * ```\n */\n constructor(config: CobblConfig) {\n if (!config.apiKey || config.apiKey.trim().length === 0) {\n throw new CobblError('API key is required', 'INVALID_CONFIG')\n }\n\n this.apiKey = config.apiKey\n }\n\n /**\n * Execute a prompt with the given input variables\n *\n * @param promptSlug - The unique slug identifier for the prompt\n * @param input - Input variables to populate the prompt template\n * @returns Promise containing the prompt execution results\n *\n * @throws {CobblError} When the request fails or API returns an error\n *\n * @example\n * ```typescript\n * const result = await client.runPrompt('sales_summary', {\n * topic: 'Q4 Results',\n * tone: 'friendly',\n * audience: 'investors'\n * })\n *\n * console.log(result.output) // AI-generated response\n * console.log(result.runId) // Save this to link feedback later\n * ```\n */\n async runPrompt(\n promptSlug: string,\n input: PromptInput\n ): Promise<RunPromptResponse> {\n if (!promptSlug || promptSlug.trim().length === 0) {\n throw new CobblError('promptSlug is required', 'INVALID_REQUEST')\n }\n\n try {\n const response = await this.makeRequest('/prompt/run', {\n method: 'POST',\n body: JSON.stringify({\n promptSlug: promptSlug.trim(),\n input,\n }),\n })\n\n if (!response.ok) {\n await this.handleErrorResponse(response)\n }\n\n const data = (await response.json()) as {\n runId: string\n output: string\n tokenUsage: TokenUsage\n renderedPrompt: string\n promptVersion: PromptVersionClient\n }\n\n return {\n runId: data.runId,\n output: data.output,\n tokenUsage: data.tokenUsage,\n renderedPrompt: data.renderedPrompt,\n promptVersion: data.promptVersion,\n }\n } catch (error) {\n if (error instanceof CobblError) {\n throw error\n }\n throw new CobblError(\n `Failed to run prompt: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'NETWORK_ERROR'\n )\n }\n }\n\n /**\n * Submit user feedback for a prompt run\n *\n * @param feedback - Feedback submission data\n * @param feedback.runId - The run ID from a previous runPrompt call\n * @param feedback.helpful - Whether the output was helpful ('helpful' or 'not_helpful')\n * @param feedback.userFeedback - Detailed feedback message from the user\n * @returns Promise containing the created feedback ID\n *\n * @throws {CobblError} When the request fails or API returns an error\n *\n * @example\n * ```typescript\n * await client.submitFeedback({\n * runId: result.runId,\n * helpful: 'not_helpful',\n * userFeedback: 'The response was too formal and lengthy'\n * })\n * ```\n */\n async submitFeedback(\n feedback: FeedbackSubmission\n ): Promise<SubmitFeedbackResponse> {\n if (!feedback.runId || feedback.runId.trim().length === 0) {\n throw new CobblError('runId is required', 'INVALID_REQUEST')\n }\n\n if (!feedback.userFeedback || feedback.userFeedback.trim().length === 0) {\n throw new CobblError('userFeedback is required', 'INVALID_REQUEST')\n }\n\n if (\n !feedback.helpful ||\n !['helpful', 'not_helpful'].includes(feedback.helpful)\n ) {\n throw new CobblError(\n 'helpful must be either \"helpful\" or \"not_helpful\"',\n 'INVALID_REQUEST'\n )\n }\n\n try {\n const response = await this.makeRequest('/feedback', {\n method: 'POST',\n body: JSON.stringify({\n runId: feedback.runId.trim(),\n helpful: feedback.helpful,\n userFeedback: feedback.userFeedback.trim(),\n }),\n })\n\n if (!response.ok) {\n await this.handleErrorResponse(response)\n }\n\n const data = (await response.json()) as {\n feedbackId: string\n message: string\n }\n\n return {\n feedbackId: data.feedbackId,\n message: data.message,\n }\n } catch (error) {\n if (error instanceof CobblError) {\n throw error\n }\n throw new CobblError(\n `Failed to submit feedback: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'NETWORK_ERROR'\n )\n }\n }\n\n /**\n * Make an HTTP request to the Cobbl API\n * @private\n */\n private async makeRequest(\n path: string,\n options: RequestInit\n ): Promise<Response> {\n const baseUrl = process.env.COBBL_API_URL || 'https://api.cobbl.ai'\n const url = `${baseUrl}${path}`\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS)\n\n try {\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n ...options.headers,\n },\n signal: controller.signal,\n })\n\n return response\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Handle error responses from the API\n * @private\n */\n private async handleErrorResponse(response: Response): Promise<never> {\n let errorData: any\n try {\n errorData = await response.json()\n } catch {\n throw new CobblError(\n `HTTP ${response.status}: ${response.statusText}`,\n 'API_ERROR',\n { status: response.status }\n )\n }\n\n const message = errorData.error || errorData.message || 'Unknown error'\n const details = errorData.details\n\n switch (response.status) {\n case 400:\n throw new CobblError(message, 'INVALID_REQUEST', details)\n case 401:\n throw new CobblError(message, 'UNAUTHORIZED', details)\n case 404:\n throw new CobblError(message, 'NOT_FOUND', details)\n case 429:\n throw new CobblError(message, 'RATE_LIMIT_EXCEEDED', details)\n case 500:\n case 502:\n case 503:\n case 504:\n throw new CobblError(message, 'SERVER_ERROR', details)\n default:\n throw new CobblError(message, 'API_ERROR', {\n status: response.status,\n ...details,\n })\n }\n }\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,233 @@
1
+ // src/errors.ts
2
+ var CobblError = class _CobblError extends Error {
3
+ constructor(message, code, details) {
4
+ super(message);
5
+ this.name = "CobblError";
6
+ this.code = code;
7
+ this.details = details;
8
+ if (Error.captureStackTrace) {
9
+ Error.captureStackTrace(this, _CobblError);
10
+ }
11
+ }
12
+ /**
13
+ * Check if an error is a CobblError
14
+ */
15
+ static isCobblError(error) {
16
+ return error instanceof _CobblError;
17
+ }
18
+ /**
19
+ * Convert error to JSON-serializable object
20
+ */
21
+ toJSON() {
22
+ return {
23
+ name: this.name,
24
+ message: this.message,
25
+ code: this.code,
26
+ details: this.details
27
+ };
28
+ }
29
+ };
30
+
31
+ // src/client.ts
32
+ var REQUEST_TIMEOUT_MS = 3e4;
33
+ var CobblClient = class {
34
+ /**
35
+ * Initialize the Cobbl SDK client
36
+ *
37
+ * @param config - Configuration object
38
+ * @param config.apiKey - Your Cobbl API key
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const client = new CobblClient({
43
+ * apiKey: process.env.COBBL_API_KEY
44
+ * })
45
+ * ```
46
+ */
47
+ constructor(config) {
48
+ if (!config.apiKey || config.apiKey.trim().length === 0) {
49
+ throw new CobblError("API key is required", "INVALID_CONFIG");
50
+ }
51
+ this.apiKey = config.apiKey;
52
+ }
53
+ /**
54
+ * Execute a prompt with the given input variables
55
+ *
56
+ * @param promptSlug - The unique slug identifier for the prompt
57
+ * @param input - Input variables to populate the prompt template
58
+ * @returns Promise containing the prompt execution results
59
+ *
60
+ * @throws {CobblError} When the request fails or API returns an error
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const result = await client.runPrompt('sales_summary', {
65
+ * topic: 'Q4 Results',
66
+ * tone: 'friendly',
67
+ * audience: 'investors'
68
+ * })
69
+ *
70
+ * console.log(result.output) // AI-generated response
71
+ * console.log(result.runId) // Save this to link feedback later
72
+ * ```
73
+ */
74
+ async runPrompt(promptSlug, input) {
75
+ if (!promptSlug || promptSlug.trim().length === 0) {
76
+ throw new CobblError("promptSlug is required", "INVALID_REQUEST");
77
+ }
78
+ try {
79
+ const response = await this.makeRequest("/prompt/run", {
80
+ method: "POST",
81
+ body: JSON.stringify({
82
+ promptSlug: promptSlug.trim(),
83
+ input
84
+ })
85
+ });
86
+ if (!response.ok) {
87
+ await this.handleErrorResponse(response);
88
+ }
89
+ const data = await response.json();
90
+ return {
91
+ runId: data.runId,
92
+ output: data.output,
93
+ tokenUsage: data.tokenUsage,
94
+ renderedPrompt: data.renderedPrompt,
95
+ promptVersion: data.promptVersion
96
+ };
97
+ } catch (error) {
98
+ if (error instanceof CobblError) {
99
+ throw error;
100
+ }
101
+ throw new CobblError(
102
+ `Failed to run prompt: ${error instanceof Error ? error.message : "Unknown error"}`,
103
+ "NETWORK_ERROR"
104
+ );
105
+ }
106
+ }
107
+ /**
108
+ * Submit user feedback for a prompt run
109
+ *
110
+ * @param feedback - Feedback submission data
111
+ * @param feedback.runId - The run ID from a previous runPrompt call
112
+ * @param feedback.helpful - Whether the output was helpful ('helpful' or 'not_helpful')
113
+ * @param feedback.userFeedback - Detailed feedback message from the user
114
+ * @returns Promise containing the created feedback ID
115
+ *
116
+ * @throws {CobblError} When the request fails or API returns an error
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * await client.submitFeedback({
121
+ * runId: result.runId,
122
+ * helpful: 'not_helpful',
123
+ * userFeedback: 'The response was too formal and lengthy'
124
+ * })
125
+ * ```
126
+ */
127
+ async submitFeedback(feedback) {
128
+ if (!feedback.runId || feedback.runId.trim().length === 0) {
129
+ throw new CobblError("runId is required", "INVALID_REQUEST");
130
+ }
131
+ if (!feedback.userFeedback || feedback.userFeedback.trim().length === 0) {
132
+ throw new CobblError("userFeedback is required", "INVALID_REQUEST");
133
+ }
134
+ if (!feedback.helpful || !["helpful", "not_helpful"].includes(feedback.helpful)) {
135
+ throw new CobblError(
136
+ 'helpful must be either "helpful" or "not_helpful"',
137
+ "INVALID_REQUEST"
138
+ );
139
+ }
140
+ try {
141
+ const response = await this.makeRequest("/feedback", {
142
+ method: "POST",
143
+ body: JSON.stringify({
144
+ runId: feedback.runId.trim(),
145
+ helpful: feedback.helpful,
146
+ userFeedback: feedback.userFeedback.trim()
147
+ })
148
+ });
149
+ if (!response.ok) {
150
+ await this.handleErrorResponse(response);
151
+ }
152
+ const data = await response.json();
153
+ return {
154
+ feedbackId: data.feedbackId,
155
+ message: data.message
156
+ };
157
+ } catch (error) {
158
+ if (error instanceof CobblError) {
159
+ throw error;
160
+ }
161
+ throw new CobblError(
162
+ `Failed to submit feedback: ${error instanceof Error ? error.message : "Unknown error"}`,
163
+ "NETWORK_ERROR"
164
+ );
165
+ }
166
+ }
167
+ /**
168
+ * Make an HTTP request to the Cobbl API
169
+ * @private
170
+ */
171
+ async makeRequest(path, options) {
172
+ const baseUrl = process.env.COBBL_API_URL || "https://api.cobbl.ai";
173
+ const url = `${baseUrl}${path}`;
174
+ const controller = new AbortController();
175
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
176
+ try {
177
+ const response = await fetch(url, {
178
+ ...options,
179
+ headers: {
180
+ "Content-Type": "application/json",
181
+ Authorization: `Bearer ${this.apiKey}`,
182
+ ...options.headers
183
+ },
184
+ signal: controller.signal
185
+ });
186
+ return response;
187
+ } finally {
188
+ clearTimeout(timeoutId);
189
+ }
190
+ }
191
+ /**
192
+ * Handle error responses from the API
193
+ * @private
194
+ */
195
+ async handleErrorResponse(response) {
196
+ let errorData;
197
+ try {
198
+ errorData = await response.json();
199
+ } catch {
200
+ throw new CobblError(
201
+ `HTTP ${response.status}: ${response.statusText}`,
202
+ "API_ERROR",
203
+ { status: response.status }
204
+ );
205
+ }
206
+ const message = errorData.error || errorData.message || "Unknown error";
207
+ const details = errorData.details;
208
+ switch (response.status) {
209
+ case 400:
210
+ throw new CobblError(message, "INVALID_REQUEST", details);
211
+ case 401:
212
+ throw new CobblError(message, "UNAUTHORIZED", details);
213
+ case 404:
214
+ throw new CobblError(message, "NOT_FOUND", details);
215
+ case 429:
216
+ throw new CobblError(message, "RATE_LIMIT_EXCEEDED", details);
217
+ case 500:
218
+ case 502:
219
+ case 503:
220
+ case 504:
221
+ throw new CobblError(message, "SERVER_ERROR", details);
222
+ default:
223
+ throw new CobblError(message, "API_ERROR", {
224
+ status: response.status,
225
+ ...details
226
+ });
227
+ }
228
+ }
229
+ };
230
+
231
+ export { CobblClient, CobblError };
232
+ //# sourceMappingURL=index.mjs.map
233
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Error types that can be thrown by the Cobbl SDK\n */\nexport type CobblErrorCode =\n | 'INVALID_CONFIG'\n | 'INVALID_REQUEST'\n | 'UNAUTHORIZED'\n | 'NOT_FOUND'\n | 'RATE_LIMIT_EXCEEDED'\n | 'SERVER_ERROR'\n | 'NETWORK_ERROR'\n | 'API_ERROR'\n\n/**\n * Custom error class for Cobbl SDK errors\n *\n * @example\n * ```typescript\n * try {\n * await client.runPrompt('my-prompt', { topic: 'test' })\n * } catch (error) {\n * if (error instanceof CobblError) {\n * console.error(`Error [${error.code}]: ${error.message}`)\n * console.error('Details:', error.details)\n * }\n * }\n * ```\n */\nexport class CobblError extends Error {\n /**\n * Error code indicating the type of error\n */\n public readonly code: CobblErrorCode\n\n /**\n * Additional details about the error (e.g., missing variables, validation issues)\n */\n public readonly details?: unknown\n\n constructor(message: string, code: CobblErrorCode, details?: unknown) {\n super(message)\n this.name = 'CobblError'\n this.code = code\n this.details = details\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CobblError)\n }\n }\n\n /**\n * Check if an error is a CobblError\n */\n static isCobblError(error: unknown): error is CobblError {\n return error instanceof CobblError\n }\n\n /**\n * Convert error to JSON-serializable object\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n details: this.details,\n }\n }\n}\n","/**\n * CobblClient - SDK for the Cobbl platform\n *\n * Provides methods to run prompts and submit feedback to the Cobbl API.\n */\n\nimport type { PromptInput, PromptVersionClient } from '@prompti/shared'\nimport type {\n RunPromptResponse,\n SubmitFeedbackResponse,\n CobblConfig,\n TokenUsage,\n FeedbackSubmission,\n} from './types'\nimport { CobblError } from './errors'\n\nconst REQUEST_TIMEOUT_MS = 30_000\n\nexport class CobblClient {\n private readonly apiKey: string\n\n /**\n * Initialize the Cobbl SDK client\n *\n * @param config - Configuration object\n * @param config.apiKey - Your Cobbl API key\n *\n * @example\n * ```typescript\n * const client = new CobblClient({\n * apiKey: process.env.COBBL_API_KEY\n * })\n * ```\n */\n constructor(config: CobblConfig) {\n if (!config.apiKey || config.apiKey.trim().length === 0) {\n throw new CobblError('API key is required', 'INVALID_CONFIG')\n }\n\n this.apiKey = config.apiKey\n }\n\n /**\n * Execute a prompt with the given input variables\n *\n * @param promptSlug - The unique slug identifier for the prompt\n * @param input - Input variables to populate the prompt template\n * @returns Promise containing the prompt execution results\n *\n * @throws {CobblError} When the request fails or API returns an error\n *\n * @example\n * ```typescript\n * const result = await client.runPrompt('sales_summary', {\n * topic: 'Q4 Results',\n * tone: 'friendly',\n * audience: 'investors'\n * })\n *\n * console.log(result.output) // AI-generated response\n * console.log(result.runId) // Save this to link feedback later\n * ```\n */\n async runPrompt(\n promptSlug: string,\n input: PromptInput\n ): Promise<RunPromptResponse> {\n if (!promptSlug || promptSlug.trim().length === 0) {\n throw new CobblError('promptSlug is required', 'INVALID_REQUEST')\n }\n\n try {\n const response = await this.makeRequest('/prompt/run', {\n method: 'POST',\n body: JSON.stringify({\n promptSlug: promptSlug.trim(),\n input,\n }),\n })\n\n if (!response.ok) {\n await this.handleErrorResponse(response)\n }\n\n const data = (await response.json()) as {\n runId: string\n output: string\n tokenUsage: TokenUsage\n renderedPrompt: string\n promptVersion: PromptVersionClient\n }\n\n return {\n runId: data.runId,\n output: data.output,\n tokenUsage: data.tokenUsage,\n renderedPrompt: data.renderedPrompt,\n promptVersion: data.promptVersion,\n }\n } catch (error) {\n if (error instanceof CobblError) {\n throw error\n }\n throw new CobblError(\n `Failed to run prompt: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'NETWORK_ERROR'\n )\n }\n }\n\n /**\n * Submit user feedback for a prompt run\n *\n * @param feedback - Feedback submission data\n * @param feedback.runId - The run ID from a previous runPrompt call\n * @param feedback.helpful - Whether the output was helpful ('helpful' or 'not_helpful')\n * @param feedback.userFeedback - Detailed feedback message from the user\n * @returns Promise containing the created feedback ID\n *\n * @throws {CobblError} When the request fails or API returns an error\n *\n * @example\n * ```typescript\n * await client.submitFeedback({\n * runId: result.runId,\n * helpful: 'not_helpful',\n * userFeedback: 'The response was too formal and lengthy'\n * })\n * ```\n */\n async submitFeedback(\n feedback: FeedbackSubmission\n ): Promise<SubmitFeedbackResponse> {\n if (!feedback.runId || feedback.runId.trim().length === 0) {\n throw new CobblError('runId is required', 'INVALID_REQUEST')\n }\n\n if (!feedback.userFeedback || feedback.userFeedback.trim().length === 0) {\n throw new CobblError('userFeedback is required', 'INVALID_REQUEST')\n }\n\n if (\n !feedback.helpful ||\n !['helpful', 'not_helpful'].includes(feedback.helpful)\n ) {\n throw new CobblError(\n 'helpful must be either \"helpful\" or \"not_helpful\"',\n 'INVALID_REQUEST'\n )\n }\n\n try {\n const response = await this.makeRequest('/feedback', {\n method: 'POST',\n body: JSON.stringify({\n runId: feedback.runId.trim(),\n helpful: feedback.helpful,\n userFeedback: feedback.userFeedback.trim(),\n }),\n })\n\n if (!response.ok) {\n await this.handleErrorResponse(response)\n }\n\n const data = (await response.json()) as {\n feedbackId: string\n message: string\n }\n\n return {\n feedbackId: data.feedbackId,\n message: data.message,\n }\n } catch (error) {\n if (error instanceof CobblError) {\n throw error\n }\n throw new CobblError(\n `Failed to submit feedback: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'NETWORK_ERROR'\n )\n }\n }\n\n /**\n * Make an HTTP request to the Cobbl API\n * @private\n */\n private async makeRequest(\n path: string,\n options: RequestInit\n ): Promise<Response> {\n const baseUrl = process.env.COBBL_API_URL || 'https://api.cobbl.ai'\n const url = `${baseUrl}${path}`\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS)\n\n try {\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n ...options.headers,\n },\n signal: controller.signal,\n })\n\n return response\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Handle error responses from the API\n * @private\n */\n private async handleErrorResponse(response: Response): Promise<never> {\n let errorData: any\n try {\n errorData = await response.json()\n } catch {\n throw new CobblError(\n `HTTP ${response.status}: ${response.statusText}`,\n 'API_ERROR',\n { status: response.status }\n )\n }\n\n const message = errorData.error || errorData.message || 'Unknown error'\n const details = errorData.details\n\n switch (response.status) {\n case 400:\n throw new CobblError(message, 'INVALID_REQUEST', details)\n case 401:\n throw new CobblError(message, 'UNAUTHORIZED', details)\n case 404:\n throw new CobblError(message, 'NOT_FOUND', details)\n case 429:\n throw new CobblError(message, 'RATE_LIMIT_EXCEEDED', details)\n case 500:\n case 502:\n case 503:\n case 504:\n throw new CobblError(message, 'SERVER_ERROR', details)\n default:\n throw new CobblError(message, 'API_ERROR', {\n status: response.status,\n ...details,\n })\n }\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@cobbl-ai/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Cobbl SDK - Close the Loop on LLM Prompt Feedback",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist/**/*",
10
+ "src/**/*",
11
+ "README.md"
12
+ ],
13
+ "exports": {
14
+ ".": {
15
+ "import": {
16
+ "types": "./dist/index.d.mts",
17
+ "default": "./dist/index.mjs"
18
+ },
19
+ "require": {
20
+ "types": "./dist/index.d.ts",
21
+ "default": "./dist/index.js"
22
+ }
23
+ }
24
+ },
25
+ "keywords": [
26
+ "prompt",
27
+ "llm",
28
+ "ai",
29
+ "feedback",
30
+ "promptops",
31
+ "sdk",
32
+ "openai",
33
+ "anthropic",
34
+ "prompt-engineering"
35
+ ],
36
+ "author": "",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": ""
41
+ },
42
+ "bugs": {
43
+ "url": ""
44
+ },
45
+ "homepage": "",
46
+ "engines": {
47
+ "node": ">=18.0.0"
48
+ },
49
+ "dependencies": {
50
+ "@prompti/shared": "0.1.0"
51
+ },
52
+ "devDependencies": {
53
+ "@jest/test-sequencer": "29.7.0",
54
+ "@types/jest": "29.5.12",
55
+ "@types/node": "^18.0.0",
56
+ "dts-bundle-generator": "^9.0.0",
57
+ "jest": "29.7.0",
58
+ "ts-jest": "^29.4.5",
59
+ "tsup": "^8.0.0",
60
+ "typescript": "^5.3.0"
61
+ },
62
+ "publishConfig": {
63
+ "access": "public"
64
+ },
65
+ "scripts": {
66
+ "build": "tsup && dts-bundle-generator -o dist/index.d.ts src/index.ts --no-check && dts-bundle-generator -o dist/index.d.mts src/index.ts --no-check",
67
+ "typecheck": "tsc --noEmit",
68
+ "clean": "rm -rf dist",
69
+ "test": "pnpm jest",
70
+ "test:watch": "pnpm jest --watch",
71
+ "test:coverage": "pnpm jest --coverage"
72
+ }
73
+ }