notdiamond 2.0.0-rc4 → 2.0.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.
Files changed (181) hide show
  1. package/CHANGELOG.md +164 -0
  2. package/LICENSE +1 -1
  3. package/README.md +294 -166
  4. package/client.d.mts +20 -23
  5. package/client.d.mts.map +1 -1
  6. package/client.d.ts +20 -23
  7. package/client.d.ts.map +1 -1
  8. package/client.js +43 -46
  9. package/client.js.map +1 -1
  10. package/client.mjs +41 -44
  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/log.d.mts +3 -3
  34. package/internal/utils/log.d.ts +3 -3
  35. package/internal/utils/path.js +1 -1
  36. package/internal/utils/path.mjs +2 -2
  37. package/internal/utils/values.js +5 -5
  38. package/internal/utils/values.mjs +6 -6
  39. package/package.json +3 -3
  40. package/resources/{pzn.d.mts → custom-router.d.mts} +16 -96
  41. package/resources/custom-router.d.mts.map +1 -0
  42. package/resources/{pzn.d.ts → custom-router.d.ts} +16 -96
  43. package/resources/custom-router.d.ts.map +1 -0
  44. package/resources/{pzn.js → custom-router.js} +13 -50
  45. package/resources/custom-router.js.map +1 -0
  46. package/resources/{pzn.mjs → custom-router.mjs} +11 -48
  47. package/resources/custom-router.mjs.map +1 -0
  48. package/resources/index.d.mts +4 -5
  49. package/resources/index.d.mts.map +1 -1
  50. package/resources/index.d.ts +4 -5
  51. package/resources/index.d.ts.map +1 -1
  52. package/resources/index.js +5 -7
  53. package/resources/index.js.map +1 -1
  54. package/resources/index.mjs +2 -3
  55. package/resources/index.mjs.map +1 -1
  56. package/resources/model-router.d.mts +6 -123
  57. package/resources/model-router.d.mts.map +1 -1
  58. package/resources/model-router.d.ts +6 -123
  59. package/resources/model-router.d.ts.map +1 -1
  60. package/resources/model-router.js +3 -32
  61. package/resources/model-router.js.map +1 -1
  62. package/resources/model-router.mjs +3 -32
  63. package/resources/model-router.mjs.map +1 -1
  64. package/resources/preferences.d.mts +4 -23
  65. package/resources/preferences.d.mts.map +1 -1
  66. package/resources/preferences.d.ts +4 -23
  67. package/resources/preferences.d.ts.map +1 -1
  68. package/resources/preferences.js +3 -25
  69. package/resources/preferences.js.map +1 -1
  70. package/resources/preferences.mjs +3 -25
  71. package/resources/preferences.mjs.map +1 -1
  72. package/resources/prompt-adaptation.d.mts +684 -0
  73. package/resources/prompt-adaptation.d.mts.map +1 -0
  74. package/resources/prompt-adaptation.d.ts +684 -0
  75. package/resources/prompt-adaptation.d.ts.map +1 -0
  76. package/resources/prompt-adaptation.js +258 -0
  77. package/resources/prompt-adaptation.js.map +1 -0
  78. package/resources/prompt-adaptation.mjs +254 -0
  79. package/resources/prompt-adaptation.mjs.map +1 -0
  80. package/src/client.ts +49 -56
  81. package/src/core/api-promise.ts +4 -4
  82. package/src/core/error.ts +2 -2
  83. package/src/core/resource.ts +3 -3
  84. package/src/index.ts +3 -3
  85. package/src/internal/parse.ts +2 -2
  86. package/src/internal/shims.ts +1 -1
  87. package/src/internal/uploads.ts +5 -5
  88. package/src/internal/utils/base64.ts +3 -3
  89. package/src/internal/utils/log.ts +3 -3
  90. package/src/internal/utils/path.ts +2 -2
  91. package/src/internal/utils/values.ts +6 -6
  92. package/src/resources/{pzn.ts → custom-router.ts} +17 -122
  93. package/src/resources/index.ts +14 -16
  94. package/src/resources/model-router.ts +5 -139
  95. package/src/resources/preferences.ts +3 -34
  96. package/src/resources/prompt-adaptation.ts +777 -0
  97. package/src/version.ts +1 -1
  98. package/version.d.mts +1 -1
  99. package/version.d.mts.map +1 -1
  100. package/version.d.ts +1 -1
  101. package/version.d.ts.map +1 -1
  102. package/version.js +1 -1
  103. package/version.js.map +1 -1
  104. package/version.mjs +1 -1
  105. package/version.mjs.map +1 -1
  106. package/resources/prompt/adapt.d.mts +0 -352
  107. package/resources/prompt/adapt.d.mts.map +0 -1
  108. package/resources/prompt/adapt.d.ts +0 -352
  109. package/resources/prompt/adapt.d.ts.map +0 -1
  110. package/resources/prompt/adapt.js +0 -154
  111. package/resources/prompt/adapt.js.map +0 -1
  112. package/resources/prompt/adapt.mjs +0 -150
  113. package/resources/prompt/adapt.mjs.map +0 -1
  114. package/resources/prompt/index.d.mts +0 -3
  115. package/resources/prompt/index.d.mts.map +0 -1
  116. package/resources/prompt/index.d.ts +0 -3
  117. package/resources/prompt/index.d.ts.map +0 -1
  118. package/resources/prompt/index.js +0 -9
  119. package/resources/prompt/index.js.map +0 -1
  120. package/resources/prompt/index.mjs +0 -4
  121. package/resources/prompt/index.mjs.map +0 -1
  122. package/resources/prompt/prompt.d.mts +0 -338
  123. package/resources/prompt/prompt.d.mts.map +0 -1
  124. package/resources/prompt/prompt.d.ts +0 -338
  125. package/resources/prompt/prompt.d.ts.map +0 -1
  126. package/resources/prompt/prompt.js +0 -128
  127. package/resources/prompt/prompt.js.map +0 -1
  128. package/resources/prompt/prompt.mjs +0 -123
  129. package/resources/prompt/prompt.mjs.map +0 -1
  130. package/resources/prompt.d.mts +0 -2
  131. package/resources/prompt.d.mts.map +0 -1
  132. package/resources/prompt.d.ts +0 -2
  133. package/resources/prompt.d.ts.map +0 -1
  134. package/resources/prompt.js +0 -6
  135. package/resources/prompt.js.map +0 -1
  136. package/resources/prompt.mjs +0 -3
  137. package/resources/prompt.mjs.map +0 -1
  138. package/resources/pzn.d.mts.map +0 -1
  139. package/resources/pzn.d.ts.map +0 -1
  140. package/resources/pzn.js.map +0 -1
  141. package/resources/pzn.mjs.map +0 -1
  142. package/resources/report/index.d.mts +0 -3
  143. package/resources/report/index.d.mts.map +0 -1
  144. package/resources/report/index.d.ts +0 -3
  145. package/resources/report/index.d.ts.map +0 -1
  146. package/resources/report/index.js +0 -9
  147. package/resources/report/index.js.map +0 -1
  148. package/resources/report/index.mjs +0 -4
  149. package/resources/report/index.mjs.map +0 -1
  150. package/resources/report/metrics.d.mts +0 -87
  151. package/resources/report/metrics.d.mts.map +0 -1
  152. package/resources/report/metrics.d.ts +0 -87
  153. package/resources/report/metrics.d.ts.map +0 -1
  154. package/resources/report/metrics.js +0 -57
  155. package/resources/report/metrics.js.map +0 -1
  156. package/resources/report/metrics.mjs +0 -53
  157. package/resources/report/metrics.mjs.map +0 -1
  158. package/resources/report/report.d.mts +0 -10
  159. package/resources/report/report.d.mts.map +0 -1
  160. package/resources/report/report.d.ts +0 -10
  161. package/resources/report/report.d.ts.map +0 -1
  162. package/resources/report/report.js +0 -17
  163. package/resources/report/report.js.map +0 -1
  164. package/resources/report/report.mjs +0 -12
  165. package/resources/report/report.mjs.map +0 -1
  166. package/resources/report.d.mts +0 -2
  167. package/resources/report.d.mts.map +0 -1
  168. package/resources/report.d.ts +0 -2
  169. package/resources/report.d.ts.map +0 -1
  170. package/resources/report.js +0 -6
  171. package/resources/report.js.map +0 -1
  172. package/resources/report.mjs +0 -3
  173. package/resources/report.mjs.map +0 -1
  174. package/src/resources/prompt/adapt.ts +0 -402
  175. package/src/resources/prompt/index.ts +0 -16
  176. package/src/resources/prompt/prompt.ts +0 -398
  177. package/src/resources/prompt.ts +0 -3
  178. package/src/resources/report/index.ts +0 -4
  179. package/src/resources/report/metrics.ts +0 -99
  180. package/src/resources/report/report.ts +0 -19
  181. package/src/resources/report.ts +0 -3
package/README.md CHANGED
@@ -1,12 +1,26 @@
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
+
9
+ ## What is Prompt Adaptation?
10
+
11
+ 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-5 might perform poorly on Claude or Gemini.
12
+ Manually rewriting prompts for each model is time-consuming and requires deep expertise in each model's quirks.
8
13
 
9
- It is generated with [Stainless](https://www.stainless.com/).
14
+ **The Solution**: Not Diamond automatically adapts your prompts with:
15
+
16
+ - Automatic optimization of both system and user prompts
17
+ - Built-in evaluation metrics
18
+ - Minimum 25 training examples recommended
19
+ - Processing time: typically 10–30 minutes
20
+
21
+ ## Documentation
22
+
23
+ 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).
10
24
 
11
25
  ## Installation
12
26
 
@@ -16,128 +30,217 @@ npm install notdiamond
16
30
 
17
31
  ## Usage
18
32
 
19
- The full API of this library can be found in [api.md](api.md).
33
+ #### Quick Start
20
34
 
21
35
  <!-- prettier-ignore -->
22
- ```js
36
+
37
+ ```ts
23
38
  import NotDiamond from 'notdiamond';
24
39
 
25
- const client = new NotDiamond({
26
- apiKey: process.env['NOT_DIAMOND_API_KEY'], // This is the default and can be omitted
40
+ const client = new Notdiamond({
41
+ apiKey: process.env['NOTDIAMOND_API_KEY'], // This is the default and can be omitted
27
42
  });
28
43
 
29
- const response = await client.modelRouter.selectModel({
30
- llm_providers: [
31
- { model: 'gpt-4o', provider: 'openai' },
32
- { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
33
- { model: 'gemini-1.5-pro', provider: 'google' },
44
+ // Step 1: Start a prompt adaptation job with prototype mode
45
+ const adaptation = await client.promptAdaptation.adapt({
46
+ fields: ['question'],
47
+ system_prompt: 'You are a mathematical assistant that counts digits accurately.',
48
+ target_models: [
49
+ {
50
+ model: 'claude-sonnet-4-5-20250929',
51
+ provider: 'anthropic',
52
+ },
53
+ {
54
+ model: 'gemini-2.5-flash',
55
+ provider: 'google',
56
+ },
34
57
  ],
35
- messages: [
36
- { role: 'system', content: 'You are a helpful assistant.' },
37
- { role: 'user', content: 'Explain quantum computing in simple terms' },
58
+ template: 'Question: {question}\nAnswer:',
59
+ train_goldens: [
60
+ {
61
+ fields: { question: 'How many digits are in (23874045494*2789392485)?' },
62
+ answer: '20',
63
+ },
64
+ {
65
+ fields: { question: 'How many odd digits are in (999*777*555*333*111)?' },
66
+ answer: '10',
67
+ },
68
+ {
69
+ fields: { question: "How often does the number '17' appear in the digits of (287558*17)?" },
70
+ answer: '0',
71
+ },
72
+ {
73
+ fields: { question: 'How many even digits are in (222*444*666*888)?' },
74
+ answer: '16',
75
+ },
76
+ {
77
+ fields: { question: 'How many 0s are in (1234567890*1357908642)?' },
78
+ answer: '2',
79
+ },
38
80
  ],
81
+ test_goldens: [
82
+ {
83
+ fields: { question: 'How many digits are in (9876543210*123456)?' },
84
+ answer: '15',
85
+ },
86
+ {
87
+ fields: { question: 'How many odd digits are in (135*579*246)?' },
88
+ answer: '8',
89
+ },
90
+ {
91
+ fields: { question: "How often does the number '42' appear in the digits of (123456789*42)?" },
92
+ answer: '1',
93
+ },
94
+ {
95
+ fields: { question: 'How many even digits are in (1111*2222*3333)?' },
96
+ answer: '10',
97
+ },
98
+ {
99
+ fields: { question: 'How many 9s are in (999999*888888)?' },
100
+ answer: '11',
101
+ },
102
+ ],
103
+ evaluation_metric: 'LLMaaJ:Sem_Sim_1', // Or use custom evaluation
104
+ prototype_mode: true, // Enable faster prototype mode for quick experimentation
39
105
  });
40
106
 
41
- console.log(response.providers);
107
+ console.log(`Adaptation started: ${adaptation.adaptation_run_id}`);
108
+
109
+ // Step 2: Poll for completion (typically takes 10-30 minutes)
110
+ let status;
111
+ while (true) {
112
+ status = await client.promptAdaptation.getAdaptStatus(adaptation.adaptation_run_id);
113
+ console.log(`Status: ${status.status}`);
114
+
115
+ if (status.status === 'queued') {
116
+ console.log(`Queue position: ${status.queue_position}`);
117
+ }
118
+
119
+ if (status.status === 'completed' || status.status === 'failed') {
120
+ break;
121
+ }
122
+
123
+ await new Promise(resolve => setTimeout(resolve, 30000)); // Poll every 30 seconds
124
+ }
125
+
126
+ // Step 3: Get the optimized prompts
127
+ if (status.status === 'completed') {
128
+ const results = await client.promptAdaptation.getAdaptResults(adaptation.adaptation_run_id);
129
+
130
+ console.log(`\nOrigin model baseline: ${results.origin_model.score.toFixed(2)}`);
131
+
132
+ for (const target of results.target_models) {
133
+ console.log('\n' + '='.repeat(50));
134
+ console.log(`Model: ${target.model.model} (${target.model.provider})`);
135
+ console.log(`Optimized System Prompt:\n${target.system_prompt}`);
136
+ console.log(`Optimized Template:\n${target.user_message_template}`);
137
+ console.log(`Pre-optimization score: ${target.pre_optimization_score.toFixed(2)}`);
138
+ console.log(`Post-optimization score: ${target.post_optimization_score.toFixed(2)}`);
139
+ console.log(`Improvement: ${((target.post_optimization_score / target.pre_optimization_score - 1) * 100).toFixed(1)}%`);
140
+ console.log(`Cost: $${target.cost.toFixed(4)}`);
141
+ }
142
+ }
42
143
  ```
43
144
 
44
- ### Request & Response types
145
+ For more details, see the [Prompt Adaptation documentation](https://docs.notdiamond.ai/docs/adapting-prompts-to-new-models).
45
146
 
46
- This library includes TypeScript definitions for all request params and response fields. You may import and use them like so:
147
+ ### Model Routing
148
+
149
+ Select the best model automatically:
47
150
 
48
151
  <!-- prettier-ignore -->
49
152
  ```ts
50
153
  import NotDiamond from 'notdiamond';
51
154
 
52
155
  const client = new NotDiamond({
53
- apiKey: process.env['NOT_DIAMOND_API_KEY'], // This is the default and can be omitted
156
+ apiKey: process.env['NOTDIAMOND_API_KEY'], // This is the default and can be omitted
54
157
  });
55
158
 
56
- const params: NotDiamond.ModelRouterSelectModelParams = {
159
+ const response = await client.modelRouter.selectModel({
57
160
  llm_providers: [
58
161
  { model: 'gpt-4o', provider: 'openai' },
59
162
  { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
60
- { model: 'gemini-1.5-pro', provider: 'google' },
163
+ { model: 'gemini-2.5-flash', provider: 'google' },
61
164
  ],
62
165
  messages: [
63
166
  { role: 'system', content: 'You are a helpful assistant.' },
64
167
  { role: 'user', content: 'Explain quantum computing in simple terms' },
65
168
  ],
66
- };
67
- const response: NotDiamond.ModelRouterSelectModelResponse = await client.modelRouter.selectModel(params);
68
- ```
69
-
70
- Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.
169
+ });
71
170
 
72
- ## File uploads
171
+ console.log(response.providers);
172
+ ```
73
173
 
74
- Request parameters that correspond to file uploads can be passed in many different forms:
174
+ ### Train Custom Router
75
175
 
76
- - `File` (or an object with the same structure)
77
- - a `fetch` `Response` (or an object with the same structure)
78
- - an `fs.ReadStream`
79
- - the return value of our `toFile` helper
176
+ For even better performance, you can train a custom router on your own dataset. This allows the router to learn the specific patterns and preferences of your use case:
80
177
 
81
178
  ```ts
82
179
  import fs from 'fs';
83
- import NotDiamond, { toFile } from 'notdiamond';
180
+ import NotDiamond from 'notdiamond';
84
181
 
85
- const client = new NotDiamond();
182
+ const client = new NotDiamond({
183
+ apiKey: process.env['NOTDIAMOND_API_KEY'], // This is the default and can be omitted
184
+ });
86
185
 
87
- // If you have access to Node `fs` we recommend using `fs.createReadStream()`:
88
- await client.pzn.submitSurveyResponse({
89
- constraint_priorities: 'constraint_priorities',
90
- email: 'email',
91
- llm_providers: 'llm_providers',
92
- use_case_desc: 'use_case_desc',
93
- user_id: 'user_id',
94
- 'x-token': 'x-token',
186
+ await client.customRouter.trainCustomRouter({
95
187
  dataset_file: fs.createReadStream('/path/to/file'),
96
- });
188
+ language: 'english',
189
+ llm_providers:
190
+ '[{"provider": "openai", "model": "gpt-4o"}, {"provider": "anthropic", "model": "claude-sonnet-4-5-20250929"}]',
191
+ maximize: true,
192
+ prompt_column: 'prompt',
193
+ });cust
194
+ ```
97
195
 
98
- // Or if you have the web `File` API you can pass a `File` instance:
99
- await client.pzn.submitSurveyResponse({
100
- constraint_priorities: 'constraint_priorities',
101
- email: 'email',
102
- llm_providers: 'llm_providers',
103
- use_case_desc: 'use_case_desc',
104
- user_id: 'user_id',
105
- 'x-token': 'x-token',
106
- dataset_file: new File(['my bytes'], 'file'),
107
- });
196
+ ### Request & Response types
108
197
 
109
- // You can also pass a `fetch` `Response`:
110
- await client.pzn.submitSurveyResponse({
111
- constraint_priorities: 'constraint_priorities',
112
- email: 'email',
113
- llm_providers: 'llm_providers',
114
- use_case_desc: 'use_case_desc',
115
- user_id: 'user_id',
116
- 'x-token': 'x-token',
117
- dataset_file: await fetch('https://somesite/file'),
118
- });
198
+ This library includes TypeScript definitions for all request params and response fields. You may import and use them like so:
119
199
 
120
- // Finally, if none of the above are convenient, you can use our `toFile` helper:
121
- await client.pzn.submitSurveyResponse({
122
- constraint_priorities: 'constraint_priorities',
123
- email: 'email',
124
- llm_providers: 'llm_providers',
125
- use_case_desc: 'use_case_desc',
126
- user_id: 'user_id',
127
- 'x-token': 'x-token',
128
- dataset_file: await toFile(Buffer.from('my bytes'), 'file'),
129
- });
130
- await client.pzn.submitSurveyResponse({
131
- constraint_priorities: 'constraint_priorities',
132
- email: 'email',
133
- llm_providers: 'llm_providers',
134
- use_case_desc: 'use_case_desc',
135
- user_id: 'user_id',
136
- 'x-token': 'x-token',
137
- dataset_file: await toFile(new Uint8Array([0, 1, 2]), 'file'),
200
+ <!-- prettier-ignore -->
201
+ ```ts
202
+ import Notdiamond from 'notdiamond';
203
+
204
+ const client = new Notdiamond({
205
+ apiKey: process.env['NOTDIAMOND_API_KEY'], // This is the default and can be omitted
138
206
  });
207
+
208
+ const params: NotDiamond.PromptAdaptCreateParams = {
209
+ fields: ['question', 'context'],
210
+ system_prompt: 'You are a helpful assistant.',
211
+ target_models: [
212
+ {
213
+ model: 'claude-sonnet-4-5-20250929',
214
+ provider: 'anthropic',
215
+ },
216
+ ],
217
+ template: 'Context: {context}\nQuestion: {question}\nAnswer:',
218
+ train_goldens: [
219
+ {
220
+ fields: {
221
+ question: 'What is 2+2?',
222
+ context: 'Basic arithmetic',
223
+ },
224
+ answer: '4',
225
+ },
226
+ // Add at least 25 examples for best results
227
+ ],
228
+ test_goldens: [
229
+ {
230
+ fields: {
231
+ question: 'What is 3*3?',
232
+ context: 'Basic arithmetic',
233
+ },
234
+ answer: '9',
235
+ },
236
+ ],
237
+ };
238
+ const response: NotDiamond.PromptAdaptCreateResponse = await client.promptAdaptation.adapt(params);
239
+ console.log(response.adaptation_run_id);
139
240
  ```
140
241
 
242
+ Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.
243
+
141
244
  ## Handling errors
142
245
 
143
246
  When the library is unable to connect to the API,
@@ -146,27 +249,47 @@ a subclass of `APIError` will be thrown:
146
249
 
147
250
  <!-- prettier-ignore -->
148
251
  ```ts
149
- const response = await client.modelRouter
150
- .selectModel({
151
- llm_providers: [
152
- { model: 'gpt-4o', provider: 'openai' },
153
- { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
154
- { model: 'gemini-1.5-pro', provider: 'google' },
252
+ import NotDiamond from 'notdiamond';
253
+
254
+ const client = new NotDiamond();
255
+
256
+ try {
257
+ await client.promptAdaptation.adapt({
258
+ fields: ['question'],
259
+ system_prompt: 'You are a helpful assistant.',
260
+ target_models: [
261
+ {
262
+ model: 'claude-sonnet-4-5-20250929',
263
+ provider: 'anthropic',
264
+ },
265
+ {
266
+ model: 'gemini-2.5-flash',
267
+ provider: 'google',
268
+ },
155
269
  ],
156
- messages: [
157
- { role: 'system', content: 'You are a helpful assistant.' },
158
- { role: 'user', content: 'Explain quantum computing in simple terms' },
270
+ template: 'Question: {question}\nAnswer:',
271
+ train_goldens: [
272
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
273
+ // Add at least 25 examples...
274
+ ],
275
+ test_goldens: [
276
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
159
277
  ],
160
- })
161
- .catch(async (err) => {
162
- if (err instanceof NotDiamond.APIError) {
163
- console.log(err.status); // 400
164
- console.log(err.name); // BadRequestError
165
- console.log(err.headers); // {server: 'nginx', ...}
166
- } else {
167
- throw err;
168
- }
169
278
  });
279
+ } catch (err) {
280
+ if (err instanceof NotDiamond.APIConnectionError) {
281
+ console.log('The server could not be reached');
282
+ console.log(err.cause); // an underlying Error, likely from fetch()
283
+ } else if (err instanceof NotDiamond.RateLimitError) {
284
+ console.log('A 429 status code was received; we should back off a bit.');
285
+ } else if (err instanceof NotDiamond.APIError) {
286
+ console.log(err.status); // 400
287
+ console.log(err.name); // BadRequestError
288
+ console.log(err.headers); // {server: 'nginx', ...}
289
+ } else {
290
+ throw err;
291
+ }
292
+ }
170
293
  ```
171
294
 
172
295
  Error codes are as follows:
@@ -182,27 +305,6 @@ Error codes are as follows:
182
305
  | >=500 | `InternalServerError` |
183
306
  | N/A | `APIConnectionError` |
184
307
 
185
- ### Retries
186
-
187
- Certain errors will be automatically retried 2 times by default, with a short exponential backoff.
188
- Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,
189
- 429 Rate Limit, and >=500 Internal errors will all be retried by default.
190
-
191
- You can use the `maxRetries` option to configure or disable this:
192
-
193
- <!-- prettier-ignore -->
194
- ```js
195
- // Configure the default for all requests:
196
- const client = new NotDiamond({
197
- maxRetries: 0, // default is 2
198
- });
199
-
200
- // Or, configure per-request:
201
- await client.modelRouter.selectModel({ llm_providers: [{ model: 'gpt-4o', provider: 'openai' }, { model: 'claude-sonnet-4-5-20250929', 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' }] }, {
202
- maxRetries: 5,
203
- });
204
- ```
205
-
206
308
  ### Timeouts
207
309
 
208
310
  Requests time out after 1 minute by default. You can configure this with a `timeout` option:
@@ -210,13 +312,13 @@ Requests time out after 1 minute by default. You can configure this with a `time
210
312
  <!-- prettier-ignore -->
211
313
  ```ts
212
314
  // Configure the default for all requests:
213
- const client = new NotDiamond({
315
+ const client = new Notdiamond({
214
316
  timeout: 20 * 1000, // 20 seconds (default is 1 minute)
215
317
  });
216
318
 
217
- // Override per-request:
218
- await client.modelRouter.selectModel({ llm_providers: [{ model: 'gpt-4o', provider: 'openai' }, { model: 'claude-sonnet-4-5-20250929', 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' }] }, {
219
- timeout: 5 * 1000,
319
+ // Override per-request (note: prompt adaptation may take 10-30 minutes, so increase timeout accordingly):
320
+ await client.prompt.getAdaptStatus('your-adaptation-run-id', {
321
+ timeout: 120 * 1000, // 2 minutes
220
322
  });
221
323
  ```
222
324
 
@@ -236,39 +338,61 @@ Unlike `.asResponse()` this method consumes the body, returning once it is parse
236
338
 
237
339
  <!-- prettier-ignore -->
238
340
  ```ts
239
- const client = new NotDiamond();
240
-
241
- const response = await client.modelRouter
242
- .selectModel({
243
- llm_providers: [
244
- { model: 'gpt-4o', provider: 'openai' },
245
- { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
246
- { model: 'gemini-1.5-pro', provider: 'google' },
341
+ const client = new Notdiamond();
342
+
343
+ const response = await client.prompt.adapt
344
+ .create({
345
+ fields: ['question'],
346
+ system_prompt: 'You are a helpful assistant.',
347
+ target_models: [
348
+ {
349
+ model: 'claude-sonnet-4-5-20250929',
350
+ provider: 'anthropic',
351
+ },
352
+ {
353
+ model: 'gemini-2.5-flash',
354
+ provider: 'google',
355
+ },
247
356
  ],
248
- messages: [
249
- { role: 'system', content: 'You are a helpful assistant.' },
250
- { role: 'user', content: 'Explain quantum computing in simple terms' },
357
+ template: 'Question: {question}\nAnswer:',
358
+ train_goldens: [
359
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
360
+ //Add at least 25 examples...
361
+ ],
362
+ test_goldens: [
363
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
251
364
  ],
252
365
  })
253
366
  .asResponse();
254
367
  console.log(response.headers.get('X-My-Header'));
255
368
  console.log(response.statusText); // access the underlying Response object
256
369
 
257
- const { data: response, response: raw } = await client.modelRouter
258
- .selectModel({
259
- llm_providers: [
260
- { model: 'gpt-4o', provider: 'openai' },
261
- { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
262
- { model: 'gemini-1.5-pro', provider: 'google' },
370
+ const { data: adaptResponse, response: raw } = await client.prompt.adapt
371
+ .create({
372
+ fields: ['question'],
373
+ system_prompt: 'You are a helpful assistant.',
374
+ target_models: [
375
+ {
376
+ model: 'claude-sonnet-4-5-20250929',
377
+ provider: 'anthropic',
378
+ },
379
+ {
380
+ model: 'gemini-2.5-flash',
381
+ provider: 'google',
382
+ },
383
+ ],
384
+ template: 'Question: {question}\nAnswer:',
385
+ train_goldens: [
386
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
387
+ // Add at least 25 examples...
263
388
  ],
264
- messages: [
265
- { role: 'system', content: 'You are a helpful assistant.' },
266
- { role: 'user', content: 'Explain quantum computing in simple terms' },
389
+ test_goldens: [
390
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
267
391
  ],
268
392
  })
269
393
  .withResponse();
270
394
  console.log(raw.headers.get('X-My-Header'));
271
- console.log(response.providers);
395
+ console.log(adaptResponse.adaptation_run_id);
272
396
  ```
273
397
 
274
398
  ### Logging
@@ -281,13 +405,13 @@ console.log(response.providers);
281
405
 
282
406
  The log level can be configured in two ways:
283
407
 
284
- 1. Via the `NOT_DIAMOND_LOG` environment variable
408
+ 1. Via the `NOTDIAMOND_LOG` environment variable
285
409
  2. Using the `logLevel` client option (overrides the environment variable if set)
286
410
 
287
411
  ```ts
288
- import NotDiamond from 'notdiamond';
412
+ import Notdiamond from 'notdiamond';
289
413
 
290
- const client = new NotDiamond({
414
+ const client = new Notdiamond({
291
415
  logLevel: 'debug', // Show all log messages
292
416
  });
293
417
  ```
@@ -313,13 +437,13 @@ When providing a custom logger, the `logLevel` option still controls which messa
313
437
  below the configured level will not be sent to your logger.
314
438
 
315
439
  ```ts
316
- import NotDiamond from 'notdiamond';
440
+ import Notdiamond from 'notdiamond';
317
441
  import pino from 'pino';
318
442
 
319
443
  const logger = pino();
320
444
 
321
- const client = new NotDiamond({
322
- logger: logger.child({ name: 'NotDiamond' }),
445
+ const client = new Notdiamond({
446
+ logger: logger.child({ name: 'Notdiamond' }),
323
447
  logLevel: 'debug', // Send all messages to pino, allowing it to filter
324
448
  });
325
449
  ```
@@ -348,10 +472,14 @@ parameter. This library doesn't validate at runtime that the request matches the
348
472
  send will be sent as-is.
349
473
 
350
474
  ```ts
351
- client.modelRouter.selectModel({
352
- // ...
353
- // @ts-expect-error baz is not yet public
354
- baz: 'undocumented option',
475
+ client.promptAdaptation.adapt({
476
+ fields: ['question'],
477
+ system_prompt: 'You are a helpful assistant.',
478
+ target_models: [{ model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' }],
479
+ template: 'Question: {question}\nAnswer:',
480
+ train_goldens: [{ fields: { question: 'What is 2+2?' }, answer: '4' }],
481
+ // @ts-expect-error experimental_feature is not yet public
482
+ experimental_feature: true,
355
483
  });
356
484
  ```
357
485
 
@@ -382,10 +510,10 @@ globalThis.fetch = fetch;
382
510
  Or pass it to the client:
383
511
 
384
512
  ```ts
385
- import NotDiamond from 'notdiamond';
513
+ import Notdiamond from 'notdiamond';
386
514
  import fetch from 'my-fetch';
387
515
 
388
- const client = new NotDiamond({ fetch });
516
+ const client = new Notdiamond({ fetch });
389
517
  ```
390
518
 
391
519
  ### Fetch options
@@ -393,9 +521,9 @@ const client = new NotDiamond({ fetch });
393
521
  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.)
394
522
 
395
523
  ```ts
396
- import NotDiamond from 'notdiamond';
524
+ import Notdiamond from 'notdiamond';
397
525
 
398
- const client = new NotDiamond({
526
+ const client = new Notdiamond({
399
527
  fetchOptions: {
400
528
  // `RequestInit` options
401
529
  },
@@ -410,11 +538,11 @@ options to requests:
410
538
  <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>
411
539
 
412
540
  ```ts
413
- import NotDiamond from 'notdiamond';
541
+ import Notdiamond from 'notdiamond';
414
542
  import * as undici from 'undici';
415
543
 
416
544
  const proxyAgent = new undici.ProxyAgent('http://localhost:8888');
417
- const client = new NotDiamond({
545
+ const client = new Notdiamond({
418
546
  fetchOptions: {
419
547
  dispatcher: proxyAgent,
420
548
  },
@@ -424,9 +552,9 @@ const client = new NotDiamond({
424
552
  <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>
425
553
 
426
554
  ```ts
427
- import NotDiamond from 'notdiamond';
555
+ import Notdiamond from 'notdiamond';
428
556
 
429
- const client = new NotDiamond({
557
+ const client = new Notdiamond({
430
558
  fetchOptions: {
431
559
  proxy: 'http://localhost:8888',
432
560
  },
@@ -436,10 +564,10 @@ const client = new NotDiamond({
436
564
  <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>
437
565
 
438
566
  ```ts
439
- import NotDiamond from 'npm:notdiamond';
567
+ import Notdiamond from 'npm:notdiamond';
440
568
 
441
569
  const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });
442
- const client = new NotDiamond({
570
+ const client = new Notdiamond({
443
571
  fetchOptions: {
444
572
  client: httpClient,
445
573
  },