notdiamond 2.0.0-rc2 → 2.0.0-rc20

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 +185 -0
  2. package/LICENSE +1 -1
  3. package/README.md +261 -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,184 @@ 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
45
+ const adaptation = await client.promptAdaptation.adapt({
46
+ fields: ['question'],
47
+ system_prompt: 'You are a helpful assistant that answers questions 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
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
61
+ { fields: { question: 'What is the capital of France?' }, answer: 'Paris' },
62
+ { fields: { question: 'Who wrote Romeo and Juliet?' }, answer: 'William Shakespeare' },
63
+ // Add at least 25 training examples for best results
64
+ // More examples = better adaptation quality
39
65
  ],
66
+ test_goldens: [
67
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
68
+ { fields: { question: 'What is the largest ocean?' }, answer: 'Pacific Ocean' },
69
+ // Add test examples to validate performance
70
+ ],
71
+ evaluation_metric: 'LLMaaJ:Sem_Sim_1', // Or use custom evaluation
40
72
  });
41
73
 
42
- console.log(response.providers);
74
+ console.log(`Adaptation started: ${adaptation.adaptation_run_id}`);
75
+
76
+ // Step 2: Poll for completion (typically takes 10-30 minutes)
77
+ let status;
78
+ while (true) {
79
+ status = await client.promptAdaptation.getAdaptStatus(adaptation.adaptation_run_id);
80
+ console.log(`Status: ${status.status}`);
81
+
82
+ if (status.status === 'queued') {
83
+ console.log(`Queue position: ${status.queue_position}`);
84
+ }
85
+
86
+ if (status.status === 'completed' || status.status === 'failed') {
87
+ break;
88
+ }
89
+
90
+ await new Promise(resolve => setTimeout(resolve, 30000)); // Poll every 30 seconds
91
+ }
92
+
93
+ // Step 3: Get the optimized prompts
94
+ if (status.status === 'completed') {
95
+ const results = await client.promptAdaptation.getAdaptResults(adaptation.adaptation_run_id);
96
+
97
+ console.log(`\nOrigin model baseline: ${results.origin_model.score.toFixed(2)}`);
98
+
99
+ for (const target of results.target_models) {
100
+ console.log('\n' + '='.repeat(50));
101
+ console.log(`Model: ${target.model.model} (${target.model.provider})`);
102
+ console.log(`Optimized System Prompt:\n${target.system_prompt}`);
103
+ console.log(`Optimized Template:\n${target.user_message_template}`);
104
+ console.log(`Pre-optimization score: ${target.pre_optimization_score.toFixed(2)}`);
105
+ console.log(`Post-optimization score: ${target.post_optimization_score.toFixed(2)}`);
106
+ console.log(`Improvement: ${((target.post_optimization_score / target.pre_optimization_score - 1) * 100).toFixed(1)}%`);
107
+ console.log(`Cost: $${target.cost.toFixed(4)}`);
108
+ }
109
+ }
43
110
  ```
44
111
 
45
- ### Request & Response types
112
+ For more details, see the [Prompt Adaptation documentation](https://docs.notdiamond.ai/docs/adapting-prompts-to-new-models).
46
113
 
47
- This library includes TypeScript definitions for all request params and response fields. You may import and use them like so:
114
+ ### Model Routing
115
+
116
+ Select the best model automatically:
48
117
 
49
118
  <!-- prettier-ignore -->
50
119
  ```ts
51
120
  import NotDiamond from 'notdiamond';
52
121
 
53
122
  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'
123
+ apiKey: process.env['NOTDIAMOND_API_KEY'], // This is the default and can be omitted
56
124
  });
57
125
 
58
- const params: NotDiamond.RoutingSelectModelParams = {
126
+ const response = await client.modelRouter.selectModel({
59
127
  llm_providers: [
60
128
  { model: 'gpt-4o', provider: 'openai' },
61
129
  { model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' },
62
- { model: 'gemini-1.5-pro', provider: 'google' },
130
+ { model: 'gemini-2.5-flash', provider: 'google' },
63
131
  ],
64
132
  messages: [
65
133
  { role: 'system', content: 'You are a helpful assistant.' },
66
134
  { role: 'user', content: 'Explain quantum computing in simple terms' },
67
135
  ],
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.
136
+ });
73
137
 
74
- ## File uploads
138
+ console.log(response.providers);
139
+ ```
75
140
 
76
- Request parameters that correspond to file uploads can be passed in many different forms:
141
+ ### Train Custom Router
77
142
 
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
143
+ 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
144
 
83
145
  ```ts
84
146
  import fs from 'fs';
85
- import NotDiamond, { toFile } from 'notdiamond';
147
+ import NotDiamond from 'notdiamond';
86
148
 
87
- const client = new NotDiamond();
149
+ const client = new NotDiamond({
150
+ apiKey: process.env['NOTDIAMOND_API_KEY'], // This is the default and can be omitted
151
+ });
88
152
 
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',
153
+ await client.customRouter.trainCustomRouter({
97
154
  dataset_file: fs.createReadStream('/path/to/file'),
98
- });
155
+ language: 'english',
156
+ llm_providers:
157
+ '[{"provider": "openai", "model": "gpt-4o"}, {"provider": "anthropic", "model": "claude-sonnet-4-5-20250929"}]',
158
+ maximize: true,
159
+ prompt_column: 'prompt',
160
+ });cust
161
+ ```
99
162
 
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
- });
163
+ ### Request & Response types
110
164
 
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
- });
165
+ This library includes TypeScript definitions for all request params and response fields. You may import and use them like so:
121
166
 
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'),
167
+ <!-- prettier-ignore -->
168
+ ```ts
169
+ import Notdiamond from 'notdiamond';
170
+
171
+ const client = new Notdiamond({
172
+ apiKey: process.env['NOTDIAMOND_API_KEY'], // This is the default and can be omitted
140
173
  });
174
+
175
+ const params: NotDiamond.PromptAdaptCreateParams = {
176
+ fields: ['question', 'context'],
177
+ system_prompt: 'You are a helpful assistant.',
178
+ target_models: [
179
+ {
180
+ model: 'claude-sonnet-4-5-20250929',
181
+ provider: 'anthropic',
182
+ },
183
+ ],
184
+ template: 'Context: {context}\nQuestion: {question}\nAnswer:',
185
+ train_goldens: [
186
+ {
187
+ fields: {
188
+ question: 'What is 2+2?',
189
+ context: 'Basic arithmetic',
190
+ },
191
+ answer: '4',
192
+ },
193
+ // Add at least 25 examples for best results
194
+ ],
195
+ test_goldens: [
196
+ {
197
+ fields: {
198
+ question: 'What is 3*3?',
199
+ context: 'Basic arithmetic',
200
+ },
201
+ answer: '9',
202
+ },
203
+ ],
204
+ };
205
+ const response: NotDiamond.PromptAdaptCreateResponse = await client.promptAdaptation.adapt(params);
206
+ console.log(response.adaptation_run_id);
141
207
  ```
142
208
 
209
+ Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.
210
+
143
211
  ## Handling errors
144
212
 
145
213
  When the library is unable to connect to the API,
@@ -148,27 +216,47 @@ a subclass of `APIError` will be thrown:
148
216
 
149
217
  <!-- prettier-ignore -->
150
218
  ```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' },
219
+ import NotDiamond from 'notdiamond';
220
+
221
+ const client = new NotDiamond();
222
+
223
+ try {
224
+ await client.promptAdaptation.adapt({
225
+ fields: ['question'],
226
+ system_prompt: 'You are a helpful assistant.',
227
+ target_models: [
228
+ {
229
+ model: 'claude-sonnet-4-5-20250929',
230
+ provider: 'anthropic',
231
+ },
232
+ {
233
+ model: 'gemini-2.5-flash',
234
+ provider: 'google',
235
+ },
157
236
  ],
158
- messages: [
159
- { role: 'system', content: 'You are a helpful assistant.' },
160
- { role: 'user', content: 'Explain quantum computing in simple terms' },
237
+ template: 'Question: {question}\nAnswer:',
238
+ train_goldens: [
239
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
240
+ // Add at least 25 examples...
241
+ ],
242
+ test_goldens: [
243
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
161
244
  ],
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
245
  });
246
+ } catch (err) {
247
+ if (err instanceof NotDiamond.APIConnectionError) {
248
+ console.log('The server could not be reached');
249
+ console.log(err.cause); // an underlying Error, likely from fetch()
250
+ } else if (err instanceof NotDiamond.RateLimitError) {
251
+ console.log('A 429 status code was received; we should back off a bit.');
252
+ } else if (err instanceof NotDiamond.APIError) {
253
+ console.log(err.status); // 400
254
+ console.log(err.name); // BadRequestError
255
+ console.log(err.headers); // {server: 'nginx', ...}
256
+ } else {
257
+ throw err;
258
+ }
259
+ }
172
260
  ```
173
261
 
174
262
  Error codes are as follows:
@@ -184,27 +272,6 @@ Error codes are as follows:
184
272
  | >=500 | `InternalServerError` |
185
273
  | N/A | `APIConnectionError` |
186
274
 
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
275
  ### Timeouts
209
276
 
210
277
  Requests time out after 1 minute by default. You can configure this with a `timeout` option:
@@ -212,13 +279,13 @@ Requests time out after 1 minute by default. You can configure this with a `time
212
279
  <!-- prettier-ignore -->
213
280
  ```ts
214
281
  // Configure the default for all requests:
215
- const client = new NotDiamond({
282
+ const client = new Notdiamond({
216
283
  timeout: 20 * 1000, // 20 seconds (default is 1 minute)
217
284
  });
218
285
 
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,
286
+ // Override per-request (note: prompt adaptation may take 10-30 minutes, so increase timeout accordingly):
287
+ await client.prompt.getAdaptStatus('your-adaptation-run-id', {
288
+ timeout: 120 * 1000, // 2 minutes
222
289
  });
223
290
  ```
224
291
 
@@ -238,39 +305,61 @@ Unlike `.asResponse()` this method consumes the body, returning once it is parse
238
305
 
239
306
  <!-- prettier-ignore -->
240
307
  ```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' },
308
+ const client = new Notdiamond();
309
+
310
+ const response = await client.prompt.adapt
311
+ .create({
312
+ fields: ['question'],
313
+ system_prompt: 'You are a helpful assistant.',
314
+ target_models: [
315
+ {
316
+ model: 'claude-sonnet-4-5-20250929',
317
+ provider: 'anthropic',
318
+ },
319
+ {
320
+ model: 'gemini-2.5-flash',
321
+ provider: 'google',
322
+ },
249
323
  ],
250
- messages: [
251
- { role: 'system', content: 'You are a helpful assistant.' },
252
- { role: 'user', content: 'Explain quantum computing in simple terms' },
324
+ template: 'Question: {question}\nAnswer:',
325
+ train_goldens: [
326
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
327
+ // Add at least 25 examples...
328
+ ],
329
+ test_goldens: [
330
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
253
331
  ],
254
332
  })
255
333
  .asResponse();
256
334
  console.log(response.headers.get('X-My-Header'));
257
335
  console.log(response.statusText); // access the underlying Response object
258
336
 
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' },
337
+ const { data: adaptResponse, response: raw } = await client.prompt.adapt
338
+ .create({
339
+ fields: ['question'],
340
+ system_prompt: 'You are a helpful assistant.',
341
+ target_models: [
342
+ {
343
+ model: 'claude-sonnet-4-5-20250929',
344
+ provider: 'anthropic',
345
+ },
346
+ {
347
+ model: 'gemini-2.5-flash',
348
+ provider: 'google',
349
+ },
350
+ ],
351
+ template: 'Question: {question}\nAnswer:',
352
+ train_goldens: [
353
+ { fields: { question: 'What is 2+2?' }, answer: '4' },
354
+ // Add at least 25 examples...
265
355
  ],
266
- messages: [
267
- { role: 'system', content: 'You are a helpful assistant.' },
268
- { role: 'user', content: 'Explain quantum computing in simple terms' },
356
+ test_goldens: [
357
+ { fields: { question: 'What is 3*3?' }, answer: '9' },
269
358
  ],
270
359
  })
271
360
  .withResponse();
272
361
  console.log(raw.headers.get('X-My-Header'));
273
- console.log(response.providers);
362
+ console.log(adaptResponse.adaptation_run_id);
274
363
  ```
275
364
 
276
365
  ### Logging
@@ -283,13 +372,13 @@ console.log(response.providers);
283
372
 
284
373
  The log level can be configured in two ways:
285
374
 
286
- 1. Via the `NOT_DIAMOND_LOG` environment variable
375
+ 1. Via the `NOTDIAMOND_LOG` environment variable
287
376
  2. Using the `logLevel` client option (overrides the environment variable if set)
288
377
 
289
378
  ```ts
290
- import NotDiamond from 'notdiamond';
379
+ import Notdiamond from 'notdiamond';
291
380
 
292
- const client = new NotDiamond({
381
+ const client = new Notdiamond({
293
382
  logLevel: 'debug', // Show all log messages
294
383
  });
295
384
  ```
@@ -315,13 +404,13 @@ When providing a custom logger, the `logLevel` option still controls which messa
315
404
  below the configured level will not be sent to your logger.
316
405
 
317
406
  ```ts
318
- import NotDiamond from 'notdiamond';
407
+ import Notdiamond from 'notdiamond';
319
408
  import pino from 'pino';
320
409
 
321
410
  const logger = pino();
322
411
 
323
- const client = new NotDiamond({
324
- logger: logger.child({ name: 'NotDiamond' }),
412
+ const client = new Notdiamond({
413
+ logger: logger.child({ name: 'Notdiamond' }),
325
414
  logLevel: 'debug', // Send all messages to pino, allowing it to filter
326
415
  });
327
416
  ```
@@ -350,10 +439,14 @@ parameter. This library doesn't validate at runtime that the request matches the
350
439
  send will be sent as-is.
351
440
 
352
441
  ```ts
353
- client.routing.selectModel({
354
- // ...
355
- // @ts-expect-error baz is not yet public
356
- baz: 'undocumented option',
442
+ client.promptAdaptation.adapt({
443
+ fields: ['question'],
444
+ system_prompt: 'You are a helpful assistant.',
445
+ target_models: [{ model: 'claude-sonnet-4-5-20250929', provider: 'anthropic' }],
446
+ template: 'Question: {question}\nAnswer:',
447
+ train_goldens: [{ fields: { question: 'What is 2+2?' }, answer: '4' }],
448
+ // @ts-expect-error experimental_feature is not yet public
449
+ experimental_feature: true,
357
450
  });
358
451
  ```
359
452
 
@@ -384,10 +477,10 @@ globalThis.fetch = fetch;
384
477
  Or pass it to the client:
385
478
 
386
479
  ```ts
387
- import NotDiamond from 'notdiamond';
480
+ import Notdiamond from 'notdiamond';
388
481
  import fetch from 'my-fetch';
389
482
 
390
- const client = new NotDiamond({ fetch });
483
+ const client = new Notdiamond({ fetch });
391
484
  ```
392
485
 
393
486
  ### Fetch options
@@ -395,9 +488,9 @@ const client = new NotDiamond({ fetch });
395
488
  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
489
 
397
490
  ```ts
398
- import NotDiamond from 'notdiamond';
491
+ import Notdiamond from 'notdiamond';
399
492
 
400
- const client = new NotDiamond({
493
+ const client = new Notdiamond({
401
494
  fetchOptions: {
402
495
  // `RequestInit` options
403
496
  },
@@ -412,11 +505,11 @@ options to requests:
412
505
  <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
506
 
414
507
  ```ts
415
- import NotDiamond from 'notdiamond';
508
+ import Notdiamond from 'notdiamond';
416
509
  import * as undici from 'undici';
417
510
 
418
511
  const proxyAgent = new undici.ProxyAgent('http://localhost:8888');
419
- const client = new NotDiamond({
512
+ const client = new Notdiamond({
420
513
  fetchOptions: {
421
514
  dispatcher: proxyAgent,
422
515
  },
@@ -426,9 +519,9 @@ const client = new NotDiamond({
426
519
  <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
520
 
428
521
  ```ts
429
- import NotDiamond from 'notdiamond';
522
+ import Notdiamond from 'notdiamond';
430
523
 
431
- const client = new NotDiamond({
524
+ const client = new Notdiamond({
432
525
  fetchOptions: {
433
526
  proxy: 'http://localhost:8888',
434
527
  },
@@ -438,10 +531,10 @@ const client = new NotDiamond({
438
531
  <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
532
 
440
533
  ```ts
441
- import NotDiamond from 'npm:notdiamond';
534
+ import Notdiamond from 'npm:notdiamond';
442
535
 
443
536
  const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });
444
- const client = new NotDiamond({
537
+ const client = new Notdiamond({
445
538
  fetchOptions: {
446
539
  client: httpClient,
447
540
  },