Initial MVP: multiplexer + chat DB
This commit is contained in:
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
node_modules
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
dev.db
|
||||||
|
*.db
|
||||||
|
prisma/migrations
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
65
README.md
Normal file
65
README.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# llm-backend
|
||||||
|
|
||||||
|
Backend API for:
|
||||||
|
- LLM multiplexer (OpenAI / Anthropic / xAI (Grok))
|
||||||
|
- Personal chat database (chats/messages + LLM call log)
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
- Node.js + TypeScript
|
||||||
|
- Fastify (HTTP)
|
||||||
|
- Prisma + SQLite (dev)
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd llm-backend
|
||||||
|
cp .env.example .env
|
||||||
|
npm run db:migrate
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open docs: `http://localhost:8787/docs`
|
||||||
|
|
||||||
|
## Auth
|
||||||
|
|
||||||
|
Set `ADMIN_TOKEN` and send:
|
||||||
|
|
||||||
|
`Authorization: Bearer <ADMIN_TOKEN>`
|
||||||
|
|
||||||
|
If `ADMIN_TOKEN` is not set, the server runs in open mode (dev).
|
||||||
|
|
||||||
|
## Env
|
||||||
|
- `OPENAI_API_KEY`
|
||||||
|
- `ANTHROPIC_API_KEY`
|
||||||
|
- `XAI_API_KEY`
|
||||||
|
|
||||||
|
## API
|
||||||
|
- `GET /health`
|
||||||
|
- `GET /v1/chats`
|
||||||
|
- `POST /v1/chats`
|
||||||
|
- `GET /v1/chats/:chatId`
|
||||||
|
- `POST /v1/chats/:chatId/messages`
|
||||||
|
- `POST /v1/chat-completions`
|
||||||
|
|
||||||
|
`POST /v1/chat-completions` body example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"chatId": "<optional chat id>",
|
||||||
|
"provider": "openai",
|
||||||
|
"model": "gpt-4.1-mini",
|
||||||
|
"messages": [
|
||||||
|
{"role":"system","content":"You are helpful."},
|
||||||
|
{"role":"user","content":"Say hi"}
|
||||||
|
],
|
||||||
|
"temperature": 0.2,
|
||||||
|
"maxTokens": 256
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next steps (planned)
|
||||||
|
- SSE streaming (`/v1/chat-completions:stream`)
|
||||||
|
- Tool/function calling normalization
|
||||||
|
- User accounts + per-device API keys
|
||||||
|
- Postgres support + migrations for prod
|
||||||
|
- Attachments + embeddings + semantic search
|
||||||
39
generated/prisma/browser.ts
Normal file
39
generated/prisma/browser.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* This file should be your main import to use Prisma-related types and utilities in a browser.
|
||||||
|
* Use it to get access to models, enums, and input types.
|
||||||
|
*
|
||||||
|
* This file does not contain a `PrismaClient` class, nor several other helpers that are intended as server-side only.
|
||||||
|
* See `client.ts` for the standard, server-side entry point.
|
||||||
|
*
|
||||||
|
* 🟢 You can import this file directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Prisma from './internal/prismaNamespaceBrowser.js'
|
||||||
|
export { Prisma }
|
||||||
|
export * as $Enums from './enums.js'
|
||||||
|
export * from './enums.js';
|
||||||
|
/**
|
||||||
|
* Model User
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type User = Prisma.UserModel
|
||||||
|
/**
|
||||||
|
* Model Chat
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type Chat = Prisma.ChatModel
|
||||||
|
/**
|
||||||
|
* Model Message
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type Message = Prisma.MessageModel
|
||||||
|
/**
|
||||||
|
* Model LlmCall
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type LlmCall = Prisma.LlmCallModel
|
||||||
61
generated/prisma/client.ts
Normal file
61
generated/prisma/client.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* This file should be your main import to use Prisma. Through it you get access to all the models, enums, and input types.
|
||||||
|
* If you're looking for something you can import in the client-side of your application, please refer to the `browser.ts` file instead.
|
||||||
|
*
|
||||||
|
* 🟢 You can import this file directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as process from 'node:process'
|
||||||
|
import * as path from 'node:path'
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
globalThis['__dirname'] = path.dirname(fileURLToPath(import.meta.url))
|
||||||
|
|
||||||
|
import * as runtime from "@prisma/client/runtime/client"
|
||||||
|
import * as $Enums from "./enums.js"
|
||||||
|
import * as $Class from "./internal/class.js"
|
||||||
|
import * as Prisma from "./internal/prismaNamespace.js"
|
||||||
|
|
||||||
|
export * as $Enums from './enums.js'
|
||||||
|
export * from "./enums.js"
|
||||||
|
/**
|
||||||
|
* ## Prisma Client
|
||||||
|
*
|
||||||
|
* Type-safe database client for TypeScript
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const prisma = new PrismaClient()
|
||||||
|
* // Fetch zero or more Users
|
||||||
|
* const users = await prisma.user.findMany()
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/client).
|
||||||
|
*/
|
||||||
|
export const PrismaClient = $Class.getPrismaClientClass()
|
||||||
|
export type PrismaClient<LogOpts extends Prisma.LogLevel = never, OmitOpts extends Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>
|
||||||
|
export { Prisma }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model User
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type User = Prisma.UserModel
|
||||||
|
/**
|
||||||
|
* Model Chat
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type Chat = Prisma.ChatModel
|
||||||
|
/**
|
||||||
|
* Model Message
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type Message = Prisma.MessageModel
|
||||||
|
/**
|
||||||
|
* Model LlmCall
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type LlmCall = Prisma.LlmCallModel
|
||||||
460
generated/prisma/commonInputTypes.ts
Normal file
460
generated/prisma/commonInputTypes.ts
Normal file
@@ -0,0 +1,460 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* This file exports various common sort, input & filter types that are not directly linked to a particular model.
|
||||||
|
*
|
||||||
|
* 🟢 You can import this file directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type * as runtime from "@prisma/client/runtime/client"
|
||||||
|
import * as $Enums from "./enums.js"
|
||||||
|
import type * as Prisma from "./internal/prismaNamespace.js"
|
||||||
|
|
||||||
|
|
||||||
|
export type StringFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
in?: string[]
|
||||||
|
notIn?: string[]
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringFilter<$PrismaModel> | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DateTimeFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
in?: Date[] | string[]
|
||||||
|
notIn?: Date[] | string[]
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeFilter<$PrismaModel> | Date | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StringNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: string[] | null
|
||||||
|
notIn?: string[] | null
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SortOrderInput = {
|
||||||
|
sort: Prisma.SortOrder
|
||||||
|
nulls?: Prisma.NullsOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StringWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
in?: string[]
|
||||||
|
notIn?: string[]
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedStringFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedStringFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
in?: Date[] | string[]
|
||||||
|
notIn?: Date[] | string[]
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StringNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: string[] | null
|
||||||
|
notIn?: string[] | null
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
|
||||||
|
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumMessageRoleFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.MessageRole | Prisma.EnumMessageRoleFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.MessageRole[]
|
||||||
|
notIn?: $Enums.MessageRole[]
|
||||||
|
not?: Prisma.NestedEnumMessageRoleFilter<$PrismaModel> | $Enums.MessageRole
|
||||||
|
}
|
||||||
|
|
||||||
|
export type JsonNullableFilter<$PrismaModel = never> =
|
||||||
|
| Prisma.PatchUndefined<
|
||||||
|
Prisma.Either<Required<JsonNullableFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonNullableFilterBase<$PrismaModel>>, 'path'>>,
|
||||||
|
Required<JsonNullableFilterBase<$PrismaModel>>
|
||||||
|
>
|
||||||
|
| Prisma.OptionalFlat<Omit<Required<JsonNullableFilterBase<$PrismaModel>>, 'path'>>
|
||||||
|
|
||||||
|
export type JsonNullableFilterBase<$PrismaModel = never> = {
|
||||||
|
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
path?: string
|
||||||
|
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
|
||||||
|
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumMessageRoleWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.MessageRole | Prisma.EnumMessageRoleFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.MessageRole[]
|
||||||
|
notIn?: $Enums.MessageRole[]
|
||||||
|
not?: Prisma.NestedEnumMessageRoleWithAggregatesFilter<$PrismaModel> | $Enums.MessageRole
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumMessageRoleFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumMessageRoleFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type JsonNullableWithAggregatesFilter<$PrismaModel = never> =
|
||||||
|
| Prisma.PatchUndefined<
|
||||||
|
Prisma.Either<Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>, 'path'>>,
|
||||||
|
Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>
|
||||||
|
>
|
||||||
|
| Prisma.OptionalFlat<Omit<Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>, 'path'>>
|
||||||
|
|
||||||
|
export type JsonNullableWithAggregatesFilterBase<$PrismaModel = never> = {
|
||||||
|
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
path?: string
|
||||||
|
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
|
||||||
|
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedJsonNullableFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedJsonNullableFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumProviderFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.Provider | Prisma.EnumProviderFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.Provider[]
|
||||||
|
notIn?: $Enums.Provider[]
|
||||||
|
not?: Prisma.NestedEnumProviderFilter<$PrismaModel> | $Enums.Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
export type JsonFilter<$PrismaModel = never> =
|
||||||
|
| Prisma.PatchUndefined<
|
||||||
|
Prisma.Either<Required<JsonFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonFilterBase<$PrismaModel>>, 'path'>>,
|
||||||
|
Required<JsonFilterBase<$PrismaModel>>
|
||||||
|
>
|
||||||
|
| Prisma.OptionalFlat<Omit<Required<JsonFilterBase<$PrismaModel>>, 'path'>>
|
||||||
|
|
||||||
|
export type JsonFilterBase<$PrismaModel = never> = {
|
||||||
|
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
path?: string
|
||||||
|
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
|
||||||
|
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IntNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: number[] | null
|
||||||
|
notIn?: number[] | null
|
||||||
|
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EnumProviderWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.Provider | Prisma.EnumProviderFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.Provider[]
|
||||||
|
notIn?: $Enums.Provider[]
|
||||||
|
not?: Prisma.NestedEnumProviderWithAggregatesFilter<$PrismaModel> | $Enums.Provider
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumProviderFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumProviderFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type JsonWithAggregatesFilter<$PrismaModel = never> =
|
||||||
|
| Prisma.PatchUndefined<
|
||||||
|
Prisma.Either<Required<JsonWithAggregatesFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonWithAggregatesFilterBase<$PrismaModel>>, 'path'>>,
|
||||||
|
Required<JsonWithAggregatesFilterBase<$PrismaModel>>
|
||||||
|
>
|
||||||
|
| Prisma.OptionalFlat<Omit<Required<JsonWithAggregatesFilterBase<$PrismaModel>>, 'path'>>
|
||||||
|
|
||||||
|
export type JsonWithAggregatesFilterBase<$PrismaModel = never> = {
|
||||||
|
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
path?: string
|
||||||
|
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
|
||||||
|
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedJsonFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedJsonFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IntNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: number[] | null
|
||||||
|
notIn?: number[] | null
|
||||||
|
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedIntNullableWithAggregatesFilter<$PrismaModel> | number | null
|
||||||
|
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_avg?: Prisma.NestedFloatNullableFilter<$PrismaModel>
|
||||||
|
_sum?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedStringFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
in?: string[]
|
||||||
|
notIn?: string[]
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringFilter<$PrismaModel> | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedDateTimeFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
in?: Date[] | string[]
|
||||||
|
notIn?: Date[] | string[]
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeFilter<$PrismaModel> | Date | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedStringNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: string[] | null
|
||||||
|
notIn?: string[] | null
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedStringWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
in?: string[]
|
||||||
|
notIn?: string[]
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedStringFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedStringFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedIntFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
in?: number[]
|
||||||
|
notIn?: number[]
|
||||||
|
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedIntFilter<$PrismaModel> | number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
in?: Date[] | string[]
|
||||||
|
notIn?: Date[] | string[]
|
||||||
|
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: string[] | null
|
||||||
|
notIn?: string[] | null
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
|
||||||
|
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedIntNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: number[] | null
|
||||||
|
notIn?: number[] | null
|
||||||
|
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumMessageRoleFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.MessageRole | Prisma.EnumMessageRoleFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.MessageRole[]
|
||||||
|
notIn?: $Enums.MessageRole[]
|
||||||
|
not?: Prisma.NestedEnumMessageRoleFilter<$PrismaModel> | $Enums.MessageRole
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumMessageRoleWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.MessageRole | Prisma.EnumMessageRoleFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.MessageRole[]
|
||||||
|
notIn?: $Enums.MessageRole[]
|
||||||
|
not?: Prisma.NestedEnumMessageRoleWithAggregatesFilter<$PrismaModel> | $Enums.MessageRole
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumMessageRoleFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumMessageRoleFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedJsonNullableFilter<$PrismaModel = never> =
|
||||||
|
| Prisma.PatchUndefined<
|
||||||
|
Prisma.Either<Required<NestedJsonNullableFilterBase<$PrismaModel>>, Exclude<keyof Required<NestedJsonNullableFilterBase<$PrismaModel>>, 'path'>>,
|
||||||
|
Required<NestedJsonNullableFilterBase<$PrismaModel>>
|
||||||
|
>
|
||||||
|
| Prisma.OptionalFlat<Omit<Required<NestedJsonNullableFilterBase<$PrismaModel>>, 'path'>>
|
||||||
|
|
||||||
|
export type NestedJsonNullableFilterBase<$PrismaModel = never> = {
|
||||||
|
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
path?: string
|
||||||
|
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
|
||||||
|
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumProviderFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.Provider | Prisma.EnumProviderFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.Provider[]
|
||||||
|
notIn?: $Enums.Provider[]
|
||||||
|
not?: Prisma.NestedEnumProviderFilter<$PrismaModel> | $Enums.Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedEnumProviderWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: $Enums.Provider | Prisma.EnumProviderFieldRefInput<$PrismaModel>
|
||||||
|
in?: $Enums.Provider[]
|
||||||
|
notIn?: $Enums.Provider[]
|
||||||
|
not?: Prisma.NestedEnumProviderWithAggregatesFilter<$PrismaModel> | $Enums.Provider
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedEnumProviderFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedEnumProviderFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedJsonFilter<$PrismaModel = never> =
|
||||||
|
| Prisma.PatchUndefined<
|
||||||
|
Prisma.Either<Required<NestedJsonFilterBase<$PrismaModel>>, Exclude<keyof Required<NestedJsonFilterBase<$PrismaModel>>, 'path'>>,
|
||||||
|
Required<NestedJsonFilterBase<$PrismaModel>>
|
||||||
|
>
|
||||||
|
| Prisma.OptionalFlat<Omit<Required<NestedJsonFilterBase<$PrismaModel>>, 'path'>>
|
||||||
|
|
||||||
|
export type NestedJsonFilterBase<$PrismaModel = never> = {
|
||||||
|
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
path?: string
|
||||||
|
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
|
||||||
|
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||||
|
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedIntNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: number[] | null
|
||||||
|
notIn?: number[] | null
|
||||||
|
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedIntNullableWithAggregatesFilter<$PrismaModel> | number | null
|
||||||
|
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_avg?: Prisma.NestedFloatNullableFilter<$PrismaModel>
|
||||||
|
_sum?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedFloatNullableFilter<$PrismaModel = never> = {
|
||||||
|
equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: number[] | null
|
||||||
|
notIn?: number[] | null
|
||||||
|
lt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
|
||||||
|
lte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
|
||||||
|
gt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
|
||||||
|
gte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedFloatNullableFilter<$PrismaModel> | number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
28
generated/prisma/enums.ts
Normal file
28
generated/prisma/enums.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* This file exports all enum related types from the schema.
|
||||||
|
*
|
||||||
|
* 🟢 You can import this file directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const Provider = {
|
||||||
|
openai: 'openai',
|
||||||
|
anthropic: 'anthropic',
|
||||||
|
xai: 'xai'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type Provider = (typeof Provider)[keyof typeof Provider]
|
||||||
|
|
||||||
|
|
||||||
|
export const MessageRole = {
|
||||||
|
system: 'system',
|
||||||
|
user: 'user',
|
||||||
|
assistant: 'assistant',
|
||||||
|
tool: 'tool'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type MessageRole = (typeof MessageRole)[keyof typeof MessageRole]
|
||||||
222
generated/prisma/internal/class.ts
Normal file
222
generated/prisma/internal/class.ts
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* WARNING: This is an internal file that is subject to change!
|
||||||
|
*
|
||||||
|
* 🛑 Under no circumstances should you import this file directly! 🛑
|
||||||
|
*
|
||||||
|
* Please import the `PrismaClient` class from the `client.ts` file instead.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as runtime from "@prisma/client/runtime/client"
|
||||||
|
import type * as Prisma from "./prismaNamespace.js"
|
||||||
|
|
||||||
|
|
||||||
|
const config: runtime.GetPrismaClientConfig = {
|
||||||
|
"previewFeatures": [],
|
||||||
|
"clientVersion": "7.3.0",
|
||||||
|
"engineVersion": "9d6ad21cbbceab97458517b147a6a09ff43aa735",
|
||||||
|
"activeProvider": "sqlite",
|
||||||
|
"inlineSchema": "// Prisma schema for the personal chat DB + LLM call log\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n}\n\nenum Provider {\n openai\n anthropic\n xai\n}\n\nenum MessageRole {\n system\n user\n assistant\n tool\n}\n\nmodel User {\n id String @id @default(cuid())\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // minimal for now (single-user is fine). Keep extensible.\n handle String? @unique\n\n chats Chat[]\n}\n\nmodel Chat {\n id String @id @default(cuid())\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n title String?\n\n user User? @relation(fields: [userId], references: [id])\n userId String?\n\n messages Message[]\n calls LlmCall[]\n\n @@index([userId])\n}\n\nmodel Message {\n id String @id @default(cuid())\n createdAt DateTime @default(now())\n\n chat Chat @relation(fields: [chatId], references: [id], onDelete: Cascade)\n chatId String\n\n role MessageRole\n content String\n\n // for tool messages or attachments later\n name String?\n metadata Json?\n\n @@index([chatId, createdAt])\n}\n\nmodel LlmCall {\n id String @id @default(cuid())\n createdAt DateTime @default(now())\n\n chat Chat @relation(fields: [chatId], references: [id], onDelete: Cascade)\n chatId String\n\n provider Provider\n model String\n\n // request/response snapshots for debugging + replay\n request Json\n response Json?\n\n // usage/cost basics\n inputTokens Int?\n outputTokens Int?\n totalTokens Int?\n\n latencyMs Int?\n\n error String?\n\n @@index([chatId, createdAt])\n @@index([provider, model, createdAt])\n}\n",
|
||||||
|
"runtimeDataModel": {
|
||||||
|
"models": {},
|
||||||
|
"enums": {},
|
||||||
|
"types": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"handle\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"chats\",\"kind\":\"object\",\"type\":\"Chat\",\"relationName\":\"ChatToUser\"}],\"dbName\":null},\"Chat\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"ChatToUser\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"messages\",\"kind\":\"object\",\"type\":\"Message\",\"relationName\":\"ChatToMessage\"},{\"name\":\"calls\",\"kind\":\"object\",\"type\":\"LlmCall\",\"relationName\":\"ChatToLlmCall\"}],\"dbName\":null},\"Message\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"chat\",\"kind\":\"object\",\"type\":\"Chat\",\"relationName\":\"ChatToMessage\"},{\"name\":\"chatId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"MessageRole\"},{\"name\":\"content\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"metadata\",\"kind\":\"scalar\",\"type\":\"Json\"}],\"dbName\":null},\"LlmCall\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"chat\",\"kind\":\"object\",\"type\":\"Chat\",\"relationName\":\"ChatToLlmCall\"},{\"name\":\"chatId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"provider\",\"kind\":\"enum\",\"type\":\"Provider\"},{\"name\":\"model\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"request\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"response\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"inputTokens\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"outputTokens\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"totalTokens\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"latencyMs\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"error\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}")
|
||||||
|
|
||||||
|
async function decodeBase64AsWasm(wasmBase64: string): Promise<WebAssembly.Module> {
|
||||||
|
const { Buffer } = await import('node:buffer')
|
||||||
|
const wasmArray = Buffer.from(wasmBase64, 'base64')
|
||||||
|
return new WebAssembly.Module(wasmArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
config.compilerWasm = {
|
||||||
|
getRuntime: async () => await import("@prisma/client/runtime/query_compiler_fast_bg.sqlite.mjs"),
|
||||||
|
|
||||||
|
getQueryCompilerWasmModule: async () => {
|
||||||
|
const { wasm } = await import("@prisma/client/runtime/query_compiler_fast_bg.sqlite.wasm-base64.mjs")
|
||||||
|
return await decodeBase64AsWasm(wasm)
|
||||||
|
},
|
||||||
|
|
||||||
|
importName: "./query_compiler_fast_bg.js"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export type LogOptions<ClientOptions extends Prisma.PrismaClientOptions> =
|
||||||
|
'log' extends keyof ClientOptions ? ClientOptions['log'] extends Array<Prisma.LogLevel | Prisma.LogDefinition> ? Prisma.GetEvents<ClientOptions['log']> : never : never
|
||||||
|
|
||||||
|
export interface PrismaClientConstructor {
|
||||||
|
/**
|
||||||
|
* ## Prisma Client
|
||||||
|
*
|
||||||
|
* Type-safe database client for TypeScript
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const prisma = new PrismaClient()
|
||||||
|
* // Fetch zero or more Users
|
||||||
|
* const users = await prisma.user.findMany()
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/client).
|
||||||
|
*/
|
||||||
|
|
||||||
|
new <
|
||||||
|
Options extends Prisma.PrismaClientOptions = Prisma.PrismaClientOptions,
|
||||||
|
LogOpts extends LogOptions<Options> = LogOptions<Options>,
|
||||||
|
OmitOpts extends Prisma.PrismaClientOptions['omit'] = Options extends { omit: infer U } ? U : Prisma.PrismaClientOptions['omit'],
|
||||||
|
ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs
|
||||||
|
>(options: Prisma.Subset<Options, Prisma.PrismaClientOptions> ): PrismaClient<LogOpts, OmitOpts, ExtArgs>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ## Prisma Client
|
||||||
|
*
|
||||||
|
* Type-safe database client for TypeScript
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const prisma = new PrismaClient()
|
||||||
|
* // Fetch zero or more Users
|
||||||
|
* const users = await prisma.user.findMany()
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/client).
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface PrismaClient<
|
||||||
|
in LogOpts extends Prisma.LogLevel = never,
|
||||||
|
in out OmitOpts extends Prisma.PrismaClientOptions['omit'] = undefined,
|
||||||
|
in out ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs
|
||||||
|
> {
|
||||||
|
[K: symbol]: { types: Prisma.TypeMap<ExtArgs>['other'] }
|
||||||
|
|
||||||
|
$on<V extends LogOpts>(eventType: V, callback: (event: V extends 'query' ? Prisma.QueryEvent : Prisma.LogEvent) => void): PrismaClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect with the database
|
||||||
|
*/
|
||||||
|
$connect(): runtime.Types.Utils.JsPromise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect from the database
|
||||||
|
*/
|
||||||
|
$disconnect(): runtime.Types.Utils.JsPromise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a prepared raw query and returns the number of affected rows.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const result = await prisma.$executeRaw`UPDATE User SET cool = ${true} WHERE email = ${'user@email.com'};`
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||||
|
*/
|
||||||
|
$executeRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a raw query and returns the number of affected rows.
|
||||||
|
* Susceptible to SQL injections, see documentation.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const result = await prisma.$executeRawUnsafe('UPDATE User SET cool = $1 WHERE email = $2 ;', true, 'user@email.com')
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||||
|
*/
|
||||||
|
$executeRawUnsafe<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a prepared raw query and returns the `SELECT` data.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${1} OR email = ${'user@email.com'};`
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||||
|
*/
|
||||||
|
$queryRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a raw query and returns the `SELECT` data.
|
||||||
|
* Susceptible to SQL injections, see documentation.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const result = await prisma.$queryRawUnsafe('SELECT * FROM User WHERE id = $1 OR email = $2;', 1, 'user@email.com')
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||||
|
*/
|
||||||
|
$queryRawUnsafe<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<T>;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the running of a sequence of read/write operations that are guaranteed to either succeed or fail as a whole.
|
||||||
|
* @example
|
||||||
|
* ```
|
||||||
|
* const [george, bob, alice] = await prisma.$transaction([
|
||||||
|
* prisma.user.create({ data: { name: 'George' } }),
|
||||||
|
* prisma.user.create({ data: { name: 'Bob' } }),
|
||||||
|
* prisma.user.create({ data: { name: 'Alice' } }),
|
||||||
|
* ])
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Read more in our [docs](https://www.prisma.io/docs/concepts/components/prisma-client/transactions).
|
||||||
|
*/
|
||||||
|
$transaction<P extends Prisma.PrismaPromise<any>[]>(arg: [...P], options?: { isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<runtime.Types.Utils.UnwrapTuple<P>>
|
||||||
|
|
||||||
|
$transaction<R>(fn: (prisma: Omit<PrismaClient, runtime.ITXClientDenyList>) => runtime.Types.Utils.JsPromise<R>, options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<R>
|
||||||
|
|
||||||
|
$extends: runtime.Types.Extensions.ExtendsHook<"extends", Prisma.TypeMapCb<OmitOpts>, ExtArgs, runtime.Types.Utils.Call<Prisma.TypeMapCb<OmitOpts>, {
|
||||||
|
extArgs: ExtArgs
|
||||||
|
}>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `prisma.user`: Exposes CRUD operations for the **User** model.
|
||||||
|
* Example usage:
|
||||||
|
* ```ts
|
||||||
|
* // Fetch zero or more Users
|
||||||
|
* const users = await prisma.user.findMany()
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
get user(): Prisma.UserDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `prisma.chat`: Exposes CRUD operations for the **Chat** model.
|
||||||
|
* Example usage:
|
||||||
|
* ```ts
|
||||||
|
* // Fetch zero or more Chats
|
||||||
|
* const chats = await prisma.chat.findMany()
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
get chat(): Prisma.ChatDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `prisma.message`: Exposes CRUD operations for the **Message** model.
|
||||||
|
* Example usage:
|
||||||
|
* ```ts
|
||||||
|
* // Fetch zero or more Messages
|
||||||
|
* const messages = await prisma.message.findMany()
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
get message(): Prisma.MessageDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `prisma.llmCall`: Exposes CRUD operations for the **LlmCall** model.
|
||||||
|
* Example usage:
|
||||||
|
* ```ts
|
||||||
|
* // Fetch zero or more LlmCalls
|
||||||
|
* const llmCalls = await prisma.llmCall.findMany()
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
get llmCall(): Prisma.LlmCallDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPrismaClientClass(): PrismaClientConstructor {
|
||||||
|
return runtime.getPrismaClient(config) as unknown as PrismaClientConstructor
|
||||||
|
}
|
||||||
1064
generated/prisma/internal/prismaNamespace.ts
Normal file
1064
generated/prisma/internal/prismaNamespace.ts
Normal file
File diff suppressed because it is too large
Load Diff
171
generated/prisma/internal/prismaNamespaceBrowser.ts
Normal file
171
generated/prisma/internal/prismaNamespaceBrowser.ts
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* WARNING: This is an internal file that is subject to change!
|
||||||
|
*
|
||||||
|
* 🛑 Under no circumstances should you import this file directly! 🛑
|
||||||
|
*
|
||||||
|
* All exports from this file are wrapped under a `Prisma` namespace object in the browser.ts file.
|
||||||
|
* While this enables partial backward compatibility, it is not part of the stable public API.
|
||||||
|
*
|
||||||
|
* If you are looking for your Models, Enums, and Input Types, please import them from the respective
|
||||||
|
* model files in the `model` directory!
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as runtime from "@prisma/client/runtime/index-browser"
|
||||||
|
|
||||||
|
export type * from '../models.js'
|
||||||
|
export type * from './prismaNamespace.js'
|
||||||
|
|
||||||
|
export const Decimal = runtime.Decimal
|
||||||
|
|
||||||
|
|
||||||
|
export const NullTypes = {
|
||||||
|
DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull),
|
||||||
|
JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull),
|
||||||
|
AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull),
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Helper for filtering JSON entries that have `null` on the database (empty on the db)
|
||||||
|
*
|
||||||
|
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||||
|
*/
|
||||||
|
export const DbNull = runtime.DbNull
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for filtering JSON entries that have JSON `null` values (not empty on the db)
|
||||||
|
*
|
||||||
|
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||||
|
*/
|
||||||
|
export const JsonNull = runtime.JsonNull
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull`
|
||||||
|
*
|
||||||
|
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||||
|
*/
|
||||||
|
export const AnyNull = runtime.AnyNull
|
||||||
|
|
||||||
|
|
||||||
|
export const ModelName = {
|
||||||
|
User: 'User',
|
||||||
|
Chat: 'Chat',
|
||||||
|
Message: 'Message',
|
||||||
|
LlmCall: 'LlmCall'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enums
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const TransactionIsolationLevel = runtime.makeStrictEnum({
|
||||||
|
Serializable: 'Serializable'
|
||||||
|
} as const)
|
||||||
|
|
||||||
|
export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel]
|
||||||
|
|
||||||
|
|
||||||
|
export const UserScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt',
|
||||||
|
handle: 'handle'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ChatScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt',
|
||||||
|
title: 'title',
|
||||||
|
userId: 'userId'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ChatScalarFieldEnum = (typeof ChatScalarFieldEnum)[keyof typeof ChatScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const MessageScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
chatId: 'chatId',
|
||||||
|
role: 'role',
|
||||||
|
content: 'content',
|
||||||
|
name: 'name',
|
||||||
|
metadata: 'metadata'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type MessageScalarFieldEnum = (typeof MessageScalarFieldEnum)[keyof typeof MessageScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const LlmCallScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
chatId: 'chatId',
|
||||||
|
provider: 'provider',
|
||||||
|
model: 'model',
|
||||||
|
request: 'request',
|
||||||
|
response: 'response',
|
||||||
|
inputTokens: 'inputTokens',
|
||||||
|
outputTokens: 'outputTokens',
|
||||||
|
totalTokens: 'totalTokens',
|
||||||
|
latencyMs: 'latencyMs',
|
||||||
|
error: 'error'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type LlmCallScalarFieldEnum = (typeof LlmCallScalarFieldEnum)[keyof typeof LlmCallScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const SortOrder = {
|
||||||
|
asc: 'asc',
|
||||||
|
desc: 'desc'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder]
|
||||||
|
|
||||||
|
|
||||||
|
export const NullableJsonNullValueInput = {
|
||||||
|
DbNull: DbNull,
|
||||||
|
JsonNull: JsonNull
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type NullableJsonNullValueInput = (typeof NullableJsonNullValueInput)[keyof typeof NullableJsonNullValueInput]
|
||||||
|
|
||||||
|
|
||||||
|
export const JsonNullValueInput = {
|
||||||
|
JsonNull: JsonNull
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type JsonNullValueInput = (typeof JsonNullValueInput)[keyof typeof JsonNullValueInput]
|
||||||
|
|
||||||
|
|
||||||
|
export const NullsOrder = {
|
||||||
|
first: 'first',
|
||||||
|
last: 'last'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
|
||||||
|
|
||||||
|
|
||||||
|
export const JsonNullValueFilter = {
|
||||||
|
DbNull: DbNull,
|
||||||
|
JsonNull: JsonNull,
|
||||||
|
AnyNull: AnyNull
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type JsonNullValueFilter = (typeof JsonNullValueFilter)[keyof typeof JsonNullValueFilter]
|
||||||
|
|
||||||
|
|
||||||
|
export const QueryMode = {
|
||||||
|
default: 'default',
|
||||||
|
insensitive: 'insensitive'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode]
|
||||||
|
|
||||||
15
generated/prisma/models.ts
Normal file
15
generated/prisma/models.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||||
|
/* eslint-disable */
|
||||||
|
// biome-ignore-all lint: generated file
|
||||||
|
// @ts-nocheck
|
||||||
|
/*
|
||||||
|
* This is a barrel export file for all models and their related types.
|
||||||
|
*
|
||||||
|
* 🟢 You can import this file directly.
|
||||||
|
*/
|
||||||
|
export type * from './models/User.js'
|
||||||
|
export type * from './models/Chat.js'
|
||||||
|
export type * from './models/Message.js'
|
||||||
|
export type * from './models/LlmCall.js'
|
||||||
|
export type * from './commonInputTypes.js'
|
||||||
1611
generated/prisma/models/Chat.ts
Normal file
1611
generated/prisma/models/Chat.ts
Normal file
File diff suppressed because it is too large
Load Diff
1644
generated/prisma/models/LlmCall.ts
Normal file
1644
generated/prisma/models/LlmCall.ts
Normal file
File diff suppressed because it is too large
Load Diff
1405
generated/prisma/models/Message.ts
Normal file
1405
generated/prisma/models/Message.ts
Normal file
File diff suppressed because it is too large
Load Diff
1302
generated/prisma/models/User.ts
Normal file
1302
generated/prisma/models/User.ts
Normal file
File diff suppressed because it is too large
Load Diff
2327
package-lock.json
generated
Normal file
2327
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
34
package.json
Normal file
34
package.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "llm-backend",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"description": "LLM multiplexer + personal chat database backend",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "tsx watch src/index.ts",
|
||||||
|
"start": "node dist/index.js",
|
||||||
|
"build": "tsc -p tsconfig.json",
|
||||||
|
"prisma:generate": "prisma generate",
|
||||||
|
"db:migrate": "prisma migrate dev",
|
||||||
|
"db:studio": "prisma studio"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@anthropic-ai/sdk": "^0.71.2",
|
||||||
|
"@fastify/cors": "^11.2.0",
|
||||||
|
"@fastify/sensible": "^6.0.4",
|
||||||
|
"@fastify/swagger": "^9.6.1",
|
||||||
|
"@fastify/swagger-ui": "^5.2.5",
|
||||||
|
"@prisma/client": "^6.16.1",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
|
"fastify": "^5.7.2",
|
||||||
|
"openai": "^6.16.0",
|
||||||
|
"pino-pretty": "^13.1.3",
|
||||||
|
"zod": "^4.3.6"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^25.0.10",
|
||||||
|
"prisma": "^6.16.1",
|
||||||
|
"tsx": "^4.21.0",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
14
prisma.config.ts.bak
Normal file
14
prisma.config.ts.bak
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// This file was generated by Prisma, and assumes you have installed the following:
|
||||||
|
// npm install --save-dev prisma dotenv
|
||||||
|
import "dotenv/config";
|
||||||
|
import { defineConfig } from "prisma/config";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
schema: "prisma/schema.prisma",
|
||||||
|
migrations: {
|
||||||
|
path: "prisma/migrations",
|
||||||
|
},
|
||||||
|
datasource: {
|
||||||
|
url: process.env["DATABASE_URL"],
|
||||||
|
},
|
||||||
|
});
|
||||||
94
prisma/schema.prisma
Normal file
94
prisma/schema.prisma
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// Prisma schema for the personal chat DB + LLM call log
|
||||||
|
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "sqlite"
|
||||||
|
url = env("DATABASE_URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Provider {
|
||||||
|
openai
|
||||||
|
anthropic
|
||||||
|
xai
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MessageRole {
|
||||||
|
system
|
||||||
|
user
|
||||||
|
assistant
|
||||||
|
tool
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
// minimal for now (single-user is fine). Keep extensible.
|
||||||
|
handle String? @unique
|
||||||
|
|
||||||
|
chats Chat[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model Chat {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
title String?
|
||||||
|
|
||||||
|
user User? @relation(fields: [userId], references: [id])
|
||||||
|
userId String?
|
||||||
|
|
||||||
|
messages Message[]
|
||||||
|
calls LlmCall[]
|
||||||
|
|
||||||
|
@@index([userId])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Message {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
chat Chat @relation(fields: [chatId], references: [id], onDelete: Cascade)
|
||||||
|
chatId String
|
||||||
|
|
||||||
|
role MessageRole
|
||||||
|
content String
|
||||||
|
|
||||||
|
// for tool messages or attachments later
|
||||||
|
name String?
|
||||||
|
metadata Json?
|
||||||
|
|
||||||
|
@@index([chatId, createdAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
model LlmCall {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
chat Chat @relation(fields: [chatId], references: [id], onDelete: Cascade)
|
||||||
|
chatId String
|
||||||
|
|
||||||
|
provider Provider
|
||||||
|
model String
|
||||||
|
|
||||||
|
// request/response snapshots for debugging + replay
|
||||||
|
request Json
|
||||||
|
response Json?
|
||||||
|
|
||||||
|
// usage/cost basics
|
||||||
|
inputTokens Int?
|
||||||
|
outputTokens Int?
|
||||||
|
totalTokens Int?
|
||||||
|
|
||||||
|
latencyMs Int?
|
||||||
|
|
||||||
|
error String?
|
||||||
|
|
||||||
|
@@index([chatId, createdAt])
|
||||||
|
@@index([provider, model, createdAt])
|
||||||
|
}
|
||||||
22
src/auth.ts
Normal file
22
src/auth.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import type { FastifyRequest } from "fastify";
|
||||||
|
import { env } from "./env.js";
|
||||||
|
|
||||||
|
export function requireAdmin(req: FastifyRequest) {
|
||||||
|
// If ADMIN_TOKEN isn't set, run in "open" mode (dev).
|
||||||
|
if (!env.ADMIN_TOKEN) return;
|
||||||
|
|
||||||
|
const auth = req.headers.authorization;
|
||||||
|
if (!auth?.startsWith("Bearer ")) {
|
||||||
|
const err = new Error("missing bearer token");
|
||||||
|
// @ts-expect-error attach status
|
||||||
|
err.statusCode = 401;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
const token = auth.slice("Bearer ".length);
|
||||||
|
if (token !== env.ADMIN_TOKEN) {
|
||||||
|
const err = new Error("invalid bearer token");
|
||||||
|
// @ts-expect-error attach status
|
||||||
|
err.statusCode = 403;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/db.ts
Normal file
16
src/db.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
|
||||||
|
export const prisma = new PrismaClient({
|
||||||
|
log: [
|
||||||
|
{ emit: "event", level: "error" },
|
||||||
|
{ emit: "event", level: "warn" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
prisma.$on("error", (e: any) => {
|
||||||
|
console.error("[prisma:error]", e);
|
||||||
|
});
|
||||||
|
|
||||||
|
prisma.$on("warn", (e: any) => {
|
||||||
|
console.warn("[prisma:warn]", e);
|
||||||
|
});
|
||||||
19
src/env.ts
Normal file
19
src/env.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
import "dotenv/config";
|
||||||
|
|
||||||
|
const EnvSchema = z.object({
|
||||||
|
PORT: z.coerce.number().int().positive().default(8787),
|
||||||
|
HOST: z.string().default("0.0.0.0"),
|
||||||
|
|
||||||
|
// simple bearer-token auth for your personal backend
|
||||||
|
ADMIN_TOKEN: z.string().min(20).optional(),
|
||||||
|
|
||||||
|
// provider keys
|
||||||
|
OPENAI_API_KEY: z.string().optional(),
|
||||||
|
ANTHROPIC_API_KEY: z.string().optional(),
|
||||||
|
XAI_API_KEY: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Env = z.infer<typeof EnvSchema>;
|
||||||
|
|
||||||
|
export const env: Env = EnvSchema.parse(process.env);
|
||||||
45
src/index.ts
Normal file
45
src/index.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import Fastify from "fastify";
|
||||||
|
import cors from "@fastify/cors";
|
||||||
|
import swagger from "@fastify/swagger";
|
||||||
|
import swaggerUI from "@fastify/swagger-ui";
|
||||||
|
import sensible from "@fastify/sensible";
|
||||||
|
import { env } from "./env.js";
|
||||||
|
import { registerRoutes } from "./routes.js";
|
||||||
|
|
||||||
|
const app = Fastify({
|
||||||
|
logger: {
|
||||||
|
transport: {
|
||||||
|
target: "pino-pretty",
|
||||||
|
options: { colorize: true, translateTime: "SYS:standard" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await app.register(cors, { origin: true, credentials: true });
|
||||||
|
|
||||||
|
await app.register(swagger, {
|
||||||
|
openapi: {
|
||||||
|
info: {
|
||||||
|
title: "LLM Multiplexer Backend",
|
||||||
|
version: "0.1.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await app.register(swaggerUI, { routePrefix: "/docs" });
|
||||||
|
await app.register(sensible);
|
||||||
|
|
||||||
|
app.setErrorHandler((err, _req, reply) => {
|
||||||
|
const e = err as any;
|
||||||
|
const statusCode = e.statusCode ?? 500;
|
||||||
|
reply.status(statusCode).send({
|
||||||
|
error: true,
|
||||||
|
message: e.message ?? String(e),
|
||||||
|
statusCode,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await registerRoutes(app);
|
||||||
|
|
||||||
|
await app.listen({ port: env.PORT, host: env.HOST });
|
||||||
|
app.log.info(`listening on http://${env.HOST}:${env.PORT}`);
|
||||||
124
src/llm/multiplexer.ts
Normal file
124
src/llm/multiplexer.ts
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import { performance } from "node:perf_hooks";
|
||||||
|
import { prisma } from "../db.js";
|
||||||
|
import { anthropicClient, openaiClient, xaiClient } from "./providers.js";
|
||||||
|
import type { MultiplexRequest, MultiplexResponse, Provider } from "./types.js";
|
||||||
|
|
||||||
|
function asProviderEnum(p: Provider) {
|
||||||
|
// Prisma enum values match these strings.
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function runMultiplex(req: MultiplexRequest): Promise<MultiplexResponse> {
|
||||||
|
const t0 = performance.now();
|
||||||
|
|
||||||
|
// Persist call record early so we can attach errors.
|
||||||
|
const call = await prisma.llmCall.create({
|
||||||
|
data: {
|
||||||
|
chatId: req.chatId ?? (await prisma.chat.create({ data: {} })).id,
|
||||||
|
provider: asProviderEnum(req.provider) as any,
|
||||||
|
model: req.model,
|
||||||
|
request: req as any,
|
||||||
|
},
|
||||||
|
select: { id: true, chatId: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
let outText = "";
|
||||||
|
let usage: MultiplexResponse["usage"] | undefined;
|
||||||
|
let raw: unknown;
|
||||||
|
|
||||||
|
if (req.provider === "openai" || req.provider === "xai") {
|
||||||
|
const client = req.provider === "openai" ? openaiClient() : xaiClient();
|
||||||
|
const r = await client.chat.completions.create({
|
||||||
|
model: req.model,
|
||||||
|
// OpenAI SDK has very specific message union types; our normalized schema is compatible.
|
||||||
|
messages: req.messages.map((m) => ({ role: m.role, content: m.content, name: m.name })) as any,
|
||||||
|
temperature: req.temperature,
|
||||||
|
max_tokens: req.maxTokens,
|
||||||
|
});
|
||||||
|
raw = r;
|
||||||
|
outText = r.choices?.[0]?.message?.content ?? "";
|
||||||
|
usage = r.usage
|
||||||
|
? {
|
||||||
|
inputTokens: r.usage.prompt_tokens,
|
||||||
|
outputTokens: r.usage.completion_tokens,
|
||||||
|
totalTokens: r.usage.total_tokens,
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
} else if (req.provider === "anthropic") {
|
||||||
|
const client = anthropicClient();
|
||||||
|
|
||||||
|
// Anthropic splits system prompt. We'll convert first system message into system string.
|
||||||
|
const system = req.messages.find((m) => m.role === "system")?.content;
|
||||||
|
const msgs = req.messages
|
||||||
|
.filter((m) => m.role !== "system")
|
||||||
|
.map((m) => ({ role: m.role === "assistant" ? "assistant" : "user", content: m.content }));
|
||||||
|
|
||||||
|
const r = await client.messages.create({
|
||||||
|
model: req.model,
|
||||||
|
system,
|
||||||
|
max_tokens: req.maxTokens ?? 1024,
|
||||||
|
temperature: req.temperature,
|
||||||
|
messages: msgs as any,
|
||||||
|
});
|
||||||
|
raw = r;
|
||||||
|
outText = r.content
|
||||||
|
.map((c: any) => (c.type === "text" ? c.text : ""))
|
||||||
|
.join("")
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
// Anthropic usage (SDK typing varies by version)
|
||||||
|
const ru: any = (r as any).usage;
|
||||||
|
if (ru) {
|
||||||
|
usage = {
|
||||||
|
inputTokens: ru.input_tokens,
|
||||||
|
outputTokens: ru.output_tokens,
|
||||||
|
totalTokens: (ru.input_tokens ?? 0) + (ru.output_tokens ?? 0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(`unknown provider: ${req.provider}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const latencyMs = Math.round(performance.now() - t0);
|
||||||
|
|
||||||
|
// Store assistant message + call record
|
||||||
|
await prisma.$transaction([
|
||||||
|
prisma.message.create({
|
||||||
|
data: {
|
||||||
|
chatId: call.chatId,
|
||||||
|
role: "assistant" as any,
|
||||||
|
content: outText,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
prisma.llmCall.update({
|
||||||
|
where: { id: call.id },
|
||||||
|
data: {
|
||||||
|
response: raw as any,
|
||||||
|
latencyMs,
|
||||||
|
inputTokens: usage?.inputTokens,
|
||||||
|
outputTokens: usage?.outputTokens,
|
||||||
|
totalTokens: usage?.totalTokens,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
provider: req.provider,
|
||||||
|
model: req.model,
|
||||||
|
message: { role: "assistant", content: outText },
|
||||||
|
usage,
|
||||||
|
raw,
|
||||||
|
};
|
||||||
|
} catch (e: any) {
|
||||||
|
const latencyMs = Math.round(performance.now() - t0);
|
||||||
|
await prisma.llmCall.update({
|
||||||
|
where: { id: call.id },
|
||||||
|
data: {
|
||||||
|
error: e?.message ?? String(e),
|
||||||
|
latencyMs,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/llm/providers.ts
Normal file
19
src/llm/providers.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import OpenAI from "openai";
|
||||||
|
import Anthropic from "@anthropic-ai/sdk";
|
||||||
|
import { env } from "../env.js";
|
||||||
|
|
||||||
|
export function openaiClient() {
|
||||||
|
if (!env.OPENAI_API_KEY) throw new Error("OPENAI_API_KEY not set");
|
||||||
|
return new OpenAI({ apiKey: env.OPENAI_API_KEY });
|
||||||
|
}
|
||||||
|
|
||||||
|
// xAI (Grok) is OpenAI-compatible at https://api.x.ai/v1
|
||||||
|
export function xaiClient() {
|
||||||
|
if (!env.XAI_API_KEY) throw new Error("XAI_API_KEY not set");
|
||||||
|
return new OpenAI({ apiKey: env.XAI_API_KEY, baseURL: "https://api.x.ai/v1" });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function anthropicClient() {
|
||||||
|
if (!env.ANTHROPIC_API_KEY) throw new Error("ANTHROPIC_API_KEY not set");
|
||||||
|
return new Anthropic({ apiKey: env.ANTHROPIC_API_KEY });
|
||||||
|
}
|
||||||
28
src/llm/types.ts
Normal file
28
src/llm/types.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
export type Provider = "openai" | "anthropic" | "xai";
|
||||||
|
|
||||||
|
export type ChatMessage = {
|
||||||
|
role: "system" | "user" | "assistant" | "tool";
|
||||||
|
content: string;
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MultiplexRequest = {
|
||||||
|
chatId?: string;
|
||||||
|
provider: Provider;
|
||||||
|
model: string;
|
||||||
|
messages: ChatMessage[];
|
||||||
|
temperature?: number;
|
||||||
|
maxTokens?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MultiplexResponse = {
|
||||||
|
provider: Provider;
|
||||||
|
model: string;
|
||||||
|
message: { role: "assistant"; content: string };
|
||||||
|
usage?: {
|
||||||
|
inputTokens?: number;
|
||||||
|
outputTokens?: number;
|
||||||
|
totalTokens?: number;
|
||||||
|
};
|
||||||
|
raw: unknown;
|
||||||
|
};
|
||||||
111
src/routes.ts
Normal file
111
src/routes.ts
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
import type { FastifyInstance } from "fastify";
|
||||||
|
import { prisma } from "./db.js";
|
||||||
|
import { requireAdmin } from "./auth.js";
|
||||||
|
import { runMultiplex } from "./llm/multiplexer.js";
|
||||||
|
|
||||||
|
export async function registerRoutes(app: FastifyInstance) {
|
||||||
|
app.get("/health", async () => ({ ok: true }));
|
||||||
|
|
||||||
|
app.get("/v1/chats", async (req) => {
|
||||||
|
requireAdmin(req);
|
||||||
|
const chats = await prisma.chat.findMany({
|
||||||
|
orderBy: { updatedAt: "desc" },
|
||||||
|
take: 100,
|
||||||
|
select: { id: true, title: true, createdAt: true, updatedAt: true },
|
||||||
|
});
|
||||||
|
return { chats };
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post("/v1/chats", async (req) => {
|
||||||
|
requireAdmin(req);
|
||||||
|
const Body = z.object({ title: z.string().optional() });
|
||||||
|
const body = Body.parse(req.body ?? {});
|
||||||
|
const chat = await prisma.chat.create({ data: { title: body.title } });
|
||||||
|
return { chat };
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/v1/chats/:chatId", async (req) => {
|
||||||
|
requireAdmin(req);
|
||||||
|
const Params = z.object({ chatId: z.string() });
|
||||||
|
const { chatId } = Params.parse(req.params);
|
||||||
|
|
||||||
|
const chat = await prisma.chat.findUnique({
|
||||||
|
where: { id: chatId },
|
||||||
|
include: { messages: { orderBy: { createdAt: "asc" } }, calls: { orderBy: { createdAt: "desc" } } },
|
||||||
|
});
|
||||||
|
if (!chat) return app.httpErrors.notFound("chat not found");
|
||||||
|
return { chat };
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post("/v1/chats/:chatId/messages", async (req) => {
|
||||||
|
requireAdmin(req);
|
||||||
|
const Params = z.object({ chatId: z.string() });
|
||||||
|
const Body = z.object({
|
||||||
|
role: z.enum(["system", "user", "assistant", "tool"]),
|
||||||
|
content: z.string(),
|
||||||
|
name: z.string().optional(),
|
||||||
|
metadata: z.unknown().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { chatId } = Params.parse(req.params);
|
||||||
|
const body = Body.parse(req.body);
|
||||||
|
|
||||||
|
const msg = await prisma.message.create({
|
||||||
|
data: {
|
||||||
|
chatId,
|
||||||
|
role: body.role as any,
|
||||||
|
content: body.content,
|
||||||
|
name: body.name,
|
||||||
|
metadata: body.metadata as any,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { message: msg };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Main: create a completion via provider+model and store everything.
|
||||||
|
app.post("/v1/chat-completions", async (req) => {
|
||||||
|
requireAdmin(req);
|
||||||
|
|
||||||
|
const Body = z.object({
|
||||||
|
chatId: z.string().optional(),
|
||||||
|
provider: z.enum(["openai", "anthropic", "xai"]),
|
||||||
|
model: z.string().min(1),
|
||||||
|
messages: z.array(
|
||||||
|
z.object({
|
||||||
|
role: z.enum(["system", "user", "assistant", "tool"]),
|
||||||
|
content: z.string(),
|
||||||
|
name: z.string().optional(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
temperature: z.number().min(0).max(2).optional(),
|
||||||
|
maxTokens: z.number().int().positive().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const body = Body.parse(req.body);
|
||||||
|
|
||||||
|
// ensure chat exists if provided
|
||||||
|
if (body.chatId) {
|
||||||
|
const exists = await prisma.chat.findUnique({ where: { id: body.chatId }, select: { id: true } });
|
||||||
|
if (!exists) return app.httpErrors.notFound("chat not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
// store user messages (anything not assistant) for DB fidelity
|
||||||
|
if (body.chatId) {
|
||||||
|
const toInsert = body.messages.filter((m) => m.role !== "assistant");
|
||||||
|
if (toInsert.length) {
|
||||||
|
await prisma.message.createMany({
|
||||||
|
data: toInsert.map((m) => ({ chatId: body.chatId!, role: m.role as any, content: m.content, name: m.name })),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await runMultiplex(body);
|
||||||
|
|
||||||
|
return {
|
||||||
|
chatId: body.chatId ?? null,
|
||||||
|
...result,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user