@lobb-js/lobb-ext-llm 0.1.16 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +1 -0
- package/.env.example +1 -0
- package/CHANGELOG.md +90 -0
- package/README.md +1 -27
- package/extensions/llm/adapters/chatgptAdapter.ts +57 -0
- package/extensions/llm/adapters/index.ts +27 -0
- package/extensions/llm/adapters/ollamaAdapter.ts +61 -0
- package/extensions/llm/adapters/utils.ts +20 -0
- package/extensions/llm/collectionRoutes.ts +13 -0
- package/extensions/llm/collections/chat.ts +10 -0
- package/extensions/llm/collections/collections.ts +10 -0
- package/extensions/llm/config/extensionConfigSchema.ts +20 -0
- package/extensions/llm/controllers/llmController.ts +49 -0
- package/extensions/llm/index.ts +17 -0
- package/extensions/llm/migrations/migrations.ts +3 -0
- package/extensions/llm/openapi.ts +88 -0
- package/extensions/llm/tests/configs/simple.ts +55 -0
- package/extensions/llm/tests/llm.test.ts +96 -0
- package/lobb.ts +51 -0
- package/package.json +13 -24
- package/todo.md +7 -0
- package/src/app.css +0 -124
- package/src/index.ts +0 -20
- package/src/lib/index.ts +0 -1
- package/src/lib/utils.ts +0 -13
- package/src/main.ts +0 -14
package/.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CHATGPT_API_KEY=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
|
package/.env.example
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CHATGPT_API_KEY=<TOKEN>
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
|
|
3
|
+
|
|
4
|
+
- - -
|
|
5
|
+
## llm-ext@0.3.1 - 2026-03-28
|
|
6
|
+
#### Bug Fixes
|
|
7
|
+
- adding readme to all packages - (3a9264a) - malik ben
|
|
8
|
+
#### Miscellaneous Chores
|
|
9
|
+
- add publishConfig and fix ext packages for npm publishing - (49747e9) - malik ben
|
|
10
|
+
|
|
11
|
+
- - -
|
|
12
|
+
|
|
13
|
+
## llm-ext@0.3.0 - 2026-03-28
|
|
14
|
+
#### Features
|
|
15
|
+
- (**llm-ext**) add mock OpenAI server for tests and base_url config option - (ece56a3) - malik ben
|
|
16
|
+
- (**llm-ext**) migrate to Bun - (95cf023) - malik ben
|
|
17
|
+
#### Bug Fixes
|
|
18
|
+
- chaning $lib to relative path - (c6d9e8f) - malik ben
|
|
19
|
+
#### Miscellaneous Chores
|
|
20
|
+
- (**llm-ext**) move extension logic and tests to extensions/llm - (7026cf2) - malik ben
|
|
21
|
+
- (**mail-ext**) move extension logic and tests to extensions/mail - (529b0dc) - malik ben
|
|
22
|
+
- (**version**) 0.25.2 - (a62acb9) - Cocogitto Bot
|
|
23
|
+
- (**version**) 0.25.1 - (afe7e69) - Cocogitto Bot
|
|
24
|
+
- (**version**) 0.25.0 - (77a383c) - Cocogitto Bot
|
|
25
|
+
- (**version**) 0.24.0 - (a8cb605) - Cocogitto Bot
|
|
26
|
+
- (**version**) 0.23.0 - (60f357e) - Cocogitto Bot
|
|
27
|
+
- (**version**) 0.22.0 - (6510e32) - Cocogitto Bot
|
|
28
|
+
- (**version**) 0.21.0 - (c973aa9) - Cocogitto Bot
|
|
29
|
+
- (**version**) 0.20.0 - (06cc303) - Cocogitto Bot
|
|
30
|
+
- rename @lobb/ scope to @lobb-js/ across all packages and apps - (cce4ce0) - malik ben
|
|
31
|
+
- update CLAUDE.md to enforce no-commit-without-explicit-instruction rule - (6d63a42) - malik ben
|
|
32
|
+
- remove all deno.json and deno.lock files from the monorepo - (84ca5d4) - malik ben
|
|
33
|
+
- replace workspace:* with exact versions in all package.json files - (74fbdb7) - malik ben
|
|
34
|
+
- rename __studio to studio and remove unused studio dirs - (77fb932) - malik ben
|
|
35
|
+
- rename studio directory to __studio for faker-ext, llm-ext, mail-ext, reports-ext, storage-ext - (47e754a) - malik ben
|
|
36
|
+
|
|
37
|
+
- - -
|
|
38
|
+
|
|
39
|
+
## llm-ext@0.2.0 - 2026-03-01
|
|
40
|
+
#### Features
|
|
41
|
+
- (**mindhar**) add storage extension integration - (bca6368) - malik ben
|
|
42
|
+
#### Miscellaneous Chores
|
|
43
|
+
- (**version**) 0.18.0 - (efc553f) - Cocogitto Bot
|
|
44
|
+
- (**version**) 0.17.0 - (4174f0c) - Cocogitto Bot
|
|
45
|
+
- (**version**) 0.16.0 - (9508655) - Cocogitto Bot
|
|
46
|
+
- (**version**) 0.14.11 - (ad92b61) - Cocogitto Bot
|
|
47
|
+
- (**version**) 0.14.8 - (0e6c1cb) - Cocogitto Bot
|
|
48
|
+
- (**version**) 0.14.3 - (76abe92) - Cocogitto Bot
|
|
49
|
+
- (**version**) 0.14.2 - (6ecdc1d) - Cocogitto Bot
|
|
50
|
+
|
|
51
|
+
- - -
|
|
52
|
+
|
|
53
|
+
## llm-ext@0.1.13 - 2026-02-21
|
|
54
|
+
#### Bug Fixes
|
|
55
|
+
- using default export instead of named export for extensions - (37dd485) - malik ben
|
|
56
|
+
#### Miscellaneous Chores
|
|
57
|
+
- (**version**) 0.13.2 - (39b0145) - Cocogitto Bot
|
|
58
|
+
- (**version**) 0.12.3 - (cd06fc0) - Cocogitto Bot
|
|
59
|
+
- (**version**) 0.12.2 - (35b2ff3) - Cocogitto Bot
|
|
60
|
+
- (**version**) 0.12.1 - (c548105) - Cocogitto Bot
|
|
61
|
+
- (**version**) 0.11.1 - (659ebd3) - Cocogitto Bot
|
|
62
|
+
- (**version**) 0.11.0 - (3f4f47e) - Cocogitto Bot
|
|
63
|
+
- (**version**) 0.10.0 - (5d79b6e) - Cocogitto Bot
|
|
64
|
+
- (**version**) 0.8.0 - (fdee7ca) - Cocogitto Bot
|
|
65
|
+
|
|
66
|
+
- - -
|
|
67
|
+
|
|
68
|
+
## llm-ext@0.1.12 - 2026-02-15
|
|
69
|
+
#### Bug Fixes
|
|
70
|
+
- fixed the name of the project for llm - (390f747) - malik ben
|
|
71
|
+
|
|
72
|
+
- - -
|
|
73
|
+
|
|
74
|
+
## llm-ext@0.1.11 - 2026-02-15
|
|
75
|
+
#### Bug Fixes
|
|
76
|
+
- fix deno publish issue - (e8dcc4f) - malik ben
|
|
77
|
+
- issue fix - (63d66d3) - malik ben
|
|
78
|
+
#### Miscellaneous Chores
|
|
79
|
+
- (**version**) 0.5.5 - (d4dedeb) - Cocogitto Bot
|
|
80
|
+
- (**version**) 0.5.4 - (1ca3970) - Cocogitto Bot
|
|
81
|
+
- (**version**) 0.5.3 - (dcdb9cb) - Cocogitto Bot
|
|
82
|
+
- (**version**) 0.5.2 - (aa66e29) - Cocogitto Bot
|
|
83
|
+
- (**version**) 0.5.1 - (41b7c35) - Cocogitto Bot
|
|
84
|
+
- (**version**) 0.5.0 - (af63147) - Cocogitto Bot
|
|
85
|
+
- (**version**) 0.4.4 - (eaed3b4) - Cocogitto Bot
|
|
86
|
+
- (**version**) 0.4.3 - (ea9ec49) - Cocogitto Bot
|
|
87
|
+
|
|
88
|
+
- - -
|
|
89
|
+
|
|
90
|
+
Changelog generated by [cocogitto](https://github.com/cocogitto/cocogitto).
|
package/README.md
CHANGED
|
@@ -1,27 +1 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
This directory contains the frontend/dashboard interface for the LLM extension.
|
|
4
|
-
|
|
5
|
-
## Structure
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
studio/
|
|
9
|
-
├── src/
|
|
10
|
-
│ ├── index.ts # Extension entry point
|
|
11
|
-
│ ├── main.ts # Vite app entry
|
|
12
|
-
│ └── pages/ # UI pages (to be added)
|
|
13
|
-
├── public/ # Static assets
|
|
14
|
-
├── index.html # HTML entry point
|
|
15
|
-
├── vite.config.ts # Vite configuration
|
|
16
|
-
├── tailwind.config.ts # Tailwind CSS configuration
|
|
17
|
-
└── tsconfig.json # TypeScript configuration
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Future Features
|
|
21
|
-
|
|
22
|
-
The studio interface could include:
|
|
23
|
-
- LLM provider configuration UI
|
|
24
|
-
- Chat interface for testing models
|
|
25
|
-
- Model selection and settings
|
|
26
|
-
- API key management
|
|
27
|
-
- Usage analytics and monitoring
|
|
1
|
+
# @lobb-js/lobb-ext-llm
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Lobb } from "@lobb-js/core";
|
|
2
|
+
import type { ChatArgs } from "./index.ts";
|
|
3
|
+
import type { ChatgptAdapterConfig, ExtensionConfig } from "../config/extensionConfigSchema.ts";
|
|
4
|
+
|
|
5
|
+
import OpenAI from "openai";
|
|
6
|
+
import { LLMAdapter } from "./index.ts";
|
|
7
|
+
|
|
8
|
+
export class ChatgptAdapter extends LLMAdapter {
|
|
9
|
+
constructor(lobb: Lobb, extensionConfig: ExtensionConfig) {
|
|
10
|
+
super(lobb, extensionConfig);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public async chat(
|
|
14
|
+
args: ChatArgs,
|
|
15
|
+
): Promise<string | ReadableStream<Uint8Array>> {
|
|
16
|
+
const extensionConfig = this.extensionConfig as ChatgptAdapterConfig;
|
|
17
|
+
|
|
18
|
+
const client = new OpenAI({
|
|
19
|
+
apiKey: extensionConfig.settings.api_key,
|
|
20
|
+
baseURL: extensionConfig.settings.base_url,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (args.stream === true) {
|
|
24
|
+
const completion = await client.chat.completions.create({
|
|
25
|
+
model: extensionConfig.settings.model,
|
|
26
|
+
stream: args.stream,
|
|
27
|
+
messages: args.messages,
|
|
28
|
+
response_format: args.format,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return new ReadableStream({
|
|
32
|
+
async start(controller) {
|
|
33
|
+
for await (const part of completion) {
|
|
34
|
+
const chunkContent = part.choices[0].delta.content;
|
|
35
|
+
|
|
36
|
+
if (chunkContent) {
|
|
37
|
+
const uint8Array = new TextEncoder().encode(chunkContent);
|
|
38
|
+
controller.enqueue(uint8Array);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (part.choices[0].finish_reason) {
|
|
42
|
+
controller.close();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
} else {
|
|
48
|
+
const completion = await client.chat.completions.create({
|
|
49
|
+
model: extensionConfig.settings.model,
|
|
50
|
+
stream: args.stream,
|
|
51
|
+
messages: args.messages,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return completion.choices[0].message.content ?? "";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Lobb } from "@lobb-js/core";
|
|
2
|
+
import type { ExtensionConfig } from "../config/extensionConfigSchema.ts";
|
|
3
|
+
|
|
4
|
+
export type Messages = {
|
|
5
|
+
role: "user" | "assistant" | "system";
|
|
6
|
+
content: string;
|
|
7
|
+
}[];
|
|
8
|
+
|
|
9
|
+
export interface ChatArgs {
|
|
10
|
+
messages: Messages;
|
|
11
|
+
stream?: boolean;
|
|
12
|
+
format: any;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export abstract class LLMAdapter {
|
|
16
|
+
protected lobb: Lobb;
|
|
17
|
+
protected extensionConfig: ExtensionConfig;
|
|
18
|
+
|
|
19
|
+
constructor(lobb: Lobb, extensionConfig: ExtensionConfig) {
|
|
20
|
+
this.lobb = lobb;
|
|
21
|
+
this.extensionConfig = extensionConfig;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public abstract chat(
|
|
25
|
+
agrs: ChatArgs,
|
|
26
|
+
): Promise<string | ReadableStream<Uint8Array>>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Lobb } from "@lobb-js/core";
|
|
2
|
+
import type { ChatArgs } from "./index.ts";
|
|
3
|
+
import type { ExtensionConfig, OllamaAdapterConfig } from "../config/extensionConfigSchema.ts";
|
|
4
|
+
|
|
5
|
+
import { LobbError } from "@lobb-js/core";
|
|
6
|
+
import { LLMAdapter } from "./index.ts";
|
|
7
|
+
|
|
8
|
+
export class OllamaAdapter extends LLMAdapter {
|
|
9
|
+
constructor(lobb: Lobb, extensionConfig: ExtensionConfig) {
|
|
10
|
+
super(lobb, extensionConfig);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public async chat(
|
|
14
|
+
agrs: ChatArgs,
|
|
15
|
+
): Promise<string | ReadableStream<Uint8Array>> {
|
|
16
|
+
const extensionConfig = this.extensionConfig as OllamaAdapterConfig;
|
|
17
|
+
const response = await fetch(
|
|
18
|
+
`${extensionConfig.settings.host}/api/chat`,
|
|
19
|
+
{
|
|
20
|
+
method: "POST",
|
|
21
|
+
body: JSON.stringify({
|
|
22
|
+
model: extensionConfig.settings.model,
|
|
23
|
+
messages: agrs.messages,
|
|
24
|
+
format: agrs.format,
|
|
25
|
+
stream: agrs.stream || false,
|
|
26
|
+
options: {
|
|
27
|
+
num_thread: extensionConfig.settings.num_thread,
|
|
28
|
+
seed: extensionConfig.settings.seed,
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
},
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
if (agrs.stream === true) {
|
|
35
|
+
if (response.ok && response.body) {
|
|
36
|
+
const reader = response.body.getReader();
|
|
37
|
+
return new ReadableStream({
|
|
38
|
+
async start(controller) {
|
|
39
|
+
let done = false;
|
|
40
|
+
while (!done) {
|
|
41
|
+
const { value, done: readerDone } = await reader.read();
|
|
42
|
+
done = readerDone;
|
|
43
|
+
controller.enqueue(value);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
controller.close();
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
throw new LobbError({
|
|
51
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
52
|
+
message: `The response from the chat API was not successful`,
|
|
53
|
+
details: await response.text(),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
const data: any = await response.json();
|
|
58
|
+
return data.message.content;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Lobb } from "@lobb-js/core";
|
|
2
|
+
import type { LLMAdapter } from "./index.ts";
|
|
3
|
+
import type { ExtensionConfig } from "../config/extensionConfigSchema.ts";
|
|
4
|
+
|
|
5
|
+
import { OllamaAdapter } from "./ollamaAdapter.ts";
|
|
6
|
+
import { LobbError } from "@lobb-js/core";
|
|
7
|
+
import { ChatgptAdapter } from "./chatgptAdapter.ts";
|
|
8
|
+
|
|
9
|
+
export function getLLMAdapter(lobb: Lobb, extensionConfig: ExtensionConfig): LLMAdapter {
|
|
10
|
+
if (extensionConfig.adapter === "chatgpt") {
|
|
11
|
+
return new ChatgptAdapter(lobb, extensionConfig);
|
|
12
|
+
} else if (extensionConfig.adapter === "ollama") {
|
|
13
|
+
return new OllamaAdapter(lobb, extensionConfig);
|
|
14
|
+
} else {
|
|
15
|
+
throw new LobbError({
|
|
16
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
17
|
+
message: `The storage adapter is not implemented`,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Hono } from "hono";
|
|
2
|
+
import type { ExtensionConfig } from "./config/extensionConfigSchema.ts";
|
|
3
|
+
|
|
4
|
+
import { LLMController } from "./controllers/llmController.ts";
|
|
5
|
+
|
|
6
|
+
export function getCollectionRoutes(extensionConfig: ExtensionConfig) {
|
|
7
|
+
return function collectionRoutes(route: Hono) {
|
|
8
|
+
route.post(
|
|
9
|
+
"/llm_chat",
|
|
10
|
+
(c) => LLMController.createOne(c, extensionConfig),
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CollectionConfig, Lobb } from "@lobb-js/core";
|
|
2
|
+
import { chatCollection } from "./chat.ts";
|
|
3
|
+
|
|
4
|
+
export function collections(
|
|
5
|
+
lobb: Lobb,
|
|
6
|
+
): Record<string, CollectionConfig> {
|
|
7
|
+
const collectionsSchemas: Record<string, CollectionConfig> = {};
|
|
8
|
+
collectionsSchemas["llm_chat"] = chatCollection;
|
|
9
|
+
return collectionsSchemas;
|
|
10
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type ChatgptAdapterConfig = {
|
|
2
|
+
adapter: "chatgpt";
|
|
3
|
+
settings: {
|
|
4
|
+
model: string;
|
|
5
|
+
api_key: string;
|
|
6
|
+
base_url?: string; // override for testing (mock server)
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type OllamaAdapterConfig = {
|
|
11
|
+
adapter: "ollama";
|
|
12
|
+
settings: {
|
|
13
|
+
model: string;
|
|
14
|
+
host?: string;
|
|
15
|
+
num_thread?: number;
|
|
16
|
+
seed?: number;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type ExtensionConfig = ChatgptAdapterConfig | OllamaAdapterConfig;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Lobb } from "@lobb-js/core";
|
|
2
|
+
import type { Context } from "hono";
|
|
3
|
+
import type { ExtensionConfig } from "../config/extensionConfigSchema.ts";
|
|
4
|
+
|
|
5
|
+
import { LobbError } from "@lobb-js/core";
|
|
6
|
+
import { getLLMAdapter } from "../adapters/utils.ts";
|
|
7
|
+
|
|
8
|
+
export class LLMController {
|
|
9
|
+
public static async createOne(c: Context, extensionConfig: ExtensionConfig) {
|
|
10
|
+
const lobb = c.get("lobb") as Lobb;
|
|
11
|
+
const payload = await lobb.utils.getRequestBody(c);
|
|
12
|
+
|
|
13
|
+
if (!payload) {
|
|
14
|
+
throw new LobbError({
|
|
15
|
+
code: "BAD_REQUEST",
|
|
16
|
+
message: `You must send a payload`,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!payload.messages) {
|
|
21
|
+
throw new LobbError({
|
|
22
|
+
code: "BAD_REQUEST",
|
|
23
|
+
message: `You must send (messages) property`,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const adapter = getLLMAdapter(lobb, extensionConfig);
|
|
28
|
+
const response = await adapter.chat({
|
|
29
|
+
messages: payload.messages,
|
|
30
|
+
format: payload.format,
|
|
31
|
+
stream: payload.stream,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (typeof response === "string") {
|
|
35
|
+
return c.json({
|
|
36
|
+
data: response,
|
|
37
|
+
}, 200);
|
|
38
|
+
} else {
|
|
39
|
+
return new Response(response, {
|
|
40
|
+
headers: {
|
|
41
|
+
"Content-Type": "text/event-stream",
|
|
42
|
+
"Cache-Control": "no-cache",
|
|
43
|
+
"Connection": "keep-alive",
|
|
44
|
+
"Transfer-Encoding": "chunked",
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Extension } from "@lobb-js/core";
|
|
2
|
+
import type { ExtensionConfig } from "./config/extensionConfigSchema.ts";
|
|
3
|
+
|
|
4
|
+
import { getCollectionRoutes } from "./collectionRoutes.ts";
|
|
5
|
+
import { collections } from "./collections/collections.ts";
|
|
6
|
+
import { migrations } from "./migrations/migrations.ts";
|
|
7
|
+
import { openapi } from "./openapi.ts";
|
|
8
|
+
|
|
9
|
+
export function llm(extensionConfig: ExtensionConfig): Extension {
|
|
10
|
+
return {
|
|
11
|
+
name: "llm",
|
|
12
|
+
collectionRoutes: getCollectionRoutes(extensionConfig),
|
|
13
|
+
collections: collections,
|
|
14
|
+
migrations: migrations,
|
|
15
|
+
openapi: openapi as any,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export const openapi = {
|
|
2
|
+
paths: {
|
|
3
|
+
"/api/collections/llm_chat": {
|
|
4
|
+
post: {
|
|
5
|
+
summary: "LLM chat",
|
|
6
|
+
description: "Talk to the llm using this endpoint",
|
|
7
|
+
requestBody: {
|
|
8
|
+
required: true,
|
|
9
|
+
content: {
|
|
10
|
+
"application/json": {
|
|
11
|
+
schema: {
|
|
12
|
+
type: "object",
|
|
13
|
+
required: ["messages"],
|
|
14
|
+
properties: {
|
|
15
|
+
stream: {
|
|
16
|
+
type: "boolean",
|
|
17
|
+
default: false,
|
|
18
|
+
example: false,
|
|
19
|
+
},
|
|
20
|
+
format: {
|
|
21
|
+
type: "string",
|
|
22
|
+
example: "json",
|
|
23
|
+
},
|
|
24
|
+
messages: {
|
|
25
|
+
type: "array",
|
|
26
|
+
items: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
role: {
|
|
30
|
+
type: "string",
|
|
31
|
+
example: "system",
|
|
32
|
+
},
|
|
33
|
+
content: {
|
|
34
|
+
type: "string",
|
|
35
|
+
example:
|
|
36
|
+
"you are a good person that listens to me carefully",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
example: [
|
|
41
|
+
{
|
|
42
|
+
"role": "system",
|
|
43
|
+
"content":
|
|
44
|
+
"you are a good person that listens to me carefully",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"role": "user",
|
|
48
|
+
"content": "generate a sentence of exactly five words",
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
responses: {
|
|
58
|
+
"200": {
|
|
59
|
+
description: "Successful operation",
|
|
60
|
+
content: {
|
|
61
|
+
"application/json": {
|
|
62
|
+
schema: {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {
|
|
65
|
+
data: {
|
|
66
|
+
type: "string",
|
|
67
|
+
example: "response text from the llm",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
"500": {
|
|
75
|
+
description: "Internal Error",
|
|
76
|
+
content: {
|
|
77
|
+
"application/json": {
|
|
78
|
+
schema: {
|
|
79
|
+
$ref: `#/components/schemas/internalErrorResponse`,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Config } from "@lobb-js/core";
|
|
2
|
+
import { llm } from "../../index.ts";
|
|
3
|
+
|
|
4
|
+
const API_KEY = Bun.env.CHATGPT_API_KEY;
|
|
5
|
+
|
|
6
|
+
if (!API_KEY) {
|
|
7
|
+
throw new Error("You need to specify the ChatGpt api_key");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const simple: Config = {
|
|
11
|
+
project: {
|
|
12
|
+
name: "Lobb",
|
|
13
|
+
force_sync: true,
|
|
14
|
+
support_email: "support@lobb.com",
|
|
15
|
+
},
|
|
16
|
+
database: {
|
|
17
|
+
host: "localhost",
|
|
18
|
+
port: 5432,
|
|
19
|
+
username: "test",
|
|
20
|
+
password: "test",
|
|
21
|
+
database: "*",
|
|
22
|
+
},
|
|
23
|
+
web_server: {
|
|
24
|
+
host: "0.0.0.0",
|
|
25
|
+
port: 0,
|
|
26
|
+
},
|
|
27
|
+
extensions: [
|
|
28
|
+
llm({
|
|
29
|
+
adapter: "chatgpt",
|
|
30
|
+
settings: {
|
|
31
|
+
model: "gpt-4o-mini",
|
|
32
|
+
api_key: API_KEY,
|
|
33
|
+
},
|
|
34
|
+
}),
|
|
35
|
+
],
|
|
36
|
+
collections: {
|
|
37
|
+
articles: {
|
|
38
|
+
indexes: {},
|
|
39
|
+
fields: {
|
|
40
|
+
id: { type: "integer" },
|
|
41
|
+
title: {
|
|
42
|
+
type: "string",
|
|
43
|
+
length: 255,
|
|
44
|
+
},
|
|
45
|
+
body: {
|
|
46
|
+
type: "string",
|
|
47
|
+
length: 255,
|
|
48
|
+
},
|
|
49
|
+
published: { type: "bool" },
|
|
50
|
+
number_of_likes: { type: "integer" },
|
|
51
|
+
user_id: { type: "integer" },
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Lobb } from "@lobb-js/core";
|
|
2
|
+
import { expect, afterAll, beforeAll, describe, it } from "bun:test";
|
|
3
|
+
import { llm } from "../index.ts";
|
|
4
|
+
import type { Config } from "@lobb-js/core";
|
|
5
|
+
|
|
6
|
+
// A minimal mock server that mimics the OpenAI /v1/chat/completions endpoint.
|
|
7
|
+
// This lets tests run without a real API key.
|
|
8
|
+
function startMockOpenAIServer() {
|
|
9
|
+
return Bun.serve({
|
|
10
|
+
port: 0, // random available port
|
|
11
|
+
fetch(req) {
|
|
12
|
+
const url = new URL(req.url);
|
|
13
|
+
|
|
14
|
+
if (url.pathname === "/v1/chat/completions") {
|
|
15
|
+
return Response.json({
|
|
16
|
+
id: "mock-id",
|
|
17
|
+
object: "chat.completion",
|
|
18
|
+
choices: [
|
|
19
|
+
{
|
|
20
|
+
index: 0,
|
|
21
|
+
message: { role: "assistant", content: "hello world mock" },
|
|
22
|
+
finish_reason: "stop",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
usage: { prompt_tokens: 5, completion_tokens: 4, total_tokens: 9 },
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return new Response("not found", { status: 404 });
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe("LLM extension (mock OpenAI server)", () => {
|
|
35
|
+
let lobb: Lobb;
|
|
36
|
+
let baseUrl: string;
|
|
37
|
+
let mockServer: ReturnType<typeof Bun.serve>;
|
|
38
|
+
|
|
39
|
+
beforeAll(async () => {
|
|
40
|
+
mockServer = startMockOpenAIServer();
|
|
41
|
+
|
|
42
|
+
const config: Config = {
|
|
43
|
+
project: { name: "Lobb", force_sync: true },
|
|
44
|
+
database: {
|
|
45
|
+
host: "localhost",
|
|
46
|
+
port: 5432,
|
|
47
|
+
username: "test",
|
|
48
|
+
password: "test",
|
|
49
|
+
database: "*",
|
|
50
|
+
},
|
|
51
|
+
web_server: { host: "0.0.0.0", port: 0 },
|
|
52
|
+
extensions: [
|
|
53
|
+
llm({
|
|
54
|
+
adapter: "chatgpt",
|
|
55
|
+
settings: {
|
|
56
|
+
model: "gpt-4o-mini",
|
|
57
|
+
api_key: "mock-key",
|
|
58
|
+
base_url: `http://localhost:${mockServer.port}/v1`,
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
],
|
|
62
|
+
collections: {
|
|
63
|
+
articles: {
|
|
64
|
+
indexes: {},
|
|
65
|
+
fields: {
|
|
66
|
+
id: { type: "integer" },
|
|
67
|
+
title: { type: "string", length: 255 },
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
lobb = await Lobb.init(config);
|
|
74
|
+
baseUrl = `http://127.0.0.1:${lobb.webServer.port}`;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
afterAll(async () => {
|
|
78
|
+
await lobb.close();
|
|
79
|
+
mockServer.stop();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("returns a response from the mock OpenAI server", async () => {
|
|
83
|
+
const response = await fetch(`${baseUrl}/api/collections/llm_chat`, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: { "Content-Type": "application/json" },
|
|
86
|
+
body: JSON.stringify({
|
|
87
|
+
messages: [{ role: "user", content: "say hello" }],
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const result = await response.json();
|
|
92
|
+
expect(response.status).toBe(200);
|
|
93
|
+
expect(typeof result.data).toBe("string");
|
|
94
|
+
expect(result.data).toBe("hello world mock");
|
|
95
|
+
});
|
|
96
|
+
});
|
package/lobb.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Lobb } from "@lobb-js/core";
|
|
2
|
+
import { llm } from "./extensions/llm/index.ts";
|
|
3
|
+
|
|
4
|
+
const CHATGPT_API_KEY = Deno.env.get("CHATGPT_API_KEY");
|
|
5
|
+
|
|
6
|
+
Lobb.init({
|
|
7
|
+
project: {
|
|
8
|
+
name: "LLM Project",
|
|
9
|
+
force_sync: true,
|
|
10
|
+
support_email: "support@lobb.com",
|
|
11
|
+
},
|
|
12
|
+
database: {
|
|
13
|
+
host: "localhost",
|
|
14
|
+
port: 5432,
|
|
15
|
+
username: "test",
|
|
16
|
+
password: "test",
|
|
17
|
+
database: "llm_ext_tests",
|
|
18
|
+
},
|
|
19
|
+
web_server: {
|
|
20
|
+
host: "0.0.0.0",
|
|
21
|
+
port: 3000,
|
|
22
|
+
},
|
|
23
|
+
extensions: [
|
|
24
|
+
llm({
|
|
25
|
+
adapter: "chatgpt",
|
|
26
|
+
settings: {
|
|
27
|
+
model: "gpt-4o-mini",
|
|
28
|
+
api_key: CHATGPT_API_KEY!,
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
],
|
|
32
|
+
collections: {
|
|
33
|
+
articles: {
|
|
34
|
+
indexes: {},
|
|
35
|
+
fields: {
|
|
36
|
+
id: { type: "integer" },
|
|
37
|
+
title: {
|
|
38
|
+
type: "string",
|
|
39
|
+
length: 255,
|
|
40
|
+
},
|
|
41
|
+
body: {
|
|
42
|
+
type: "string",
|
|
43
|
+
length: 255,
|
|
44
|
+
},
|
|
45
|
+
published: { type: "bool" },
|
|
46
|
+
number_of_likes: { type: "integer" },
|
|
47
|
+
user_id: { type: "integer" },
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
package/package.json
CHANGED
|
@@ -1,37 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobb-js/lobb-ext-llm",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"license": "AGPL-3.0-only",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"publishConfig": {
|
|
6
7
|
"access": "public"
|
|
7
8
|
},
|
|
8
|
-
"files": [
|
|
9
|
-
"src"
|
|
10
|
-
],
|
|
11
9
|
"exports": {
|
|
12
|
-
".": "./
|
|
10
|
+
".": "./extensions/llm/index.ts"
|
|
13
11
|
},
|
|
14
12
|
"scripts": {
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
13
|
+
"test": "bun run test:lobb",
|
|
14
|
+
"test:lobb": "bun test extensions/llm/tests",
|
|
15
|
+
"dev": "bun run lobb.ts"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@lobb-js/core": "0.13.1",
|
|
19
|
+
"hono": "^4.7.0",
|
|
20
|
+
"ollama": "^0.5.14",
|
|
21
|
+
"openai": "^4.87.3"
|
|
19
22
|
},
|
|
20
23
|
"devDependencies": {
|
|
21
|
-
"
|
|
22
|
-
"@lucide/svelte": "^0.563.1",
|
|
23
|
-
"@sveltejs/vite-plugin-svelte": "6.2.1",
|
|
24
|
-
"@tailwindcss/vite": "^4.1.18",
|
|
25
|
-
"@tsconfig/svelte": "^5.0.6",
|
|
26
|
-
"@types/node": "^24.10.1",
|
|
27
|
-
"clsx": "^2.1.1",
|
|
28
|
-
"svelte": "^5.49.1",
|
|
29
|
-
"svelte-check": "^4.3.4",
|
|
30
|
-
"tailwind-merge": "^3.4.0",
|
|
31
|
-
"tailwind-variants": "^3.2.2",
|
|
32
|
-
"tailwindcss": "4.1.18",
|
|
33
|
-
"tw-animate-css": "^1.4.0",
|
|
34
|
-
"typescript": "~5.9.3",
|
|
35
|
-
"vite": "6.3.3"
|
|
24
|
+
"bun-types": "latest"
|
|
36
25
|
}
|
|
37
26
|
}
|
package/todo.md
ADDED
package/src/app.css
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
2
|
-
|
|
3
|
-
@import "tw-animate-css";
|
|
4
|
-
|
|
5
|
-
@source "../../../../packages";
|
|
6
|
-
@source "../node_modules/@lobb-js";
|
|
7
|
-
|
|
8
|
-
@custom-variant dark (&:is(.dark *));
|
|
9
|
-
|
|
10
|
-
:root {
|
|
11
|
-
--radius: 0.625rem;
|
|
12
|
-
--background: oklch(1 0 0);
|
|
13
|
-
--foreground: oklch(0.129 0.042 264.695);
|
|
14
|
-
--card: oklch(1 0 0);
|
|
15
|
-
--card-foreground: oklch(0.129 0.042 264.695);
|
|
16
|
-
--popover: oklch(1 0 0);
|
|
17
|
-
--popover-foreground: oklch(0.129 0.042 264.695);
|
|
18
|
-
--primary: oklch(0.208 0.042 265.755);
|
|
19
|
-
--primary-foreground: oklch(0.984 0.003 247.858);
|
|
20
|
-
--secondary: oklch(0.968 0.007 247.896);
|
|
21
|
-
--secondary-foreground: oklch(0.208 0.042 265.755);
|
|
22
|
-
--muted: oklch(0.968 0.007 247.896);
|
|
23
|
-
--muted-foreground: oklch(0.554 0.046 257.417);
|
|
24
|
-
--accent: oklch(0.968 0.007 247.896);
|
|
25
|
-
--accent-foreground: oklch(0.208 0.042 265.755);
|
|
26
|
-
--destructive: oklch(0.577 0.245 27.325);
|
|
27
|
-
--border: oklch(0.929 0.013 255.508);
|
|
28
|
-
--input: oklch(0.929 0.013 255.508);
|
|
29
|
-
--ring: oklch(0.704 0.04 256.788);
|
|
30
|
-
--chart-1: oklch(0.646 0.222 41.116);
|
|
31
|
-
--chart-2: oklch(0.6 0.118 184.704);
|
|
32
|
-
--chart-3: oklch(0.398 0.07 227.392);
|
|
33
|
-
--chart-4: oklch(0.828 0.189 84.429);
|
|
34
|
-
--chart-5: oklch(0.769 0.188 70.08);
|
|
35
|
-
--sidebar: oklch(0.984 0.003 247.858);
|
|
36
|
-
--sidebar-foreground: oklch(0.129 0.042 264.695);
|
|
37
|
-
--sidebar-primary: oklch(0.208 0.042 265.755);
|
|
38
|
-
--sidebar-primary-foreground: oklch(0.984 0.003 247.858);
|
|
39
|
-
--sidebar-accent: oklch(0.968 0.007 247.896);
|
|
40
|
-
--sidebar-accent-foreground: oklch(0.208 0.042 265.755);
|
|
41
|
-
--sidebar-border: oklch(0.929 0.013 255.508);
|
|
42
|
-
--sidebar-ring: oklch(0.704 0.04 256.788);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.dark {
|
|
46
|
-
--background: oklch(0.129 0.042 264.695);
|
|
47
|
-
--foreground: oklch(0.984 0.003 247.858);
|
|
48
|
-
--card: oklch(0.208 0.042 265.755);
|
|
49
|
-
--card-foreground: oklch(0.984 0.003 247.858);
|
|
50
|
-
--popover: oklch(0.208 0.042 265.755);
|
|
51
|
-
--popover-foreground: oklch(0.984 0.003 247.858);
|
|
52
|
-
--primary: oklch(0.929 0.013 255.508);
|
|
53
|
-
--primary-foreground: oklch(0.208 0.042 265.755);
|
|
54
|
-
--secondary: oklch(0.279 0.041 260.031);
|
|
55
|
-
--secondary-foreground: oklch(0.984 0.003 247.858);
|
|
56
|
-
--muted: oklch(0.279 0.041 260.031);
|
|
57
|
-
--muted-foreground: oklch(0.704 0.04 256.788);
|
|
58
|
-
--accent: oklch(0.279 0.041 260.031);
|
|
59
|
-
--accent-foreground: oklch(0.984 0.003 247.858);
|
|
60
|
-
--destructive: oklch(0.704 0.191 22.216);
|
|
61
|
-
--border: oklch(1 0 0 / 10%);
|
|
62
|
-
--input: oklch(1 0 0 / 15%);
|
|
63
|
-
--ring: oklch(0.551 0.027 264.364);
|
|
64
|
-
--chart-1: oklch(0.488 0.243 264.376);
|
|
65
|
-
--chart-2: oklch(0.696 0.17 162.48);
|
|
66
|
-
--chart-3: oklch(0.769 0.188 70.08);
|
|
67
|
-
--chart-4: oklch(0.627 0.265 303.9);
|
|
68
|
-
--chart-5: oklch(0.645 0.246 16.439);
|
|
69
|
-
--sidebar: oklch(0.208 0.042 265.755);
|
|
70
|
-
--sidebar-foreground: oklch(0.984 0.003 247.858);
|
|
71
|
-
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
72
|
-
--sidebar-primary-foreground: oklch(0.984 0.003 247.858);
|
|
73
|
-
--sidebar-accent: oklch(0.279 0.041 260.031);
|
|
74
|
-
--sidebar-accent-foreground: oklch(0.984 0.003 247.858);
|
|
75
|
-
--sidebar-border: oklch(1 0 0 / 10%);
|
|
76
|
-
--sidebar-ring: oklch(0.551 0.027 264.364);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
@theme inline {
|
|
80
|
-
--radius-sm: calc(var(--radius) - 4px);
|
|
81
|
-
--radius-md: calc(var(--radius) - 2px);
|
|
82
|
-
--radius-lg: var(--radius);
|
|
83
|
-
--radius-xl: calc(var(--radius) + 4px);
|
|
84
|
-
--color-background: var(--background);
|
|
85
|
-
--color-foreground: var(--foreground);
|
|
86
|
-
--color-card: var(--card);
|
|
87
|
-
--color-card-foreground: var(--card-foreground);
|
|
88
|
-
--color-popover: var(--popover);
|
|
89
|
-
--color-popover-foreground: var(--popover-foreground);
|
|
90
|
-
--color-primary: var(--primary);
|
|
91
|
-
--color-primary-foreground: var(--primary-foreground);
|
|
92
|
-
--color-secondary: var(--secondary);
|
|
93
|
-
--color-secondary-foreground: var(--secondary-foreground);
|
|
94
|
-
--color-muted: var(--muted);
|
|
95
|
-
--color-muted-foreground: var(--muted-foreground);
|
|
96
|
-
--color-accent: var(--accent);
|
|
97
|
-
--color-accent-foreground: var(--accent-foreground);
|
|
98
|
-
--color-destructive: var(--destructive);
|
|
99
|
-
--color-border: var(--border);
|
|
100
|
-
--color-input: var(--input);
|
|
101
|
-
--color-ring: var(--ring);
|
|
102
|
-
--color-chart-1: var(--chart-1);
|
|
103
|
-
--color-chart-2: var(--chart-2);
|
|
104
|
-
--color-chart-3: var(--chart-3);
|
|
105
|
-
--color-chart-4: var(--chart-4);
|
|
106
|
-
--color-chart-5: var(--chart-5);
|
|
107
|
-
--color-sidebar: var(--sidebar);
|
|
108
|
-
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
109
|
-
--color-sidebar-primary: var(--sidebar-primary);
|
|
110
|
-
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
111
|
-
--color-sidebar-accent: var(--sidebar-accent);
|
|
112
|
-
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
113
|
-
--color-sidebar-border: var(--sidebar-border);
|
|
114
|
-
--color-sidebar-ring: var(--sidebar-ring);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
@layer base {
|
|
118
|
-
* {
|
|
119
|
-
@apply border-border outline-ring/50;
|
|
120
|
-
}
|
|
121
|
-
body {
|
|
122
|
-
@apply bg-background text-foreground;
|
|
123
|
-
}
|
|
124
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { Extension, ExtensionUtils } from "../extension.types";
|
|
2
|
-
|
|
3
|
-
export default function extension(utils: ExtensionUtils): Extension {
|
|
4
|
-
return {
|
|
5
|
-
name: "llm",
|
|
6
|
-
// onStartup: onStartup,
|
|
7
|
-
components: {
|
|
8
|
-
// "pages.settings": Settings,
|
|
9
|
-
},
|
|
10
|
-
dashboardNavs: {
|
|
11
|
-
middle: [
|
|
12
|
-
// {
|
|
13
|
-
// label: "LLM",
|
|
14
|
-
// icon: utils.components.Icons.Bot,
|
|
15
|
-
// href: "/extensions/llm/settings",
|
|
16
|
-
// },
|
|
17
|
-
],
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
}
|
package/src/lib/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// place files you want to import through the `$lib` alias in this folder.
|
package/src/lib/utils.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { clsx, type ClassValue } from "clsx";
|
|
2
|
-
import { twMerge } from "tailwind-merge";
|
|
3
|
-
|
|
4
|
-
export function cn(...inputs: ClassValue[]) {
|
|
5
|
-
return twMerge(clsx(inputs));
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
-
export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T;
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
-
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T;
|
|
12
|
-
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
|
|
13
|
-
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
|
package/src/main.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import "./app.css";
|
|
2
|
-
|
|
3
|
-
import { mount } from "svelte";
|
|
4
|
-
import { Studio } from "@lobb-js/studio";
|
|
5
|
-
import { extension } from "./index";
|
|
6
|
-
|
|
7
|
-
const app = mount(Studio, {
|
|
8
|
-
target: document.getElementById("app")!,
|
|
9
|
-
props: {
|
|
10
|
-
extensions: [extension],
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
export default app;
|