mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-26 17:06:23 +02:00
use rowboat model gateway when logged in
This commit is contained in:
parent
bd6ef0df28
commit
7311501343
8 changed files with 121 additions and 6 deletions
8
apps/x/packages/core/src/account/account.ts
Normal file
8
apps/x/packages/core/src/account/account.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import container from '../di/container.js';
|
||||
import { IOAuthRepo } from '../auth/repo.js';
|
||||
|
||||
export async function isSignedIn(): Promise<boolean> {
|
||||
const oauthRepo = container.resolve<IOAuthRepo>('oauthRepo');
|
||||
const { tokens } = await oauthRepo.read('rowboat');
|
||||
return !!tokens;
|
||||
}
|
||||
|
|
@ -15,6 +15,8 @@ import { isBlocked, extractCommandNames } from "../application/lib/command-execu
|
|||
import container from "../di/container.js";
|
||||
import { IModelConfigRepo } from "../models/repo.js";
|
||||
import { createProvider } from "../models/models.js";
|
||||
import { isSignedIn } from "../account/account.js";
|
||||
import { getGatewayProvider } from "../models/gateway.js";
|
||||
import { IAgentsRepo } from "./repo.js";
|
||||
import { IMonotonicallyIncreasingIdGenerator } from "../application/lib/id-gen.js";
|
||||
import { IBus } from "../application/lib/bus.js";
|
||||
|
|
@ -768,7 +770,9 @@ export async function* streamAgent({
|
|||
const tools = await buildTools(agent);
|
||||
|
||||
// set up provider + model
|
||||
const provider = createProvider(modelConfig.provider);
|
||||
const provider = await isSignedIn()
|
||||
? await getGatewayProvider()
|
||||
: createProvider(modelConfig.provider);
|
||||
const knowledgeGraphAgents = ["note_creation", "email-draft", "meeting-prep", "labeling_agent", "note_tagging_agent"];
|
||||
const modelId = (knowledgeGraphAgents.includes(state.agentName!) && modelConfig.knowledgeGraphModel)
|
||||
? modelConfig.knowledgeGraphModel
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ import type { ToolContext } from "./exec-tool.js";
|
|||
import { generateText } from "ai";
|
||||
import { createProvider } from "../../models/models.js";
|
||||
import { IModelConfigRepo } from "../../models/repo.js";
|
||||
import { isSignedIn } from "../../account/account.js";
|
||||
import { getGatewayProvider } from "../../models/gateway.js";
|
||||
// Parser libraries are loaded dynamically inside parseFile.execute()
|
||||
// to avoid pulling pdfjs-dist's DOM polyfills into the main bundle.
|
||||
// Import paths are computed so esbuild cannot statically resolve them.
|
||||
|
|
@ -632,7 +634,9 @@ export const BuiltinTools: z.infer<typeof BuiltinToolsSchema> = {
|
|||
// Resolve model config from DI container
|
||||
const modelConfigRepo = container.resolve<IModelConfigRepo>('modelConfigRepo');
|
||||
const modelConfig = await modelConfigRepo.getConfig();
|
||||
const provider = createProvider(modelConfig.provider);
|
||||
const provider = await isSignedIn()
|
||||
? await getGatewayProvider()
|
||||
: createProvider(modelConfig.provider);
|
||||
const model = provider.languageModel(modelConfig.model);
|
||||
|
||||
const userPrompt = prompt || 'Convert this file to well-structured markdown.';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
const SUPABASE_PROJECT_URL = 'http://127.0.0.1:54321';
|
||||
import { SUPABASE_PROJECT_URL } from '../config/env.js';
|
||||
|
||||
/**
|
||||
* Discovery configuration - how to get OAuth endpoints
|
||||
|
|
@ -56,7 +55,7 @@ const providerConfigs: ProviderConfig = {
|
|||
rowboat: {
|
||||
discovery: {
|
||||
mode: 'issuer',
|
||||
issuer: `${SUPABASE_PROJECT_URL}/.well-known/oauth-authorization-server`,
|
||||
issuer: `${SUPABASE_PROJECT_URL}/auth/v1/.well-known/oauth-authorization-server`,
|
||||
},
|
||||
client: {
|
||||
mode: 'dcr',
|
||||
|
|
|
|||
5
apps/x/packages/core/src/config/env.ts
Normal file
5
apps/x/packages/core/src/config/env.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export const ROWBOAT_AI_GATEWAY_BASE_URL =
|
||||
process.env.ROWBOAT_AI_GATEWAY_BASE_URL || 'http://localhost:3002/v1';
|
||||
|
||||
export const SUPABASE_PROJECT_URL =
|
||||
process.env.SUPABASE_PROJECT_URL || 'http://127.0.0.1:54321';
|
||||
86
apps/x/packages/core/src/models/gateway.ts
Normal file
86
apps/x/packages/core/src/models/gateway.ts
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import { ProviderV2 } from '@ai-sdk/provider';
|
||||
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
|
||||
import container from '../di/container.js';
|
||||
import { IOAuthRepo } from '../auth/repo.js';
|
||||
import { IClientRegistrationRepo } from '../auth/client-repo.js';
|
||||
import { getProviderConfig } from '../auth/providers.js';
|
||||
import * as oauthClient from '../auth/oauth-client.js';
|
||||
import { ROWBOAT_AI_GATEWAY_BASE_URL } from '../config/env.js';
|
||||
|
||||
async function getAccessToken(): Promise<string> {
|
||||
const oauthRepo = container.resolve<IOAuthRepo>('oauthRepo');
|
||||
const { tokens } = await oauthRepo.read('rowboat');
|
||||
if (!tokens) {
|
||||
throw new Error('Not signed into Rowboat');
|
||||
}
|
||||
|
||||
if (!oauthClient.isTokenExpired(tokens)) {
|
||||
return tokens.access_token;
|
||||
}
|
||||
|
||||
if (!tokens.refresh_token) {
|
||||
throw new Error('Rowboat token expired and no refresh token available. Please sign in again.');
|
||||
}
|
||||
|
||||
const providerConfig = getProviderConfig('rowboat');
|
||||
if (providerConfig.discovery.mode !== 'issuer') {
|
||||
throw new Error('Rowboat provider requires issuer discovery mode');
|
||||
}
|
||||
|
||||
const clientRepo = container.resolve<IClientRegistrationRepo>('clientRegistrationRepo');
|
||||
const registration = await clientRepo.getClientRegistration('rowboat');
|
||||
if (!registration) {
|
||||
throw new Error('Rowboat client not registered. Please sign in again.');
|
||||
}
|
||||
|
||||
const config = await oauthClient.discoverConfiguration(
|
||||
providerConfig.discovery.issuer,
|
||||
registration.client_id,
|
||||
);
|
||||
|
||||
const refreshed = await oauthClient.refreshTokens(
|
||||
config,
|
||||
tokens.refresh_token,
|
||||
tokens.scopes,
|
||||
);
|
||||
await oauthRepo.upsert('rowboat', { tokens: refreshed });
|
||||
|
||||
return refreshed.access_token;
|
||||
}
|
||||
|
||||
export async function getGatewayProvider(): Promise<ProviderV2> {
|
||||
const accessToken = await getAccessToken();
|
||||
return createOpenRouter({
|
||||
baseURL: ROWBOAT_AI_GATEWAY_BASE_URL,
|
||||
apiKey: accessToken,
|
||||
});
|
||||
}
|
||||
|
||||
type ProviderSummary = {
|
||||
id: string;
|
||||
name: string;
|
||||
models: Array<{
|
||||
id: string;
|
||||
name?: string;
|
||||
release_date?: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
export async function listGatewayModels(): Promise<{ providers: ProviderSummary[] }> {
|
||||
const accessToken = await getAccessToken();
|
||||
const response = await fetch(`${ROWBOAT_AI_GATEWAY_BASE_URL}/models`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Gateway /v1/models failed: ${response.status}`);
|
||||
}
|
||||
const body = await response.json() as { data: Array<{ id: string }> };
|
||||
const models = body.data.map((m) => ({ id: m.id }));
|
||||
return {
|
||||
providers: [{
|
||||
id: 'rowboat',
|
||||
name: 'Rowboat',
|
||||
models,
|
||||
}],
|
||||
};
|
||||
}
|
||||
|
|
@ -8,6 +8,8 @@ import { createOpenRouter } from '@openrouter/ai-sdk-provider';
|
|||
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
||||
import { LlmModelConfig, LlmProvider } from "@x/shared/dist/models.js";
|
||||
import z from "zod";
|
||||
import { isSignedIn } from "../account/account.js";
|
||||
import { getGatewayProvider } from "./gateway.js";
|
||||
|
||||
export const Provider = LlmProvider;
|
||||
export const ModelConfig = LlmModelConfig;
|
||||
|
|
@ -78,7 +80,9 @@ export async function testModelConnection(
|
|||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), effectiveTimeout);
|
||||
try {
|
||||
const provider = createProvider(providerConfig);
|
||||
const provider = await isSignedIn()
|
||||
? await getGatewayProvider()
|
||||
: createProvider(providerConfig);
|
||||
const languageModel = provider.languageModel(model);
|
||||
await generateText({
|
||||
model: languageModel,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue