Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ollama support #313

Merged
merged 29 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e07c382
initial soup of commits to add ollama support
keturiosakys Oct 9, 2024
240ba6a
formatting
keturiosakys Oct 9, 2024
6e3fbd8
Add mechanism to invoke ollama-specific prompts
brettimus Oct 9, 2024
41e6969
Add some tweaks to ollama prompting and response parsing
brettimus Oct 9, 2024
4cabaf0
Remove excessive logging
brettimus Oct 9, 2024
eab12e2
Reinforce schema in prompt
brettimus Oct 9, 2024
01f7984
Merge branch 'main' into ollama
brettimus Oct 9, 2024
2e75e6c
Add handler context - 3.1b has a big context window
brettimus Oct 9, 2024
9a26c9b
Do not use static anlaysis when ai provider is ollama
brettimus Oct 9, 2024
b5caf4c
Remove console.log
brettimus Oct 9, 2024
ae3f615
Make ollamaBaseUrl optional
brettimus Oct 9, 2024
269e4ea
Remove default value from the ollamaBaseUrl type
brettimus Oct 9, 2024
dd52729
split up the json schema and the tool into separate things so they ca…
keturiosakys Oct 11, 2024
5e39697
tweak prompts
keturiosakys Oct 11, 2024
831ab08
add a few shot to improve the likelihood that the tool gets called in…
keturiosakys Oct 11, 2024
f32d5a3
make sure the prefs get pulled
keturiosakys Oct 11, 2024
67c69b3
formatting
keturiosakys Oct 11, 2024
59bb8e3
formatting
keturiosakys Oct 11, 2024
a5c070a
Merge branch 'main' into ollama
keturiosakys Oct 21, 2024
62e569a
system prompt
keturiosakys Oct 21, 2024
527d9e0
add ollama to the settings
keturiosakys Oct 21, 2024
46421c1
add ollama flow to the request
keturiosakys Oct 21, 2024
cfcef16
formatting
keturiosakys Oct 21, 2024
1fa0302
get the correct provider property
keturiosakys Oct 21, 2024
58582a2
ollama default
keturiosakys Oct 21, 2024
f7302d1
update docs for AI settings
keturiosakys Oct 21, 2024
48bf5e0
improve error message
keturiosakys Oct 22, 2024
26144bb
fix the list and remove format checker for the website from CI
keturiosakys Oct 22, 2024
9dab0b4
formatting
keturiosakys Oct 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,16 @@
"@ai-sdk/anthropic": "^0.0.51",
"@ai-sdk/mistral": "^0.0.42",
"@ai-sdk/openai": "^0.0.66",
"@anthropic-ai/sdk": "^0.24.3",
"@clack/core": "^0.3.4",
"@clack/prompts": "^0.7.0",
"@neondatabase/api-client": "^1.10.3",
"giget": "^1.2.3",
brettimus marked this conversation as resolved.
Show resolved Hide resolved
"open": "^10.1.0",
"oslo": "^1.2.1",
"picocolors": "^1.0.1",
"@anthropic-ai/sdk": "^0.24.3",
"@fiberplane/fpx-types": "workspace:*",
"@hono/node-server": "^1.11.1",
"@hono/zod-validator": "^0.2.2",
"@iarna/toml": "^2.2.5",
"@langchain/core": "^0.2.15",
"@libsql/client": "^0.6.2",
"@neondatabase/api-client": "^1.10.3",
"acorn": "^8.11.3",
"acorn-walk": "^8.3.2",
"ai": "^3.4.10",
Expand All @@ -65,9 +61,14 @@
"drizzle-orm": "^0.33.0",
"drizzle-zod": "^0.5.1",
"figlet": "^1.7.0",
"giget": "^1.2.3",
"hono": "^4.6.2",
"minimatch": "^10.0.1",
"ollama-ai-provider": "^0.15.2",
"open": "^10.1.0",
"openai": "^4.47.1",
"oslo": "^1.2.1",
"picocolors": "^1.0.1",
"source-map": "^0.7.4",
"typescript": "^5.5.4",
"typescript-language-server": "^4.3.3",
Expand Down
130 changes: 112 additions & 18 deletions api/src/lib/ai/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { createAnthropic } from "@ai-sdk/anthropic";
import { createMistral } from "@ai-sdk/mistral";
import { createOpenAI } from "@ai-sdk/openai";
import type { Settings } from "@fiberplane/fpx-types";
import { generateObject } from "ai";
import { type APICallError, generateObject } from "ai";
import { createOllama } from "ollama-ai-provider";
import logger from "../../logger.js";
import { invokeRequestGenerationPrompt } from "./prompts.js";
import { requestSchema } from "./tools.js";
import { getSystemPrompt, invokeRequestGenerationPrompt } from "./prompts.js";
import { makeRequestTool, requestSchema } from "./tools.js";

function configureProvider(
aiProvider: string,
Expand Down Expand Up @@ -38,6 +39,14 @@ function configureProvider(
return mistral(providerConfig.model);
}

if (aiProvider === "ollama") {
const ollama = createOllama({
baseURL: providerConfig.baseUrl ?? undefined,
});

return ollama(providerConfig.model);
}

throw new Error("Unknown AI provider");
}

Expand Down Expand Up @@ -95,24 +104,94 @@ export async function generateRequestWithAiProvider({
});

try {
const samplePrompt = `
I need to make a request to one of my Hono api handlers.

Here are some recent requests/responses, which you can use as inspiration for future requests.
E.g., if we recently created a resource, you can look that resource up.

<history>
</history>

The request you make should be a GET request to route: /api/geese/:id

Here is the OpenAPI spec for the handler:
<openapi/>

Here is the middleware that will be applied to the request:
<middleware/>

Here is some additional context for the middleware that will be applied to the request:
<middlewareContext/>

Here is the code for the handler:
<code/>

Here is some additional context for the handler source code, if you need it:
<context/>
`;

const userPrompt = await invokeRequestGenerationPrompt({
persona,
method,
path,
handler,
handlerContext,
history,
openApiSpec,
middleware,
middlewareContext,
});

const systemPrompt = getSystemPrompt(persona, aiProvider);

const {
object: generatedObject,
warnings,
usage,
} = await generateObject({
model: provider,
schema: requestSchema,
prompt: await invokeRequestGenerationPrompt({
handler,
handlerContext,
history,
openApiSpec,
middleware,
middlewareContext,
persona,
method,
path,
}),
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: samplePrompt },
{
role: "assistant",
content: [
{
type: "tool-call",
toolCallId: "call_1",
toolName: "make_request",
args: makeRequestTool,
},
],
},
{
role: "tool",
content: [
{
type: "tool-result",
toolCallId: "call_1",
toolName: "make_request",
result: JSON.stringify({
path: "/api/users/123",
pathParams: [{ key: ":id", value: "123" }],
queryParams: [
{ key: "include", value: "profile" },
{ key: "fields", value: "name,email" },
],
body: JSON.stringify({
name: "John Doe",
email: "[email protected]",
}),
bodyType: { type: "json", isMultipart: false },
headers: [],
}),
},
],
},
{ role: "user", content: userPrompt },
],
});

logger.debug("Generated object, warnings, usage", {
Expand All @@ -134,17 +213,27 @@ export async function generateRequestWithAiProvider({
logger.error("Error generating request with AI provider", {
error,
});
const errorMessage =
error instanceof Error
? error.message
: "Error generating request with AI provider";
const errorMessage = createErrorMessage(error);
logger.debug("Error message", { errorMessage });
return {
data: null,
error: { message: errorMessage },
};
}
}

function createErrorMessage(error: unknown) {
if (typeof error === "object" && error !== null && "responseBody" in error) {
return `${(error as APICallError).message}: ${(error as APICallError).responseBody}`;
}

if (error instanceof Error) {
return error.message;
}

return "Error generating request with AI provider";
}

// NOTE - Copy-pasted from frontend
function hasValidAiConfig(settings: Settings) {
const provider = settings.aiProvider;
Expand All @@ -170,6 +259,11 @@ function hasValidAiConfig(settings: Settings) {
const model = mistral?.model;
return !!apiKey && !!model;
}
case "ollama": {
const ollama = settings.aiProviderConfigurations?.ollama;
const model = ollama?.model;
return !!model;
}
default:
return false;
}
Expand Down
Loading
Loading