mycomesh-consumer 0.9.14 → 0.9.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/networks/mycomesh-v11-sepolia.json +504 -7
- package/package.json +1 -1
- package/src/cli.mjs +1 -1
- package/src/consumer.mjs +26 -0
- package/src/dialects.mjs +68 -13
- package/src/web/console.html +1 -1
|
@@ -13,6 +13,166 @@
|
|
|
13
13
|
"oracle": "0x5ba28de9415c7bc2d14f3f31a12fbca226e38a8f",
|
|
14
14
|
"oracle_block": 11820984,
|
|
15
15
|
"models": {
|
|
16
|
+
"gpt-6.1-sol": {
|
|
17
|
+
"tier": 1,
|
|
18
|
+
"vendor": "OpenAI",
|
|
19
|
+
"name": "GPT-6.1-Sol",
|
|
20
|
+
"reasoning_efforts": [
|
|
21
|
+
"low",
|
|
22
|
+
"medium",
|
|
23
|
+
"high",
|
|
24
|
+
"xhigh",
|
|
25
|
+
"max",
|
|
26
|
+
"ultra"
|
|
27
|
+
],
|
|
28
|
+
"summary": "OpenAI's latest workhorse model for coding and everyday work (Codex default)",
|
|
29
|
+
"tier_name": "OpenAI frontier",
|
|
30
|
+
"capabilities": {
|
|
31
|
+
"input": [
|
|
32
|
+
"text",
|
|
33
|
+
"image"
|
|
34
|
+
],
|
|
35
|
+
"output": [
|
|
36
|
+
"text"
|
|
37
|
+
],
|
|
38
|
+
"streaming": true,
|
|
39
|
+
"tools": true,
|
|
40
|
+
"dialects": [
|
|
41
|
+
"openai-responses",
|
|
42
|
+
"openai-chat",
|
|
43
|
+
"anthropic-messages",
|
|
44
|
+
"gemini-generate-content"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"gpt-6-astra": {
|
|
49
|
+
"tier": 1,
|
|
50
|
+
"vendor": "OpenAI",
|
|
51
|
+
"name": "GPT-6-Astra",
|
|
52
|
+
"reasoning_efforts": [
|
|
53
|
+
"low",
|
|
54
|
+
"medium",
|
|
55
|
+
"high",
|
|
56
|
+
"xhigh",
|
|
57
|
+
"max",
|
|
58
|
+
"ultra"
|
|
59
|
+
],
|
|
60
|
+
"summary": "OpenAI frontier intelligence for the most demanding work",
|
|
61
|
+
"tier_name": "OpenAI frontier",
|
|
62
|
+
"capabilities": {
|
|
63
|
+
"input": [
|
|
64
|
+
"text",
|
|
65
|
+
"image"
|
|
66
|
+
],
|
|
67
|
+
"output": [
|
|
68
|
+
"text"
|
|
69
|
+
],
|
|
70
|
+
"streaming": true,
|
|
71
|
+
"tools": true,
|
|
72
|
+
"dialects": [
|
|
73
|
+
"openai-responses",
|
|
74
|
+
"openai-chat",
|
|
75
|
+
"anthropic-messages",
|
|
76
|
+
"gemini-generate-content"
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"gpt-6-sol": {
|
|
81
|
+
"tier": 1,
|
|
82
|
+
"vendor": "OpenAI",
|
|
83
|
+
"name": "GPT-6-Sol",
|
|
84
|
+
"reasoning_efforts": [
|
|
85
|
+
"low",
|
|
86
|
+
"medium",
|
|
87
|
+
"high",
|
|
88
|
+
"xhigh",
|
|
89
|
+
"max",
|
|
90
|
+
"ultra"
|
|
91
|
+
],
|
|
92
|
+
"summary": "OpenAI's previous-generation workhorse model",
|
|
93
|
+
"tier_name": "OpenAI frontier",
|
|
94
|
+
"capabilities": {
|
|
95
|
+
"input": [
|
|
96
|
+
"text",
|
|
97
|
+
"image"
|
|
98
|
+
],
|
|
99
|
+
"output": [
|
|
100
|
+
"text"
|
|
101
|
+
],
|
|
102
|
+
"streaming": true,
|
|
103
|
+
"tools": true,
|
|
104
|
+
"dialects": [
|
|
105
|
+
"openai-responses",
|
|
106
|
+
"openai-chat",
|
|
107
|
+
"anthropic-messages",
|
|
108
|
+
"gemini-generate-content"
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"gpt-5.6-sol": {
|
|
113
|
+
"tier": 1,
|
|
114
|
+
"vendor": "OpenAI",
|
|
115
|
+
"name": "GPT-5.6-Sol",
|
|
116
|
+
"reasoning_efforts": [
|
|
117
|
+
"low",
|
|
118
|
+
"medium",
|
|
119
|
+
"high",
|
|
120
|
+
"xhigh",
|
|
121
|
+
"max",
|
|
122
|
+
"ultra"
|
|
123
|
+
],
|
|
124
|
+
"summary": "OpenAI's older-generation workhorse model",
|
|
125
|
+
"tier_name": "OpenAI frontier",
|
|
126
|
+
"capabilities": {
|
|
127
|
+
"input": [
|
|
128
|
+
"text",
|
|
129
|
+
"image"
|
|
130
|
+
],
|
|
131
|
+
"output": [
|
|
132
|
+
"text"
|
|
133
|
+
],
|
|
134
|
+
"streaming": true,
|
|
135
|
+
"tools": true,
|
|
136
|
+
"dialects": [
|
|
137
|
+
"openai-responses",
|
|
138
|
+
"openai-chat",
|
|
139
|
+
"anthropic-messages",
|
|
140
|
+
"gemini-generate-content"
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"gpt-5.6-terra": {
|
|
145
|
+
"tier": 1,
|
|
146
|
+
"vendor": "OpenAI",
|
|
147
|
+
"name": "GPT-5.6-Terra",
|
|
148
|
+
"reasoning_efforts": [
|
|
149
|
+
"low",
|
|
150
|
+
"medium",
|
|
151
|
+
"high",
|
|
152
|
+
"xhigh",
|
|
153
|
+
"max",
|
|
154
|
+
"ultra"
|
|
155
|
+
],
|
|
156
|
+
"summary": "OpenAI's older balanced model for straightforward work",
|
|
157
|
+
"tier_name": "OpenAI frontier",
|
|
158
|
+
"capabilities": {
|
|
159
|
+
"input": [
|
|
160
|
+
"text",
|
|
161
|
+
"image"
|
|
162
|
+
],
|
|
163
|
+
"output": [
|
|
164
|
+
"text"
|
|
165
|
+
],
|
|
166
|
+
"streaming": true,
|
|
167
|
+
"tools": true,
|
|
168
|
+
"dialects": [
|
|
169
|
+
"openai-responses",
|
|
170
|
+
"openai-chat",
|
|
171
|
+
"anthropic-messages",
|
|
172
|
+
"gemini-generate-content"
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
},
|
|
16
176
|
"gpt-5.5": {
|
|
17
177
|
"tier": 1,
|
|
18
178
|
"vendor": "OpenAI",
|
|
@@ -23,12 +183,44 @@
|
|
|
23
183
|
"high",
|
|
24
184
|
"xhigh"
|
|
25
185
|
],
|
|
26
|
-
"summary": "OpenAI
|
|
186
|
+
"summary": "OpenAI legacy coding model",
|
|
27
187
|
"tier_name": "OpenAI frontier",
|
|
28
188
|
"capabilities": {
|
|
29
189
|
"input": [
|
|
190
|
+
"text",
|
|
191
|
+
"image"
|
|
192
|
+
],
|
|
193
|
+
"output": [
|
|
30
194
|
"text"
|
|
31
195
|
],
|
|
196
|
+
"streaming": true,
|
|
197
|
+
"tools": true,
|
|
198
|
+
"dialects": [
|
|
199
|
+
"openai-responses",
|
|
200
|
+
"openai-chat",
|
|
201
|
+
"anthropic-messages",
|
|
202
|
+
"gemini-generate-content"
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"gpt-6-luna": {
|
|
207
|
+
"tier": 3,
|
|
208
|
+
"vendor": "OpenAI",
|
|
209
|
+
"name": "GPT-6-Luna",
|
|
210
|
+
"reasoning_efforts": [
|
|
211
|
+
"low",
|
|
212
|
+
"medium",
|
|
213
|
+
"high",
|
|
214
|
+
"xhigh",
|
|
215
|
+
"max"
|
|
216
|
+
],
|
|
217
|
+
"summary": "OpenAI's fast, affordable model for easier tasks",
|
|
218
|
+
"tier_name": "OpenAI fast",
|
|
219
|
+
"capabilities": {
|
|
220
|
+
"input": [
|
|
221
|
+
"text",
|
|
222
|
+
"image"
|
|
223
|
+
],
|
|
32
224
|
"output": [
|
|
33
225
|
"text"
|
|
34
226
|
],
|
|
@@ -42,16 +234,120 @@
|
|
|
42
234
|
]
|
|
43
235
|
}
|
|
44
236
|
},
|
|
45
|
-
"
|
|
237
|
+
"gpt-5.6-luna": {
|
|
238
|
+
"tier": 3,
|
|
239
|
+
"vendor": "OpenAI",
|
|
240
|
+
"name": "GPT-5.6-Luna",
|
|
241
|
+
"reasoning_efforts": [
|
|
242
|
+
"low",
|
|
243
|
+
"medium",
|
|
244
|
+
"high",
|
|
245
|
+
"xhigh",
|
|
246
|
+
"max"
|
|
247
|
+
],
|
|
248
|
+
"summary": "OpenAI's older fast and efficient model",
|
|
249
|
+
"tier_name": "OpenAI fast",
|
|
250
|
+
"capabilities": {
|
|
251
|
+
"input": [
|
|
252
|
+
"text",
|
|
253
|
+
"image"
|
|
254
|
+
],
|
|
255
|
+
"output": [
|
|
256
|
+
"text"
|
|
257
|
+
],
|
|
258
|
+
"streaming": true,
|
|
259
|
+
"tools": true,
|
|
260
|
+
"dialects": [
|
|
261
|
+
"openai-responses",
|
|
262
|
+
"openai-chat",
|
|
263
|
+
"anthropic-messages",
|
|
264
|
+
"gemini-generate-content"
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
"claude-fable-5-1": {
|
|
269
|
+
"tier": 4,
|
|
270
|
+
"vendor": "Anthropic",
|
|
271
|
+
"name": "Claude Fable 5.1",
|
|
272
|
+
"summary": "Anthropic's most capable widely released model",
|
|
273
|
+
"tier_name": "Anthropic Claude Fable",
|
|
274
|
+
"capabilities": {
|
|
275
|
+
"input": [
|
|
276
|
+
"text",
|
|
277
|
+
"image"
|
|
278
|
+
],
|
|
279
|
+
"output": [
|
|
280
|
+
"text"
|
|
281
|
+
],
|
|
282
|
+
"streaming": true,
|
|
283
|
+
"tools": true,
|
|
284
|
+
"dialects": [
|
|
285
|
+
"openai-responses",
|
|
286
|
+
"openai-chat",
|
|
287
|
+
"anthropic-messages",
|
|
288
|
+
"gemini-generate-content"
|
|
289
|
+
]
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
"claude-fable-5": {
|
|
293
|
+
"tier": 4,
|
|
294
|
+
"vendor": "Anthropic",
|
|
295
|
+
"name": "Claude Fable 5",
|
|
296
|
+
"summary": "The previous Fable release",
|
|
297
|
+
"tier_name": "Anthropic Claude Fable",
|
|
298
|
+
"capabilities": {
|
|
299
|
+
"input": [
|
|
300
|
+
"text",
|
|
301
|
+
"image"
|
|
302
|
+
],
|
|
303
|
+
"output": [
|
|
304
|
+
"text"
|
|
305
|
+
],
|
|
306
|
+
"streaming": true,
|
|
307
|
+
"tools": true,
|
|
308
|
+
"dialects": [
|
|
309
|
+
"openai-responses",
|
|
310
|
+
"openai-chat",
|
|
311
|
+
"anthropic-messages",
|
|
312
|
+
"gemini-generate-content"
|
|
313
|
+
]
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
"claude-opus-5-5": {
|
|
46
317
|
"tier": 2,
|
|
47
318
|
"vendor": "Anthropic",
|
|
48
|
-
"name": "Claude
|
|
49
|
-
"summary": "Anthropic's
|
|
319
|
+
"name": "Claude Opus 5.5",
|
|
320
|
+
"summary": "Anthropic's Opus line for long-running agentic coding and knowledge work",
|
|
50
321
|
"tier_name": "Anthropic Claude",
|
|
51
322
|
"capabilities": {
|
|
52
323
|
"input": [
|
|
324
|
+
"text",
|
|
325
|
+
"image"
|
|
326
|
+
],
|
|
327
|
+
"output": [
|
|
53
328
|
"text"
|
|
54
329
|
],
|
|
330
|
+
"streaming": true,
|
|
331
|
+
"tools": true,
|
|
332
|
+
"dialects": [
|
|
333
|
+
"openai-responses",
|
|
334
|
+
"openai-chat",
|
|
335
|
+
"anthropic-messages",
|
|
336
|
+
"gemini-generate-content"
|
|
337
|
+
]
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
"claude-opus-5": {
|
|
341
|
+
"tier": 2,
|
|
342
|
+
"vendor": "Anthropic",
|
|
343
|
+
"name": "Claude Opus 5",
|
|
344
|
+
"summary": "The previous Opus",
|
|
345
|
+
"tier_name": "Anthropic Claude",
|
|
346
|
+
"capabilities": {
|
|
347
|
+
"input": [
|
|
348
|
+
"text",
|
|
349
|
+
"image"
|
|
350
|
+
],
|
|
55
351
|
"output": [
|
|
56
352
|
"text"
|
|
57
353
|
],
|
|
@@ -69,12 +365,181 @@
|
|
|
69
365
|
"tier": 2,
|
|
70
366
|
"vendor": "Anthropic",
|
|
71
367
|
"name": "Claude Opus 4.8",
|
|
72
|
-
"summary": "
|
|
368
|
+
"summary": "The most capable Opus 4 model",
|
|
369
|
+
"tier_name": "Anthropic Claude",
|
|
370
|
+
"capabilities": {
|
|
371
|
+
"input": [
|
|
372
|
+
"text",
|
|
373
|
+
"image"
|
|
374
|
+
],
|
|
375
|
+
"output": [
|
|
376
|
+
"text"
|
|
377
|
+
],
|
|
378
|
+
"streaming": true,
|
|
379
|
+
"tools": true,
|
|
380
|
+
"dialects": [
|
|
381
|
+
"openai-responses",
|
|
382
|
+
"openai-chat",
|
|
383
|
+
"anthropic-messages",
|
|
384
|
+
"gemini-generate-content"
|
|
385
|
+
]
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
"claude-opus-4-7": {
|
|
389
|
+
"tier": 2,
|
|
390
|
+
"vendor": "Anthropic",
|
|
391
|
+
"name": "Claude Opus 4.7",
|
|
392
|
+
"summary": "Previous-generation Opus 4",
|
|
393
|
+
"tier_name": "Anthropic Claude",
|
|
394
|
+
"capabilities": {
|
|
395
|
+
"input": [
|
|
396
|
+
"text",
|
|
397
|
+
"image"
|
|
398
|
+
],
|
|
399
|
+
"output": [
|
|
400
|
+
"text"
|
|
401
|
+
],
|
|
402
|
+
"streaming": true,
|
|
403
|
+
"tools": true,
|
|
404
|
+
"dialects": [
|
|
405
|
+
"openai-responses",
|
|
406
|
+
"openai-chat",
|
|
407
|
+
"anthropic-messages",
|
|
408
|
+
"gemini-generate-content"
|
|
409
|
+
]
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
"claude-opus-4-6": {
|
|
413
|
+
"tier": 2,
|
|
414
|
+
"vendor": "Anthropic",
|
|
415
|
+
"name": "Claude Opus 4.6",
|
|
416
|
+
"summary": "Older Opus 4",
|
|
417
|
+
"tier_name": "Anthropic Claude",
|
|
418
|
+
"capabilities": {
|
|
419
|
+
"input": [
|
|
420
|
+
"text",
|
|
421
|
+
"image"
|
|
422
|
+
],
|
|
423
|
+
"output": [
|
|
424
|
+
"text"
|
|
425
|
+
],
|
|
426
|
+
"streaming": true,
|
|
427
|
+
"tools": true,
|
|
428
|
+
"dialects": [
|
|
429
|
+
"openai-responses",
|
|
430
|
+
"openai-chat",
|
|
431
|
+
"anthropic-messages",
|
|
432
|
+
"gemini-generate-content"
|
|
433
|
+
]
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
"claude-sonnet-5-5": {
|
|
437
|
+
"tier": 2,
|
|
438
|
+
"vendor": "Anthropic",
|
|
439
|
+
"name": "Claude Sonnet 5.5",
|
|
440
|
+
"summary": "Anthropic's current balanced model for everyday and coding work",
|
|
73
441
|
"tier_name": "Anthropic Claude",
|
|
74
442
|
"capabilities": {
|
|
75
443
|
"input": [
|
|
444
|
+
"text",
|
|
445
|
+
"image"
|
|
446
|
+
],
|
|
447
|
+
"output": [
|
|
76
448
|
"text"
|
|
77
449
|
],
|
|
450
|
+
"streaming": true,
|
|
451
|
+
"tools": true,
|
|
452
|
+
"dialects": [
|
|
453
|
+
"openai-responses",
|
|
454
|
+
"openai-chat",
|
|
455
|
+
"anthropic-messages",
|
|
456
|
+
"gemini-generate-content"
|
|
457
|
+
]
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
"claude-sonnet-5": {
|
|
461
|
+
"tier": 2,
|
|
462
|
+
"vendor": "Anthropic",
|
|
463
|
+
"name": "Claude Sonnet 5",
|
|
464
|
+
"summary": "The previous Sonnet",
|
|
465
|
+
"tier_name": "Anthropic Claude",
|
|
466
|
+
"capabilities": {
|
|
467
|
+
"input": [
|
|
468
|
+
"text",
|
|
469
|
+
"image"
|
|
470
|
+
],
|
|
471
|
+
"output": [
|
|
472
|
+
"text"
|
|
473
|
+
],
|
|
474
|
+
"streaming": true,
|
|
475
|
+
"tools": true,
|
|
476
|
+
"dialects": [
|
|
477
|
+
"openai-responses",
|
|
478
|
+
"openai-chat",
|
|
479
|
+
"anthropic-messages",
|
|
480
|
+
"gemini-generate-content"
|
|
481
|
+
]
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
"claude-sonnet-4-6": {
|
|
485
|
+
"tier": 2,
|
|
486
|
+
"vendor": "Anthropic",
|
|
487
|
+
"name": "Claude Sonnet 4.6",
|
|
488
|
+
"summary": "Previous-generation Sonnet",
|
|
489
|
+
"tier_name": "Anthropic Claude",
|
|
490
|
+
"capabilities": {
|
|
491
|
+
"input": [
|
|
492
|
+
"text",
|
|
493
|
+
"image"
|
|
494
|
+
],
|
|
495
|
+
"output": [
|
|
496
|
+
"text"
|
|
497
|
+
],
|
|
498
|
+
"streaming": true,
|
|
499
|
+
"tools": true,
|
|
500
|
+
"dialects": [
|
|
501
|
+
"openai-responses",
|
|
502
|
+
"openai-chat",
|
|
503
|
+
"anthropic-messages",
|
|
504
|
+
"gemini-generate-content"
|
|
505
|
+
]
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
"claude-haiku-5-5": {
|
|
509
|
+
"tier": 5,
|
|
510
|
+
"vendor": "Anthropic",
|
|
511
|
+
"name": "Claude Haiku 5.5",
|
|
512
|
+
"summary": "Anthropic's fast, low-cost model",
|
|
513
|
+
"tier_name": "Anthropic Claude Haiku",
|
|
514
|
+
"capabilities": {
|
|
515
|
+
"input": [
|
|
516
|
+
"text",
|
|
517
|
+
"image"
|
|
518
|
+
],
|
|
519
|
+
"output": [
|
|
520
|
+
"text"
|
|
521
|
+
],
|
|
522
|
+
"streaming": true,
|
|
523
|
+
"tools": true,
|
|
524
|
+
"dialects": [
|
|
525
|
+
"openai-responses",
|
|
526
|
+
"openai-chat",
|
|
527
|
+
"anthropic-messages",
|
|
528
|
+
"gemini-generate-content"
|
|
529
|
+
]
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
"claude-haiku-4-5": {
|
|
533
|
+
"tier": 5,
|
|
534
|
+
"vendor": "Anthropic",
|
|
535
|
+
"name": "Claude Haiku 4.5",
|
|
536
|
+
"summary": "Previous-generation Haiku",
|
|
537
|
+
"tier_name": "Anthropic Claude Haiku",
|
|
538
|
+
"capabilities": {
|
|
539
|
+
"input": [
|
|
540
|
+
"text",
|
|
541
|
+
"image"
|
|
542
|
+
],
|
|
78
543
|
"output": [
|
|
79
544
|
"text"
|
|
80
545
|
],
|
|
@@ -93,6 +558,11 @@
|
|
|
93
558
|
"1": {
|
|
94
559
|
"name": "OpenAI frontier",
|
|
95
560
|
"models": [
|
|
561
|
+
"gpt-6.1-sol",
|
|
562
|
+
"gpt-6-astra",
|
|
563
|
+
"gpt-6-sol",
|
|
564
|
+
"gpt-5.6-sol",
|
|
565
|
+
"gpt-5.6-terra",
|
|
96
566
|
"gpt-5.5"
|
|
97
567
|
],
|
|
98
568
|
"capability_floor": 0.85
|
|
@@ -100,8 +570,35 @@
|
|
|
100
570
|
"2": {
|
|
101
571
|
"name": "Anthropic Claude",
|
|
102
572
|
"models": [
|
|
103
|
-
"claude-
|
|
104
|
-
"claude-opus-
|
|
573
|
+
"claude-opus-5-5",
|
|
574
|
+
"claude-opus-5",
|
|
575
|
+
"claude-opus-4-8",
|
|
576
|
+
"claude-opus-4-7",
|
|
577
|
+
"claude-opus-4-6",
|
|
578
|
+
"claude-sonnet-5-5",
|
|
579
|
+
"claude-sonnet-5",
|
|
580
|
+
"claude-sonnet-4-6"
|
|
581
|
+
]
|
|
582
|
+
},
|
|
583
|
+
"3": {
|
|
584
|
+
"name": "OpenAI fast",
|
|
585
|
+
"models": [
|
|
586
|
+
"gpt-6-luna",
|
|
587
|
+
"gpt-5.6-luna"
|
|
588
|
+
]
|
|
589
|
+
},
|
|
590
|
+
"4": {
|
|
591
|
+
"name": "Anthropic Claude Fable",
|
|
592
|
+
"models": [
|
|
593
|
+
"claude-fable-5-1",
|
|
594
|
+
"claude-fable-5"
|
|
595
|
+
]
|
|
596
|
+
},
|
|
597
|
+
"5": {
|
|
598
|
+
"name": "Anthropic Claude Haiku",
|
|
599
|
+
"models": [
|
|
600
|
+
"claude-haiku-5-5",
|
|
601
|
+
"claude-haiku-4-5"
|
|
105
602
|
]
|
|
106
603
|
}
|
|
107
604
|
},
|
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -86,7 +86,7 @@ export async function main(argv = process.argv.slice(2), { stdout = process.stdo
|
|
|
86
86
|
options: {
|
|
87
87
|
network: { type: "string" }, "data-dir": { type: "string" }, "owner-key-file": { type: "string" },
|
|
88
88
|
deposit: { type: "string" }, "max-per-request": { type: "string" }, owner: { type: "string" },
|
|
89
|
-
model: { type: "string", default: "gpt-
|
|
89
|
+
model: { type: "string", default: "gpt-6.1-sol" }, "max-fee": { type: "string", default: "1000000" },
|
|
90
90
|
port: { type: "string", default: "8110" }, host: { type: "string", default: "127.0.0.1" },
|
|
91
91
|
"max-output-tokens": { type: "string", default: "4096" }, help: { type: "boolean" },
|
|
92
92
|
reason: { type: "string", default: "unrelated_response" }, faucet: { type: "boolean" }, provider: { type: "string" },
|
package/src/consumer.mjs
CHANGED
|
@@ -43,6 +43,20 @@ class Cached {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
const MAX_REQUEST_BYTES = 7_500_000; // the sealed request must fit the network's 8 MB plaintext limit
|
|
47
|
+
|
|
48
|
+
/** What a request asks a backend to read besides text: "image", "file". */
|
|
49
|
+
export function inputKinds(content) {
|
|
50
|
+
const kinds = new Set();
|
|
51
|
+
for (const message of Array.isArray(content) ? content : []) {
|
|
52
|
+
for (const part of Array.isArray(message?.content) ? message.content : []) {
|
|
53
|
+
if (part?.type === "image_url" || part?.type === "input_image") kinds.add("image");
|
|
54
|
+
if (part?.type === "file" || part?.type === "input_file") kinds.add("file");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return [...kinds].sort();
|
|
58
|
+
}
|
|
59
|
+
|
|
46
60
|
// Session affinity: a conversation goes back to the Provider that answered its last turn, whose upstream
|
|
47
61
|
// account holds the conversation's prompt cache (measured: a new Codex thread with the same 10k-token prefix
|
|
48
62
|
// read 9,728 tokens from cache on the same account, none on another).
|
|
@@ -397,6 +411,12 @@ export class Consumer {
|
|
|
397
411
|
async attempt({ endpoint, model, content, maxOutputTokens = 4096, options = {}, provider, session, onDelta }) {
|
|
398
412
|
let lastError;
|
|
399
413
|
let raisedFee = 0;
|
|
414
|
+
const size = Buffer.byteLength(JSON.stringify({ content, tools: options.tools ?? null }), "utf8");
|
|
415
|
+
if (size > MAX_REQUEST_BYTES) {
|
|
416
|
+
throw Object.assign(new Error(`this request is ${(size / 1e6).toFixed(1)} MB; the network carries up to ${MAX_REQUEST_BYTES / 1e6} MB (smaller or fewer images)`), { status: 413 });
|
|
417
|
+
}
|
|
418
|
+
const needs = inputKinds(content); // images and files go only to Providers whose backend reads them
|
|
419
|
+
let unreadable = false;
|
|
400
420
|
const conversation = sessionKey({ endpoint, model, content, options, session });
|
|
401
421
|
const preferred = this.stickyProvider(conversation);
|
|
402
422
|
for (const relay of await this.relays()) {
|
|
@@ -404,6 +424,9 @@ export class Consumer {
|
|
|
404
424
|
try {
|
|
405
425
|
candidates = (await this.providers(relay)).filter((descriptor) => (descriptor.models || []).includes(model)
|
|
406
426
|
&& (!provider || descriptor.provider_signer === provider.toLowerCase()));
|
|
427
|
+
const able = candidates.filter((descriptor) => needs.every((kind) => (descriptor.inputs || ["text"]).includes(kind)));
|
|
428
|
+
if (able.length < candidates.length && !able.length) unreadable = true;
|
|
429
|
+
candidates = able;
|
|
407
430
|
}
|
|
408
431
|
catch (error) { lastError = error; continue; }
|
|
409
432
|
const records = await this.reputations({ waitMs: REPUTATION_WAIT_MS }).catch(() => ({}));
|
|
@@ -478,6 +501,9 @@ export class Consumer {
|
|
|
478
501
|
if (reply.body?.dispatched !== false || ![502, 503].includes(reply.status)) throw lastError;
|
|
479
502
|
}
|
|
480
503
|
}
|
|
504
|
+
if (!lastError && unreadable) {
|
|
505
|
+
throw Object.assign(new Error(`no Provider online for ${model} reads ${needs.join(" and ")} input (Codex Providers read text and images, not files)`), { status: 400 });
|
|
506
|
+
}
|
|
481
507
|
throw lastError || new Error(`no Provider serves model ${model}`);
|
|
482
508
|
}
|
|
483
509
|
}
|
package/src/dialects.mjs
CHANGED
|
@@ -10,7 +10,50 @@ export class DialectError extends Error {
|
|
|
10
10
|
constructor(message, status = 400) { super(message); this.status = status; }
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Content in the network's parts (OpenAI Chat): a string when it is all text, else text, image_url (a data: or
|
|
15
|
+
* https URL) and file (a data: URL and its filename) parts. Anthropic blocks, Responses inputs and Gemini parts
|
|
16
|
+
* all land here.
|
|
17
|
+
*/
|
|
18
|
+
export function parts(content, where) {
|
|
19
|
+
if (typeof content === "string" || content === undefined || content === null) return content ?? "";
|
|
20
|
+
if (!Array.isArray(content)) throw new DialectError(`${where}: content must be text`);
|
|
21
|
+
const out = [];
|
|
22
|
+
for (const part of content) {
|
|
23
|
+
const media = mediaPart(part);
|
|
24
|
+
if (media) out.push(media);
|
|
25
|
+
else { const words = text([part], where); if (words) out.push({ type: "text", text: words }); }
|
|
26
|
+
}
|
|
27
|
+
return out.every((p) => p.type === "text") ? out.map((p) => p.text).join("") : out;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const dataUrl = (mime, data) => `data:${mime || "application/octet-stream"};base64,${data}`;
|
|
31
|
+
|
|
32
|
+
/** An image or document block of any dialect as a network part; null for text and the rest. */
|
|
33
|
+
function mediaPart(part) {
|
|
34
|
+
if (!part || typeof part !== "object") return null;
|
|
35
|
+
if (part.type === "image" && part.source) { // Anthropic
|
|
36
|
+
const url = part.source.type === "base64" ? dataUrl(part.source.media_type, part.source.data) : part.source.url;
|
|
37
|
+
return url ? { type: "image_url", image_url: { url } } : null;
|
|
38
|
+
}
|
|
39
|
+
if (part.type === "document" && part.source?.type === "base64") {
|
|
40
|
+
return { type: "file", file: { filename: part.title || "document.pdf", file_data: dataUrl(part.source.media_type, part.source.data) } };
|
|
41
|
+
}
|
|
42
|
+
if (part.type === "input_image" && (part.image_url || part.url)) return { type: "image_url", image_url: { url: part.image_url || part.url } }; // Responses
|
|
43
|
+
if (part.type === "input_file" && part.file_data) {
|
|
44
|
+
return { type: "file", file: { filename: part.filename || "file", file_data: part.file_data.startsWith("data:") ? part.file_data : dataUrl("application/pdf", part.file_data) } };
|
|
45
|
+
}
|
|
46
|
+
if (part.type === "image_url" && part.image_url) return { type: "image_url", image_url: { url: part.image_url.url || part.image_url } }; // Chat
|
|
47
|
+
if (part.type === "file" && part.file) return { type: "file", file: part.file };
|
|
48
|
+
if (part.inlineData?.data) { // Gemini
|
|
49
|
+
const url = dataUrl(part.inlineData.mimeType, part.inlineData.data);
|
|
50
|
+
return part.inlineData.mimeType?.startsWith("image/") ? { type: "image_url", image_url: { url } }
|
|
51
|
+
: { type: "file", file: { filename: "file", file_data: url } };
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The text of content (images and documents become a note): for places that can hold only text. */
|
|
14
57
|
function text(content, where) {
|
|
15
58
|
if (typeof content === "string") return content;
|
|
16
59
|
if (content === undefined || content === null) return "";
|
|
@@ -19,8 +62,9 @@ function text(content, where) {
|
|
|
19
62
|
if (typeof part === "string") return part;
|
|
20
63
|
if (part && typeof part.text === "string" && (part.type === undefined || part.type === "text")) return part.text;
|
|
21
64
|
if (part?.type === "thinking" || part?.type === "redacted_thinking" || part?.thought) return "";
|
|
22
|
-
if (part?.type === "image" || part?.inlineData || part?.type === "input_image") return "[image
|
|
23
|
-
if (part?.type === "document") return part.source?.type === "text" ? String(part.source.data ?? "") : "[document
|
|
65
|
+
if (part?.type === "image" || part?.inlineData || part?.type === "input_image" || part?.type === "image_url") return "[image]";
|
|
66
|
+
if (part?.type === "document") return part.source?.type === "text" ? String(part.source.data ?? "") : "[document]";
|
|
67
|
+
if (part?.type === "input_file" || part?.type === "file") return "[file]";
|
|
24
68
|
if (part?.type === "input_text" || part?.type === "output_text") return String(part.text ?? "");
|
|
25
69
|
throw new DialectError(`${where}: unsupported content (${part?.type || Object.keys(part || {})[0] || "unknown"})`);
|
|
26
70
|
}).join("");
|
|
@@ -57,13 +101,20 @@ export function fromAnthropic(body) {
|
|
|
57
101
|
messages.push({ role: "assistant", content: words || (calls.length ? null : ""), ...(calls.length ? { tool_calls: calls } : {}) });
|
|
58
102
|
continue;
|
|
59
103
|
}
|
|
60
|
-
// A user turn: tool results answer the previous assistant's calls; the rest is what the user said.
|
|
104
|
+
// A user turn: tool results answer the previous assistant's calls; the rest is what the user said. A tool
|
|
105
|
+
// result can only be text, so images it returned (a screenshot Read) follow in a user message.
|
|
106
|
+
const shown = [];
|
|
61
107
|
for (const block of blocks.filter((b) => b?.type === "tool_result")) {
|
|
62
|
-
const
|
|
108
|
+
const content = Array.isArray(block.content) ? block.content : [{ type: "text", text: String(block.content ?? "") }];
|
|
109
|
+
const media = content.map(mediaPart).filter(Boolean);
|
|
110
|
+
const result = text(content.filter((b) => !mediaPart(b)), "tool_result") + (media.length ? `\n[${media.length} attachment(s) follow]` : "");
|
|
63
111
|
messages.push({ role: "tool", tool_call_id: block.tool_use_id, content: block.is_error ? `Error: ${result}` : result });
|
|
112
|
+
if (media.length) shown.push({ type: "text", text: `Attachments returned by tool call ${block.tool_use_id}:` }, ...media);
|
|
64
113
|
}
|
|
65
114
|
const rest = blocks.filter((b) => b?.type !== "tool_result");
|
|
66
|
-
|
|
115
|
+
const said = rest.length ? parts(rest, "user message") : "";
|
|
116
|
+
if (shown.length) messages.push({ role: "user", content: [...shown, ...(typeof said === "string" ? (said ? [{ type: "text", text: said }] : []) : said)] });
|
|
117
|
+
else if (rest.length || !blocks.length) messages.push({ role: "user", content: said });
|
|
67
118
|
}
|
|
68
119
|
const options = {};
|
|
69
120
|
for (const key of ["temperature", "top_p"]) if (body[key] !== undefined) options[key] = body[key];
|
|
@@ -190,16 +241,17 @@ export function fromResponses(body) {
|
|
|
190
241
|
const type = item?.type || (item?.role ? "message" : "");
|
|
191
242
|
if (type === "message") {
|
|
192
243
|
const role = item.role === "developer" ? "system" : item.role;
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
else messages.push({ role, content: words });
|
|
244
|
+
if (role === "assistant") { const a = assistant(); a.content = (a.content || "") + text(item.content, "assistant message"); }
|
|
245
|
+
else messages.push({ role, content: role === "user" ? parts(item.content, "user message") : text(item.content, `${role} message`) });
|
|
196
246
|
} else if (type === "function_call" || type === "custom_tool_call") {
|
|
197
247
|
const a = assistant();
|
|
198
248
|
(a.tool_calls ||= []).push({ id: item.call_id, type: "function", function: { name: item.name,
|
|
199
249
|
arguments: type === "custom_tool_call" ? JSON.stringify({ input: item.input ?? "" }) : (item.arguments ?? "{}") } });
|
|
200
250
|
} else if (type === "function_call_output" || type === "custom_tool_call_output") {
|
|
201
|
-
const
|
|
251
|
+
const media = Array.isArray(item.output) ? item.output.map(mediaPart).filter(Boolean) : [];
|
|
252
|
+
const output = typeof item.output === "string" ? item.output : text(item.output.filter((b) => !mediaPart(b)), "tool output");
|
|
202
253
|
messages.push({ role: "tool", tool_call_id: item.call_id, content: output });
|
|
254
|
+
if (media.length) messages.push({ role: "user", content: [{ type: "text", text: `Attachments returned by tool call ${item.call_id}:` }, ...media] });
|
|
203
255
|
} // reasoning items and the like stay with the client
|
|
204
256
|
}
|
|
205
257
|
for (const message of messages) if (message.role === "assistant" && !message.tool_calls?.length) delete message.tool_calls;
|
|
@@ -242,6 +294,8 @@ export function geminiRoute(path) {
|
|
|
242
294
|
return match ? { model: decodeURIComponent(match[1]), stream: match[2] === "streamGenerateContent", count: match[2] === "countTokens" } : null;
|
|
243
295
|
}
|
|
244
296
|
|
|
297
|
+
const partsOf = (value, where) => parts(value, where);
|
|
298
|
+
|
|
245
299
|
export function fromGemini(body, model) {
|
|
246
300
|
if (!Array.isArray(body.contents)) throw new DialectError("contents are required");
|
|
247
301
|
const messages = [];
|
|
@@ -255,7 +309,8 @@ export function fromGemini(body, model) {
|
|
|
255
309
|
const parts = item.parts || [];
|
|
256
310
|
const calls = parts.filter((p) => p.functionCall);
|
|
257
311
|
const results = parts.filter((p) => p.functionResponse);
|
|
258
|
-
const
|
|
312
|
+
const said = parts.filter((p) => !p.functionCall && !p.functionResponse);
|
|
313
|
+
const words = item.role === "model" ? text(said, "model content") : partsOf(said, "user content");
|
|
259
314
|
if (item.role === "model") {
|
|
260
315
|
const toolCalls = calls.map((p) => {
|
|
261
316
|
const call = { id: p.functionCall.id || `call_${counter++}`, type: "function",
|
|
@@ -266,13 +321,13 @@ export function fromGemini(body, model) {
|
|
|
266
321
|
messages.push({ role: "assistant", content: words || (toolCalls.length ? null : ""), ...(toolCalls.length ? { tool_calls: toolCalls } : {}) });
|
|
267
322
|
continue;
|
|
268
323
|
}
|
|
269
|
-
for (const part of results) {
|
|
324
|
+
for (const part of results) { // results first: they answer the calls the model just made
|
|
270
325
|
const index = open.findIndex((call) => call.function.name === part.functionResponse.name);
|
|
271
326
|
const call = index >= 0 ? open.splice(index, 1)[0] : null;
|
|
272
327
|
messages.push({ role: "tool", tool_call_id: part.functionResponse.id || call?.id || `call_${counter++}`,
|
|
273
328
|
content: JSON.stringify(part.functionResponse.response ?? {}) });
|
|
274
329
|
}
|
|
275
|
-
if (words || !results.length) messages.push({ role: "user", content: words });
|
|
330
|
+
if ((typeof words === "string" ? words : words.length) || !results.length) messages.push({ role: "user", content: words });
|
|
276
331
|
}
|
|
277
332
|
const config = body.generationConfig || body.generation_config || {};
|
|
278
333
|
const options = {};
|
package/src/web/console.html
CHANGED
|
@@ -342,7 +342,7 @@ $("send").onclick = async () => {
|
|
|
342
342
|
};
|
|
343
343
|
async function loadModels() {
|
|
344
344
|
const data = await fetch("/v1/models").then((r) => r.json());
|
|
345
|
-
$("model").innerHTML = data.data.map((m) => `<option>${m.id}</option>`).join("") || "<option>gpt-
|
|
345
|
+
$("model").innerHTML = data.data.map((m) => `<option>${m.id}</option>`).join("") || "<option>gpt-6.1-sol</option>";
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
// ---------------- history ----------------
|