notdiamond 2.0.0-rc2 → 2.0.0-rc21

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 (147) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/LICENSE +1 -1
  3. package/README.md +294 -168
  4. package/client.d.mts +26 -43
  5. package/client.d.mts.map +1 -1
  6. package/client.d.ts +26 -43
  7. package/client.d.ts.map +1 -1
  8. package/client.js +49 -68
  9. package/client.js.map +1 -1
  10. package/client.mjs +47 -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/uploads.d.mts +4 -4
  29. package/internal/uploads.d.ts +4 -4
  30. package/internal/utils/base64.js +2 -2
  31. package/internal/utils/base64.mjs +3 -3
  32. package/internal/utils/env.d.mts.map +1 -1
  33. package/internal/utils/env.d.ts.map +1 -1
  34. package/internal/utils/env.js +4 -2
  35. package/internal/utils/env.js.map +1 -1
  36. package/internal/utils/env.mjs +4 -2
  37. package/internal/utils/env.mjs.map +1 -1
  38. package/internal/utils/log.d.mts +3 -3
  39. package/internal/utils/log.d.ts +3 -3
  40. package/internal/utils/path.js +1 -1
  41. package/internal/utils/path.mjs +2 -2
  42. package/internal/utils/values.js +5 -5
  43. package/internal/utils/values.mjs +6 -6
  44. package/package.json +11 -12
  45. package/resources/custom-router.d.mts +145 -0
  46. package/resources/custom-router.d.mts.map +1 -0
  47. package/resources/custom-router.d.ts +145 -0
  48. package/resources/custom-router.d.ts.map +1 -0
  49. package/resources/custom-router.js +83 -0
  50. package/resources/custom-router.js.map +1 -0
  51. package/resources/custom-router.mjs +79 -0
  52. package/resources/custom-router.mjs.map +1 -0
  53. package/resources/index.d.mts +5 -6
  54. package/resources/index.d.mts.map +1 -1
  55. package/resources/index.d.ts +5 -6
  56. package/resources/index.d.ts.map +1 -1
  57. package/resources/index.js +5 -7
  58. package/resources/index.js.map +1 -1
  59. package/resources/index.mjs +2 -3
  60. package/resources/index.mjs.map +1 -1
  61. package/resources/model-router.d.mts +194 -0
  62. package/resources/model-router.d.mts.map +1 -0
  63. package/resources/model-router.d.ts +194 -0
  64. package/resources/model-router.d.ts.map +1 -0
  65. package/resources/model-router.js +68 -0
  66. package/resources/model-router.js.map +1 -0
  67. package/resources/model-router.mjs +64 -0
  68. package/resources/model-router.mjs.map +1 -0
  69. package/resources/models.d.mts +50 -25
  70. package/resources/models.d.mts.map +1 -1
  71. package/resources/models.d.ts +50 -25
  72. package/resources/models.d.ts.map +1 -1
  73. package/resources/models.js +5 -0
  74. package/resources/models.js.map +1 -1
  75. package/resources/models.mjs +5 -0
  76. package/resources/models.mjs.map +1 -1
  77. package/resources/preferences.d.mts +37 -54
  78. package/resources/preferences.d.mts.map +1 -1
  79. package/resources/preferences.d.ts +37 -54
  80. package/resources/preferences.d.ts.map +1 -1
  81. package/resources/preferences.js +17 -42
  82. package/resources/preferences.js.map +1 -1
  83. package/resources/preferences.mjs +17 -42
  84. package/resources/preferences.mjs.map +1 -1
  85. package/resources/prompt-adaptation.d.mts +340 -249
  86. package/resources/prompt-adaptation.d.mts.map +1 -1
  87. package/resources/prompt-adaptation.d.ts +340 -249
  88. package/resources/prompt-adaptation.d.ts.map +1 -1
  89. package/resources/prompt-adaptation.js +36 -79
  90. package/resources/prompt-adaptation.js.map +1 -1
  91. package/resources/prompt-adaptation.mjs +36 -79
  92. package/resources/prompt-adaptation.mjs.map +1 -1
  93. package/src/client.ts +72 -128
  94. package/src/core/api-promise.ts +4 -4
  95. package/src/core/error.ts +2 -2
  96. package/src/core/resource.ts +3 -3
  97. package/src/index.ts +3 -3
  98. package/src/internal/parse.ts +2 -2
  99. package/src/internal/shims.ts +1 -1
  100. package/src/internal/uploads.ts +5 -5
  101. package/src/internal/utils/base64.ts +3 -3
  102. package/src/internal/utils/env.ts +4 -2
  103. package/src/internal/utils/log.ts +3 -3
  104. package/src/internal/utils/path.ts +2 -2
  105. package/src/internal/utils/values.ts +6 -6
  106. package/src/resources/custom-router.ts +168 -0
  107. package/src/resources/index.ts +20 -32
  108. package/src/resources/model-router.ts +222 -0
  109. package/src/resources/models.ts +55 -32
  110. package/src/resources/preferences.ts +43 -83
  111. package/src/resources/prompt-adaptation.ts +358 -300
  112. package/src/version.ts +1 -1
  113. package/version.d.mts +1 -1
  114. package/version.d.mts.map +1 -1
  115. package/version.d.ts +1 -1
  116. package/version.d.ts.map +1 -1
  117. package/version.js +1 -1
  118. package/version.js.map +1 -1
  119. package/version.mjs +1 -1
  120. package/version.mjs.map +1 -1
  121. package/resources/admin.d.mts +0 -4
  122. package/resources/admin.d.mts.map +0 -1
  123. package/resources/admin.d.ts +0 -4
  124. package/resources/admin.d.ts.map +0 -1
  125. package/resources/admin.js +0 -9
  126. package/resources/admin.js.map +0 -1
  127. package/resources/admin.mjs +0 -5
  128. package/resources/admin.mjs.map +0 -1
  129. package/resources/report.d.mts +0 -245
  130. package/resources/report.d.mts.map +0 -1
  131. package/resources/report.d.ts +0 -245
  132. package/resources/report.d.ts.map +0 -1
  133. package/resources/report.js +0 -86
  134. package/resources/report.js.map +0 -1
  135. package/resources/report.mjs +0 -82
  136. package/resources/report.mjs.map +0 -1
  137. package/resources/routing.d.mts +0 -391
  138. package/resources/routing.d.mts.map +0 -1
  139. package/resources/routing.d.ts +0 -391
  140. package/resources/routing.d.ts.map +0 -1
  141. package/resources/routing.js +0 -163
  142. package/resources/routing.js.map +0 -1
  143. package/resources/routing.mjs +0 -159
  144. package/resources/routing.mjs.map +0 -1
  145. package/src/resources/admin.ts +0 -5
  146. package/src/resources/report.ts +0 -300
  147. package/src/resources/routing.ts +0 -476
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,130 +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
27
- environment: 'staging', // defaults to 'production'
40
+ const client = new Notdiamond({
41
+ apiKey: process.env['NOTDIAMOND_API_KEY'], // This is the default and can be omitted
28
42
  });
29
43
 
30
- const response = await client.routing.selectModel({
31
- llm_providers: [
32
- { model: 'gpt-4o', provider: 'openai' },
33
- { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
34
- { 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
+ },
35
57
  ],
36
- messages: [
37
- { role: 'system', content: 'You are a helpful assistant.' },
38
- { 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
+ },
39
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
40
105
  });
41
106
 
42
- 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
+ }
43
143
  ```
44
144
 
45
- ### Request & Response types
145
+ For more details, see the [Prompt Adaptation documentation](https://docs.notdiamond.ai/docs/adapting-prompts-to-new-models).
46
146
 
47
- 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:
48
150
 
49
151
  <!-- prettier-ignore -->
50
152
  ```ts
51
153
  import NotDiamond from 'notdiamond';
52
154
 
53
155
  const client = new NotDiamond({
54
- apiKey: process.env['NOT_DIAMOND_API_KEY'], // This is the default and can be omitted
55
- environment: 'staging', // defaults to 'production'
156
+ apiKey: process.env['NOTDIAMOND_API_KEY'], // This is the default and can be omitted
56
157
  });
57
158
 
58
- const params: NotDiamond.RoutingSelectModelParams = {
159
+ const response = await client.modelRouter.selectModel({
59
160
  llm_providers: [
60
161
  { model: 'gpt-4o', provider: 'openai' },
61
162
  { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
62
- { model: 'gemini-1.5-pro', provider: 'google' },
163
+ { model: 'gemini-2.5-flash', provider: 'google' },
63
164
  ],
64
165
  messages: [
65
166
  { role: 'system', content: 'You are a helpful assistant.' },
66
167
  { role: 'user', content: 'Explain quantum computing in simple terms' },
67
168
  ],
68
- };
69
- const response: NotDiamond.RoutingSelectModelResponse = await client.routing.selectModel(params);
70
- ```
71
-
72
- Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.
169
+ });
73
170
 
74
- ## File uploads
171
+ console.log(response.providers);
172
+ ```
75
173
 
76
- Request parameters that correspond to file uploads can be passed in many different forms:
174
+ ### Train Custom Router
77
175
 
78
- - `File` (or an object with the same structure)
79
- - a `fetch` `Response` (or an object with the same structure)
80
- - an `fs.ReadStream`
81
- - 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:
82
177
 
83
178
  ```ts
84
179
  import fs from 'fs';
85
- import NotDiamond, { toFile } from 'notdiamond';
180
+ import NotDiamond from 'notdiamond';
86
181
 
87
- 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
+ });
88
185
 
89
- // 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',
186
+ await client.customRouter.trainCustomRouter({
97
187
  dataset_file: fs.createReadStream('/path/to/file'),
98
- });
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
+ ```
99
195
 
100
- // 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',
108
- dataset_file: new File(['my bytes'], 'file'),
109
- });
196
+ ### Request & Response types
110
197
 
111
- // 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',
119
- dataset_file: await fetch('https://somesite/file'),
120
- });
198
+ This library includes TypeScript definitions for all request params and response fields. You may import and use them like so:
121
199
 
122
- // 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',
130
- dataset_file: await toFile(Buffer.from('my bytes'), 'file'),
131
- });
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',
139
- 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
140
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);
141
240
  ```
142
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
+
143
244
  ## Handling errors
144
245
 
145
246
  When the library is unable to connect to the API,
@@ -148,27 +249,47 @@ a subclass of `APIError` will be thrown:
148
249
 
149
250
  <!-- prettier-ignore -->
150
251
  ```ts
151
- const response = await client.routing
152
- .selectModel({
153
- llm_providers: [
154
- { model: 'gpt-4o', provider: 'openai' },
155
- { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
156
- { 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
+ },
157
269
  ],
158
- messages: [
159
- { role: 'system', content: 'You are a helpful assistant.' },
160
- { 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' },
161
277
  ],
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
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
+ }
172
293
  ```
173
294
 
174
295
  Error codes are as follows:
@@ -184,27 +305,6 @@ Error codes are as follows:
184
305
  | >=500 | `InternalServerError` |
185
306
  | N/A | `APIConnectionError` |
186
307
 
187
- ### Retries
188
-
189
- Certain errors will be automatically retried 2 times by default, with a short exponential backoff.
190
- Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,
191
- 429 Rate Limit, and >=500 Internal errors will all be retried by default.
192
-
193
- You can use the `maxRetries` option to configure or disable this:
194
-
195
- <!-- prettier-ignore -->
196
- ```js
197
- // Configure the default for all requests:
198
- const client = new NotDiamond({
199
- maxRetries: 0, // default is 2
200
- });
201
-
202
- // Or, configure per-request:
203
- await client.routing.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' }] }, {
204
- maxRetries: 5,
205
- });
206
- ```
207
-
208
308
  ### Timeouts
209
309
 
210
310
  Requests time out after 1 minute by default. You can configure this with a `timeout` option:
@@ -212,13 +312,13 @@ Requests time out after 1 minute by default. You can configure this with a `time
212
312
  <!-- prettier-ignore -->
213
313
  ```ts
214
314
  // Configure the default for all requests:
215
- const client = new NotDiamond({
315
+ const client = new Notdiamond({
216
316
  timeout: 20 * 1000, // 20 seconds (default is 1 minute)
217
317
  });
218
318
 
219
- // Override per-request:
220
- await client.routing.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' }] }, {
221
- 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
222
322
  });
223
323
  ```
224
324
 
@@ -238,39 +338,61 @@ Unlike `.asResponse()` this method consumes the body, returning once it is parse
238
338
 
239
339
  <!-- prettier-ignore -->
240
340
  ```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-sonnet-4-5-20250929', provider: 'anthropic' },
248
- { 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
+ },
249
356
  ],
250
- messages: [
251
- { role: 'system', content: 'You are a helpful assistant.' },
252
- { 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' },
253
364
  ],
254
365
  })
255
366
  .asResponse();
256
367
  console.log(response.headers.get('X-My-Header'));
257
368
  console.log(response.statusText); // access the underlying Response object
258
369
 
259
- const { data: response, response: raw } = await client.routing
260
- .selectModel({
261
- llm_providers: [
262
- { model: 'gpt-4o', provider: 'openai' },
263
- { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
264
- { 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...
265
388
  ],
266
- messages: [
267
- { role: 'system', content: 'You are a helpful assistant.' },
268
- { role: 'user', content: 'Explain quantum computing in simple terms' },
389
+ test_goldens: [
390
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
269
391
  ],
270
392
  })
271
393
  .withResponse();
272
394
  console.log(raw.headers.get('X-My-Header'));
273
- console.log(response.providers);
395
+ console.log(adaptResponse.adaptation_run_id);
274
396
  ```
275
397
 
276
398
  ### Logging
@@ -283,13 +405,13 @@ console.log(response.providers);
283
405
 
284
406
  The log level can be configured in two ways:
285
407
 
286
- 1. Via the `NOT_DIAMOND_LOG` environment variable
408
+ 1. Via the `NOTDIAMOND_LOG` environment variable
287
409
  2. Using the `logLevel` client option (overrides the environment variable if set)
288
410
 
289
411
  ```ts
290
- import NotDiamond from 'notdiamond';
412
+ import Notdiamond from 'notdiamond';
291
413
 
292
- const client = new NotDiamond({
414
+ const client = new Notdiamond({
293
415
  logLevel: 'debug', // Show all log messages
294
416
  });
295
417
  ```
@@ -315,13 +437,13 @@ When providing a custom logger, the `logLevel` option still controls which messa
315
437
  below the configured level will not be sent to your logger.
316
438
 
317
439
  ```ts
318
- import NotDiamond from 'notdiamond';
440
+ import Notdiamond from 'notdiamond';
319
441
  import pino from 'pino';
320
442
 
321
443
  const logger = pino();
322
444
 
323
- const client = new NotDiamond({
324
- logger: logger.child({ name: 'NotDiamond' }),
445
+ const client = new Notdiamond({
446
+ logger: logger.child({ name: 'Notdiamond' }),
325
447
  logLevel: 'debug', // Send all messages to pino, allowing it to filter
326
448
  });
327
449
  ```
@@ -350,10 +472,14 @@ parameter. This library doesn't validate at runtime that the request matches the
350
472
  send will be sent as-is.
351
473
 
352
474
  ```ts
353
- client.routing.selectModel({
354
- // ...
355
- // @ts-expect-error baz is not yet public
356
- 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,
357
483
  });
358
484
  ```
359
485
 
@@ -384,10 +510,10 @@ globalThis.fetch = fetch;
384
510
  Or pass it to the client:
385
511
 
386
512
  ```ts
387
- import NotDiamond from 'notdiamond';
513
+ import Notdiamond from 'notdiamond';
388
514
  import fetch from 'my-fetch';
389
515
 
390
- const client = new NotDiamond({ fetch });
516
+ const client = new Notdiamond({ fetch });
391
517
  ```
392
518
 
393
519
  ### Fetch options
@@ -395,9 +521,9 @@ const client = new NotDiamond({ fetch });
395
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.)
396
522
 
397
523
  ```ts
398
- import NotDiamond from 'notdiamond';
524
+ import Notdiamond from 'notdiamond';
399
525
 
400
- const client = new NotDiamond({
526
+ const client = new Notdiamond({
401
527
  fetchOptions: {
402
528
  // `RequestInit` options
403
529
  },
@@ -412,11 +538,11 @@ options to requests:
412
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>
413
539
 
414
540
  ```ts
415
- import NotDiamond from 'notdiamond';
541
+ import Notdiamond from 'notdiamond';
416
542
  import * as undici from 'undici';
417
543
 
418
544
  const proxyAgent = new undici.ProxyAgent('http://localhost:8888');
419
- const client = new NotDiamond({
545
+ const client = new Notdiamond({
420
546
  fetchOptions: {
421
547
  dispatcher: proxyAgent,
422
548
  },
@@ -426,9 +552,9 @@ const client = new NotDiamond({
426
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>
427
553
 
428
554
  ```ts
429
- import NotDiamond from 'notdiamond';
555
+ import Notdiamond from 'notdiamond';
430
556
 
431
- const client = new NotDiamond({
557
+ const client = new Notdiamond({
432
558
  fetchOptions: {
433
559
  proxy: 'http://localhost:8888',
434
560
  },
@@ -438,10 +564,10 @@ const client = new NotDiamond({
438
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>
439
565
 
440
566
  ```ts
441
- import NotDiamond from 'npm:notdiamond';
567
+ import Notdiamond from 'npm:notdiamond';
442
568
 
443
569
  const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });
444
- const client = new NotDiamond({
570
+ const client = new Notdiamond({
445
571
  fetchOptions: {
446
572
  client: httpClient,
447
573
  },