@dexto/server 1.6.20 → 1.6.22
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/dist/a2a/jsonrpc/methods.cjs +1 -1
- package/dist/a2a/jsonrpc/methods.d.ts +14 -4
- package/dist/a2a/jsonrpc/methods.d.ts.map +1 -1
- package/dist/a2a/jsonrpc/methods.js +1 -1
- package/dist/approval/wire-approval-events.cjs +44 -0
- package/dist/approval/wire-approval-events.d.ts +4 -0
- package/dist/approval/wire-approval-events.d.ts.map +1 -0
- package/dist/approval/wire-approval-events.js +20 -0
- package/dist/events/session-sse-subscriber.cjs +167 -0
- package/dist/events/session-sse-subscriber.d.ts +13 -0
- package/dist/events/session-sse-subscriber.d.ts.map +1 -0
- package/dist/events/session-sse-subscriber.js +143 -0
- package/dist/hono/__tests__/test-fixtures.cjs +8 -0
- package/dist/hono/__tests__/test-fixtures.d.ts +1 -0
- package/dist/hono/__tests__/test-fixtures.d.ts.map +1 -1
- package/dist/hono/__tests__/test-fixtures.js +8 -0
- package/dist/hono/index.cjs +40 -8
- package/dist/hono/index.d.ts +45 -4531
- package/dist/hono/index.d.ts.map +1 -1
- package/dist/hono/index.js +43 -9
- package/dist/hono/node/index.cjs +51 -6
- package/dist/hono/node/index.d.ts.map +1 -1
- package/dist/hono/node/index.js +51 -6
- package/dist/hono/routes/a2a-jsonrpc.d.ts.map +1 -1
- package/dist/hono/routes/a2a-tasks.cjs +158 -32
- package/dist/hono/routes/a2a-tasks.d.ts +1 -502
- package/dist/hono/routes/a2a-tasks.d.ts.map +1 -1
- package/dist/hono/routes/a2a-tasks.js +162 -32
- package/dist/hono/routes/a2a.d.ts.map +1 -1
- package/dist/hono/routes/agents.cjs +410 -329
- package/dist/hono/routes/agents.d.ts +16043 -68
- package/dist/hono/routes/agents.d.ts.map +1 -1
- package/dist/hono/routes/agents.js +418 -330
- package/dist/hono/routes/approvals.cjs +102 -88
- package/dist/hono/routes/approvals.d.ts +2089 -142
- package/dist/hono/routes/approvals.d.ts.map +1 -1
- package/dist/hono/routes/approvals.js +108 -89
- package/dist/hono/routes/dexto-auth.cjs +40 -33
- package/dist/hono/routes/dexto-auth.d.ts +401 -2
- package/dist/hono/routes/dexto-auth.d.ts.map +1 -1
- package/dist/hono/routes/dexto-auth.js +40 -33
- package/dist/hono/routes/discovery.cjs +16 -14
- package/dist/hono/routes/discovery.d.ts +586 -1
- package/dist/hono/routes/discovery.d.ts.map +1 -1
- package/dist/hono/routes/discovery.js +16 -14
- package/dist/hono/routes/greeting.cjs +26 -22
- package/dist/hono/routes/greeting.d.ts +787 -3
- package/dist/hono/routes/greeting.d.ts.map +1 -1
- package/dist/hono/routes/greeting.js +26 -22
- package/dist/hono/routes/health.d.ts +1 -1
- package/dist/hono/routes/key.cjs +60 -52
- package/dist/hono/routes/key.d.ts +1597 -1
- package/dist/hono/routes/key.d.ts.map +1 -1
- package/dist/hono/routes/key.js +60 -52
- package/dist/hono/routes/llm.cjs +382 -349
- package/dist/hono/routes/llm.d.ts +12148 -98
- package/dist/hono/routes/llm.d.ts.map +1 -1
- package/dist/hono/routes/llm.js +386 -349
- package/dist/hono/routes/mcp.cjs +257 -226
- package/dist/hono/routes/mcp.d.ts +6605 -309
- package/dist/hono/routes/mcp.d.ts.map +1 -1
- package/dist/hono/routes/mcp.js +263 -225
- package/dist/hono/routes/memory.cjs +102 -89
- package/dist/hono/routes/memory.d.ts +5368 -4
- package/dist/hono/routes/memory.d.ts.map +1 -1
- package/dist/hono/routes/memory.js +108 -90
- package/dist/hono/routes/messages.cjs +189 -191
- package/dist/hono/routes/messages.d.ts +3900 -12
- package/dist/hono/routes/messages.d.ts.map +1 -1
- package/dist/hono/routes/messages.js +192 -191
- package/dist/hono/routes/models.cjs +106 -64
- package/dist/hono/routes/models.d.ts +2875 -2
- package/dist/hono/routes/models.d.ts.map +1 -1
- package/dist/hono/routes/models.js +108 -64
- package/dist/hono/routes/openrouter.cjs +79 -65
- package/dist/hono/routes/openrouter.d.ts +854 -1
- package/dist/hono/routes/openrouter.d.ts.map +1 -1
- package/dist/hono/routes/openrouter.js +79 -65
- package/dist/hono/routes/prompts.cjs +136 -109
- package/dist/hono/routes/prompts.d.ts +2818 -10
- package/dist/hono/routes/prompts.d.ts.map +1 -1
- package/dist/hono/routes/prompts.js +138 -109
- package/dist/hono/routes/queue.cjs +133 -120
- package/dist/hono/routes/queue.d.ts +5240 -11
- package/dist/hono/routes/queue.d.ts.map +1 -1
- package/dist/hono/routes/queue.js +136 -120
- package/dist/hono/routes/resources.cjs +65 -46
- package/dist/hono/routes/resources.d.ts +1983 -5
- package/dist/hono/routes/resources.d.ts.map +1 -1
- package/dist/hono/routes/resources.js +72 -47
- package/dist/hono/routes/schedules.cjs +233 -226
- package/dist/hono/routes/schedules.d.ts +4198 -22
- package/dist/hono/routes/schedules.d.ts.map +1 -1
- package/dist/hono/routes/schedules.js +233 -226
- package/dist/hono/routes/search.cjs +34 -30
- package/dist/hono/routes/search.d.ts +3094 -17
- package/dist/hono/routes/search.d.ts.map +1 -1
- package/dist/hono/routes/search.js +40 -31
- package/dist/hono/routes/sessions.cjs +491 -393
- package/dist/hono/routes/sessions.d.ts +18263 -65
- package/dist/hono/routes/sessions.d.ts.map +1 -1
- package/dist/hono/routes/sessions.js +497 -395
- package/dist/hono/routes/static.d.ts.map +1 -1
- package/dist/hono/routes/system-prompt.cjs +57 -61
- package/dist/hono/routes/system-prompt.d.ts +1228 -2
- package/dist/hono/routes/system-prompt.d.ts.map +1 -1
- package/dist/hono/routes/system-prompt.js +58 -62
- package/dist/hono/routes/tools.cjs +29 -34
- package/dist/hono/routes/tools.d.ts +1755 -6
- package/dist/hono/routes/tools.d.ts.map +1 -1
- package/dist/hono/routes/tools.js +33 -33
- package/dist/hono/routes/webhooks.cjs +115 -123
- package/dist/hono/routes/webhooks.d.ts +2501 -11
- package/dist/hono/routes/webhooks.d.ts.map +1 -1
- package/dist/hono/routes/webhooks.js +120 -124
- package/dist/hono/routes/workspaces.cjs +84 -79
- package/dist/hono/routes/workspaces.d.ts +2093 -2
- package/dist/hono/routes/workspaces.d.ts.map +1 -1
- package/dist/hono/routes/workspaces.js +89 -80
- package/dist/hono/schemas/responses.cjs +463 -260
- package/dist/hono/schemas/responses.d.ts +1893 -209
- package/dist/hono/schemas/responses.d.ts.map +1 -1
- package/dist/hono/schemas/responses.js +203 -14
- package/dist/hono/start-server.cjs +9 -0
- package/dist/hono/start-server.d.ts.map +1 -1
- package/dist/hono/start-server.js +9 -0
- package/dist/hono/types.d.ts +11 -0
- package/dist/hono/types.d.ts.map +1 -1
- package/dist/index.cjs +5 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/package.json +7 -7
package/dist/hono/routes/llm.js
CHANGED
|
@@ -30,9 +30,13 @@ import {
|
|
|
30
30
|
isDextoAuthEnabled
|
|
31
31
|
} from "@dexto/agent-management";
|
|
32
32
|
import {
|
|
33
|
+
BadRequestErrorResponse,
|
|
34
|
+
ConflictErrorResponse,
|
|
35
|
+
InternalErrorResponse,
|
|
33
36
|
ProviderCatalogSchema,
|
|
34
37
|
ModelFlatSchema,
|
|
35
38
|
LLMConfigResponseSchema,
|
|
39
|
+
NotFoundErrorResponse,
|
|
36
40
|
StandardErrorEnvelopeSchema
|
|
37
41
|
} from "../schemas/responses.js";
|
|
38
42
|
const MODEL_PICKER_FEATURED_LIMIT = 8;
|
|
@@ -52,7 +56,7 @@ const CatalogQuerySchema = z.object({
|
|
|
52
56
|
hasKey: z.union([z.literal("true"), z.literal("false"), z.literal("1"), z.literal("0")]).optional().transform(
|
|
53
57
|
(raw) => raw === "true" || raw === "1" ? true : raw === "false" || raw === "0" ? false : void 0
|
|
54
58
|
).describe("Filter by API key presence (true or false)"),
|
|
55
|
-
fileType: z.enum(SUPPORTED_FILE_TYPES).optional().describe("Filter by supported file type (audio, pdf, or
|
|
59
|
+
fileType: z.enum(SUPPORTED_FILE_TYPES).optional().describe("Filter by supported file type (audio, pdf, image, video, or document)"),
|
|
56
60
|
defaultOnly: z.union([z.literal("true"), z.literal("false"), z.literal("1"), z.literal("0")]).optional().transform(
|
|
57
61
|
(raw) => raw === "true" || raw === "1" ? true : raw === "false" || raw === "0" ? false : void 0
|
|
58
62
|
).describe("Include only default models (true or false)"),
|
|
@@ -105,356 +109,374 @@ const ModelPickerErrorResponses = {
|
|
|
105
109
|
}
|
|
106
110
|
}
|
|
107
111
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
112
|
+
const CapabilitiesQuerySchema = z.object({
|
|
113
|
+
provider: z.enum(LLM_PROVIDERS).describe("LLM provider name"),
|
|
114
|
+
model: z.string().min(1).describe("Model name (supports both native and OpenRouter format)")
|
|
115
|
+
}).strict().describe("Query parameters for model capability lookup");
|
|
116
|
+
const SetFavoritesBodySchema = z.object({
|
|
117
|
+
favorites: z.array(ModelPickerModelRefSchema).describe("Complete list of favorite model references")
|
|
118
|
+
}).strict().describe("Request body for setting favorite models");
|
|
119
|
+
const currentRoute = createRoute({
|
|
120
|
+
method: "get",
|
|
121
|
+
path: "/llm/current",
|
|
122
|
+
summary: "Get Current LLM Config",
|
|
123
|
+
description: "Retrieves the current LLM configuration for the agent or a specific session",
|
|
124
|
+
tags: ["llm"],
|
|
125
|
+
request: { query: CurrentQuerySchema },
|
|
126
|
+
responses: {
|
|
127
|
+
200: {
|
|
128
|
+
description: "Current LLM config",
|
|
129
|
+
content: {
|
|
130
|
+
"application/json": {
|
|
131
|
+
schema: z.object({
|
|
132
|
+
config: LLMConfigResponseSchema.partial({
|
|
133
|
+
maxIterations: true
|
|
134
|
+
}).extend({
|
|
135
|
+
displayName: z.string().optional().describe("Human-readable model display name")
|
|
136
|
+
}),
|
|
137
|
+
routing: z.object({
|
|
138
|
+
viaDexto: z.boolean().describe("Whether requests route through Dexto gateway")
|
|
139
|
+
}).describe("Routing information for the current LLM configuration")
|
|
140
|
+
}).describe("Response containing current LLM configuration")
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
400: BadRequestErrorResponse,
|
|
145
|
+
404: NotFoundErrorResponse,
|
|
146
|
+
500: InternalErrorResponse
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
const catalogRoute = createRoute({
|
|
150
|
+
method: "get",
|
|
151
|
+
path: "/llm/catalog",
|
|
152
|
+
summary: "LLM Catalog",
|
|
153
|
+
description: "Providers, models, capabilities, and API key status",
|
|
154
|
+
tags: ["llm"],
|
|
155
|
+
request: { query: CatalogQuerySchema },
|
|
156
|
+
responses: {
|
|
157
|
+
200: {
|
|
158
|
+
description: "LLM catalog",
|
|
159
|
+
content: {
|
|
160
|
+
"application/json": {
|
|
161
|
+
schema: z.union([
|
|
162
|
+
z.object({
|
|
163
|
+
providers: z.record(z.enum(LLM_PROVIDERS), ProviderCatalogSchema).describe(
|
|
164
|
+
"Providers grouped by ID with their models and capabilities"
|
|
165
|
+
)
|
|
166
|
+
}).strict().describe("Grouped catalog response (mode=grouped)"),
|
|
167
|
+
z.object({
|
|
168
|
+
models: z.array(ModelFlatSchema).describe(
|
|
169
|
+
"Flat list of all models with provider information"
|
|
134
170
|
)
|
|
135
|
-
}).describe("
|
|
136
|
-
|
|
171
|
+
}).strict().describe("Flat catalog response (mode=flat)")
|
|
172
|
+
]).describe(
|
|
173
|
+
"LLM catalog in grouped or flat format based on mode query parameter"
|
|
174
|
+
)
|
|
137
175
|
}
|
|
138
176
|
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
"Providers grouped by ID with their models and capabilities"
|
|
157
|
-
)
|
|
158
|
-
}).strict().describe("Grouped catalog response (mode=grouped)"),
|
|
159
|
-
z.object({
|
|
160
|
-
models: z.array(ModelFlatSchema).describe(
|
|
161
|
-
"Flat list of all models with provider information"
|
|
162
|
-
)
|
|
163
|
-
}).strict().describe("Flat catalog response (mode=flat)")
|
|
164
|
-
]).describe(
|
|
165
|
-
"LLM catalog in grouped or flat format based on mode query parameter"
|
|
166
|
-
)
|
|
167
|
-
}
|
|
177
|
+
},
|
|
178
|
+
400: BadRequestErrorResponse,
|
|
179
|
+
404: NotFoundErrorResponse,
|
|
180
|
+
500: InternalErrorResponse
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
const switchRoute = createRoute({
|
|
184
|
+
method: "post",
|
|
185
|
+
path: "/llm/switch",
|
|
186
|
+
summary: "Switch LLM",
|
|
187
|
+
description: "Switches the LLM configuration for the agent or a specific session",
|
|
188
|
+
tags: ["llm"],
|
|
189
|
+
request: {
|
|
190
|
+
body: {
|
|
191
|
+
content: {
|
|
192
|
+
"application/json": {
|
|
193
|
+
schema: SwitchLLMBodySchema
|
|
168
194
|
}
|
|
169
195
|
}
|
|
170
196
|
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
197
|
+
},
|
|
198
|
+
responses: {
|
|
199
|
+
200: {
|
|
200
|
+
description: "LLM switch result",
|
|
201
|
+
content: {
|
|
202
|
+
"application/json": {
|
|
203
|
+
schema: z.object({
|
|
204
|
+
config: LLMConfigResponseSchema.describe(
|
|
205
|
+
"New LLM configuration with all defaults applied (apiKey omitted)"
|
|
206
|
+
),
|
|
207
|
+
sessionId: z.string().optional().describe("Session ID if session-specific switch")
|
|
208
|
+
}).describe("LLM switch result")
|
|
184
209
|
}
|
|
185
210
|
}
|
|
186
211
|
},
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
212
|
+
400: BadRequestErrorResponse,
|
|
213
|
+
404: NotFoundErrorResponse,
|
|
214
|
+
409: ConflictErrorResponse,
|
|
215
|
+
500: InternalErrorResponse
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
const listCustomModelsRoute = createRoute({
|
|
219
|
+
method: "get",
|
|
220
|
+
path: "/llm/custom-models",
|
|
221
|
+
summary: "List Custom Models",
|
|
222
|
+
description: "Returns all saved custom openai-compatible model configurations",
|
|
223
|
+
tags: ["llm"],
|
|
224
|
+
responses: {
|
|
225
|
+
200: {
|
|
226
|
+
description: "List of custom models",
|
|
227
|
+
content: {
|
|
228
|
+
"application/json": {
|
|
229
|
+
schema: z.object({
|
|
230
|
+
models: z.array(CustomModelSchema).describe("List of custom models")
|
|
231
|
+
})
|
|
199
232
|
}
|
|
200
233
|
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
234
|
+
},
|
|
235
|
+
400: BadRequestErrorResponse,
|
|
236
|
+
404: NotFoundErrorResponse,
|
|
237
|
+
500: InternalErrorResponse
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
const createCustomModelRoute = createRoute({
|
|
241
|
+
method: "post",
|
|
242
|
+
path: "/llm/custom-models",
|
|
243
|
+
summary: "Create Custom Model",
|
|
244
|
+
description: "Saves a new custom openai-compatible model configuration",
|
|
245
|
+
tags: ["llm"],
|
|
246
|
+
request: {
|
|
247
|
+
body: { content: { "application/json": { schema: CustomModelSchema } } }
|
|
248
|
+
},
|
|
249
|
+
responses: {
|
|
250
|
+
200: {
|
|
251
|
+
description: "Custom model saved",
|
|
252
|
+
content: {
|
|
253
|
+
"application/json": {
|
|
254
|
+
schema: z.object({
|
|
255
|
+
ok: z.literal(true).describe("Success indicator"),
|
|
256
|
+
model: CustomModelSchema
|
|
257
|
+
})
|
|
218
258
|
}
|
|
219
259
|
}
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
const createCustomModelRoute = createRoute({
|
|
223
|
-
method: "post",
|
|
224
|
-
path: "/llm/custom-models",
|
|
225
|
-
summary: "Create Custom Model",
|
|
226
|
-
description: "Saves a new custom openai-compatible model configuration",
|
|
227
|
-
tags: ["llm"],
|
|
228
|
-
request: {
|
|
229
|
-
body: { content: { "application/json": { schema: CustomModelSchema } } }
|
|
230
260
|
},
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
261
|
+
400: BadRequestErrorResponse,
|
|
262
|
+
404: NotFoundErrorResponse,
|
|
263
|
+
409: ConflictErrorResponse,
|
|
264
|
+
500: InternalErrorResponse
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
const deleteCustomModelRoute = createRoute({
|
|
268
|
+
method: "delete",
|
|
269
|
+
path: "/llm/custom-models/{name}",
|
|
270
|
+
summary: "Delete Custom Model",
|
|
271
|
+
description: "Deletes a custom model by name",
|
|
272
|
+
tags: ["llm"],
|
|
273
|
+
request: {
|
|
274
|
+
params: z.object({
|
|
275
|
+
name: z.string().min(1).describe("Model name to delete")
|
|
276
|
+
})
|
|
277
|
+
},
|
|
278
|
+
responses: {
|
|
279
|
+
200: {
|
|
280
|
+
description: "Custom model deleted",
|
|
281
|
+
content: {
|
|
282
|
+
"application/json": {
|
|
283
|
+
schema: z.object({
|
|
284
|
+
ok: z.literal(true).describe("Success indicator"),
|
|
285
|
+
deleted: z.string().describe("Name of the deleted model")
|
|
286
|
+
})
|
|
241
287
|
}
|
|
242
288
|
}
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
const deleteCustomModelRoute = createRoute({
|
|
246
|
-
method: "delete",
|
|
247
|
-
path: "/llm/custom-models/{name}",
|
|
248
|
-
summary: "Delete Custom Model",
|
|
249
|
-
description: "Deletes a custom model by name",
|
|
250
|
-
tags: ["llm"],
|
|
251
|
-
request: {
|
|
252
|
-
params: z.object({
|
|
253
|
-
name: z.string().min(1).describe("Model name to delete")
|
|
254
|
-
})
|
|
255
289
|
},
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
290
|
+
400: BadRequestErrorResponse,
|
|
291
|
+
404: NotFoundErrorResponse,
|
|
292
|
+
500: InternalErrorResponse
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
const capabilitiesRoute = createRoute({
|
|
296
|
+
method: "get",
|
|
297
|
+
path: "/llm/capabilities",
|
|
298
|
+
summary: "Get Model Capabilities",
|
|
299
|
+
description: "Returns the capabilities (supported file types) for a specific provider/model combination. Handles gateway providers (dexto-nova, openrouter) by resolving to the underlying model capabilities.",
|
|
300
|
+
tags: ["llm"],
|
|
301
|
+
request: {
|
|
302
|
+
query: CapabilitiesQuerySchema
|
|
303
|
+
},
|
|
304
|
+
responses: {
|
|
305
|
+
200: {
|
|
306
|
+
description: "Model capabilities",
|
|
307
|
+
content: {
|
|
308
|
+
"application/json": {
|
|
309
|
+
schema: z.object({
|
|
310
|
+
provider: z.enum(LLM_PROVIDERS).describe("Provider name"),
|
|
311
|
+
model: z.string().describe("Model name as provided"),
|
|
312
|
+
supportedFileTypes: z.array(z.enum(SUPPORTED_FILE_TYPES)).describe("File types supported by this model"),
|
|
313
|
+
reasoning: z.object({
|
|
314
|
+
capable: z.boolean().describe(
|
|
315
|
+
"Whether Dexto considers this provider/model reasoning-capable (derived from registry metadata plus explicit provider/model rules)"
|
|
316
|
+
),
|
|
317
|
+
paradigm: z.enum([
|
|
318
|
+
"effort",
|
|
319
|
+
"adaptive-effort",
|
|
320
|
+
"thinking-level",
|
|
321
|
+
"budget",
|
|
322
|
+
"none"
|
|
323
|
+
]).describe("Reasoning control paradigm for this model"),
|
|
324
|
+
variants: z.array(
|
|
325
|
+
z.object({
|
|
326
|
+
id: z.string().describe(
|
|
327
|
+
"Native reasoning variant identifier"
|
|
328
|
+
),
|
|
329
|
+
label: z.string().describe(
|
|
330
|
+
"Display label for the native reasoning variant"
|
|
331
|
+
)
|
|
332
|
+
}).strict()
|
|
333
|
+
).describe("Native reasoning variants exposed to users"),
|
|
334
|
+
supportedVariants: z.array(z.string()).describe(
|
|
335
|
+
"Native reasoning variant IDs supported for this model/provider"
|
|
336
|
+
),
|
|
337
|
+
defaultVariant: z.string().optional().describe(
|
|
338
|
+
"Default reasoning variant used when no explicit override is set"
|
|
339
|
+
),
|
|
340
|
+
supportsBudgetTokens: z.boolean().describe(
|
|
341
|
+
"Whether this provider/model supports a budgetTokens-style escape hatch"
|
|
342
|
+
)
|
|
343
|
+
}).strict().describe(
|
|
344
|
+
"Reasoning tuning capabilities derived from registry metadata and explicit provider/model rules"
|
|
345
|
+
)
|
|
346
|
+
})
|
|
277
347
|
}
|
|
278
348
|
}
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
const capabilitiesRoute = createRoute({
|
|
282
|
-
method: "get",
|
|
283
|
-
path: "/llm/capabilities",
|
|
284
|
-
summary: "Get Model Capabilities",
|
|
285
|
-
description: "Returns the capabilities (supported file types) for a specific provider/model combination. Handles gateway providers (dexto-nova, openrouter) by resolving to the underlying model capabilities.",
|
|
286
|
-
tags: ["llm"],
|
|
287
|
-
request: {
|
|
288
|
-
query: z.object({
|
|
289
|
-
provider: z.enum(LLM_PROVIDERS).describe("LLM provider name"),
|
|
290
|
-
model: z.string().min(1).describe("Model name (supports both native and OpenRouter format)")
|
|
291
|
-
})
|
|
292
349
|
},
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
id: z.string().describe(
|
|
316
|
-
"Native reasoning variant identifier"
|
|
317
|
-
),
|
|
318
|
-
label: z.string().describe(
|
|
319
|
-
"Display label for the native reasoning variant"
|
|
320
|
-
)
|
|
321
|
-
}).strict()
|
|
322
|
-
).describe("Native reasoning variants exposed to users"),
|
|
323
|
-
supportedVariants: z.array(z.string()).describe(
|
|
324
|
-
"Native reasoning variant IDs supported for this model/provider"
|
|
325
|
-
),
|
|
326
|
-
defaultVariant: z.string().optional().describe(
|
|
327
|
-
"Default reasoning variant used when no explicit override is set"
|
|
328
|
-
),
|
|
329
|
-
supportsBudgetTokens: z.boolean().describe(
|
|
330
|
-
"Whether this provider/model supports a budgetTokens-style escape hatch"
|
|
331
|
-
)
|
|
332
|
-
}).strict().describe(
|
|
333
|
-
"Reasoning tuning capabilities derived from registry metadata and explicit provider/model rules"
|
|
334
|
-
)
|
|
335
|
-
})
|
|
336
|
-
}
|
|
350
|
+
400: BadRequestErrorResponse,
|
|
351
|
+
404: NotFoundErrorResponse,
|
|
352
|
+
500: InternalErrorResponse
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
const modelPickerStateRoute = createRoute({
|
|
356
|
+
method: "get",
|
|
357
|
+
path: "/llm/model-picker-state",
|
|
358
|
+
summary: "Model Picker State",
|
|
359
|
+
description: "Returns hydrated Featured, Recents, Favorites, and Custom sections for the model picker.",
|
|
360
|
+
tags: ["llm"],
|
|
361
|
+
responses: {
|
|
362
|
+
200: {
|
|
363
|
+
description: "Hydrated model picker sections",
|
|
364
|
+
content: {
|
|
365
|
+
"application/json": {
|
|
366
|
+
schema: z.object({
|
|
367
|
+
featured: z.array(ModelPickerEntrySchema).describe("Curated featured models"),
|
|
368
|
+
recents: z.array(ModelPickerEntrySchema).describe("Most recently used models"),
|
|
369
|
+
favorites: z.array(ModelPickerEntrySchema).describe("User favorited models"),
|
|
370
|
+
custom: z.array(ModelPickerEntrySchema).describe("User-defined custom models")
|
|
371
|
+
}).strict()
|
|
337
372
|
}
|
|
338
373
|
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}).strict()
|
|
358
|
-
}
|
|
374
|
+
},
|
|
375
|
+
400: ModelPickerErrorResponses[400],
|
|
376
|
+
404: ModelPickerErrorResponses[404],
|
|
377
|
+
500: ModelPickerErrorResponses[500]
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
const recordRecentModelRoute = createRoute({
|
|
381
|
+
method: "post",
|
|
382
|
+
path: "/llm/model-picker-state/recents",
|
|
383
|
+
summary: "Record Recent Model",
|
|
384
|
+
description: "Records a model selection in recents.",
|
|
385
|
+
tags: ["llm"],
|
|
386
|
+
request: {
|
|
387
|
+
body: {
|
|
388
|
+
required: true,
|
|
389
|
+
content: {
|
|
390
|
+
"application/json": {
|
|
391
|
+
schema: ModelPickerModelRefSchema
|
|
359
392
|
}
|
|
360
|
-
}
|
|
361
|
-
...ModelPickerErrorResponses
|
|
393
|
+
}
|
|
362
394
|
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
required: true,
|
|
373
|
-
content: {
|
|
374
|
-
"application/json": {
|
|
375
|
-
schema: ModelPickerModelRefSchema
|
|
376
|
-
}
|
|
395
|
+
},
|
|
396
|
+
responses: {
|
|
397
|
+
200: {
|
|
398
|
+
description: "Recent model recorded",
|
|
399
|
+
content: {
|
|
400
|
+
"application/json": {
|
|
401
|
+
schema: z.object({
|
|
402
|
+
ok: z.literal(true).describe("Success indicator")
|
|
403
|
+
}).strict()
|
|
377
404
|
}
|
|
378
405
|
}
|
|
379
406
|
},
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
407
|
+
400: ModelPickerErrorResponses[400],
|
|
408
|
+
404: ModelPickerErrorResponses[404],
|
|
409
|
+
500: ModelPickerErrorResponses[500]
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
const toggleFavoriteModelRoute = createRoute({
|
|
413
|
+
method: "post",
|
|
414
|
+
path: "/llm/model-picker-state/favorites/toggle",
|
|
415
|
+
summary: "Toggle Favorite Model",
|
|
416
|
+
description: "Adds or removes a model from favorites.",
|
|
417
|
+
tags: ["llm"],
|
|
418
|
+
request: {
|
|
419
|
+
body: {
|
|
420
|
+
required: true,
|
|
421
|
+
content: {
|
|
422
|
+
"application/json": {
|
|
423
|
+
schema: ModelPickerModelRefSchema
|
|
389
424
|
}
|
|
390
|
-
}
|
|
391
|
-
...ModelPickerErrorResponses
|
|
425
|
+
}
|
|
392
426
|
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
content: {
|
|
404
|
-
"application/json": {
|
|
405
|
-
schema: ModelPickerModelRefSchema
|
|
406
|
-
}
|
|
427
|
+
},
|
|
428
|
+
responses: {
|
|
429
|
+
200: {
|
|
430
|
+
description: "Favorite toggled",
|
|
431
|
+
content: {
|
|
432
|
+
"application/json": {
|
|
433
|
+
schema: z.object({
|
|
434
|
+
ok: z.literal(true).describe("Success indicator"),
|
|
435
|
+
isFavorite: z.boolean().describe("Whether the model is now favorited")
|
|
436
|
+
}).strict()
|
|
407
437
|
}
|
|
408
438
|
}
|
|
409
439
|
},
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
440
|
+
400: ModelPickerErrorResponses[400],
|
|
441
|
+
404: ModelPickerErrorResponses[404],
|
|
442
|
+
500: ModelPickerErrorResponses[500]
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
const setFavoritesRoute = createRoute({
|
|
446
|
+
method: "put",
|
|
447
|
+
path: "/llm/model-picker-state/favorites",
|
|
448
|
+
summary: "Set Favorite Models",
|
|
449
|
+
description: "Replaces favorite models list. Used by migration or bulk updates.",
|
|
450
|
+
tags: ["llm"],
|
|
451
|
+
request: {
|
|
452
|
+
body: {
|
|
453
|
+
required: true,
|
|
454
|
+
content: {
|
|
455
|
+
"application/json": {
|
|
456
|
+
schema: SetFavoritesBodySchema
|
|
420
457
|
}
|
|
421
|
-
}
|
|
422
|
-
...ModelPickerErrorResponses
|
|
458
|
+
}
|
|
423
459
|
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
content: {
|
|
435
|
-
"application/json": {
|
|
436
|
-
schema: z.object({
|
|
437
|
-
favorites: z.array(ModelPickerModelRefSchema).describe("Complete list of favorite model references")
|
|
438
|
-
}).strict()
|
|
439
|
-
}
|
|
460
|
+
},
|
|
461
|
+
responses: {
|
|
462
|
+
200: {
|
|
463
|
+
description: "Favorites updated",
|
|
464
|
+
content: {
|
|
465
|
+
"application/json": {
|
|
466
|
+
schema: z.object({
|
|
467
|
+
ok: z.literal(true).describe("Success indicator"),
|
|
468
|
+
count: z.number().int().nonnegative().describe("Number of favorites persisted")
|
|
469
|
+
}).strict()
|
|
440
470
|
}
|
|
441
471
|
}
|
|
442
472
|
},
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
count: z.number().int().nonnegative().describe("Number of favorites persisted")
|
|
451
|
-
}).strict()
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
},
|
|
455
|
-
...ModelPickerErrorResponses
|
|
456
|
-
}
|
|
457
|
-
});
|
|
473
|
+
400: ModelPickerErrorResponses[400],
|
|
474
|
+
404: ModelPickerErrorResponses[404],
|
|
475
|
+
500: ModelPickerErrorResponses[500]
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
function createLlmRouter(getAgent) {
|
|
479
|
+
const app = new OpenAPIHono();
|
|
458
480
|
const isProviderEnabled = (provider) => provider !== "dexto-nova" || isDextoAuthEnabled();
|
|
459
481
|
const dedupeEntries = (entries) => {
|
|
460
482
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -594,16 +616,19 @@ function createLlmRouter(getAgent) {
|
|
|
594
616
|
}
|
|
595
617
|
const { apiKey, ...configWithoutKey } = currentConfig;
|
|
596
618
|
const viaDexto = isDextoAuthEnabled() && currentConfig.provider === "dexto-nova";
|
|
597
|
-
return ctx.json(
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
619
|
+
return ctx.json(
|
|
620
|
+
{
|
|
621
|
+
config: {
|
|
622
|
+
...configWithoutKey,
|
|
623
|
+
hasApiKey: !!apiKey,
|
|
624
|
+
...displayName && { displayName }
|
|
625
|
+
},
|
|
626
|
+
routing: {
|
|
627
|
+
viaDexto
|
|
628
|
+
}
|
|
602
629
|
},
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
}
|
|
606
|
-
});
|
|
630
|
+
200
|
|
631
|
+
);
|
|
607
632
|
}).openapi(catalogRoute, (ctx) => {
|
|
608
633
|
const queryParams = ctx.req.valid("query");
|
|
609
634
|
const includeModels = queryParams.includeModels ?? true;
|
|
@@ -686,9 +711,9 @@ function createLlmRouter(getAgent) {
|
|
|
686
711
|
flat.push({ provider: id, ...model });
|
|
687
712
|
}
|
|
688
713
|
}
|
|
689
|
-
return ctx.json({ models: flat });
|
|
714
|
+
return ctx.json({ models: flat }, 200);
|
|
690
715
|
}
|
|
691
|
-
return ctx.json({ providers: filtered });
|
|
716
|
+
return ctx.json({ providers: filtered }, 200);
|
|
692
717
|
}).openapi(switchRoute, async (ctx) => {
|
|
693
718
|
const agent = await getAgent(ctx);
|
|
694
719
|
const raw = ctx.req.valid("json");
|
|
@@ -703,20 +728,23 @@ function createLlmRouter(getAgent) {
|
|
|
703
728
|
} catch {
|
|
704
729
|
}
|
|
705
730
|
const { apiKey, ...configWithoutKey } = config;
|
|
706
|
-
return ctx.json(
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
731
|
+
return ctx.json(
|
|
732
|
+
{
|
|
733
|
+
config: {
|
|
734
|
+
...configWithoutKey,
|
|
735
|
+
hasApiKey: !!apiKey
|
|
736
|
+
},
|
|
737
|
+
sessionId
|
|
710
738
|
},
|
|
711
|
-
|
|
712
|
-
|
|
739
|
+
200
|
|
740
|
+
);
|
|
713
741
|
}).openapi(listCustomModelsRoute, async (ctx) => {
|
|
714
742
|
const models = await loadCustomModels();
|
|
715
|
-
return ctx.json({ models });
|
|
743
|
+
return ctx.json({ models }, 200);
|
|
716
744
|
}).openapi(createCustomModelRoute, async (ctx) => {
|
|
717
745
|
const model = ctx.req.valid("json");
|
|
718
746
|
await saveCustomModel(model);
|
|
719
|
-
return ctx.json({ ok: true, model });
|
|
747
|
+
return ctx.json({ ok: true, model }, 200);
|
|
720
748
|
}).openapi(deleteCustomModelRoute, async (ctx) => {
|
|
721
749
|
const { name: encodedName } = ctx.req.valid("param");
|
|
722
750
|
const name = decodeURIComponent(encodedName);
|
|
@@ -733,27 +761,33 @@ function createLlmRouter(getAgent) {
|
|
|
733
761
|
return ctx.json({ ok: true, deleted: name }, 200);
|
|
734
762
|
}).openapi(modelPickerStateRoute, async (ctx) => {
|
|
735
763
|
const sections = await buildModelPickerSections();
|
|
736
|
-
return ctx.json(sections);
|
|
764
|
+
return ctx.json(sections, 200);
|
|
737
765
|
}).openapi(recordRecentModelRoute, async (ctx) => {
|
|
738
766
|
const modelRef = ctx.req.valid("json");
|
|
739
767
|
await recordRecentModel(modelRef);
|
|
740
|
-
return ctx.json({ ok: true });
|
|
768
|
+
return ctx.json({ ok: true }, 200);
|
|
741
769
|
}).openapi(toggleFavoriteModelRoute, async (ctx) => {
|
|
742
770
|
const modelRef = ctx.req.valid("json");
|
|
743
771
|
const result = await toggleFavoriteModel(modelRef);
|
|
744
|
-
return ctx.json(
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
772
|
+
return ctx.json(
|
|
773
|
+
{
|
|
774
|
+
ok: true,
|
|
775
|
+
isFavorite: result.isFavorite
|
|
776
|
+
},
|
|
777
|
+
200
|
|
778
|
+
);
|
|
748
779
|
}).openapi(setFavoritesRoute, async (ctx) => {
|
|
749
780
|
const payload = ctx.req.valid("json");
|
|
750
781
|
const state = await setFavoriteModels({
|
|
751
782
|
favorites: payload.favorites
|
|
752
783
|
});
|
|
753
|
-
return ctx.json(
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
784
|
+
return ctx.json(
|
|
785
|
+
{
|
|
786
|
+
ok: true,
|
|
787
|
+
count: state.favorites.length
|
|
788
|
+
},
|
|
789
|
+
200
|
|
790
|
+
);
|
|
757
791
|
}).openapi(capabilitiesRoute, (ctx) => {
|
|
758
792
|
const { provider, model } = ctx.req.valid("query");
|
|
759
793
|
let supportedFileTypes;
|
|
@@ -764,12 +798,15 @@ function createLlmRouter(getAgent) {
|
|
|
764
798
|
supportedFileTypes = providerInfo?.supportedFileTypes ?? [];
|
|
765
799
|
}
|
|
766
800
|
const reasoning = getReasoningProfile(provider, model);
|
|
767
|
-
return ctx.json(
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
801
|
+
return ctx.json(
|
|
802
|
+
{
|
|
803
|
+
provider,
|
|
804
|
+
model,
|
|
805
|
+
supportedFileTypes,
|
|
806
|
+
reasoning
|
|
807
|
+
},
|
|
808
|
+
200
|
|
809
|
+
);
|
|
773
810
|
});
|
|
774
811
|
}
|
|
775
812
|
export {
|