Sujal Shah
commited on
Commit
·
4ac0af4
1
Parent(s):
88700c2
fix: enhance prompt "Invalid or missing provider" bad request error
Browse files- app/lib/hooks/usePromptEnhancer.ts +19 -18
- app/routes/api.enhancer.ts +19 -14
app/lib/hooks/usePromptEnhancer.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import { useState } from 'react';
|
|
|
|
| 2 |
import { createScopedLogger } from '~/utils/logger';
|
| 3 |
|
| 4 |
const logger = createScopedLogger('usePromptEnhancement');
|
|
@@ -13,54 +14,54 @@ export function usePromptEnhancer() {
|
|
| 13 |
};
|
| 14 |
|
| 15 |
const enhancePrompt = async (
|
| 16 |
-
input: string,
|
| 17 |
setInput: (value: string) => void,
|
| 18 |
model: string,
|
| 19 |
-
provider:
|
| 20 |
-
apiKeys?: Record<string, string
|
| 21 |
) => {
|
| 22 |
setEnhancingPrompt(true);
|
| 23 |
setPromptEnhanced(false);
|
| 24 |
-
|
| 25 |
const requestBody: any = {
|
| 26 |
message: input,
|
| 27 |
model,
|
| 28 |
provider,
|
| 29 |
};
|
| 30 |
-
|
| 31 |
if (apiKeys) {
|
| 32 |
requestBody.apiKeys = apiKeys;
|
| 33 |
}
|
| 34 |
-
|
| 35 |
const response = await fetch('/api/enhancer', {
|
| 36 |
method: 'POST',
|
| 37 |
body: JSON.stringify(requestBody),
|
| 38 |
});
|
| 39 |
-
|
| 40 |
const reader = response.body?.getReader();
|
| 41 |
-
|
| 42 |
const originalInput = input;
|
| 43 |
-
|
| 44 |
if (reader) {
|
| 45 |
const decoder = new TextDecoder();
|
| 46 |
-
|
| 47 |
let _input = '';
|
| 48 |
let _error;
|
| 49 |
-
|
| 50 |
try {
|
| 51 |
setInput('');
|
| 52 |
-
|
| 53 |
while (true) {
|
| 54 |
const { value, done } = await reader.read();
|
| 55 |
-
|
| 56 |
if (done) {
|
| 57 |
break;
|
| 58 |
}
|
| 59 |
-
|
| 60 |
_input += decoder.decode(value);
|
| 61 |
-
|
| 62 |
logger.trace('Set input', _input);
|
| 63 |
-
|
| 64 |
setInput(_input);
|
| 65 |
}
|
| 66 |
} catch (error) {
|
|
@@ -70,10 +71,10 @@ export function usePromptEnhancer() {
|
|
| 70 |
if (_error) {
|
| 71 |
logger.error(_error);
|
| 72 |
}
|
| 73 |
-
|
| 74 |
setEnhancingPrompt(false);
|
| 75 |
setPromptEnhanced(true);
|
| 76 |
-
|
| 77 |
setTimeout(() => {
|
| 78 |
setInput(_input);
|
| 79 |
});
|
|
|
|
| 1 |
import { useState } from 'react';
|
| 2 |
+
import type { ProviderInfo } from '~/types/model';
|
| 3 |
import { createScopedLogger } from '~/utils/logger';
|
| 4 |
|
| 5 |
const logger = createScopedLogger('usePromptEnhancement');
|
|
|
|
| 14 |
};
|
| 15 |
|
| 16 |
const enhancePrompt = async (
|
| 17 |
+
input: string,
|
| 18 |
setInput: (value: string) => void,
|
| 19 |
model: string,
|
| 20 |
+
provider: ProviderInfo,
|
| 21 |
+
apiKeys?: Record<string, string>,
|
| 22 |
) => {
|
| 23 |
setEnhancingPrompt(true);
|
| 24 |
setPromptEnhanced(false);
|
| 25 |
+
|
| 26 |
const requestBody: any = {
|
| 27 |
message: input,
|
| 28 |
model,
|
| 29 |
provider,
|
| 30 |
};
|
| 31 |
+
|
| 32 |
if (apiKeys) {
|
| 33 |
requestBody.apiKeys = apiKeys;
|
| 34 |
}
|
| 35 |
+
|
| 36 |
const response = await fetch('/api/enhancer', {
|
| 37 |
method: 'POST',
|
| 38 |
body: JSON.stringify(requestBody),
|
| 39 |
});
|
| 40 |
+
|
| 41 |
const reader = response.body?.getReader();
|
| 42 |
+
|
| 43 |
const originalInput = input;
|
| 44 |
+
|
| 45 |
if (reader) {
|
| 46 |
const decoder = new TextDecoder();
|
| 47 |
+
|
| 48 |
let _input = '';
|
| 49 |
let _error;
|
| 50 |
+
|
| 51 |
try {
|
| 52 |
setInput('');
|
| 53 |
+
|
| 54 |
while (true) {
|
| 55 |
const { value, done } = await reader.read();
|
| 56 |
+
|
| 57 |
if (done) {
|
| 58 |
break;
|
| 59 |
}
|
| 60 |
+
|
| 61 |
_input += decoder.decode(value);
|
| 62 |
+
|
| 63 |
logger.trace('Set input', _input);
|
| 64 |
+
|
| 65 |
setInput(_input);
|
| 66 |
}
|
| 67 |
} catch (error) {
|
|
|
|
| 71 |
if (_error) {
|
| 72 |
logger.error(_error);
|
| 73 |
}
|
| 74 |
+
|
| 75 |
setEnhancingPrompt(false);
|
| 76 |
setPromptEnhanced(true);
|
| 77 |
+
|
| 78 |
setTimeout(() => {
|
| 79 |
setInput(_input);
|
| 80 |
});
|
app/routes/api.enhancer.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type ActionFunctionArgs } from '@remix-run/cloudflare';
|
|
| 2 |
import { StreamingTextResponse, parseStreamPart } from 'ai';
|
| 3 |
import { streamText } from '~/lib/.server/llm/stream-text';
|
| 4 |
import { stripIndents } from '~/utils/stripIndent';
|
| 5 |
-
import type {
|
| 6 |
|
| 7 |
const encoder = new TextEncoder();
|
| 8 |
const decoder = new TextDecoder();
|
|
@@ -12,25 +12,27 @@ export async function action(args: ActionFunctionArgs) {
|
|
| 12 |
}
|
| 13 |
|
| 14 |
async function enhancerAction({ context, request }: ActionFunctionArgs) {
|
| 15 |
-
const { message, model, provider, apiKeys } = await request.json<{
|
| 16 |
message: string;
|
| 17 |
model: string;
|
| 18 |
-
provider:
|
| 19 |
apiKeys?: Record<string, string>;
|
| 20 |
}>();
|
| 21 |
|
| 22 |
-
|
|
|
|
|
|
|
| 23 |
if (!model || typeof model !== 'string') {
|
| 24 |
throw new Response('Invalid or missing model', {
|
| 25 |
status: 400,
|
| 26 |
-
statusText: 'Bad Request'
|
| 27 |
});
|
| 28 |
}
|
| 29 |
|
| 30 |
-
if (!
|
| 31 |
throw new Response('Invalid or missing provider', {
|
| 32 |
status: 400,
|
| 33 |
-
statusText: 'Bad Request'
|
| 34 |
});
|
| 35 |
}
|
| 36 |
|
|
@@ -39,7 +41,9 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) {
|
|
| 39 |
[
|
| 40 |
{
|
| 41 |
role: 'user',
|
| 42 |
-
content:
|
|
|
|
|
|
|
| 43 |
I want you to improve the user prompt that is wrapped in \`<original_prompt>\` tags.
|
| 44 |
|
| 45 |
IMPORTANT: Only respond with the improved prompt and nothing else!
|
|
@@ -52,23 +56,24 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) {
|
|
| 52 |
],
|
| 53 |
context.cloudflare.env,
|
| 54 |
undefined,
|
| 55 |
-
apiKeys
|
| 56 |
);
|
| 57 |
|
| 58 |
const transformStream = new TransformStream({
|
| 59 |
transform(chunk, controller) {
|
| 60 |
const text = decoder.decode(chunk);
|
| 61 |
-
const lines = text.split('\n').filter(line => line.trim() !== '');
|
| 62 |
-
|
| 63 |
for (const line of lines) {
|
| 64 |
try {
|
| 65 |
const parsed = parseStreamPart(line);
|
|
|
|
| 66 |
if (parsed.type === 'text') {
|
| 67 |
controller.enqueue(encoder.encode(parsed.value));
|
| 68 |
}
|
| 69 |
} catch (e) {
|
| 70 |
-
//
|
| 71 |
-
console.warn('Failed to parse stream part:', line);
|
| 72 |
}
|
| 73 |
}
|
| 74 |
},
|
|
@@ -83,7 +88,7 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) {
|
|
| 83 |
if (error instanceof Error && error.message?.includes('API key')) {
|
| 84 |
throw new Response('Invalid or missing API key', {
|
| 85 |
status: 401,
|
| 86 |
-
statusText: 'Unauthorized'
|
| 87 |
});
|
| 88 |
}
|
| 89 |
|
|
|
|
| 2 |
import { StreamingTextResponse, parseStreamPart } from 'ai';
|
| 3 |
import { streamText } from '~/lib/.server/llm/stream-text';
|
| 4 |
import { stripIndents } from '~/utils/stripIndent';
|
| 5 |
+
import type { ProviderInfo } from '~/types/model';
|
| 6 |
|
| 7 |
const encoder = new TextEncoder();
|
| 8 |
const decoder = new TextDecoder();
|
|
|
|
| 12 |
}
|
| 13 |
|
| 14 |
async function enhancerAction({ context, request }: ActionFunctionArgs) {
|
| 15 |
+
const { message, model, provider, apiKeys } = await request.json<{
|
| 16 |
message: string;
|
| 17 |
model: string;
|
| 18 |
+
provider: ProviderInfo;
|
| 19 |
apiKeys?: Record<string, string>;
|
| 20 |
}>();
|
| 21 |
|
| 22 |
+
const { name: providerName } = provider;
|
| 23 |
+
|
| 24 |
+
// validate 'model' and 'provider' fields
|
| 25 |
if (!model || typeof model !== 'string') {
|
| 26 |
throw new Response('Invalid or missing model', {
|
| 27 |
status: 400,
|
| 28 |
+
statusText: 'Bad Request',
|
| 29 |
});
|
| 30 |
}
|
| 31 |
|
| 32 |
+
if (!providerName || typeof providerName !== 'string') {
|
| 33 |
throw new Response('Invalid or missing provider', {
|
| 34 |
status: 400,
|
| 35 |
+
statusText: 'Bad Request',
|
| 36 |
});
|
| 37 |
}
|
| 38 |
|
|
|
|
| 41 |
[
|
| 42 |
{
|
| 43 |
role: 'user',
|
| 44 |
+
content:
|
| 45 |
+
`[Model: ${model}]\n\n[Provider: ${providerName}]\n\n` +
|
| 46 |
+
stripIndents`
|
| 47 |
I want you to improve the user prompt that is wrapped in \`<original_prompt>\` tags.
|
| 48 |
|
| 49 |
IMPORTANT: Only respond with the improved prompt and nothing else!
|
|
|
|
| 56 |
],
|
| 57 |
context.cloudflare.env,
|
| 58 |
undefined,
|
| 59 |
+
apiKeys,
|
| 60 |
);
|
| 61 |
|
| 62 |
const transformStream = new TransformStream({
|
| 63 |
transform(chunk, controller) {
|
| 64 |
const text = decoder.decode(chunk);
|
| 65 |
+
const lines = text.split('\n').filter((line) => line.trim() !== '');
|
| 66 |
+
|
| 67 |
for (const line of lines) {
|
| 68 |
try {
|
| 69 |
const parsed = parseStreamPart(line);
|
| 70 |
+
|
| 71 |
if (parsed.type === 'text') {
|
| 72 |
controller.enqueue(encoder.encode(parsed.value));
|
| 73 |
}
|
| 74 |
} catch (e) {
|
| 75 |
+
// skip invalid JSON lines
|
| 76 |
+
console.warn('Failed to parse stream part:', line, e);
|
| 77 |
}
|
| 78 |
}
|
| 79 |
},
|
|
|
|
| 88 |
if (error instanceof Error && error.message?.includes('API key')) {
|
| 89 |
throw new Response('Invalid or missing API key', {
|
| 90 |
status: 401,
|
| 91 |
+
statusText: 'Unauthorized',
|
| 92 |
});
|
| 93 |
}
|
| 94 |
|