genkitx-patientseek
Version:
A community plugin for Firebase Genkit to integrate DeepSeek medical models.
296 lines • 10.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.toOpenAIRole = toOpenAIRole;
exports.toOpenAiMessages = toOpenAiMessages;
exports.fromOpenAiToolCall = fromOpenAiToolCall;
exports.fromOpenAiChoice = fromOpenAiChoice;
exports.fromOpenAiChunkChoice = fromOpenAiChunkChoice;
exports.toOpenAiRequestBody = toOpenAiRequestBody;
exports.gptRunner = gptRunner;
const genkit_1 = require("genkit");
const models_js_1 = require("./models.js");
const utils_js_1 = require("./utils.js");
function toOpenAIRole(role) {
switch (role) {
case "user":
return "user";
case "model":
return "assistant";
case "system":
return "system";
case "tool":
return "tool";
default:
throw new Error(`role ${role} doesn't map to an OpenAI role.`);
}
}
function toOpenAiTool(tool) {
return {
type: "function",
function: {
name: tool.name,
parameters: tool.inputSchema !== null ? tool.inputSchema : undefined,
},
};
}
function toOpenAiMessages(messages) {
const openAiMsgs = [];
for (const message of messages) {
const msg = new genkit_1.Message(message);
const role = toOpenAIRole(message.role);
switch (role) {
case "user":
openAiMsgs.push({
role: role,
content: msg.text,
});
break;
case "system":
openAiMsgs.push({
role: role,
content: msg.text,
});
break;
case "assistant": {
const toolCalls = msg.content
.filter((part) => Boolean(part.toolRequest))
.map((part) => ({
id: part.toolRequest.ref ?? "",
type: "function",
function: {
name: part.toolRequest.name,
arguments: JSON.stringify(part.toolRequest.input),
},
}));
if (toolCalls.length > 0) {
openAiMsgs.push({
role: role,
tool_calls: toolCalls,
});
}
else {
openAiMsgs.push({
role: role,
content: msg.text,
});
}
break;
}
case "tool": {
const toolResponseParts = msg.toolResponseParts();
toolResponseParts.map((part) => {
openAiMsgs.push({
role: role,
tool_call_id: part.toolResponse.ref ?? "",
content: typeof part.toolResponse.output === "string"
? part.toolResponse.output
: JSON.stringify(part.toolResponse.output),
});
});
break;
}
}
}
return openAiMsgs;
}
const finishReasonMap = {
length: "length",
stop: "stop",
tool_calls: "stop",
content_filter: "blocked",
function_call: "other",
};
function fromOpenAiToolCall(toolCall, choice) {
if (!toolCall.function) {
throw Error(`Unexpected openAI chunk choice. tool_calls was provided but one or more tool_calls is missing.`);
}
const f = toolCall.function;
if (choice.finish_reason === "tool_calls") {
return {
toolRequest: {
name: f.name,
ref: toolCall.id,
input: f.arguments ? JSON.parse(f.arguments) : f.arguments,
},
};
}
else {
return {
toolRequest: {
name: f.name,
ref: toolCall.id,
input: "",
},
};
}
}
function fromOpenAiChoice(choice, jsonMode = false) {
const toolRequestParts = choice.message.tool_calls?.map((toolCall) => fromOpenAiToolCall(toolCall, choice));
return {
index: choice.index,
finishReason: finishReasonMap[choice.finish_reason] ||
"other",
message: {
role: "model",
content: toolRequestParts
? toolRequestParts
: [
jsonMode
? { data: JSON.parse(choice.message.content) }
: { text: choice.message.content },
],
},
custom: {},
};
}
function fromOpenAiChunkChoice(choice, jsonMode = false) {
const toolRequestParts = choice.delta.tool_calls?.map((toolCall) => fromOpenAiToolCall(toolCall, choice));
return {
index: choice.index,
finishReason: choice.finish_reason
? finishReasonMap[choice.finish_reason] || "other"
: "unknown",
message: {
role: "model",
content: toolRequestParts
? toolRequestParts
: [
jsonMode
? { data: JSON.parse(choice.delta.content) }
: { text: choice.delta.content },
],
},
custom: {},
};
}
function toOpenAiRequestBody(modelName, request) {
const model = models_js_1.SUPPORTED_DEEPSEEK_MODELS[modelName];
if (!model)
throw new Error(`Unsupported model: ${modelName}`);
const openAiMessages = toOpenAiMessages(request.messages);
const mappedModelName = request.config?.version || model.version || modelName;
const body = {
model: mappedModelName,
messages: openAiMessages,
temperature: request.config?.temperature,
max_tokens: request.config?.maxOutputTokens,
top_p: request.config?.topP,
stop: request.config?.stopSequences,
frequency_penalty: request.config?.frequencyPenalty,
logprobs: request.config?.logProbs,
presence_penalty: request.config?.presencePenalty,
seed: request.config?.seed,
top_logprobs: request.config?.topLogProbs,
user: request.config?.user,
tools: request.tools?.map(toOpenAiTool),
n: request.candidates,
};
const response_format = request.output?.format;
if (response_format &&
models_js_1.MODELS_SUPPORTING_OPENAI_RESPONSE_FORMAT.includes(mappedModelName)) {
if (response_format === "json" &&
model.info?.supports?.output?.includes("json")) {
body.response_format = {
type: "json_schema",
json_schema: { name: "default", strict: true, description: "default", schema: { type: "object", properties: {
text: { type: "string" }
} } },
};
}
else if (response_format === "text" &&
model.info?.supports?.output?.includes("text")) {
body.response_format = {
type: "text",
};
}
else {
throw new Error(`${response_format} format is not supported for GPT models currently`);
}
}
(0, utils_js_1.removeEmptyKeys)(body);
return body;
}
function gptRunner(name, client) {
return async (request, streamingCallback) => {
let response;
const body = toOpenAiRequestBody(name, request);
if (streamingCallback) {
const streamResponse = await client.chat.completions.create({
...body,
stream: true,
});
let accumulatedContent = "";
let accumulatedReasoningContent = "";
let currentIndex = 0;
try {
for await (const chunk of streamResponse) {
if (chunk.choices && chunk.choices.length > 0) {
const choice = chunk.choices[0];
currentIndex = choice.index || 0;
if (choice.delta) {
const deltaAny = choice.delta;
if (deltaAny.reasoning_content) {
accumulatedReasoningContent += deltaAny.reasoning_content;
streamingCallback?.({
index: currentIndex,
content: [{ text: deltaAny.reasoning_content }],
custom: { isReasoning: true }
});
}
if (choice.delta.content) {
accumulatedContent += choice.delta.content;
streamingCallback?.({
index: currentIndex,
content: [{ text: choice.delta.content }],
});
}
}
}
}
}
catch (error) {
console.error("Error processing stream chunk:", error);
}
response = {
id: `chatcmpl-${Date.now()}`,
object: "chat.completion",
created: Math.floor(Date.now() / 1000),
model: body.model,
choices: [
{
index: currentIndex,
message: {
role: "assistant",
content: accumulatedContent,
},
finish_reason: "stop",
},
],
usage: {
prompt_tokens: 0,
completion_tokens: 0,
total_tokens: 0,
},
};
if (accumulatedReasoningContent) {
response.reasoning_content = accumulatedReasoningContent;
}
}
else {
response = await client.chat.completions.create(body);
}
return {
candidates: response.choices.map((c) => fromOpenAiChoice(c, request.output?.format === "json")),
usage: {
inputTokens: response.usage?.prompt_tokens,
outputTokens: response.usage?.completion_tokens,
totalTokens: response.usage?.total_tokens,
},
custom: {
...response,
reasoning_content: response.reasoning_content
},
};
};
}
//# sourceMappingURL=runner.js.map