@dexto/server 1.6.8 → 1.6.9
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/hono/index.d.ts +173 -12
- package/dist/hono/index.d.ts.map +1 -1
- package/dist/hono/routes/llm.cjs +282 -0
- package/dist/hono/routes/llm.d.ts +90 -0
- package/dist/hono/routes/llm.d.ts.map +1 -1
- package/dist/hono/routes/llm.js +295 -2
- package/dist/hono/routes/sessions.cjs +73 -44
- package/dist/hono/routes/sessions.d.ts +71 -0
- package/dist/hono/routes/sessions.d.ts.map +1 -1
- package/dist/hono/routes/sessions.js +78 -45
- package/dist/hono/routes/system-prompt.d.ts +12 -12
- package/dist/hono/schemas/responses.cjs +2 -1
- package/dist/hono/schemas/responses.d.ts +3 -0
- package/dist/hono/schemas/responses.d.ts.map +1 -1
- package/dist/hono/schemas/responses.js +2 -1
- package/package.json +8 -8
package/dist/hono/index.d.ts
CHANGED
|
@@ -71,17 +71,9 @@ export declare function createDextoApp(options: CreateDextoAppOptions): OpenAPIH
|
|
|
71
71
|
priority?: number | undefined;
|
|
72
72
|
};
|
|
73
73
|
};
|
|
74
|
-
output:
|
|
75
|
-
id: string;
|
|
76
|
-
enabled: boolean;
|
|
77
|
-
removed?: boolean | undefined;
|
|
78
|
-
priority?: number | undefined;
|
|
79
|
-
replaced?: boolean | undefined;
|
|
80
|
-
contentLength?: number | undefined;
|
|
81
|
-
truncated?: boolean | undefined;
|
|
82
|
-
};
|
|
74
|
+
output: never;
|
|
83
75
|
outputFormat: "json";
|
|
84
|
-
status:
|
|
76
|
+
status: 400;
|
|
85
77
|
} | {
|
|
86
78
|
input: {
|
|
87
79
|
json: {
|
|
@@ -91,9 +83,17 @@ export declare function createDextoApp(options: CreateDextoAppOptions): OpenAPIH
|
|
|
91
83
|
priority?: number | undefined;
|
|
92
84
|
};
|
|
93
85
|
};
|
|
94
|
-
output:
|
|
86
|
+
output: {
|
|
87
|
+
id: string;
|
|
88
|
+
enabled: boolean;
|
|
89
|
+
removed?: boolean | undefined;
|
|
90
|
+
priority?: number | undefined;
|
|
91
|
+
replaced?: boolean | undefined;
|
|
92
|
+
contentLength?: number | undefined;
|
|
93
|
+
truncated?: boolean | undefined;
|
|
94
|
+
};
|
|
95
95
|
outputFormat: "json";
|
|
96
|
-
status:
|
|
96
|
+
status: 200;
|
|
97
97
|
};
|
|
98
98
|
};
|
|
99
99
|
}, "/api"> & import("hono/types").MergeSchemaPath<{
|
|
@@ -2474,6 +2474,7 @@ export declare function createDextoApp(options: CreateDextoAppOptions): OpenAPIH
|
|
|
2474
2474
|
lastUsedAt: number;
|
|
2475
2475
|
}[] | undefined;
|
|
2476
2476
|
workspaceId?: string | null | undefined;
|
|
2477
|
+
parentSessionId?: string | null | undefined;
|
|
2477
2478
|
}[];
|
|
2478
2479
|
};
|
|
2479
2480
|
outputFormat: "json";
|
|
@@ -2521,12 +2522,79 @@ export declare function createDextoApp(options: CreateDextoAppOptions): OpenAPIH
|
|
|
2521
2522
|
lastUsedAt: number;
|
|
2522
2523
|
}[] | undefined;
|
|
2523
2524
|
workspaceId?: string | null | undefined;
|
|
2525
|
+
parentSessionId?: string | null | undefined;
|
|
2524
2526
|
};
|
|
2525
2527
|
};
|
|
2526
2528
|
outputFormat: "json";
|
|
2527
2529
|
status: 201;
|
|
2528
2530
|
};
|
|
2529
2531
|
};
|
|
2532
|
+
} & {
|
|
2533
|
+
"/sessions/:sessionId/fork": {
|
|
2534
|
+
$post: {
|
|
2535
|
+
input: {
|
|
2536
|
+
param: {
|
|
2537
|
+
sessionId: string;
|
|
2538
|
+
};
|
|
2539
|
+
};
|
|
2540
|
+
output: {
|
|
2541
|
+
session: {
|
|
2542
|
+
id: string;
|
|
2543
|
+
messageCount: number;
|
|
2544
|
+
createdAt: number | null;
|
|
2545
|
+
lastActivity: number | null;
|
|
2546
|
+
title?: string | null | undefined;
|
|
2547
|
+
tokenUsage?: {
|
|
2548
|
+
inputTokens: number;
|
|
2549
|
+
outputTokens: number;
|
|
2550
|
+
reasoningTokens: number;
|
|
2551
|
+
totalTokens: number;
|
|
2552
|
+
cacheReadTokens: number;
|
|
2553
|
+
cacheWriteTokens: number;
|
|
2554
|
+
} | undefined;
|
|
2555
|
+
estimatedCost?: number | undefined;
|
|
2556
|
+
modelStats?: {
|
|
2557
|
+
tokenUsage: {
|
|
2558
|
+
inputTokens: number;
|
|
2559
|
+
outputTokens: number;
|
|
2560
|
+
reasoningTokens: number;
|
|
2561
|
+
totalTokens: number;
|
|
2562
|
+
cacheReadTokens: number;
|
|
2563
|
+
cacheWriteTokens: number;
|
|
2564
|
+
};
|
|
2565
|
+
model: string;
|
|
2566
|
+
provider: string;
|
|
2567
|
+
messageCount: number;
|
|
2568
|
+
estimatedCost: number;
|
|
2569
|
+
firstUsedAt: number;
|
|
2570
|
+
lastUsedAt: number;
|
|
2571
|
+
}[] | undefined;
|
|
2572
|
+
workspaceId?: string | null | undefined;
|
|
2573
|
+
parentSessionId?: string | null | undefined;
|
|
2574
|
+
};
|
|
2575
|
+
};
|
|
2576
|
+
outputFormat: "json";
|
|
2577
|
+
status: 201;
|
|
2578
|
+
} | {
|
|
2579
|
+
input: {
|
|
2580
|
+
param: {
|
|
2581
|
+
sessionId: string;
|
|
2582
|
+
};
|
|
2583
|
+
};
|
|
2584
|
+
output: never;
|
|
2585
|
+
outputFormat: "json";
|
|
2586
|
+
status: 400;
|
|
2587
|
+
} | {
|
|
2588
|
+
input: {
|
|
2589
|
+
param: {
|
|
2590
|
+
sessionId: string;
|
|
2591
|
+
};
|
|
2592
|
+
};
|
|
2593
|
+
output: never;
|
|
2594
|
+
outputFormat: "json";
|
|
2595
|
+
status: 404;
|
|
2596
|
+
};
|
|
2597
|
+
};
|
|
2530
2598
|
} & {
|
|
2531
2599
|
"/sessions/:sessionId": {
|
|
2532
2600
|
$get: {
|
|
@@ -2569,6 +2637,7 @@ export declare function createDextoApp(options: CreateDextoAppOptions): OpenAPIH
|
|
|
2569
2637
|
lastUsedAt: number;
|
|
2570
2638
|
}[] | undefined;
|
|
2571
2639
|
workspaceId?: string | null | undefined;
|
|
2640
|
+
parentSessionId?: string | null | undefined;
|
|
2572
2641
|
};
|
|
2573
2642
|
};
|
|
2574
2643
|
outputFormat: "json";
|
|
@@ -2721,6 +2790,7 @@ export declare function createDextoApp(options: CreateDextoAppOptions): OpenAPIH
|
|
|
2721
2790
|
lastUsedAt: number;
|
|
2722
2791
|
}[] | undefined;
|
|
2723
2792
|
workspaceId?: string | null | undefined;
|
|
2793
|
+
parentSessionId?: string | null | undefined;
|
|
2724
2794
|
};
|
|
2725
2795
|
};
|
|
2726
2796
|
outputFormat: "json";
|
|
@@ -2783,6 +2853,7 @@ export declare function createDextoApp(options: CreateDextoAppOptions): OpenAPIH
|
|
|
2783
2853
|
lastUsedAt: number;
|
|
2784
2854
|
}[] | undefined;
|
|
2785
2855
|
workspaceId?: string | null | undefined;
|
|
2856
|
+
parentSessionId?: string | null | undefined;
|
|
2786
2857
|
};
|
|
2787
2858
|
};
|
|
2788
2859
|
outputFormat: "json";
|
|
@@ -3396,6 +3467,96 @@ export declare function createDextoApp(options: CreateDextoAppOptions): OpenAPIH
|
|
|
3396
3467
|
status: 404;
|
|
3397
3468
|
};
|
|
3398
3469
|
};
|
|
3470
|
+
} & {
|
|
3471
|
+
"/llm/model-picker-state": {
|
|
3472
|
+
$get: {
|
|
3473
|
+
input: {};
|
|
3474
|
+
output: {
|
|
3475
|
+
custom: {
|
|
3476
|
+
model: string;
|
|
3477
|
+
provider: "openai" | "openai-compatible" | "anthropic" | "google" | "groq" | "xai" | "cohere" | "minimax" | "glm" | "openrouter" | "litellm" | "glama" | "vertex" | "bedrock" | "local" | "ollama" | "dexto-nova";
|
|
3478
|
+
supportedFileTypes: ("image" | "audio" | "pdf")[];
|
|
3479
|
+
source: "custom" | "catalog" | "local-installed";
|
|
3480
|
+
displayName?: string | undefined;
|
|
3481
|
+
}[];
|
|
3482
|
+
featured: {
|
|
3483
|
+
model: string;
|
|
3484
|
+
provider: "openai" | "openai-compatible" | "anthropic" | "google" | "groq" | "xai" | "cohere" | "minimax" | "glm" | "openrouter" | "litellm" | "glama" | "vertex" | "bedrock" | "local" | "ollama" | "dexto-nova";
|
|
3485
|
+
supportedFileTypes: ("image" | "audio" | "pdf")[];
|
|
3486
|
+
source: "custom" | "catalog" | "local-installed";
|
|
3487
|
+
displayName?: string | undefined;
|
|
3488
|
+
}[];
|
|
3489
|
+
recents: {
|
|
3490
|
+
model: string;
|
|
3491
|
+
provider: "openai" | "openai-compatible" | "anthropic" | "google" | "groq" | "xai" | "cohere" | "minimax" | "glm" | "openrouter" | "litellm" | "glama" | "vertex" | "bedrock" | "local" | "ollama" | "dexto-nova";
|
|
3492
|
+
supportedFileTypes: ("image" | "audio" | "pdf")[];
|
|
3493
|
+
source: "custom" | "catalog" | "local-installed";
|
|
3494
|
+
displayName?: string | undefined;
|
|
3495
|
+
}[];
|
|
3496
|
+
favorites: {
|
|
3497
|
+
model: string;
|
|
3498
|
+
provider: "openai" | "openai-compatible" | "anthropic" | "google" | "groq" | "xai" | "cohere" | "minimax" | "glm" | "openrouter" | "litellm" | "glama" | "vertex" | "bedrock" | "local" | "ollama" | "dexto-nova";
|
|
3499
|
+
supportedFileTypes: ("image" | "audio" | "pdf")[];
|
|
3500
|
+
source: "custom" | "catalog" | "local-installed";
|
|
3501
|
+
displayName?: string | undefined;
|
|
3502
|
+
}[];
|
|
3503
|
+
};
|
|
3504
|
+
outputFormat: "json";
|
|
3505
|
+
status: 200;
|
|
3506
|
+
};
|
|
3507
|
+
};
|
|
3508
|
+
} & {
|
|
3509
|
+
"/llm/model-picker-state/recents": {
|
|
3510
|
+
$post: {
|
|
3511
|
+
input: {
|
|
3512
|
+
json: {
|
|
3513
|
+
model: string;
|
|
3514
|
+
provider: "openai" | "openai-compatible" | "anthropic" | "google" | "groq" | "xai" | "cohere" | "minimax" | "glm" | "openrouter" | "litellm" | "glama" | "vertex" | "bedrock" | "local" | "ollama" | "dexto-nova";
|
|
3515
|
+
};
|
|
3516
|
+
};
|
|
3517
|
+
output: {
|
|
3518
|
+
ok: true;
|
|
3519
|
+
};
|
|
3520
|
+
outputFormat: "json";
|
|
3521
|
+
status: 200;
|
|
3522
|
+
};
|
|
3523
|
+
};
|
|
3524
|
+
} & {
|
|
3525
|
+
"/llm/model-picker-state/favorites/toggle": {
|
|
3526
|
+
$post: {
|
|
3527
|
+
input: {
|
|
3528
|
+
json: {
|
|
3529
|
+
model: string;
|
|
3530
|
+
provider: "openai" | "openai-compatible" | "anthropic" | "google" | "groq" | "xai" | "cohere" | "minimax" | "glm" | "openrouter" | "litellm" | "glama" | "vertex" | "bedrock" | "local" | "ollama" | "dexto-nova";
|
|
3531
|
+
};
|
|
3532
|
+
};
|
|
3533
|
+
output: {
|
|
3534
|
+
ok: true;
|
|
3535
|
+
isFavorite: boolean;
|
|
3536
|
+
};
|
|
3537
|
+
outputFormat: "json";
|
|
3538
|
+
status: 200;
|
|
3539
|
+
};
|
|
3540
|
+
};
|
|
3541
|
+
} & {
|
|
3542
|
+
"/llm/model-picker-state/favorites": {
|
|
3543
|
+
$put: {
|
|
3544
|
+
input: {
|
|
3545
|
+
json: {
|
|
3546
|
+
favorites: {
|
|
3547
|
+
model: string;
|
|
3548
|
+
provider: "openai" | "openai-compatible" | "anthropic" | "google" | "groq" | "xai" | "cohere" | "minimax" | "glm" | "openrouter" | "litellm" | "glama" | "vertex" | "bedrock" | "local" | "ollama" | "dexto-nova";
|
|
3549
|
+
}[];
|
|
3550
|
+
};
|
|
3551
|
+
};
|
|
3552
|
+
output: {
|
|
3553
|
+
ok: true;
|
|
3554
|
+
count: number;
|
|
3555
|
+
};
|
|
3556
|
+
outputFormat: "json";
|
|
3557
|
+
status: 200;
|
|
3558
|
+
};
|
|
3559
|
+
};
|
|
3399
3560
|
} & {
|
|
3400
3561
|
"/llm/capabilities": {
|
|
3401
3562
|
$get: {
|
package/dist/hono/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hono/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAmBzD,OAAO,EAAsB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAUlF,OAAO,EAGH,KAAK,kBAAkB,EAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAKxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAiE1E,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAC5E,MAAM,MAAM,oBAAoB,GAAG,CAC/B,GAAG,EAAE,OAAO,KACX,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;AAEtD,MAAM,MAAM,qBAAqB,GAAG;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,UAAU,CAAC;IACrB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;IAC1C,YAAY,EAAE,MAAM,SAAS,CAAC;IAC9B,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,iBAAiB,EAAE,sBAAsB,CAAC;IAC1C,aAAa,EAAE,qBAAqB,CAAC;IACrC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAKF,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hono/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAmBzD,OAAO,EAAsB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAUlF,OAAO,EAGH,KAAK,kBAAkB,EAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAKxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAiE1E,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAC5E,MAAM,MAAM,oBAAoB,GAAG,CAC/B,GAAG,EAAE,OAAO,KACX,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;AAEtD,MAAM,MAAM,qBAAqB,GAAG;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,UAAU,CAAC;IACrB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;IAC1C,YAAY,EAAE,MAAM,SAAS,CAAC;IAC9B,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,iBAAiB,EAAE,sBAAsB,CAAC;IAC1C,aAAa,EAAE,qBAAqB,CAAC;IACrC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAKF,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAgG5B,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAlJD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBA6QhC;AAID,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAGxD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/hono/routes/llm.cjs
CHANGED
|
@@ -26,6 +26,7 @@ var import_core = require("@dexto/core");
|
|
|
26
26
|
var import_core2 = require("@dexto/core");
|
|
27
27
|
var import_agent_management = require("@dexto/agent-management");
|
|
28
28
|
var import_responses = require("../schemas/responses.js");
|
|
29
|
+
const MODEL_PICKER_FEATURED_LIMIT = 8;
|
|
29
30
|
const CurrentQuerySchema = import_zod_openapi.z.object({
|
|
30
31
|
sessionId: import_zod_openapi.z.string().optional().describe("Session identifier to retrieve session-specific LLM configuration")
|
|
31
32
|
}).strict().describe("Query parameters for getting current LLM configuration");
|
|
@@ -53,6 +54,46 @@ const SwitchLLMBodySchema = import_core2.LLMUpdatesSchema.and(
|
|
|
53
54
|
sessionId: import_zod_openapi.z.string().optional().describe("Session identifier for session-specific LLM configuration")
|
|
54
55
|
})
|
|
55
56
|
).describe("LLM switch request body with optional session ID and LLM fields");
|
|
57
|
+
const ModelPickerModelRefSchema = import_zod_openapi.z.object({
|
|
58
|
+
provider: import_zod_openapi.z.enum(import_core2.LLM_PROVIDERS).describe("LLM provider"),
|
|
59
|
+
model: import_zod_openapi.z.string().trim().min(1).describe("Model ID")
|
|
60
|
+
}).strict().describe("Provider/model pair for model picker state operations");
|
|
61
|
+
const ModelPickerEntrySchema = import_zod_openapi.z.object({
|
|
62
|
+
provider: import_zod_openapi.z.enum(import_core2.LLM_PROVIDERS).describe("LLM provider"),
|
|
63
|
+
model: import_zod_openapi.z.string().describe("Model ID"),
|
|
64
|
+
displayName: import_zod_openapi.z.string().optional().describe("Human-readable model name"),
|
|
65
|
+
supportedFileTypes: import_zod_openapi.z.array(import_zod_openapi.z.enum(import_core2.SUPPORTED_FILE_TYPES)).describe("File types supported by this model"),
|
|
66
|
+
source: import_zod_openapi.z.enum(["catalog", "custom", "local-installed"]).describe("Where this model comes from")
|
|
67
|
+
}).strict().describe("Hydrated model picker entry");
|
|
68
|
+
const ModelPickerErrorSchema = import_responses.StandardErrorEnvelopeSchema.describe(
|
|
69
|
+
"Standard error response for model picker endpoints"
|
|
70
|
+
);
|
|
71
|
+
const ModelPickerErrorResponses = {
|
|
72
|
+
400: {
|
|
73
|
+
description: "Validation or request error",
|
|
74
|
+
content: {
|
|
75
|
+
"application/json": {
|
|
76
|
+
schema: ModelPickerErrorSchema
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
404: {
|
|
81
|
+
description: "Resource not found",
|
|
82
|
+
content: {
|
|
83
|
+
"application/json": {
|
|
84
|
+
schema: ModelPickerErrorSchema
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
500: {
|
|
89
|
+
description: "Internal server error",
|
|
90
|
+
content: {
|
|
91
|
+
"application/json": {
|
|
92
|
+
schema: ModelPickerErrorSchema
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
56
97
|
function createLlmRouter(getAgent) {
|
|
57
98
|
const app = new import_zod_openapi.OpenAPIHono();
|
|
58
99
|
const currentRoute = (0, import_zod_openapi.createRoute)({
|
|
@@ -286,6 +327,217 @@ function createLlmRouter(getAgent) {
|
|
|
286
327
|
}
|
|
287
328
|
}
|
|
288
329
|
});
|
|
330
|
+
const modelPickerStateRoute = (0, import_zod_openapi.createRoute)({
|
|
331
|
+
method: "get",
|
|
332
|
+
path: "/llm/model-picker-state",
|
|
333
|
+
summary: "Model Picker State",
|
|
334
|
+
description: "Returns hydrated Featured, Recents, Favorites, and Custom sections for the model picker.",
|
|
335
|
+
tags: ["llm"],
|
|
336
|
+
responses: {
|
|
337
|
+
200: {
|
|
338
|
+
description: "Hydrated model picker sections",
|
|
339
|
+
content: {
|
|
340
|
+
"application/json": {
|
|
341
|
+
schema: import_zod_openapi.z.object({
|
|
342
|
+
featured: import_zod_openapi.z.array(ModelPickerEntrySchema).describe("Curated featured models"),
|
|
343
|
+
recents: import_zod_openapi.z.array(ModelPickerEntrySchema).describe("Most recently used models"),
|
|
344
|
+
favorites: import_zod_openapi.z.array(ModelPickerEntrySchema).describe("User favorited models"),
|
|
345
|
+
custom: import_zod_openapi.z.array(ModelPickerEntrySchema).describe("User-defined custom models")
|
|
346
|
+
}).strict()
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
...ModelPickerErrorResponses
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
const recordRecentModelRoute = (0, import_zod_openapi.createRoute)({
|
|
354
|
+
method: "post",
|
|
355
|
+
path: "/llm/model-picker-state/recents",
|
|
356
|
+
summary: "Record Recent Model",
|
|
357
|
+
description: "Records a model selection in recents.",
|
|
358
|
+
tags: ["llm"],
|
|
359
|
+
request: {
|
|
360
|
+
body: {
|
|
361
|
+
required: true,
|
|
362
|
+
content: {
|
|
363
|
+
"application/json": {
|
|
364
|
+
schema: ModelPickerModelRefSchema
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
responses: {
|
|
370
|
+
200: {
|
|
371
|
+
description: "Recent model recorded",
|
|
372
|
+
content: {
|
|
373
|
+
"application/json": {
|
|
374
|
+
schema: import_zod_openapi.z.object({
|
|
375
|
+
ok: import_zod_openapi.z.literal(true).describe("Success indicator")
|
|
376
|
+
}).strict()
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
},
|
|
380
|
+
...ModelPickerErrorResponses
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
const toggleFavoriteModelRoute = (0, import_zod_openapi.createRoute)({
|
|
384
|
+
method: "post",
|
|
385
|
+
path: "/llm/model-picker-state/favorites/toggle",
|
|
386
|
+
summary: "Toggle Favorite Model",
|
|
387
|
+
description: "Adds or removes a model from favorites.",
|
|
388
|
+
tags: ["llm"],
|
|
389
|
+
request: {
|
|
390
|
+
body: {
|
|
391
|
+
required: true,
|
|
392
|
+
content: {
|
|
393
|
+
"application/json": {
|
|
394
|
+
schema: ModelPickerModelRefSchema
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
responses: {
|
|
400
|
+
200: {
|
|
401
|
+
description: "Favorite toggled",
|
|
402
|
+
content: {
|
|
403
|
+
"application/json": {
|
|
404
|
+
schema: import_zod_openapi.z.object({
|
|
405
|
+
ok: import_zod_openapi.z.literal(true).describe("Success indicator"),
|
|
406
|
+
isFavorite: import_zod_openapi.z.boolean().describe("Whether the model is now favorited")
|
|
407
|
+
}).strict()
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
...ModelPickerErrorResponses
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
const setFavoritesRoute = (0, import_zod_openapi.createRoute)({
|
|
415
|
+
method: "put",
|
|
416
|
+
path: "/llm/model-picker-state/favorites",
|
|
417
|
+
summary: "Set Favorite Models",
|
|
418
|
+
description: "Replaces favorite models list. Used by migration or bulk updates.",
|
|
419
|
+
tags: ["llm"],
|
|
420
|
+
request: {
|
|
421
|
+
body: {
|
|
422
|
+
required: true,
|
|
423
|
+
content: {
|
|
424
|
+
"application/json": {
|
|
425
|
+
schema: import_zod_openapi.z.object({
|
|
426
|
+
favorites: import_zod_openapi.z.array(ModelPickerModelRefSchema).describe("Complete list of favorite model references")
|
|
427
|
+
}).strict()
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
responses: {
|
|
433
|
+
200: {
|
|
434
|
+
description: "Favorites updated",
|
|
435
|
+
content: {
|
|
436
|
+
"application/json": {
|
|
437
|
+
schema: import_zod_openapi.z.object({
|
|
438
|
+
ok: import_zod_openapi.z.literal(true).describe("Success indicator"),
|
|
439
|
+
count: import_zod_openapi.z.number().int().nonnegative().describe("Number of favorites persisted")
|
|
440
|
+
}).strict()
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
...ModelPickerErrorResponses
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
const isProviderEnabled = (provider) => provider !== "dexto-nova" || (0, import_agent_management.isDextoAuthEnabled)();
|
|
448
|
+
const dedupeEntries = (entries) => {
|
|
449
|
+
const seen = /* @__PURE__ */ new Set();
|
|
450
|
+
const deduped = [];
|
|
451
|
+
for (const entry of entries) {
|
|
452
|
+
const key = (0, import_agent_management.toModelPickerKey)(entry);
|
|
453
|
+
if (seen.has(key)) {
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
seen.add(key);
|
|
457
|
+
deduped.push(entry);
|
|
458
|
+
}
|
|
459
|
+
return deduped;
|
|
460
|
+
};
|
|
461
|
+
const buildModelPickerSections = async () => {
|
|
462
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
463
|
+
const customSection = [];
|
|
464
|
+
for (const provider of import_core2.LLM_PROVIDERS) {
|
|
465
|
+
if (!isProviderEnabled(provider)) {
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
const providerInfo = import_core2.LLM_REGISTRY[provider];
|
|
469
|
+
for (const model of (0, import_core2.getAllModelsForProvider)(provider)) {
|
|
470
|
+
const supportedFileTypes = Array.isArray(model.supportedFileTypes) && model.supportedFileTypes.length > 0 ? model.supportedFileTypes : providerInfo.supportedFileTypes;
|
|
471
|
+
const entry = {
|
|
472
|
+
provider,
|
|
473
|
+
model: model.name,
|
|
474
|
+
displayName: model.displayName || model.name,
|
|
475
|
+
supportedFileTypes,
|
|
476
|
+
source: "catalog"
|
|
477
|
+
};
|
|
478
|
+
const key = (0, import_agent_management.toModelPickerKey)(entry);
|
|
479
|
+
if (!byKey.has(key)) {
|
|
480
|
+
byKey.set(key, entry);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
const customModels = await (0, import_agent_management.loadCustomModels)();
|
|
485
|
+
for (const customModel of customModels) {
|
|
486
|
+
const provider = customModel.provider ?? "openai-compatible";
|
|
487
|
+
if (!isProviderEnabled(provider)) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
const providerInfo = import_core2.LLM_REGISTRY[provider];
|
|
491
|
+
const entry = {
|
|
492
|
+
provider,
|
|
493
|
+
model: customModel.name,
|
|
494
|
+
displayName: customModel.displayName || customModel.name,
|
|
495
|
+
supportedFileTypes: providerInfo?.supportedFileTypes ?? [],
|
|
496
|
+
source: "custom"
|
|
497
|
+
};
|
|
498
|
+
byKey.set((0, import_agent_management.toModelPickerKey)(entry), entry);
|
|
499
|
+
customSection.push(entry);
|
|
500
|
+
}
|
|
501
|
+
const localProviderSupportedFileTypes = import_core2.LLM_REGISTRY.local.supportedFileTypes;
|
|
502
|
+
const installedLocalModels = await (0, import_agent_management.getAllInstalledModels)();
|
|
503
|
+
for (const installedModel of installedLocalModels) {
|
|
504
|
+
const modelInfo = (0, import_core2.getLocalModelById)(installedModel.id);
|
|
505
|
+
const entry = {
|
|
506
|
+
provider: "local",
|
|
507
|
+
model: installedModel.id,
|
|
508
|
+
displayName: modelInfo?.name || installedModel.id,
|
|
509
|
+
supportedFileTypes: localProviderSupportedFileTypes,
|
|
510
|
+
source: "local-installed"
|
|
511
|
+
};
|
|
512
|
+
byKey.set((0, import_agent_management.toModelPickerKey)(entry), entry);
|
|
513
|
+
}
|
|
514
|
+
const featuredProviders = import_core2.LLM_PROVIDERS.filter((provider) => isProviderEnabled(provider));
|
|
515
|
+
const featured = (0, import_core2.getCuratedModelRefsForProviders)({
|
|
516
|
+
providers: featuredProviders,
|
|
517
|
+
max: MODEL_PICKER_FEATURED_LIMIT
|
|
518
|
+
}).map((ref) => byKey.get((0, import_agent_management.toModelPickerKey)(ref))).filter((entry) => Boolean(entry));
|
|
519
|
+
const state = await (0, import_agent_management.loadModelPickerState)();
|
|
520
|
+
const pruned = (0, import_agent_management.pruneModelPickerState)({
|
|
521
|
+
state,
|
|
522
|
+
allowedKeys: new Set(byKey.keys())
|
|
523
|
+
});
|
|
524
|
+
const shouldPersistPrunedState = state.recents.length !== pruned.recents.length || state.favorites.length !== pruned.favorites.length;
|
|
525
|
+
if (shouldPersistPrunedState) {
|
|
526
|
+
void (0, import_agent_management.saveModelPickerState)(pruned).catch((error) => {
|
|
527
|
+
import_core.logger.warn(
|
|
528
|
+
`Failed to persist pruned model picker state: ${error instanceof Error ? error.message : String(error)}`
|
|
529
|
+
);
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
const recents = pruned.recents.map((entry) => byKey.get((0, import_agent_management.toModelPickerKey)(entry))).filter((entry) => Boolean(entry));
|
|
533
|
+
const favorites = pruned.favorites.map((entry) => byKey.get((0, import_agent_management.toModelPickerKey)(entry))).filter((entry) => Boolean(entry));
|
|
534
|
+
return {
|
|
535
|
+
featured: dedupeEntries(featured),
|
|
536
|
+
recents,
|
|
537
|
+
favorites,
|
|
538
|
+
custom: dedupeEntries(customSection)
|
|
539
|
+
};
|
|
540
|
+
};
|
|
289
541
|
return app.openapi(currentRoute, async (ctx) => {
|
|
290
542
|
const agent = await getAgent(ctx);
|
|
291
543
|
const { sessionId } = ctx.req.valid("query");
|
|
@@ -407,6 +659,13 @@ function createLlmRouter(getAgent) {
|
|
|
407
659
|
const raw = ctx.req.valid("json");
|
|
408
660
|
const { sessionId, ...llmUpdates } = raw;
|
|
409
661
|
const config = await agent.switchLLM(llmUpdates, sessionId);
|
|
662
|
+
try {
|
|
663
|
+
await (0, import_agent_management.recordRecentModel)({
|
|
664
|
+
provider: config.provider,
|
|
665
|
+
model: config.model
|
|
666
|
+
});
|
|
667
|
+
} catch {
|
|
668
|
+
}
|
|
410
669
|
const { apiKey, ...configWithoutKey } = config;
|
|
411
670
|
return ctx.json({
|
|
412
671
|
config: {
|
|
@@ -436,6 +695,29 @@ function createLlmRouter(getAgent) {
|
|
|
436
695
|
);
|
|
437
696
|
}
|
|
438
697
|
return ctx.json({ ok: true, deleted: name }, 200);
|
|
698
|
+
}).openapi(modelPickerStateRoute, async (ctx) => {
|
|
699
|
+
const sections = await buildModelPickerSections();
|
|
700
|
+
return ctx.json(sections);
|
|
701
|
+
}).openapi(recordRecentModelRoute, async (ctx) => {
|
|
702
|
+
const modelRef = ctx.req.valid("json");
|
|
703
|
+
await (0, import_agent_management.recordRecentModel)(modelRef);
|
|
704
|
+
return ctx.json({ ok: true });
|
|
705
|
+
}).openapi(toggleFavoriteModelRoute, async (ctx) => {
|
|
706
|
+
const modelRef = ctx.req.valid("json");
|
|
707
|
+
const result = await (0, import_agent_management.toggleFavoriteModel)(modelRef);
|
|
708
|
+
return ctx.json({
|
|
709
|
+
ok: true,
|
|
710
|
+
isFavorite: result.isFavorite
|
|
711
|
+
});
|
|
712
|
+
}).openapi(setFavoritesRoute, async (ctx) => {
|
|
713
|
+
const payload = ctx.req.valid("json");
|
|
714
|
+
const state = await (0, import_agent_management.setFavoriteModels)({
|
|
715
|
+
favorites: payload.favorites
|
|
716
|
+
});
|
|
717
|
+
return ctx.json({
|
|
718
|
+
ok: true,
|
|
719
|
+
count: state.favorites.length
|
|
720
|
+
});
|
|
439
721
|
}).openapi(capabilitiesRoute, (ctx) => {
|
|
440
722
|
const { provider, model } = ctx.req.valid("query");
|
|
441
723
|
let supportedFileTypes;
|