@dexto/server 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/approval/manual-approval-handler.cjs +23 -15
  2. package/dist/approval/manual-approval-handler.d.ts.map +1 -1
  3. package/dist/approval/manual-approval-handler.js +23 -15
  4. package/dist/events/webhook-subscriber.cjs +1 -1
  5. package/dist/events/webhook-subscriber.d.ts.map +1 -1
  6. package/dist/events/webhook-subscriber.js +1 -1
  7. package/dist/hono/__tests__/test-fixtures.cjs +2 -2
  8. package/dist/hono/__tests__/test-fixtures.d.ts.map +1 -1
  9. package/dist/hono/__tests__/test-fixtures.js +2 -2
  10. package/dist/hono/index.cjs +6 -1
  11. package/dist/hono/index.d.ts +433 -88
  12. package/dist/hono/index.d.ts.map +1 -1
  13. package/dist/hono/index.js +6 -1
  14. package/dist/hono/middleware/error.d.ts.map +1 -1
  15. package/dist/hono/routes/agents.cjs +8 -10
  16. package/dist/hono/routes/agents.d.ts +15 -8
  17. package/dist/hono/routes/agents.d.ts.map +1 -1
  18. package/dist/hono/routes/agents.js +10 -10
  19. package/dist/hono/routes/approvals.cjs +52 -1
  20. package/dist/hono/routes/approvals.d.ts +25 -0
  21. package/dist/hono/routes/approvals.d.ts.map +1 -1
  22. package/dist/hono/routes/approvals.js +52 -1
  23. package/dist/hono/routes/llm.cjs +110 -31
  24. package/dist/hono/routes/llm.d.ts +72 -20
  25. package/dist/hono/routes/llm.d.ts.map +1 -1
  26. package/dist/hono/routes/llm.js +108 -25
  27. package/dist/hono/routes/mcp.cjs +8 -4
  28. package/dist/hono/routes/mcp.d.ts +4 -1
  29. package/dist/hono/routes/mcp.d.ts.map +1 -1
  30. package/dist/hono/routes/mcp.js +9 -5
  31. package/dist/hono/routes/memory.d.ts +1 -1
  32. package/dist/hono/routes/messages.cjs +54 -62
  33. package/dist/hono/routes/messages.d.ts +87 -43
  34. package/dist/hono/routes/messages.d.ts.map +1 -1
  35. package/dist/hono/routes/messages.js +55 -63
  36. package/dist/hono/routes/prompts.d.ts +6 -6
  37. package/dist/hono/routes/queue.cjs +202 -0
  38. package/dist/hono/routes/queue.d.ts +171 -0
  39. package/dist/hono/routes/queue.d.ts.map +1 -0
  40. package/dist/hono/routes/queue.js +178 -0
  41. package/dist/hono/routes/resources.d.ts +1 -1
  42. package/dist/hono/routes/search.d.ts +33 -7
  43. package/dist/hono/routes/search.d.ts.map +1 -1
  44. package/dist/hono/routes/sessions.cjs +65 -11
  45. package/dist/hono/routes/sessions.d.ts +22 -1
  46. package/dist/hono/routes/sessions.d.ts.map +1 -1
  47. package/dist/hono/routes/sessions.js +65 -11
  48. package/dist/hono/schemas/responses.cjs +24 -5
  49. package/dist/hono/schemas/responses.d.ts +799 -81
  50. package/dist/hono/schemas/responses.d.ts.map +1 -1
  51. package/dist/hono/schemas/responses.js +24 -10
  52. package/package.json +3 -3
@@ -23,6 +23,7 @@ __export(llm_exports, {
23
23
  module.exports = __toCommonJS(llm_exports);
24
24
  var import_zod_openapi = require("@hono/zod-openapi");
25
25
  var import_core = require("@dexto/core");
26
+ var import_core2 = require("@dexto/core");
26
27
  var import_agent_management = require("@dexto/agent-management");
27
28
  var import_responses = require("../schemas/responses.js");
28
29
  const CurrentQuerySchema = import_zod_openapi.z.object({
@@ -35,18 +36,17 @@ const CatalogQuerySchema = import_zod_openapi.z.object({
35
36
  hasKey: import_zod_openapi.z.union([import_zod_openapi.z.literal("true"), import_zod_openapi.z.literal("false"), import_zod_openapi.z.literal("1"), import_zod_openapi.z.literal("0")]).optional().transform(
36
37
  (raw) => raw === "true" || raw === "1" ? true : raw === "false" || raw === "0" ? false : void 0
37
38
  ).describe("Filter by API key presence (true or false)"),
38
- router: import_zod_openapi.z.enum(import_core.LLM_ROUTERS).optional().describe("Filter by router type (vercel or in-built)"),
39
- fileType: import_zod_openapi.z.enum(import_core.SUPPORTED_FILE_TYPES).optional().describe("Filter by supported file type (audio, pdf, or image)"),
39
+ fileType: import_zod_openapi.z.enum(import_core2.SUPPORTED_FILE_TYPES).optional().describe("Filter by supported file type (audio, pdf, or image)"),
40
40
  defaultOnly: import_zod_openapi.z.union([import_zod_openapi.z.literal("true"), import_zod_openapi.z.literal("false"), import_zod_openapi.z.literal("1"), import_zod_openapi.z.literal("0")]).optional().transform(
41
41
  (raw) => raw === "true" || raw === "1" ? true : raw === "false" || raw === "0" ? false : void 0
42
42
  ).describe("Include only default models (true or false)"),
43
43
  mode: import_zod_openapi.z.enum(["grouped", "flat"]).default("grouped").describe("Response format mode (grouped by provider or flat list)")
44
44
  }).describe("Query parameters for filtering and formatting the LLM catalog");
45
45
  const SaveKeySchema = import_zod_openapi.z.object({
46
- provider: import_zod_openapi.z.enum(import_core.LLM_PROVIDERS).describe("LLM provider identifier (e.g., openai, anthropic)"),
46
+ provider: import_zod_openapi.z.enum(import_core2.LLM_PROVIDERS).describe("LLM provider identifier (e.g., openai, anthropic)"),
47
47
  apiKey: import_zod_openapi.z.string().min(1, "API key is required").describe("API key for the provider (writeOnly - never returned in responses)").openapi({ writeOnly: true })
48
48
  }).describe("Request body for saving a provider API key");
49
- const SwitchLLMBodySchema = import_core.LLMUpdatesSchema.and(
49
+ const SwitchLLMBodySchema = import_core2.LLMUpdatesSchema.and(
50
50
  import_zod_openapi.z.object({
51
51
  sessionId: import_zod_openapi.z.string().optional().describe("Session identifier for session-specific LLM configuration")
52
52
  })
@@ -67,8 +67,7 @@ function createLlmRouter(getAgent) {
67
67
  "application/json": {
68
68
  schema: import_zod_openapi.z.object({
69
69
  config: import_responses.LLMConfigResponseSchema.partial({
70
- maxIterations: true,
71
- router: true
70
+ maxIterations: true
72
71
  }).extend({
73
72
  displayName: import_zod_openapi.z.string().optional().describe("Human-readable model display name")
74
73
  })
@@ -92,7 +91,7 @@ function createLlmRouter(getAgent) {
92
91
  "application/json": {
93
92
  schema: import_zod_openapi.z.union([
94
93
  import_zod_openapi.z.object({
95
- providers: import_zod_openapi.z.record(import_zod_openapi.z.enum(import_core.LLM_PROVIDERS), import_responses.ProviderCatalogSchema).describe(
94
+ providers: import_zod_openapi.z.record(import_zod_openapi.z.enum(import_core2.LLM_PROVIDERS), import_responses.ProviderCatalogSchema).describe(
96
95
  "Providers grouped by ID with their models and capabilities"
97
96
  )
98
97
  }).strict().describe("Grouped catalog response (mode=grouped)"),
@@ -123,7 +122,7 @@ function createLlmRouter(getAgent) {
123
122
  "application/json": {
124
123
  schema: import_zod_openapi.z.object({
125
124
  ok: import_zod_openapi.z.literal(true).describe("Operation success indicator"),
126
- provider: import_zod_openapi.z.enum(import_core.LLM_PROVIDERS).describe("Provider for which the key was saved"),
125
+ provider: import_zod_openapi.z.enum(import_core2.LLM_PROVIDERS).describe("Provider for which the key was saved"),
127
126
  envVar: import_zod_openapi.z.string().describe("Environment variable name where key was stored")
128
127
  }).strict().describe("API key save response")
129
128
  }
@@ -162,13 +161,91 @@ function createLlmRouter(getAgent) {
162
161
  }
163
162
  }
164
163
  });
164
+ const listCustomModelsRoute = (0, import_zod_openapi.createRoute)({
165
+ method: "get",
166
+ path: "/llm/custom-models",
167
+ summary: "List Custom Models",
168
+ description: "Returns all saved custom openai-compatible model configurations",
169
+ tags: ["llm"],
170
+ responses: {
171
+ 200: {
172
+ description: "List of custom models",
173
+ content: {
174
+ "application/json": {
175
+ schema: import_zod_openapi.z.object({
176
+ models: import_zod_openapi.z.array(import_agent_management.CustomModelSchema).describe("List of custom models")
177
+ })
178
+ }
179
+ }
180
+ }
181
+ }
182
+ });
183
+ const createCustomModelRoute = (0, import_zod_openapi.createRoute)({
184
+ method: "post",
185
+ path: "/llm/custom-models",
186
+ summary: "Create Custom Model",
187
+ description: "Saves a new custom openai-compatible model configuration",
188
+ tags: ["llm"],
189
+ request: {
190
+ body: { content: { "application/json": { schema: import_agent_management.CustomModelSchema } } }
191
+ },
192
+ responses: {
193
+ 200: {
194
+ description: "Custom model saved",
195
+ content: {
196
+ "application/json": {
197
+ schema: import_zod_openapi.z.object({
198
+ ok: import_zod_openapi.z.literal(true).describe("Success indicator"),
199
+ model: import_agent_management.CustomModelSchema
200
+ })
201
+ }
202
+ }
203
+ }
204
+ }
205
+ });
206
+ const deleteCustomModelRoute = (0, import_zod_openapi.createRoute)({
207
+ method: "delete",
208
+ path: "/llm/custom-models/{name}",
209
+ summary: "Delete Custom Model",
210
+ description: "Deletes a custom model by name",
211
+ tags: ["llm"],
212
+ request: {
213
+ params: import_zod_openapi.z.object({
214
+ name: import_zod_openapi.z.string().min(1).describe("Model name to delete")
215
+ })
216
+ },
217
+ responses: {
218
+ 200: {
219
+ description: "Custom model deleted",
220
+ content: {
221
+ "application/json": {
222
+ schema: import_zod_openapi.z.object({
223
+ ok: import_zod_openapi.z.literal(true).describe("Success indicator"),
224
+ deleted: import_zod_openapi.z.string().describe("Name of the deleted model")
225
+ })
226
+ }
227
+ }
228
+ },
229
+ 404: {
230
+ description: "Custom model not found",
231
+ content: {
232
+ "application/json": {
233
+ schema: import_zod_openapi.z.object({
234
+ ok: import_zod_openapi.z.literal(false).describe("Failure indicator"),
235
+ error: import_zod_openapi.z.string().describe("Error message")
236
+ })
237
+ }
238
+ }
239
+ }
240
+ }
241
+ });
165
242
  return app.openapi(currentRoute, (ctx) => {
166
243
  const agent = getAgent();
167
244
  const { sessionId } = ctx.req.valid("query");
168
245
  const currentConfig = sessionId ? agent.getEffectiveConfig(sessionId).llm : agent.getCurrentLLMConfig();
169
246
  let displayName;
170
247
  try {
171
- const model = import_core.LLM_REGISTRY[currentConfig.provider]?.models.find(
248
+ const model = import_core2.LLM_REGISTRY[currentConfig.provider]?.models.find(
172
249
  (m) => m.name.toLowerCase() === String(currentConfig.model).toLowerCase()
173
250
  );
174
251
  displayName = model?.displayName || void 0;
@@ -185,16 +262,15 @@ function createLlmRouter(getAgent) {
185
262
  }).openapi(catalogRoute, (ctx) => {
186
263
  const queryParams = ctx.req.valid("query");
187
264
  const providers = {};
188
- for (const provider of import_core.LLM_PROVIDERS) {
189
- const info = import_core.LLM_REGISTRY[provider];
265
+ for (const provider of import_core2.LLM_PROVIDERS) {
266
+ const info = import_core2.LLM_REGISTRY[provider];
190
267
  const displayName = provider.charAt(0).toUpperCase() + provider.slice(1);
191
268
  const keyStatus = (0, import_agent_management.getProviderKeyStatus)(provider);
192
269
  providers[provider] = {
193
270
  name: displayName,
194
271
  hasApiKey: keyStatus.hasApiKey,
195
272
  primaryEnvVar: keyStatus.envVar,
196
- supportedRouters: (0, import_core.getSupportedRoutersForProvider)(provider),
197
- supportsBaseURL: (0, import_core.supportsBaseURL)(provider),
273
+ supportsBaseURL: (0, import_core2.supportsBaseURL)(provider),
198
274
  models: info.models,
199
275
  supportedFileTypes: info.supportedFileTypes
200
276
  };
@@ -203,7 +279,7 @@ function createLlmRouter(getAgent) {
203
279
  if (queryParams.provider && queryParams.provider.length > 0) {
204
280
  const allowed = new Set(
205
281
  queryParams.provider.filter(
206
- (p) => import_core.LLM_PROVIDERS.includes(p)
282
+ (p) => import_core2.LLM_PROVIDERS.includes(p)
207
283
  )
208
284
  );
209
285
  const filteredByProvider = {};
@@ -223,23 +299,6 @@ function createLlmRouter(getAgent) {
223
299
  }
224
300
  filtered = byKey;
225
301
  }
226
- if (queryParams.router) {
227
- const byRouter = {};
228
- for (const [id, catalog] of Object.entries(filtered)) {
229
- if (!catalog.supportedRouters.includes(queryParams.router)) continue;
230
- const models = catalog.models.filter(
231
- (model) => (0, import_core.isRouterSupportedForModel)(
232
- id,
233
- model.name,
234
- queryParams.router
235
- )
236
- );
237
- if (models.length > 0) {
238
- byRouter[id] = { ...catalog, models };
239
- }
240
- }
241
- filtered = byRouter;
242
- }
243
302
  if (queryParams.fileType) {
244
303
  const byFileType = {};
245
304
  for (const [id, catalog] of Object.entries(filtered)) {
@@ -290,6 +349,26 @@ function createLlmRouter(getAgent) {
290
349
  },
291
350
  sessionId
292
351
  });
352
+ }).openapi(listCustomModelsRoute, async (ctx) => {
353
+ const models = await (0, import_agent_management.loadCustomModels)();
354
+ return ctx.json({ models });
355
+ }).openapi(createCustomModelRoute, async (ctx) => {
356
+ const model = ctx.req.valid("json");
357
+ await (0, import_agent_management.saveCustomModel)(model);
358
+ return ctx.json({ ok: true, model });
359
+ }).openapi(deleteCustomModelRoute, async (ctx) => {
360
+ const { name } = ctx.req.valid("param");
361
+ const deleted = await (0, import_agent_management.deleteCustomModel)(name);
362
+ if (!deleted) {
363
+ throw new import_core.DextoRuntimeError(
364
+ "custom_model_not_found",
365
+ import_core.ErrorScope.LLM,
366
+ import_core.ErrorType.NOT_FOUND,
367
+ `Custom model '${name}' not found`,
368
+ { modelName: name }
369
+ );
370
+ }
371
+ return ctx.json({ ok: true, deleted: name }, 200);
293
372
  });
294
373
  }
295
374
  // Annotate the CommonJS export names for ESM import in node:
@@ -12,7 +12,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
12
12
  config: {
13
13
  model: string;
14
14
  provider: "openai" | "openai-compatible" | "anthropic" | "google" | "groq" | "xai" | "cohere";
15
- router?: "vercel" | "in-built" | undefined;
16
15
  maxIterations?: number | undefined;
17
16
  baseURL?: string | undefined;
18
17
  maxInputTokens?: number | undefined;
@@ -33,7 +32,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
33
32
  input: {
34
33
  query: {
35
34
  provider?: string | string[] | undefined;
36
- router?: "vercel" | "in-built" | undefined;
37
35
  hasKey?: "0" | "1" | "true" | "false" | undefined;
38
36
  fileType?: "image" | "audio" | "pdf" | undefined;
39
37
  defaultOnly?: "0" | "1" | "true" | "false" | undefined;
@@ -46,7 +44,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
46
44
  name: string;
47
45
  hasApiKey: boolean;
48
46
  supportedFileTypes: ("image" | "audio" | "pdf")[];
49
- supportedRouters: ("vercel" | "in-built")[];
50
47
  primaryEnvVar: string;
51
48
  supportsBaseURL: boolean;
52
49
  models: {
@@ -54,7 +51,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
54
51
  maxInputTokens: number;
55
52
  supportedFileTypes: ("image" | "audio" | "pdf")[];
56
53
  default?: boolean | undefined;
57
- supportedRouters?: ("vercel" | "in-built")[] | undefined;
58
54
  displayName?: string | undefined;
59
55
  pricing?: {
60
56
  inputPerM: number;
@@ -70,7 +66,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
70
66
  name: string;
71
67
  hasApiKey: boolean;
72
68
  supportedFileTypes: ("image" | "audio" | "pdf")[];
73
- supportedRouters: ("vercel" | "in-built")[];
74
69
  primaryEnvVar: string;
75
70
  supportsBaseURL: boolean;
76
71
  models: {
@@ -78,7 +73,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
78
73
  maxInputTokens: number;
79
74
  supportedFileTypes: ("image" | "audio" | "pdf")[];
80
75
  default?: boolean | undefined;
81
- supportedRouters?: ("vercel" | "in-built")[] | undefined;
82
76
  displayName?: string | undefined;
83
77
  pricing?: {
84
78
  inputPerM: number;
@@ -94,7 +88,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
94
88
  name: string;
95
89
  hasApiKey: boolean;
96
90
  supportedFileTypes: ("image" | "audio" | "pdf")[];
97
- supportedRouters: ("vercel" | "in-built")[];
98
91
  primaryEnvVar: string;
99
92
  supportsBaseURL: boolean;
100
93
  models: {
@@ -102,7 +95,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
102
95
  maxInputTokens: number;
103
96
  supportedFileTypes: ("image" | "audio" | "pdf")[];
104
97
  default?: boolean | undefined;
105
- supportedRouters?: ("vercel" | "in-built")[] | undefined;
106
98
  displayName?: string | undefined;
107
99
  pricing?: {
108
100
  inputPerM: number;
@@ -118,7 +110,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
118
110
  name: string;
119
111
  hasApiKey: boolean;
120
112
  supportedFileTypes: ("image" | "audio" | "pdf")[];
121
- supportedRouters: ("vercel" | "in-built")[];
122
113
  primaryEnvVar: string;
123
114
  supportsBaseURL: boolean;
124
115
  models: {
@@ -126,7 +117,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
126
117
  maxInputTokens: number;
127
118
  supportedFileTypes: ("image" | "audio" | "pdf")[];
128
119
  default?: boolean | undefined;
129
- supportedRouters?: ("vercel" | "in-built")[] | undefined;
130
120
  displayName?: string | undefined;
131
121
  pricing?: {
132
122
  inputPerM: number;
@@ -142,7 +132,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
142
132
  name: string;
143
133
  hasApiKey: boolean;
144
134
  supportedFileTypes: ("image" | "audio" | "pdf")[];
145
- supportedRouters: ("vercel" | "in-built")[];
146
135
  primaryEnvVar: string;
147
136
  supportsBaseURL: boolean;
148
137
  models: {
@@ -150,7 +139,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
150
139
  maxInputTokens: number;
151
140
  supportedFileTypes: ("image" | "audio" | "pdf")[];
152
141
  default?: boolean | undefined;
153
- supportedRouters?: ("vercel" | "in-built")[] | undefined;
154
142
  displayName?: string | undefined;
155
143
  pricing?: {
156
144
  inputPerM: number;
@@ -166,7 +154,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
166
154
  name: string;
167
155
  hasApiKey: boolean;
168
156
  supportedFileTypes: ("image" | "audio" | "pdf")[];
169
- supportedRouters: ("vercel" | "in-built")[];
170
157
  primaryEnvVar: string;
171
158
  supportsBaseURL: boolean;
172
159
  models: {
@@ -174,7 +161,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
174
161
  maxInputTokens: number;
175
162
  supportedFileTypes: ("image" | "audio" | "pdf")[];
176
163
  default?: boolean | undefined;
177
- supportedRouters?: ("vercel" | "in-built")[] | undefined;
178
164
  displayName?: string | undefined;
179
165
  pricing?: {
180
166
  inputPerM: number;
@@ -190,7 +176,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
190
176
  name: string;
191
177
  hasApiKey: boolean;
192
178
  supportedFileTypes: ("image" | "audio" | "pdf")[];
193
- supportedRouters: ("vercel" | "in-built")[];
194
179
  primaryEnvVar: string;
195
180
  supportsBaseURL: boolean;
196
181
  models: {
@@ -198,7 +183,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
198
183
  maxInputTokens: number;
199
184
  supportedFileTypes: ("image" | "audio" | "pdf")[];
200
185
  default?: boolean | undefined;
201
- supportedRouters?: ("vercel" | "in-built")[] | undefined;
202
186
  displayName?: string | undefined;
203
187
  pricing?: {
204
188
  inputPerM: number;
@@ -218,7 +202,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
218
202
  maxInputTokens: number;
219
203
  supportedFileTypes: ("image" | "audio" | "pdf")[];
220
204
  default?: boolean | undefined;
221
- supportedRouters?: ("vercel" | "in-built")[] | undefined;
222
205
  displayName?: string | undefined;
223
206
  pricing?: {
224
207
  inputPerM: number;
@@ -257,10 +240,9 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
257
240
  $post: {
258
241
  input: {
259
242
  json: {
260
- apiKey?: string | undefined;
261
243
  model?: string | undefined;
262
244
  provider?: "openai" | "openai-compatible" | "anthropic" | "google" | "groq" | "xai" | "cohere" | undefined;
263
- router?: "vercel" | "in-built" | undefined;
245
+ apiKey?: string | undefined;
264
246
  maxIterations?: number | undefined;
265
247
  baseURL?: string | undefined;
266
248
  maxInputTokens?: number | undefined;
@@ -275,7 +257,6 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
275
257
  config: {
276
258
  model: string;
277
259
  provider: "openai" | "openai-compatible" | "anthropic" | "google" | "groq" | "xai" | "cohere";
278
- router: "vercel" | "in-built";
279
260
  maxIterations: number;
280
261
  baseURL?: string | undefined;
281
262
  maxInputTokens?: number | undefined;
@@ -290,5 +271,76 @@ export declare function createLlmRouter(getAgent: () => DextoAgent): OpenAPIHono
290
271
  status: 200;
291
272
  };
292
273
  };
274
+ } & {
275
+ "/llm/custom-models": {
276
+ $get: {
277
+ input: {};
278
+ output: {
279
+ models: {
280
+ name: string;
281
+ baseURL: string;
282
+ displayName?: string | undefined | undefined;
283
+ maxInputTokens?: number | undefined | undefined;
284
+ maxOutputTokens?: number | undefined | undefined;
285
+ }[];
286
+ };
287
+ outputFormat: "json";
288
+ status: 200;
289
+ };
290
+ };
291
+ } & {
292
+ "/llm/custom-models": {
293
+ $post: {
294
+ input: {
295
+ json: {
296
+ name: string;
297
+ baseURL: string;
298
+ displayName?: string | undefined;
299
+ maxInputTokens?: number | undefined;
300
+ maxOutputTokens?: number | undefined;
301
+ };
302
+ };
303
+ output: {
304
+ model: {
305
+ name: string;
306
+ baseURL: string;
307
+ displayName?: string | undefined | undefined;
308
+ maxInputTokens?: number | undefined | undefined;
309
+ maxOutputTokens?: number | undefined | undefined;
310
+ };
311
+ ok: true;
312
+ };
313
+ outputFormat: "json";
314
+ status: 200;
315
+ };
316
+ };
317
+ } & {
318
+ "/llm/custom-models/:name": {
319
+ $delete: {
320
+ input: {
321
+ param: {
322
+ name: string;
323
+ };
324
+ };
325
+ output: {
326
+ ok: true;
327
+ deleted: string;
328
+ };
329
+ outputFormat: "json";
330
+ status: 200;
331
+ } | {
332
+ input: {
333
+ param: {
334
+ name: string;
335
+ };
336
+ };
337
+ output: {
338
+ ok: false;
339
+ error: string;
340
+ };
341
+ outputFormat: "json";
342
+ status: 404;
343
+ };
344
+ };
293
345
  }, "/">;
294
346
  //# sourceMappingURL=llm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../../src/hono/routes/llm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAmG9C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyTzD"}
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../../src/hono/routes/llm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAoG9C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA2YzD"}
@@ -1,15 +1,20 @@
1
1
  import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
2
+ import { DextoRuntimeError, ErrorScope, ErrorType } from "@dexto/core";
2
3
  import {
3
4
  LLM_REGISTRY,
4
5
  LLM_PROVIDERS,
5
- LLM_ROUTERS,
6
6
  SUPPORTED_FILE_TYPES,
7
- getSupportedRoutersForProvider,
8
7
  supportsBaseURL,
9
- isRouterSupportedForModel,
10
8
  LLMUpdatesSchema
11
9
  } from "@dexto/core";
12
- import { getProviderKeyStatus, saveProviderApiKey } from "@dexto/agent-management";
10
+ import {
11
+ getProviderKeyStatus,
12
+ saveProviderApiKey,
13
+ loadCustomModels,
14
+ saveCustomModel,
15
+ deleteCustomModel,
16
+ CustomModelSchema
17
+ } from "@dexto/agent-management";
13
18
  import {
14
19
  ProviderCatalogSchema,
15
20
  ModelFlatSchema,
@@ -25,7 +30,6 @@ const CatalogQuerySchema = z.object({
25
30
  hasKey: z.union([z.literal("true"), z.literal("false"), z.literal("1"), z.literal("0")]).optional().transform(
26
31
  (raw) => raw === "true" || raw === "1" ? true : raw === "false" || raw === "0" ? false : void 0
27
32
  ).describe("Filter by API key presence (true or false)"),
28
- router: z.enum(LLM_ROUTERS).optional().describe("Filter by router type (vercel or in-built)"),
29
33
  fileType: z.enum(SUPPORTED_FILE_TYPES).optional().describe("Filter by supported file type (audio, pdf, or image)"),
30
34
  defaultOnly: z.union([z.literal("true"), z.literal("false"), z.literal("1"), z.literal("0")]).optional().transform(
31
35
  (raw) => raw === "true" || raw === "1" ? true : raw === "false" || raw === "0" ? false : void 0
@@ -57,8 +61,7 @@ function createLlmRouter(getAgent) {
57
61
  "application/json": {
58
62
  schema: z.object({
59
63
  config: LLMConfigResponseSchema.partial({
60
- maxIterations: true,
61
- router: true
64
+ maxIterations: true
62
65
  }).extend({
63
66
  displayName: z.string().optional().describe("Human-readable model display name")
64
67
  })
@@ -152,6 +155,84 @@ function createLlmRouter(getAgent) {
152
155
  }
153
156
  }
154
157
  });
158
+ const listCustomModelsRoute = createRoute({
159
+ method: "get",
160
+ path: "/llm/custom-models",
161
+ summary: "List Custom Models",
162
+ description: "Returns all saved custom openai-compatible model configurations",
163
+ tags: ["llm"],
164
+ responses: {
165
+ 200: {
166
+ description: "List of custom models",
167
+ content: {
168
+ "application/json": {
169
+ schema: z.object({
170
+ models: z.array(CustomModelSchema).describe("List of custom models")
171
+ })
172
+ }
173
+ }
174
+ }
175
+ }
176
+ });
177
+ const createCustomModelRoute = createRoute({
178
+ method: "post",
179
+ path: "/llm/custom-models",
180
+ summary: "Create Custom Model",
181
+ description: "Saves a new custom openai-compatible model configuration",
182
+ tags: ["llm"],
183
+ request: {
184
+ body: { content: { "application/json": { schema: CustomModelSchema } } }
185
+ },
186
+ responses: {
187
+ 200: {
188
+ description: "Custom model saved",
189
+ content: {
190
+ "application/json": {
191
+ schema: z.object({
192
+ ok: z.literal(true).describe("Success indicator"),
193
+ model: CustomModelSchema
194
+ })
195
+ }
196
+ }
197
+ }
198
+ }
199
+ });
200
+ const deleteCustomModelRoute = createRoute({
201
+ method: "delete",
202
+ path: "/llm/custom-models/{name}",
203
+ summary: "Delete Custom Model",
204
+ description: "Deletes a custom model by name",
205
+ tags: ["llm"],
206
+ request: {
207
+ params: z.object({
208
+ name: z.string().min(1).describe("Model name to delete")
209
+ })
210
+ },
211
+ responses: {
212
+ 200: {
213
+ description: "Custom model deleted",
214
+ content: {
215
+ "application/json": {
216
+ schema: z.object({
217
+ ok: z.literal(true).describe("Success indicator"),
218
+ deleted: z.string().describe("Name of the deleted model")
219
+ })
220
+ }
221
+ }
222
+ },
223
+ 404: {
224
+ description: "Custom model not found",
225
+ content: {
226
+ "application/json": {
227
+ schema: z.object({
228
+ ok: z.literal(false).describe("Failure indicator"),
229
+ error: z.string().describe("Error message")
230
+ })
231
+ }
232
+ }
233
+ }
234
+ }
235
+ });
155
236
  return app.openapi(currentRoute, (ctx) => {
156
237
  const agent = getAgent();
157
238
  const { sessionId } = ctx.req.valid("query");
@@ -183,7 +264,6 @@ function createLlmRouter(getAgent) {
183
264
  name: displayName,
184
265
  hasApiKey: keyStatus.hasApiKey,
185
266
  primaryEnvVar: keyStatus.envVar,
186
- supportedRouters: getSupportedRoutersForProvider(provider),
187
267
  supportsBaseURL: supportsBaseURL(provider),
188
268
  models: info.models,
189
269
  supportedFileTypes: info.supportedFileTypes
@@ -213,23 +293,6 @@ function createLlmRouter(getAgent) {
213
293
  }
214
294
  filtered = byKey;
215
295
  }
216
- if (queryParams.router) {
217
- const byRouter = {};
218
- for (const [id, catalog] of Object.entries(filtered)) {
219
- if (!catalog.supportedRouters.includes(queryParams.router)) continue;
220
- const models = catalog.models.filter(
221
- (model) => isRouterSupportedForModel(
222
- id,
223
- model.name,
224
- queryParams.router
225
- )
226
- );
227
- if (models.length > 0) {
228
- byRouter[id] = { ...catalog, models };
229
- }
230
- }
231
- filtered = byRouter;
232
- }
233
296
  if (queryParams.fileType) {
234
297
  const byFileType = {};
235
298
  for (const [id, catalog] of Object.entries(filtered)) {
@@ -280,6 +343,26 @@ function createLlmRouter(getAgent) {
280
343
  },
281
344
  sessionId
282
345
  });
346
+ }).openapi(listCustomModelsRoute, async (ctx) => {
347
+ const models = await loadCustomModels();
348
+ return ctx.json({ models });
349
+ }).openapi(createCustomModelRoute, async (ctx) => {
350
+ const model = ctx.req.valid("json");
351
+ await saveCustomModel(model);
352
+ return ctx.json({ ok: true, model });
353
+ }).openapi(deleteCustomModelRoute, async (ctx) => {
354
+ const { name } = ctx.req.valid("param");
355
+ const deleted = await deleteCustomModel(name);
356
+ if (!deleted) {
357
+ throw new DextoRuntimeError(
358
+ "custom_model_not_found",
359
+ ErrorScope.LLM,
360
+ ErrorType.NOT_FOUND,
361
+ `Custom model '${name}' not found`,
362
+ { modelName: name }
363
+ );
364
+ }
365
+ return ctx.json({ ok: true, deleted: name }, 200);
283
366
  });
284
367
  }
285
368
  export {
@@ -40,7 +40,7 @@ const ServerStatusResponseSchema = import_zod_openapi.z.object({
40
40
  const ServerInfoSchema = import_zod_openapi.z.object({
41
41
  id: import_zod_openapi.z.string().describe("Server identifier"),
42
42
  name: import_zod_openapi.z.string().describe("Server name"),
43
- status: import_zod_openapi.z.enum(["connected", "error", "disconnected"]).describe("Server status")
43
+ status: import_zod_openapi.z.enum(import_core.MCP_CONNECTION_STATUSES).describe("Server status")
44
44
  }).strict().describe("MCP server information");
45
45
  const ServersListResponseSchema = import_zod_openapi.z.object({
46
46
  servers: import_zod_openapi.z.array(ServerInfoSchema).describe("Array of server information")
@@ -230,8 +230,11 @@ function createMcpRouter(getAgent) {
230
230
  return app.openapi(addServerRoute, async (ctx) => {
231
231
  const agent = getAgent();
232
232
  const { name, config, persistToAgent } = ctx.req.valid("json");
233
- await agent.connectMcpServer(name, config);
234
- import_core.logger.info(`Successfully connected to new server '${name}' via API request.`);
233
+ await agent.addMcpServer(name, config);
234
+ const isConnected = config.enabled !== false;
235
+ import_core.logger.info(
236
+ isConnected ? `Successfully connected to new server '${name}' via API request.` : `Registered server '${name}' (disabled) via API request.`
237
+ );
235
238
  if (persistToAgent === true) {
236
239
  try {
237
240
  const currentConfig = agent.getEffectiveConfig();
@@ -262,7 +265,8 @@ function createMcpRouter(getAgent) {
262
265
  );
263
266
  }
264
267
  }
265
- return ctx.json({ status: "connected", name }, 200);
268
+ const status = isConnected ? "connected" : "registered";
269
+ return ctx.json({ status, name }, 200);
266
270
  }).openapi(listServersRoute, async (ctx) => {
267
271
  const agent = getAgent();
268
272
  const clientsMap = agent.getMcpClients();