Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
66 changes: 66 additions & 0 deletions src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,30 @@
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.

import { createServerRootRoute } from '@tanstack/react-start/server'

import { Route as rootRouteImport } from './routes/__root'
Comment thread
nickytonline marked this conversation as resolved.
import { Route as IndexRouteImport } from './routes/index'
import { ServerRoute as ApiModelsServerRouteImport } from './routes/api/models'
import { ServerRoute as ApiChatServerRouteImport } from './routes/api/chat'

const rootServerRouteImport = createServerRootRoute()

const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
getParentRoute: () => rootRouteImport,
} as any)
const ApiModelsServerRoute = ApiModelsServerRouteImport.update({
id: '/api/models',
path: '/api/models',
getParentRoute: () => rootServerRouteImport,
} as any)
const ApiChatServerRoute = ApiChatServerRouteImport.update({
id: '/api/chat',
path: '/api/chat',
getParentRoute: () => rootServerRouteImport,
} as any)

export interface FileRoutesByFullPath {
'/': typeof IndexRoute
Expand All @@ -38,6 +54,31 @@ export interface FileRouteTypes {
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
}
export interface FileServerRoutesByFullPath {
'/api/chat': typeof ApiChatServerRoute
'/api/models': typeof ApiModelsServerRoute
}
export interface FileServerRoutesByTo {
'/api/chat': typeof ApiChatServerRoute
'/api/models': typeof ApiModelsServerRoute
}
export interface FileServerRoutesById {
__root__: typeof rootServerRouteImport
'/api/chat': typeof ApiChatServerRoute
'/api/models': typeof ApiModelsServerRoute
}
export interface FileServerRouteTypes {
fileServerRoutesByFullPath: FileServerRoutesByFullPath
fullPaths: '/api/chat' | '/api/models'
fileServerRoutesByTo: FileServerRoutesByTo
to: '/api/chat' | '/api/models'
id: '__root__' | '/api/chat' | '/api/models'
fileServerRoutesById: FileServerRoutesById
}
export interface RootServerRouteChildren {
ApiChatServerRoute: typeof ApiChatServerRoute
ApiModelsServerRoute: typeof ApiModelsServerRoute
}

declare module '@tanstack/react-router' {
interface FileRoutesByPath {
Expand All @@ -50,10 +91,35 @@ declare module '@tanstack/react-router' {
}
}
}
declare module '@tanstack/react-start/server' {
interface ServerFileRoutesByPath {
'/api/models': {
id: '/api/models'
path: '/api/models'
fullPath: '/api/models'
preLoaderRoute: typeof ApiModelsServerRouteImport
parentRoute: typeof rootServerRouteImport
}
'/api/chat': {
id: '/api/chat'
path: '/api/chat'
fullPath: '/api/chat'
preLoaderRoute: typeof ApiChatServerRouteImport
parentRoute: typeof rootServerRouteImport
}
}
}

const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
}
export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()
const rootServerRouteChildren: RootServerRouteChildren = {
ApiChatServerRoute: ApiChatServerRoute,
ApiModelsServerRoute: ApiModelsServerRoute,
}
export const serverRouteTree = rootServerRouteImport
._addFileChildren(rootServerRouteChildren)
._addFileTypes<FileServerRouteTypes>()
6 changes: 3 additions & 3 deletions src/routes/api/chat.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createAPIFileRoute } from '@tanstack/react-start/api'
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The routes build fine now and work.

❯ nr build                                

> build
> vite build

vite v6.3.5 building for production...
Generated route tree in 49ms
✓ 2131 modules transformed.
.tanstack/start/build/client-dist/.vite/manifest.json           0.75 kB │ gzip:   0.29 kB
.tanstack/start/build/client-dist/assets/styles-CQwW1aux.css   40.46 kB │ gzip:   8.22 kB
.tanstack/start/build/client-dist/assets/index-Cial-gel.js    225.23 kB │ gzip:  65.85 kB
.tanstack/start/build/client-dist/assets/main-ZcC2hSab.js     420.19 kB │ gzip: 134.14 kB
✓ built in 1.40s
vite v6.3.5 building SSR bundle for production...
"H3Error", "MIMES", "callNodeListener", "createApp", "createAppEventHandler", "createError", "createEvent", "createRouter", "defineLazyEventHandler", "defineNodeListener", "defineNodeMiddleware", "defineRequestMiddleware", "defineResponseMiddleware", "defineWebSocket", "dynamicEventHandler", "fromNodeMiddleware", "fromPlainHandler", "fromWebHandler", "isCorsOriginAllowed", "isError", "isEventHandler", "isStream", "isWebResponse", "lazyEventHandler", "promisifyNodeListener", "sanitizeStatusCode", "sanitizeStatusMessage", "serveStatic", "splitCookiesString", "toEventHandler", "toNodeListener", "toPlainHandler", "toWebHandler" and "useBase" are imported from external module "h3" but never used in "node_modules/@tanstack/start-server-core/dist/esm/h3.js" and "node_modules/@tanstack/start-server-core/dist/esm/index.js".
"default" is imported from external module "react" but never used in "src/contexts/UserContext.tsx", "src/hooks/useLocalStorage.ts", "src/contexts/ModelContext.tsx", "src/components/ui/button.tsx", "src/components/ThemeToggle.tsx", "src/components/ui/dropdown-menu.tsx", "src/components/Header.tsx", "src/components/ServerSelector.tsx", "src/components/ui/textarea.tsx", "src/components/ChatInput.tsx" and "src/components/Chat.tsx".
✓ 61 modules transformed.
[plugin vite:css-post] Sourcemap is likely to be incorrect: a plugin (vite:css-post) was used to transform files, but didn't generate a sourcemap for the transformation. Consult the plugin documentation for help
✓ built in 128ms
✔ Generated public .output/public                                                                                                                                             nitro 5:49:44 PM
ℹ Building Nitro Server (preset: node-server, compatibility date: 2024-11-13)                                                                                                 nitro 5:49:44 PM
✔ Nitro Server built                                                                                                                                                          nitro 5:49:46 PM
  ├─ .output/server/chunks/_/_tanstack-start-manifest_v-CevWQBeX.mjs (661 B) (328 B gzip)
  ├─ .output/server/chunks/_/_tanstack-start-manifest_v-CevWQBeX.mjs.map (126 B) (124 B gzip)
  ├─ .output/server/chunks/_/_tanstack-start-server-fn-manifest_v-DtgTK7xl.mjs (177 B) (142 B gzip)
  ├─ .output/server/chunks/_/_tanstack-start-server-fn-manifest_v-DtgTK7xl.mjs.map (136 B) (130 B gzip)
  ├─ .output/server/chunks/_/index-fZH4EjzZ.mjs (22.9 kB) (5.62 kB gzip)
  ├─ .output/server/chunks/_/index-fZH4EjzZ.mjs.map (17.4 kB) (4.35 kB gzip)
  ├─ .output/server/chunks/_/ssr.mjs (82.3 kB) (19.7 kB gzip)
  ├─ .output/server/chunks/_/ssr.mjs.map (275 B) (192 B gzip)
  ├─ .output/server/index.mjs (149 kB) (37 kB gzip)
  └─ .output/server/package.json (4.94 kB) (1.45 kB gzip)
Σ Total size: 5.27 MB (1.25 MB gzip)
✔ You can preview this build using node .output/server/index.mjs                                                                                                              nitro 5:49:46 PM
✔ Client and Server bundles for TanStack Start have been successfully built.

If you regenerate the routes if in dev mode or via npx @tanstack/router-cli@latest generate, it's normal to see a message like this for the moment. They're still sorting some stuff out in the devinxied Tanstack start, but the routes do work.

❯ npx @tanstack/router-cli@latest generate
Route file "import { createServerFileRoute } from '@tanstack/react-start/server'
import { chatRequestSchema } from '../../lib/schemas'
import OpenAI from 'openai'
import type { Tool } from 'openai/resources/responses/responses.mjs'
import { streamText } from '../../lib/streaming'

export const ServerRoute = createServerFileRoute('/api/chat').methods({
  async POST({ request }) {
    const bearerToken = request.headers.get('Authorization')?.split(' ')[1]

    try {
      const body = await request.json()

      // Ensure messages have the correct structure before validation
      const formattedBody = {
        ...body,
        messages: body.messages.map((msg: any) => ({
          ...msg,
          parts: [
            {
              type: 'text',
              text: msg.content,
            },
          ],
        })),
      }

      const result = chatRequestSchema.safeParse(formattedBody)

      if (!result.success) {
        console.error('Validation error:', result.error.errors)
        return new Response(JSON.stringify({ error: result.error.errors }), {
          status: 400,
          headers: { 'Content-Type': 'application/json' },
        })
      }

      const { messages, servers, model } = result.data

      if (messages.length === 0) {
        return new Response(JSON.stringify({ error: 'No messages provided' }), {
          status: 400,
          headers: { 'Content-Type': 'application/json' },
        })
      }

      // Function to sanitize server labels for OpenAI API requirements
      const sanitizeServerLabel = (name: string): string => {
        return name
          .replace(/[^a-zA-Z0-9\-_]/g, '_') // Replace invalid chars with underscore
          .replace(/^[^a-zA-Z]/, 'server_') // Ensure it starts with a letter
          .replace(/_{2,}/g, '_') // Replace multiple underscores with single one
      }

      const tools = Object.entries(servers)
        .filter(([_, server]) => server.status === 'connected')
        .map(([_id, server]) => ({
          type: 'mcp',
          server_label: sanitizeServerLabel(server.name),
          server_url: server.url,
          require_approval: 'never',
          headers: {
            Authorization: `Bearer ${bearerToken}`,
          },
        })) satisfies Tool[]

      // Format the conversation history into a single input string with proper message parts
      const input = messages
        .map((msg) => ({
          role: msg.role,
          parts: [
            {
              type: 'text',
              text: msg.content,
            },
          ],
        }))
        .map(
          (msg) =>
            `${msg.role === 'user' ? 'User' : 'Assistant'}: ${msg.parts[0].text}`,
        )
        .join('\n\n')

      const client = new OpenAI()
      const answer = await client.responses.create({
        model,
        tools,
        input,
        stream: true,
      })

      return streamText(answer)
    } catch (error) {
      console.error('Error in chat route:', error)
      return new Response(JSON.stringify({ error: 'Internal server error' }), {
        status: 500,
        headers: { 'Content-Type': 'application/json' },
      })
    }
  },
})
" does not export any route piece. This is likely a mistake.
Route file "import { createServerFileRoute } from '@tanstack/react-start/server'
import OpenAI from 'openai'

const SUPPORTED_MODEL_PREFIXES = [
  'gpt-4o',
  'chatgpt-4o',
  'gpt-4.1',
  'o1',
  'o3',
  'o4-mini',
]

function isSupportedModel(id: string) {
  return SUPPORTED_MODEL_PREFIXES.some((prefix) => id.startsWith(prefix))
}

export const ServerRoute = createServerFileRoute('/api/models').methods({
  async GET({ request }) {
    try {
      const client = new OpenAI()
      const models = await client.models.list()
      const filtered = models.data
        .filter((model) => isSupportedModel(model.id))
        .sort((a, b) => a.id.localeCompare(b.id))
      return new Response(JSON.stringify(filtered), {
        headers: { 'Content-Type': 'application/json' },
      })
    } catch (error) {
      console.error('Error fetching models:', error)
      return new Response(JSON.stringify({ error: 'Failed to fetch models' }), {
        status: 500,
        headers: { 'Content-Type': 'application/json' },
      })
    }
  },
})
" does not export any route piece. This is likely a mistake.
Generated route tree in 71ms

import { createServerFileRoute } from '@tanstack/react-start/server'
import { chatRequestSchema } from '../../lib/schemas'
import OpenAI from 'openai'
import type { Tool } from 'openai/resources/responses/responses.mjs'
import { streamText } from '../../lib/streaming'

export const route = createAPIFileRoute('/api/chat')({
POST: async ({ request }) => {
export const ServerRoute = createServerFileRoute('/api/chat').methods({
async POST({ request }) {
const bearerToken = request.headers.get('Authorization')?.split(' ')[1]

try {
Expand Down
8 changes: 3 additions & 5 deletions src/routes/api/models.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createAPIFileRoute } from '@tanstack/react-start/api'
import { createServerFileRoute } from '@tanstack/react-start/server'
import OpenAI from 'openai'

const SUPPORTED_MODEL_PREFIXES = [
Expand All @@ -14,16 +14,14 @@ function isSupportedModel(id: string) {
return SUPPORTED_MODEL_PREFIXES.some((prefix) => id.startsWith(prefix))
}

export const route = createAPIFileRoute('/api/models')({
GET: async () => {
export const ServerRoute = createServerFileRoute('/api/models').methods({
async GET({ request }) {
try {
const client = new OpenAI()
const models = await client.models.list()

const filtered = models.data
.filter((model) => isSupportedModel(model.id))
.sort((a, b) => a.id.localeCompare(b.id))

return new Response(JSON.stringify(filtered), {
headers: { 'Content-Type': 'application/json' },
})
Expand Down