- Update package.json description to reflect new branding - Add fix_chat_input function to update Pro URL references - Rename all Dyad-related functions and tags to MoreMinimore - Update test files to use new function names - Remove Pro restrictions from Annotator component - Update branding text throughout the application
212 lines
6.5 KiB
TypeScript
212 lines
6.5 KiB
TypeScript
import { OpenAICompatibleChatLanguageModel } from "@ai-sdk/openai-compatible";
|
|
import {
|
|
FetchFunction,
|
|
loadApiKey,
|
|
withoutTrailingSlash,
|
|
} from "@ai-sdk/provider-utils";
|
|
|
|
import log from "electron-log";
|
|
import { getExtraProviderOptions } from "./thinking_utils";
|
|
import type { UserSettings } from "../../lib/schemas";
|
|
import { LanguageModelV2 } from "@ai-sdk/provider";
|
|
|
|
const logger = log.scope("llm_engine_provider");
|
|
|
|
export type ExampleChatModelId = string & {};
|
|
export interface ExampleChatSettings {}
|
|
export interface ExampleProviderSettings {
|
|
/**
|
|
Example API key.
|
|
*/
|
|
apiKey?: string;
|
|
/**
|
|
Base URL for the API calls.
|
|
*/
|
|
baseURL?: string;
|
|
/**
|
|
Custom headers to include in the requests.
|
|
*/
|
|
headers?: Record<string, string>;
|
|
/**
|
|
Optional custom url query parameters to include in request urls.
|
|
*/
|
|
queryParams?: Record<string, string>;
|
|
/**
|
|
Custom fetch implementation. You can use it as a middleware to intercept requests,
|
|
or to provide a custom fetch implementation for e.g. testing.
|
|
*/
|
|
fetch?: FetchFunction;
|
|
|
|
originalProviderId: string;
|
|
dyadOptions: {
|
|
enableLazyEdits?: boolean;
|
|
enableSmartFilesContext?: boolean;
|
|
enableWebSearch?: boolean;
|
|
};
|
|
settings: UserSettings;
|
|
}
|
|
|
|
export interface MoreMinimoreEngineProvider {
|
|
/**
|
|
Creates a model for text generation.
|
|
*/
|
|
(
|
|
modelId: ExampleChatModelId,
|
|
settings?: ExampleChatSettings,
|
|
): LanguageModelV2;
|
|
|
|
/**
|
|
Creates a chat model for text generation.
|
|
*/
|
|
chatModel(
|
|
modelId: ExampleChatModelId,
|
|
settings?: ExampleChatSettings,
|
|
): LanguageModelV2;
|
|
}
|
|
|
|
export function createMoreMinimoreEngine(
|
|
options: ExampleProviderSettings,
|
|
): MoreMinimoreEngineProvider {
|
|
const baseURL = withoutTrailingSlash(options.baseURL);
|
|
logger.info("creating dyad engine with baseURL", baseURL);
|
|
|
|
// Track request ID attempts
|
|
const requestIdAttempts = new Map<string, number>();
|
|
|
|
const getHeaders = () => ({
|
|
Authorization: `Bearer ${loadApiKey({
|
|
apiKey: options.apiKey,
|
|
environmentVariableName: "DYAD_PRO_API_KEY",
|
|
description: "Example API key",
|
|
})}`,
|
|
...options.headers,
|
|
});
|
|
|
|
interface CommonModelConfig {
|
|
provider: string;
|
|
url: ({ path }: { path: string }) => string;
|
|
headers: () => Record<string, string>;
|
|
fetch?: FetchFunction;
|
|
}
|
|
|
|
const getCommonModelConfig = (): CommonModelConfig => ({
|
|
provider: `dyad-engine`,
|
|
url: ({ path }) => {
|
|
const url = new URL(`${baseURL}${path}`);
|
|
if (options.queryParams) {
|
|
url.search = new URLSearchParams(options.queryParams).toString();
|
|
}
|
|
return url.toString();
|
|
},
|
|
headers: getHeaders,
|
|
fetch: options.fetch,
|
|
});
|
|
|
|
const createChatModel = (modelId: ExampleChatModelId) => {
|
|
// Create configuration with file handling
|
|
const config = {
|
|
...getCommonModelConfig(),
|
|
// defaultObjectGenerationMode:
|
|
// "tool" as LanguageModelV1ObjectGenerationMode,
|
|
// Custom fetch implementation that adds files to the request
|
|
fetch: (input: RequestInfo | URL, init?: RequestInit) => {
|
|
// Use default fetch if no init or body
|
|
if (!init || !init.body || typeof init.body !== "string") {
|
|
return (options.fetch || fetch)(input, init);
|
|
}
|
|
|
|
try {
|
|
// Parse the request body to manipulate it
|
|
const parsedBody = {
|
|
...JSON.parse(init.body),
|
|
...getExtraProviderOptions(
|
|
options.originalProviderId,
|
|
options.settings,
|
|
),
|
|
};
|
|
const dyadVersionedFiles = parsedBody.dyadVersionedFiles;
|
|
if ("dyadVersionedFiles" in parsedBody) {
|
|
delete parsedBody.dyadVersionedFiles;
|
|
}
|
|
const dyadFiles = parsedBody.dyadFiles;
|
|
if ("dyadFiles" in parsedBody) {
|
|
delete parsedBody.dyadFiles;
|
|
}
|
|
const requestId = parsedBody.dyadRequestId;
|
|
if ("dyadRequestId" in parsedBody) {
|
|
delete parsedBody.dyadRequestId;
|
|
}
|
|
const dyadAppId = parsedBody.dyadAppId;
|
|
if ("dyadAppId" in parsedBody) {
|
|
delete parsedBody.dyadAppId;
|
|
}
|
|
const dyadDisableFiles = parsedBody.dyadDisableFiles;
|
|
if ("dyadDisableFiles" in parsedBody) {
|
|
delete parsedBody.dyadDisableFiles;
|
|
}
|
|
const dyadMentionedApps = parsedBody.dyadMentionedApps;
|
|
if ("dyadMentionedApps" in parsedBody) {
|
|
delete parsedBody.dyadMentionedApps;
|
|
}
|
|
const dyadSmartContextMode = parsedBody.dyadSmartContextMode;
|
|
if ("dyadSmartContextMode" in parsedBody) {
|
|
delete parsedBody.dyadSmartContextMode;
|
|
}
|
|
|
|
// Track and modify requestId with attempt number
|
|
let modifiedRequestId = requestId;
|
|
if (requestId) {
|
|
const currentAttempt = (requestIdAttempts.get(requestId) || 0) + 1;
|
|
requestIdAttempts.set(requestId, currentAttempt);
|
|
modifiedRequestId = `${requestId}:attempt-${currentAttempt}`;
|
|
}
|
|
|
|
// Add files to the request if they exist
|
|
if (!dyadDisableFiles) {
|
|
parsedBody.dyad_options = {
|
|
files: dyadFiles,
|
|
versioned_files: dyadVersionedFiles,
|
|
enable_lazy_edits: options.dyadOptions.enableLazyEdits,
|
|
enable_smart_files_context:
|
|
options.dyadOptions.enableSmartFilesContext,
|
|
smart_context_mode: dyadSmartContextMode,
|
|
enable_web_search: options.dyadOptions.enableWebSearch,
|
|
app_id: dyadAppId,
|
|
};
|
|
if (dyadMentionedApps?.length) {
|
|
parsedBody.dyad_options.mentioned_apps = dyadMentionedApps;
|
|
}
|
|
}
|
|
|
|
// Return modified request with files included and requestId in headers
|
|
const modifiedInit = {
|
|
...init,
|
|
headers: {
|
|
...init.headers,
|
|
...(modifiedRequestId && {
|
|
"X-MoreMinimore-Request-Id": modifiedRequestId,
|
|
}),
|
|
},
|
|
body: JSON.stringify(parsedBody),
|
|
};
|
|
|
|
// Use the provided fetch or default fetch
|
|
return (options.fetch || fetch)(input, modifiedInit);
|
|
} catch (e) {
|
|
logger.error("Error parsing request body", e);
|
|
// If parsing fails, use original request
|
|
return (options.fetch || fetch)(input, init);
|
|
}
|
|
},
|
|
};
|
|
|
|
return new OpenAICompatibleChatLanguageModel(modelId, config);
|
|
};
|
|
|
|
const provider = (modelId: ExampleChatModelId) => createChatModel(modelId);
|
|
|
|
provider.chatModel = createChatModel;
|
|
|
|
return provider;
|
|
}
|