notdiamond 2.0.0-rc1 → 2.0.0-rc11

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.
Files changed (175) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/LICENSE +1 -1
  3. package/README.md +327 -124
  4. package/client.d.mts +28 -42
  5. package/client.d.mts.map +1 -1
  6. package/client.d.ts +28 -42
  7. package/client.d.ts.map +1 -1
  8. package/client.js +52 -68
  9. package/client.js.map +1 -1
  10. package/client.mjs +50 -66
  11. package/client.mjs.map +1 -1
  12. package/core/api-promise.d.mts +2 -2
  13. package/core/api-promise.d.ts +2 -2
  14. package/core/error.d.mts +2 -2
  15. package/core/error.d.ts +2 -2
  16. package/core/error.js +4 -4
  17. package/core/error.mjs +2 -2
  18. package/core/resource.d.mts +3 -3
  19. package/core/resource.d.ts +3 -3
  20. package/index.d.mts +3 -3
  21. package/index.d.ts +3 -3
  22. package/index.js +4 -4
  23. package/index.mjs +3 -3
  24. package/internal/parse.d.mts +2 -2
  25. package/internal/parse.d.ts +2 -2
  26. package/internal/shims.js +1 -1
  27. package/internal/shims.mjs +1 -1
  28. package/internal/tslib.js +17 -17
  29. package/internal/uploads.d.mts +4 -4
  30. package/internal/uploads.d.ts +4 -4
  31. package/internal/utils/base64.js +2 -2
  32. package/internal/utils/base64.mjs +3 -3
  33. package/internal/utils/env.d.mts.map +1 -1
  34. package/internal/utils/env.d.ts.map +1 -1
  35. package/internal/utils/env.js +4 -2
  36. package/internal/utils/env.js.map +1 -1
  37. package/internal/utils/env.mjs +4 -2
  38. package/internal/utils/env.mjs.map +1 -1
  39. package/internal/utils/log.d.mts +3 -3
  40. package/internal/utils/log.d.ts +3 -3
  41. package/internal/utils/path.js +1 -1
  42. package/internal/utils/path.mjs +2 -2
  43. package/internal/utils/values.js +5 -5
  44. package/internal/utils/values.mjs +6 -6
  45. package/package.json +11 -12
  46. package/resources/custom-router.d.mts +145 -0
  47. package/resources/custom-router.d.mts.map +1 -0
  48. package/resources/custom-router.d.ts +145 -0
  49. package/resources/custom-router.d.ts.map +1 -0
  50. package/resources/custom-router.js +83 -0
  51. package/resources/custom-router.js.map +1 -0
  52. package/resources/custom-router.mjs +79 -0
  53. package/resources/custom-router.mjs.map +1 -0
  54. package/resources/index.d.mts +6 -6
  55. package/resources/index.d.mts.map +1 -1
  56. package/resources/index.d.ts +6 -6
  57. package/resources/index.d.ts.map +1 -1
  58. package/resources/index.js +6 -6
  59. package/resources/index.js.map +1 -1
  60. package/resources/index.mjs +3 -3
  61. package/resources/index.mjs.map +1 -1
  62. package/resources/model-router.d.mts +196 -0
  63. package/resources/model-router.d.mts.map +1 -0
  64. package/resources/model-router.d.ts +196 -0
  65. package/resources/model-router.d.ts.map +1 -0
  66. package/resources/model-router.js +70 -0
  67. package/resources/model-router.js.map +1 -0
  68. package/resources/model-router.mjs +66 -0
  69. package/resources/model-router.mjs.map +1 -0
  70. package/resources/models.d.mts +50 -25
  71. package/resources/models.d.mts.map +1 -1
  72. package/resources/models.d.ts +50 -25
  73. package/resources/models.d.ts.map +1 -1
  74. package/resources/models.js +5 -0
  75. package/resources/models.js.map +1 -1
  76. package/resources/models.mjs +5 -0
  77. package/resources/models.mjs.map +1 -1
  78. package/resources/preferences.d.mts +34 -48
  79. package/resources/preferences.d.mts.map +1 -1
  80. package/resources/preferences.d.ts +34 -48
  81. package/resources/preferences.d.ts.map +1 -1
  82. package/resources/preferences.js +14 -36
  83. package/resources/preferences.js.map +1 -1
  84. package/resources/preferences.mjs +14 -36
  85. package/resources/preferences.mjs.map +1 -1
  86. package/resources/prompt-adaptation.d.mts +339 -234
  87. package/resources/prompt-adaptation.d.mts.map +1 -1
  88. package/resources/prompt-adaptation.d.ts +339 -234
  89. package/resources/prompt-adaptation.d.ts.map +1 -1
  90. package/resources/prompt-adaptation.js +30 -53
  91. package/resources/prompt-adaptation.js.map +1 -1
  92. package/resources/prompt-adaptation.mjs +30 -53
  93. package/resources/prompt-adaptation.mjs.map +1 -1
  94. package/resources/report/index.d.mts +3 -0
  95. package/resources/report/index.d.mts.map +1 -0
  96. package/resources/report/index.d.ts +3 -0
  97. package/resources/report/index.d.ts.map +1 -0
  98. package/resources/report/index.js +9 -0
  99. package/resources/report/index.js.map +1 -0
  100. package/resources/report/index.mjs +4 -0
  101. package/resources/report/index.mjs.map +1 -0
  102. package/resources/report/metrics.d.mts +87 -0
  103. package/resources/report/metrics.d.mts.map +1 -0
  104. package/resources/report/metrics.d.ts +87 -0
  105. package/resources/report/metrics.d.ts.map +1 -0
  106. package/resources/report/metrics.js +57 -0
  107. package/resources/report/metrics.js.map +1 -0
  108. package/resources/report/metrics.mjs +53 -0
  109. package/resources/report/metrics.mjs.map +1 -0
  110. package/resources/report/report.d.mts +10 -0
  111. package/resources/report/report.d.mts.map +1 -0
  112. package/resources/report/report.d.ts +10 -0
  113. package/resources/report/report.d.ts.map +1 -0
  114. package/resources/report/report.js +17 -0
  115. package/resources/report/report.js.map +1 -0
  116. package/resources/report/report.mjs +12 -0
  117. package/resources/report/report.mjs.map +1 -0
  118. package/resources/report.d.mts +1 -244
  119. package/resources/report.d.mts.map +1 -1
  120. package/resources/report.d.ts +1 -244
  121. package/resources/report.d.ts.map +1 -1
  122. package/resources/report.js +2 -82
  123. package/resources/report.js.map +1 -1
  124. package/resources/report.mjs +1 -80
  125. package/resources/report.mjs.map +1 -1
  126. package/src/client.ts +80 -131
  127. package/src/core/api-promise.ts +4 -4
  128. package/src/core/error.ts +2 -2
  129. package/src/core/resource.ts +3 -3
  130. package/src/index.ts +3 -3
  131. package/src/internal/parse.ts +2 -2
  132. package/src/internal/shims.ts +1 -1
  133. package/src/internal/uploads.ts +5 -5
  134. package/src/internal/utils/base64.ts +3 -3
  135. package/src/internal/utils/env.ts +4 -2
  136. package/src/internal/utils/log.ts +3 -3
  137. package/src/internal/utils/path.ts +2 -2
  138. package/src/internal/utils/values.ts +6 -6
  139. package/src/resources/custom-router.ts +168 -0
  140. package/src/resources/index.ts +23 -34
  141. package/src/resources/model-router.ts +224 -0
  142. package/src/resources/models.ts +55 -32
  143. package/src/resources/preferences.ts +40 -77
  144. package/src/resources/prompt-adaptation.ts +361 -291
  145. package/src/resources/report/index.ts +4 -0
  146. package/src/resources/report/metrics.ts +99 -0
  147. package/src/resources/report/report.ts +19 -0
  148. package/src/resources/report.ts +1 -298
  149. package/src/version.ts +1 -1
  150. package/version.d.mts +1 -1
  151. package/version.d.mts.map +1 -1
  152. package/version.d.ts +1 -1
  153. package/version.d.ts.map +1 -1
  154. package/version.js +1 -1
  155. package/version.js.map +1 -1
  156. package/version.mjs +1 -1
  157. package/version.mjs.map +1 -1
  158. package/resources/admin.d.mts +0 -4
  159. package/resources/admin.d.mts.map +0 -1
  160. package/resources/admin.d.ts +0 -4
  161. package/resources/admin.d.ts.map +0 -1
  162. package/resources/admin.js +0 -9
  163. package/resources/admin.js.map +0 -1
  164. package/resources/admin.mjs +0 -5
  165. package/resources/admin.mjs.map +0 -1
  166. package/resources/routing.d.mts +0 -391
  167. package/resources/routing.d.mts.map +0 -1
  168. package/resources/routing.d.ts +0 -391
  169. package/resources/routing.d.ts.map +0 -1
  170. package/resources/routing.js +0 -163
  171. package/resources/routing.js.map +0 -1
  172. package/resources/routing.mjs +0 -159
  173. package/resources/routing.mjs.map +0 -1
  174. package/src/resources/admin.ts +0 -5
  175. package/src/resources/routing.ts +0 -476
package/README.md CHANGED
@@ -1,13 +1,30 @@
1
- # Not Diamond TypeScript API Library
1
+ # Notdiamond TypeScript API Library
2
2
 
3
3
  [![NPM version](<https://img.shields.io/npm/v/notdiamond.svg?label=npm%20(stable)>)](https://npmjs.org/package/notdiamond) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/notdiamond)
4
4
 
5
- This library provides convenient access to the Not Diamond REST API from server-side TypeScript or JavaScript.
5
+ This library provides convenient access to the Notdiamond REST API from server-side TypeScript or JavaScript.
6
6
 
7
- The REST API documentation can be found on [docs.notdiamond.ai](https://docs.notdiamond.ai). The full API of this library can be found in [api.md](api.md).
7
+ The library includes type definitions for all request params and response fields.
8
8
 
9
9
  It is generated with [Stainless](https://www.stainless.com/).
10
10
 
11
+ ## What is Prompt Adaptation?
12
+
13
+ Not Diamond specializes in **Prompt Adaptation** - automatically optimizing your prompts to work optimally across different LLMs. Each language model has unique characteristics, instruction-following patterns, and preferred prompt formats. A prompt that works perfectly for GPT-4 might perform poorly on Claude or Gemini.
14
+
15
+ **The Problem**: Manually rewriting prompts for each model is time-consuming and requires deep expertise in each model's quirks.
16
+
17
+ **The Solution**: Not Diamond automatically adapts your prompts through:
18
+
19
+ - Systematic optimization using your evaluation dataset
20
+ - Automated testing across target models
21
+ - Performance metrics to validate improvements
22
+ - Both system prompt and user message template optimization
23
+
24
+ ## Documentation
25
+
26
+ The REST API documentation can be found on [docs.notdiamond.ai](https://docs.notdiamond.ai). The full API of this library can be found in [api.md](api.md).
27
+
11
28
  ## Installation
12
29
 
13
30
  ```sh
@@ -16,22 +33,127 @@ npm install notdiamond
16
33
 
17
34
  ## Usage
18
35
 
19
- The full API of this library can be found in [api.md](api.md).
36
+ ### Prompt Adaptation
37
+
38
+ Automatically optimize your prompts to work better across different language models. Each model has unique characteristics and preferences - what works well for GPT-4 might not work as well for Claude or Gemini. Prompt Adaptation helps you get optimal performance from each model.
39
+
40
+ #### Quick Start
20
41
 
21
42
  <!-- prettier-ignore -->
22
- ```js
43
+
44
+ ```ts
23
45
  import NotDiamond from 'notdiamond';
24
46
 
25
- const client = new NotDiamond({
47
+ const client = new Notdiamond({
26
48
  apiKey: process.env['NOT_DIAMOND_API_KEY'], // This is the default and can be omitted
27
- environment: 'staging', // defaults to 'production'
28
49
  });
29
50
 
30
- const response = await client.routing.selectModel({
51
+ // Step 1: Start a prompt adaptation job
52
+ const adaptation = await client.prompt.adapt.create({
53
+ fields: ['question'],
54
+ system_prompt: 'You are a helpful assistant that answers questions accurately.',
55
+ target_models: [
56
+ {
57
+ model: 'claude-sonnet-4-5-20250929',
58
+ provider: 'anthropic',
59
+ },
60
+ {
61
+ model: 'gemini-2.5-flash',
62
+ provider: 'google',
63
+ },
64
+ ],
65
+ template: 'Question: {question}\nAnswer:',
66
+ train_goldens: [
67
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
68
+ { fields: { question: 'What is the capital of France?' }, answer: 'Paris' },
69
+ { fields: { question: 'Who wrote Romeo and Juliet?' }, answer: 'William Shakespeare' },
70
+ // Add at least 25 training examples for best results
71
+ // More examples = better adaptation quality
72
+ ],
73
+ test_goldens: [
74
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
75
+ { fields: { question: 'What is the largest ocean?' }, answer: 'Pacific Ocean' },
76
+ // Add test examples to validate performance
77
+ ],
78
+ evaluation_metric: 'LLMaaJ:Sem_Sim_1', // Or use custom evaluation
79
+ });
80
+
81
+ console.log(`Adaptation started: ${adaptation.adaptation_run_id}`);
82
+
83
+ // Step 2: Poll for completion (typically takes 10-30 minutes)
84
+ let status;
85
+ while (true) {
86
+ status = await client.prompt.getAdaptStatus(adaptation.adaptation_run_id);
87
+ console.log(`Status: ${status.status}`);
88
+
89
+ if (status.status === 'queued') {
90
+ console.log(`Queue position: ${status.queue_position}`);
91
+ }
92
+
93
+ if (status.status === 'completed' || status.status === 'failed') {
94
+ break;
95
+ }
96
+
97
+ await new Promise(resolve => setTimeout(resolve, 30000)); // Poll every 30 seconds
98
+ }
99
+
100
+ // Step 3: Get the optimized prompts
101
+ if (status.status === 'completed') {
102
+ const results = await client.prompt.getAdaptResults(adaptation.adaptation_run_id);
103
+
104
+ console.log(`\nOrigin model baseline: ${results.origin_model.score.toFixed(2)}`);
105
+
106
+ for (const target of results.target_models) {
107
+ console.log('\n' + '='.repeat(50));
108
+ console.log(`Model: ${target.model.model} (${target.model.provider})`);
109
+ console.log(`Optimized System Prompt:\n${target.system_prompt}`);
110
+ console.log(`Optimized Template:\n${target.user_message_template}`);
111
+ console.log(`Pre-optimization score: ${target.pre_optimization_score.toFixed(2)}`);
112
+ console.log(`Post-optimization score: ${target.post_optimization_score.toFixed(2)}`);
113
+ console.log(`Improvement: ${((target.post_optimization_score / target.pre_optimization_score - 1) * 100).toFixed(1)}%`);
114
+ console.log(`Cost: $${target.cost.toFixed(4)}`);
115
+ }
116
+ }
117
+ ```
118
+
119
+ #### Key Features
120
+
121
+ - **Automatic Optimization**: Adapts both system prompts and user message templates
122
+ - **Evaluation Metrics**: Choose from standard metrics (semantic similarity, JSON matching, SQL) or provide custom evaluation
123
+ - **Dataset Requirements**: Minimum 25 training examples (more examples = better results)
124
+ - **Processing Time**: Typically 10-30 minutes depending on dataset size and number of target models
125
+ - **Subscription Tiers**: Support for 1-10 target models depending on your plan
126
+
127
+ #### Evaluation Metrics
128
+
129
+ Choose from standard metrics:
130
+
131
+ - `LLMaaJ:Sem_Sim_1`, `LLMaaJ:Sem_Sim_3`, `LLMaaJ:Sem_Sim_10` - Semantic similarity
132
+ - `LLMaaJ:SQL` - SQL query validation
133
+ - `JSON_Match` - JSON structure matching
134
+
135
+ Or provide custom evaluation configuration with your own LLM judge.
136
+
137
+ #### Best Practices
138
+
139
+ 1. **Use Representative Examples**: Include diverse examples from your production workload
140
+ 2. **Sufficient Dataset Size**: Use at least 25 training examples (50+ recommended)
141
+ 3. **Train/Test Split**: Separate train_goldens and test_goldens for proper validation
142
+ 4. **A/B Test Results**: Validate optimized prompts in production before full deployment
143
+
144
+ For more details, see the [Prompt Adaptation documentation](https://docs.notdiamond.ai/docs/adapting-prompts-to-new-models).
145
+
146
+ ### Model Routing
147
+
148
+ Not Diamond also provides intelligent model routing to select the best model for your query:
149
+
150
+ <!-- prettier-ignore -->
151
+ ```ts
152
+ const response = await client.modelRouter.selectModel({
31
153
  llm_providers: [
32
154
  { model: 'gpt-4o', provider: 'openai' },
33
- { model: 'claude-3-5-sonnet-20241022', provider: 'anthropic' },
34
- { model: 'gemini-1.5-pro', provider: 'google' },
155
+ { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
156
+ { model: 'gemini-2.5-flash', provider: 'google' },
35
157
  ],
36
158
  messages: [
37
159
  { role: 'system', content: 'You are a helpful assistant.' },
@@ -48,25 +170,44 @@ This library includes TypeScript definitions for all request params and response
48
170
 
49
171
  <!-- prettier-ignore -->
50
172
  ```ts
51
- import NotDiamond from 'notdiamond';
173
+ import Notdiamond from 'notdiamond';
52
174
 
53
- const client = new NotDiamond({
175
+ const client = new Notdiamond({
54
176
  apiKey: process.env['NOT_DIAMOND_API_KEY'], // This is the default and can be omitted
55
- environment: 'staging', // defaults to 'production'
56
177
  });
57
178
 
58
- const params: NotDiamond.RoutingSelectModelParams = {
59
- llm_providers: [
60
- { model: 'gpt-4o', provider: 'openai' },
61
- { model: 'claude-3-5-sonnet-20241022', provider: 'anthropic' },
62
- { model: 'gemini-1.5-pro', provider: 'google' },
179
+ const params: NotDiamond.PromptAdaptCreateParams = {
180
+ fields: ['question', 'context'],
181
+ system_prompt: 'You are a helpful assistant.',
182
+ target_models: [
183
+ {
184
+ model: 'claude-sonnet-4-5-20250929',
185
+ provider: 'anthropic',
186
+ },
63
187
  ],
64
- messages: [
65
- { role: 'system', content: 'You are a helpful assistant.' },
66
- { role: 'user', content: 'Explain quantum computing in simple terms' },
188
+ template: 'Context: {context}\nQuestion: {question}\nAnswer:',
189
+ train_goldens: [
190
+ {
191
+ fields: {
192
+ question: 'What is 2+2?',
193
+ context: 'Basic arithmetic',
194
+ },
195
+ answer: '4',
196
+ },
197
+ // Add at least 25 examples for best results
198
+ ],
199
+ test_goldens: [
200
+ {
201
+ fields: {
202
+ question: 'What is 3*3?',
203
+ context: 'Basic arithmetic',
204
+ },
205
+ answer: '9',
206
+ },
67
207
  ],
68
208
  };
69
- const response: NotDiamond.RoutingSelectModelResponse = await client.routing.selectModel(params);
209
+ const response: NotDiamond.PromptAdaptCreateResponse = await client.prompt.adapt.create(params);
210
+ console.log(response.adaptation_run_id);
70
211
  ```
71
212
 
72
213
  Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.
@@ -82,61 +223,56 @@ Request parameters that correspond to file uploads can be passed in many differe
82
223
 
83
224
  ```ts
84
225
  import fs from 'fs';
85
- import NotDiamond, { toFile } from 'notdiamond';
226
+ import Notdiamond, { toFile } from 'notdiamond';
86
227
 
87
- const client = new NotDiamond();
228
+ const client = new Notdiamond();
88
229
 
89
230
  // If you have access to Node `fs` we recommend using `fs.createReadStream()`:
90
- await client.routing.createSurveyResponse({
91
- constraint_priorities: 'constraint_priorities',
92
- email: 'email',
93
- llm_providers: 'llm_providers',
94
- use_case_desc: 'use_case_desc',
95
- user_id: 'user_id',
96
- 'x-token': 'x-token',
231
+ await client.customRouter.trainCustomRouter({
97
232
  dataset_file: fs.createReadStream('/path/to/file'),
233
+ language: 'english',
234
+ llm_providers:
235
+ '[{"provider": "openai", "model": "gpt-4o"}, {"provider": "anthropic", "model": "claude-sonnet-4-5-20250929"}]',
236
+ maximize: true,
237
+ prompt_column: 'prompt',
98
238
  });
99
239
 
100
240
  // Or if you have the web `File` API you can pass a `File` instance:
101
- await client.routing.createSurveyResponse({
102
- constraint_priorities: 'constraint_priorities',
103
- email: 'email',
104
- llm_providers: 'llm_providers',
105
- use_case_desc: 'use_case_desc',
106
- user_id: 'user_id',
107
- 'x-token': 'x-token',
241
+ await client.customRouter.trainCustomRouter({
108
242
  dataset_file: new File(['my bytes'], 'file'),
243
+ language: 'english',
244
+ llm_providers:
245
+ '[{"provider": "openai", "model": "gpt-4o"}, {"provider": "anthropic", "model": "claude-sonnet-4-5-20250929"}]',
246
+ maximize: true,
247
+ prompt_column: 'prompt',
109
248
  });
110
249
 
111
250
  // You can also pass a `fetch` `Response`:
112
- await client.routing.createSurveyResponse({
113
- constraint_priorities: 'constraint_priorities',
114
- email: 'email',
115
- llm_providers: 'llm_providers',
116
- use_case_desc: 'use_case_desc',
117
- user_id: 'user_id',
118
- 'x-token': 'x-token',
251
+ await client.customRouter.trainCustomRouter({
119
252
  dataset_file: await fetch('https://somesite/file'),
253
+ language: 'english',
254
+ llm_providers:
255
+ '[{"provider": "openai", "model": "gpt-4o"}, {"provider": "anthropic", "model": "claude-sonnet-4-5-20250929"}]',
256
+ maximize: true,
257
+ prompt_column: 'prompt',
120
258
  });
121
259
 
122
260
  // Finally, if none of the above are convenient, you can use our `toFile` helper:
123
- await client.routing.createSurveyResponse({
124
- constraint_priorities: 'constraint_priorities',
125
- email: 'email',
126
- llm_providers: 'llm_providers',
127
- use_case_desc: 'use_case_desc',
128
- user_id: 'user_id',
129
- 'x-token': 'x-token',
261
+ await client.customRouter.trainCustomRouter({
130
262
  dataset_file: await toFile(Buffer.from('my bytes'), 'file'),
263
+ language: 'english',
264
+ llm_providers:
265
+ '[{"provider": "openai", "model": "gpt-4o"}, {"provider": "anthropic", "model": "claude-sonnet-4-5-20250929"}]',
266
+ maximize: true,
267
+ prompt_column: 'prompt',
131
268
  });
132
- await client.routing.createSurveyResponse({
133
- constraint_priorities: 'constraint_priorities',
134
- email: 'email',
135
- llm_providers: 'llm_providers',
136
- use_case_desc: 'use_case_desc',
137
- user_id: 'user_id',
138
- 'x-token': 'x-token',
269
+ await client.customRouter.trainCustomRouter({
139
270
  dataset_file: await toFile(new Uint8Array([0, 1, 2]), 'file'),
271
+ language: 'english',
272
+ llm_providers:
273
+ '[{"provider": "openai", "model": "gpt-4o"}, {"provider": "anthropic", "model": "claude-sonnet-4-5-20250929"}]',
274
+ maximize: true,
275
+ prompt_column: 'prompt',
140
276
  });
141
277
  ```
142
278
 
@@ -148,27 +284,47 @@ a subclass of `APIError` will be thrown:
148
284
 
149
285
  <!-- prettier-ignore -->
150
286
  ```ts
151
- const response = await client.routing
152
- .selectModel({
153
- llm_providers: [
154
- { model: 'gpt-4o', provider: 'openai' },
155
- { model: 'claude-3-5-sonnet-20241022', provider: 'anthropic' },
156
- { model: 'gemini-1.5-pro', provider: 'google' },
287
+ import NotDiamond from 'notdiamond';
288
+
289
+ const client = new NotDiamond();
290
+
291
+ try {
292
+ await client.prompt.adapt.create({
293
+ fields: ['question'],
294
+ system_prompt: 'You are a helpful assistant.',
295
+ target_models: [
296
+ {
297
+ model: 'claude-sonnet-4-5-20250929',
298
+ provider: 'anthropic',
299
+ },
300
+ {
301
+ model: 'gemini-2.5-flash',
302
+ provider: 'google',
303
+ },
157
304
  ],
158
- messages: [
159
- { role: 'system', content: 'You are a helpful assistant.' },
160
- { role: 'user', content: 'Explain quantum computing in simple terms' },
305
+ template: 'Question: {question}\nAnswer:',
306
+ train_goldens: [
307
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
308
+ // Add at least 25 examples...
309
+ ],
310
+ test_goldens: [
311
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
161
312
  ],
162
- })
163
- .catch(async (err) => {
164
- if (err instanceof NotDiamond.APIError) {
165
- console.log(err.status); // 400
166
- console.log(err.name); // BadRequestError
167
- console.log(err.headers); // {server: 'nginx', ...}
168
- } else {
169
- throw err;
170
- }
171
313
  });
314
+ } catch (err) {
315
+ if (err instanceof NotDiamond.APIConnectionError) {
316
+ console.log('The server could not be reached');
317
+ console.log(err.cause); // an underlying Error, likely from fetch()
318
+ } else if (err instanceof NotDiamond.RateLimitError) {
319
+ console.log('A 429 status code was received; we should back off a bit.');
320
+ } else if (err instanceof NotDiamond.APIError) {
321
+ console.log(err.status); // 400
322
+ console.log(err.name); // BadRequestError
323
+ console.log(err.headers); // {server: 'nginx', ...}
324
+ } else {
325
+ throw err;
326
+ }
327
+ }
172
328
  ```
173
329
 
174
330
  Error codes are as follows:
@@ -195,12 +351,33 @@ You can use the `maxRetries` option to configure or disable this:
195
351
  <!-- prettier-ignore -->
196
352
  ```js
197
353
  // Configure the default for all requests:
198
- const client = new NotDiamond({
354
+ const client = new Notdiamond({
199
355
  maxRetries: 0, // default is 2
200
356
  });
201
357
 
202
358
  // Or, configure per-request:
203
- await client.routing.selectModel({ llm_providers: [{ model: 'gpt-4o', provider: 'openai' }, { model: 'claude-3-5-sonnet-20241022', provider: 'anthropic' }, { model: 'gemini-1.5-pro', provider: 'google' }], messages: [{ role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Explain quantum computing in simple terms' }] }, {
359
+ await client.prompt.adapt.create({
360
+ fields: ['question'],
361
+ system_prompt: 'You are a helpful assistant.',
362
+ target_models: [
363
+ {
364
+ model: 'claude-sonnet-4-5-20250929',
365
+ provider: 'anthropic',
366
+ },
367
+ {
368
+ model: 'gemini-2.5-flash',
369
+ provider: 'google',
370
+ },
371
+ ],
372
+ template: 'Question: {question}\nAnswer:',
373
+ train_goldens: [
374
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
375
+ // Add at least 25 examples...
376
+ ],
377
+ test_goldens: [
378
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
379
+ ],
380
+ }, {
204
381
  maxRetries: 5,
205
382
  });
206
383
  ```
@@ -212,13 +389,13 @@ Requests time out after 1 minute by default. You can configure this with a `time
212
389
  <!-- prettier-ignore -->
213
390
  ```ts
214
391
  // Configure the default for all requests:
215
- const client = new NotDiamond({
392
+ const client = new Notdiamond({
216
393
  timeout: 20 * 1000, // 20 seconds (default is 1 minute)
217
394
  });
218
395
 
219
- // Override per-request:
220
- await client.routing.selectModel({ llm_providers: [{ model: 'gpt-4o', provider: 'openai' }, { model: 'claude-3-5-sonnet-20241022', provider: 'anthropic' }, { model: 'gemini-1.5-pro', provider: 'google' }], messages: [{ role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Explain quantum computing in simple terms' }] }, {
221
- timeout: 5 * 1000,
396
+ // Override per-request (note: prompt adaptation may take 10-30 minutes, so increase timeout accordingly):
397
+ await client.prompt.getAdaptStatus('your-adaptation-run-id', {
398
+ timeout: 120 * 1000, // 2 minutes
222
399
  });
223
400
  ```
224
401
 
@@ -238,39 +415,61 @@ Unlike `.asResponse()` this method consumes the body, returning once it is parse
238
415
 
239
416
  <!-- prettier-ignore -->
240
417
  ```ts
241
- const client = new NotDiamond();
242
-
243
- const response = await client.routing
244
- .selectModel({
245
- llm_providers: [
246
- { model: 'gpt-4o', provider: 'openai' },
247
- { model: 'claude-3-5-sonnet-20241022', provider: 'anthropic' },
248
- { model: 'gemini-1.5-pro', provider: 'google' },
418
+ const client = new Notdiamond();
419
+
420
+ const response = await client.prompt.adapt
421
+ .create({
422
+ fields: ['question'],
423
+ system_prompt: 'You are a helpful assistant.',
424
+ target_models: [
425
+ {
426
+ model: 'claude-sonnet-4-5-20250929',
427
+ provider: 'anthropic',
428
+ },
429
+ {
430
+ model: 'gemini-2.5-flash',
431
+ provider: 'google',
432
+ },
249
433
  ],
250
- messages: [
251
- { role: 'system', content: 'You are a helpful assistant.' },
252
- { role: 'user', content: 'Explain quantum computing in simple terms' },
434
+ template: 'Question: {question}\nAnswer:',
435
+ train_goldens: [
436
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
437
+ // Add at least 25 examples...
438
+ ],
439
+ test_goldens: [
440
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
253
441
  ],
254
442
  })
255
443
  .asResponse();
256
444
  console.log(response.headers.get('X-My-Header'));
257
445
  console.log(response.statusText); // access the underlying Response object
258
446
 
259
- const { data: response, response: raw } = await client.routing
260
- .selectModel({
261
- llm_providers: [
262
- { model: 'gpt-4o', provider: 'openai' },
263
- { model: 'claude-3-5-sonnet-20241022', provider: 'anthropic' },
264
- { model: 'gemini-1.5-pro', provider: 'google' },
447
+ const { data: adaptResponse, response: raw } = await client.prompt.adapt
448
+ .create({
449
+ fields: ['question'],
450
+ system_prompt: 'You are a helpful assistant.',
451
+ target_models: [
452
+ {
453
+ model: 'claude-sonnet-4-5-20250929',
454
+ provider: 'anthropic',
455
+ },
456
+ {
457
+ model: 'gemini-2.5-flash',
458
+ provider: 'google',
459
+ },
460
+ ],
461
+ template: 'Question: {question}\nAnswer:',
462
+ train_goldens: [
463
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
464
+ // Add at least 25 examples...
265
465
  ],
266
- messages: [
267
- { role: 'system', content: 'You are a helpful assistant.' },
268
- { role: 'user', content: 'Explain quantum computing in simple terms' },
466
+ test_goldens: [
467
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
269
468
  ],
270
469
  })
271
470
  .withResponse();
272
471
  console.log(raw.headers.get('X-My-Header'));
273
- console.log(response.providers);
472
+ console.log(adaptResponse.adaptation_run_id);
274
473
  ```
275
474
 
276
475
  ### Logging
@@ -283,13 +482,13 @@ console.log(response.providers);
283
482
 
284
483
  The log level can be configured in two ways:
285
484
 
286
- 1. Via the `NOT_DIAMOND_LOG` environment variable
485
+ 1. Via the `NOTDIAMOND_LOG` environment variable
287
486
  2. Using the `logLevel` client option (overrides the environment variable if set)
288
487
 
289
488
  ```ts
290
- import NotDiamond from 'notdiamond';
489
+ import Notdiamond from 'notdiamond';
291
490
 
292
- const client = new NotDiamond({
491
+ const client = new Notdiamond({
293
492
  logLevel: 'debug', // Show all log messages
294
493
  });
295
494
  ```
@@ -315,13 +514,13 @@ When providing a custom logger, the `logLevel` option still controls which messa
315
514
  below the configured level will not be sent to your logger.
316
515
 
317
516
  ```ts
318
- import NotDiamond from 'notdiamond';
517
+ import Notdiamond from 'notdiamond';
319
518
  import pino from 'pino';
320
519
 
321
520
  const logger = pino();
322
521
 
323
- const client = new NotDiamond({
324
- logger: logger.child({ name: 'NotDiamond' }),
522
+ const client = new Notdiamond({
523
+ logger: logger.child({ name: 'Notdiamond' }),
325
524
  logLevel: 'debug', // Send all messages to pino, allowing it to filter
326
525
  });
327
526
  ```
@@ -350,10 +549,14 @@ parameter. This library doesn't validate at runtime that the request matches the
350
549
  send will be sent as-is.
351
550
 
352
551
  ```ts
353
- client.routing.selectModel({
354
- // ...
355
- // @ts-expect-error baz is not yet public
356
- baz: 'undocumented option',
552
+ client.prompt.adapt.create({
553
+ fields: ['question'],
554
+ system_prompt: 'You are a helpful assistant.',
555
+ target_models: [{ model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' }],
556
+ template: 'Question: {question}\nAnswer:',
557
+ train_goldens: [{ fields: { question: 'What is 2+2?' }, answer: '4' }],
558
+ // @ts-expect-error experimental_feature is not yet public
559
+ experimental_feature: true,
357
560
  });
358
561
  ```
359
562
 
@@ -384,10 +587,10 @@ globalThis.fetch = fetch;
384
587
  Or pass it to the client:
385
588
 
386
589
  ```ts
387
- import NotDiamond from 'notdiamond';
590
+ import Notdiamond from 'notdiamond';
388
591
  import fetch from 'my-fetch';
389
592
 
390
- const client = new NotDiamond({ fetch });
593
+ const client = new Notdiamond({ fetch });
391
594
  ```
392
595
 
393
596
  ### Fetch options
@@ -395,9 +598,9 @@ const client = new NotDiamond({ fetch });
395
598
  If you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.)
396
599
 
397
600
  ```ts
398
- import NotDiamond from 'notdiamond';
601
+ import Notdiamond from 'notdiamond';
399
602
 
400
- const client = new NotDiamond({
603
+ const client = new Notdiamond({
401
604
  fetchOptions: {
402
605
  // `RequestInit` options
403
606
  },
@@ -412,11 +615,11 @@ options to requests:
412
615
  <img src="https://raw.githubusercontent.com/stainless-api/sdk-assets/refs/heads/main/node.svg" align="top" width="18" height="21"> **Node** <sup>[[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]</sup>
413
616
 
414
617
  ```ts
415
- import NotDiamond from 'notdiamond';
618
+ import Notdiamond from 'notdiamond';
416
619
  import * as undici from 'undici';
417
620
 
418
621
  const proxyAgent = new undici.ProxyAgent('http://localhost:8888');
419
- const client = new NotDiamond({
622
+ const client = new Notdiamond({
420
623
  fetchOptions: {
421
624
  dispatcher: proxyAgent,
422
625
  },
@@ -426,9 +629,9 @@ const client = new NotDiamond({
426
629
  <img src="https://raw.githubusercontent.com/stainless-api/sdk-assets/refs/heads/main/bun.svg" align="top" width="18" height="21"> **Bun** <sup>[[docs](https://bun.sh/guides/http/proxy)]</sup>
427
630
 
428
631
  ```ts
429
- import NotDiamond from 'notdiamond';
632
+ import Notdiamond from 'notdiamond';
430
633
 
431
- const client = new NotDiamond({
634
+ const client = new Notdiamond({
432
635
  fetchOptions: {
433
636
  proxy: 'http://localhost:8888',
434
637
  },
@@ -438,10 +641,10 @@ const client = new NotDiamond({
438
641
  <img src="https://raw.githubusercontent.com/stainless-api/sdk-assets/refs/heads/main/deno.svg" align="top" width="18" height="21"> **Deno** <sup>[[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]</sup>
439
642
 
440
643
  ```ts
441
- import NotDiamond from 'npm:notdiamond';
644
+ import Notdiamond from 'npm:notdiamond';
442
645
 
443
646
  const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });
444
- const client = new NotDiamond({
647
+ const client = new Notdiamond({
445
648
  fetchOptions: {
446
649
  client: httpClient,
447
650
  },