@mariozechner/pi-web-ui 0.5.44
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/README.md +252 -0
- package/dist/ChatPanel.d.ts +23 -0
- package/dist/ChatPanel.d.ts.map +1 -0
- package/dist/ChatPanel.js +224 -0
- package/dist/ChatPanel.js.map +1 -0
- package/dist/app.css +2 -0
- package/dist/components/AgentInterface.d.ts +35 -0
- package/dist/components/AgentInterface.d.ts.map +1 -0
- package/dist/components/AgentInterface.js +308 -0
- package/dist/components/AgentInterface.js.map +1 -0
- package/dist/components/AttachmentTile.d.ts +12 -0
- package/dist/components/AttachmentTile.d.ts.map +1 -0
- package/dist/components/AttachmentTile.js +114 -0
- package/dist/components/AttachmentTile.js.map +1 -0
- package/dist/components/ConsoleBlock.d.ts +11 -0
- package/dist/components/ConsoleBlock.d.ts.map +1 -0
- package/dist/components/ConsoleBlock.js +77 -0
- package/dist/components/ConsoleBlock.js.map +1 -0
- package/dist/components/Input.d.ts +26 -0
- package/dist/components/Input.d.ts.map +1 -0
- package/dist/components/Input.js +56 -0
- package/dist/components/Input.js.map +1 -0
- package/dist/components/MessageEditor.d.ts +38 -0
- package/dist/components/MessageEditor.d.ts.map +1 -0
- package/dist/components/MessageEditor.js +296 -0
- package/dist/components/MessageEditor.js.map +1 -0
- package/dist/components/MessageList.d.ts +13 -0
- package/dist/components/MessageList.d.ts.map +1 -0
- package/dist/components/MessageList.js +88 -0
- package/dist/components/MessageList.js.map +1 -0
- package/dist/components/Messages.d.ts +53 -0
- package/dist/components/Messages.d.ts.map +1 -0
- package/dist/components/Messages.js +323 -0
- package/dist/components/Messages.js.map +1 -0
- package/dist/components/ProviderKeyInput.d.ts +16 -0
- package/dist/components/ProviderKeyInput.d.ts.map +1 -0
- package/dist/components/ProviderKeyInput.js +183 -0
- package/dist/components/ProviderKeyInput.js.map +1 -0
- package/dist/components/SandboxedIframe.d.ts +63 -0
- package/dist/components/SandboxedIframe.d.ts.map +1 -0
- package/dist/components/SandboxedIframe.js +435 -0
- package/dist/components/SandboxedIframe.js.map +1 -0
- package/dist/components/StreamingMessageContainer.d.ts +17 -0
- package/dist/components/StreamingMessageContainer.d.ts.map +1 -0
- package/dist/components/StreamingMessageContainer.js +114 -0
- package/dist/components/StreamingMessageContainer.js.map +1 -0
- package/dist/dialogs/ApiKeyPromptDialog.d.ts +15 -0
- package/dist/dialogs/ApiKeyPromptDialog.d.ts.map +1 -0
- package/dist/dialogs/ApiKeyPromptDialog.js +80 -0
- package/dist/dialogs/ApiKeyPromptDialog.js.map +1 -0
- package/dist/dialogs/AttachmentOverlay.d.ts +32 -0
- package/dist/dialogs/AttachmentOverlay.d.ts.map +1 -0
- package/dist/dialogs/AttachmentOverlay.js +575 -0
- package/dist/dialogs/AttachmentOverlay.js.map +1 -0
- package/dist/dialogs/ModelSelector.d.ts +27 -0
- package/dist/dialogs/ModelSelector.d.ts.map +1 -0
- package/dist/dialogs/ModelSelector.js +334 -0
- package/dist/dialogs/ModelSelector.js.map +1 -0
- package/dist/dialogs/SettingsDialog.d.ts +31 -0
- package/dist/dialogs/SettingsDialog.d.ts.map +1 -0
- package/dist/dialogs/SettingsDialog.js +228 -0
- package/dist/dialogs/SettingsDialog.js.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/state/agent-session.d.ts +58 -0
- package/dist/state/agent-session.d.ts.map +1 -0
- package/dist/state/agent-session.js +252 -0
- package/dist/state/agent-session.js.map +1 -0
- package/dist/state/transports/AppTransport.d.ts +13 -0
- package/dist/state/transports/AppTransport.d.ts.map +1 -0
- package/dist/state/transports/AppTransport.js +316 -0
- package/dist/state/transports/AppTransport.js.map +1 -0
- package/dist/state/transports/ProviderTransport.d.ts +12 -0
- package/dist/state/transports/ProviderTransport.d.ts.map +1 -0
- package/dist/state/transports/ProviderTransport.js +44 -0
- package/dist/state/transports/ProviderTransport.js.map +1 -0
- package/dist/state/transports/index.d.ts +4 -0
- package/dist/state/transports/index.d.ts.map +1 -0
- package/dist/state/transports/index.js +4 -0
- package/dist/state/transports/index.js.map +1 -0
- package/dist/state/transports/proxy-types.d.ts +48 -0
- package/dist/state/transports/proxy-types.d.ts.map +1 -0
- package/dist/state/transports/proxy-types.js +2 -0
- package/dist/state/transports/proxy-types.js.map +1 -0
- package/dist/state/transports/types.d.ts +11 -0
- package/dist/state/transports/types.d.ts.map +1 -0
- package/dist/state/transports/types.js +2 -0
- package/dist/state/transports/types.js.map +1 -0
- package/dist/state/types.d.ts +15 -0
- package/dist/state/types.d.ts.map +1 -0
- package/dist/state/types.js +2 -0
- package/dist/state/types.js.map +1 -0
- package/dist/storage/app-storage.d.ts +26 -0
- package/dist/storage/app-storage.d.ts.map +1 -0
- package/dist/storage/app-storage.js +44 -0
- package/dist/storage/app-storage.js.map +1 -0
- package/dist/storage/backends/chrome-storage-backend.d.ts +18 -0
- package/dist/storage/backends/chrome-storage-backend.d.ts.map +1 -0
- package/dist/storage/backends/chrome-storage-backend.js +67 -0
- package/dist/storage/backends/chrome-storage-backend.js.map +1 -0
- package/dist/storage/backends/indexeddb-backend.d.ts +20 -0
- package/dist/storage/backends/indexeddb-backend.d.ts.map +1 -0
- package/dist/storage/backends/indexeddb-backend.js +89 -0
- package/dist/storage/backends/indexeddb-backend.js.map +1 -0
- package/dist/storage/backends/local-storage-backend.d.ts +18 -0
- package/dist/storage/backends/local-storage-backend.d.ts.map +1 -0
- package/dist/storage/backends/local-storage-backend.js +69 -0
- package/dist/storage/backends/local-storage-backend.js.map +1 -0
- package/dist/storage/repositories/provider-keys-repository.d.ts +34 -0
- package/dist/storage/repositories/provider-keys-repository.d.ts.map +1 -0
- package/dist/storage/repositories/provider-keys-repository.js +50 -0
- package/dist/storage/repositories/provider-keys-repository.js.map +1 -0
- package/dist/storage/repositories/settings-repository.d.ts +34 -0
- package/dist/storage/repositories/settings-repository.d.ts.map +1 -0
- package/dist/storage/repositories/settings-repository.js +46 -0
- package/dist/storage/repositories/settings-repository.js.map +1 -0
- package/dist/storage/types.d.ts +43 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/tools/artifacts/ArtifactElement.d.ts +10 -0
- package/dist/tools/artifacts/ArtifactElement.d.ts.map +1 -0
- package/dist/tools/artifacts/ArtifactElement.js +12 -0
- package/dist/tools/artifacts/ArtifactElement.js.map +1 -0
- package/dist/tools/artifacts/HtmlArtifact.d.ts +30 -0
- package/dist/tools/artifacts/HtmlArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/HtmlArtifact.js +217 -0
- package/dist/tools/artifacts/HtmlArtifact.js.map +1 -0
- package/dist/tools/artifacts/MarkdownArtifact.d.ts +20 -0
- package/dist/tools/artifacts/MarkdownArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/MarkdownArtifact.js +84 -0
- package/dist/tools/artifacts/MarkdownArtifact.js.map +1 -0
- package/dist/tools/artifacts/SvgArtifact.d.ts +19 -0
- package/dist/tools/artifacts/SvgArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/SvgArtifact.js +80 -0
- package/dist/tools/artifacts/SvgArtifact.js.map +1 -0
- package/dist/tools/artifacts/TextArtifact.d.ts +20 -0
- package/dist/tools/artifacts/TextArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/TextArtifact.js +147 -0
- package/dist/tools/artifacts/TextArtifact.js.map +1 -0
- package/dist/tools/artifacts/artifacts.d.ts +67 -0
- package/dist/tools/artifacts/artifacts.d.ts.map +1 -0
- package/dist/tools/artifacts/artifacts.js +836 -0
- package/dist/tools/artifacts/artifacts.js.map +1 -0
- package/dist/tools/artifacts/index.d.ts +7 -0
- package/dist/tools/artifacts/index.d.ts.map +1 -0
- package/dist/tools/artifacts/index.js +7 -0
- package/dist/tools/artifacts/index.js.map +1 -0
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +29 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/javascript-repl.d.ts +43 -0
- package/dist/tools/javascript-repl.d.ts.map +1 -0
- package/dist/tools/javascript-repl.js +252 -0
- package/dist/tools/javascript-repl.js.map +1 -0
- package/dist/tools/renderer-registry.d.ts +11 -0
- package/dist/tools/renderer-registry.d.ts.map +1 -0
- package/dist/tools/renderer-registry.js +15 -0
- package/dist/tools/renderer-registry.js.map +1 -0
- package/dist/tools/renderers/BashRenderer.d.ts +12 -0
- package/dist/tools/renderers/BashRenderer.d.ts.map +1 -0
- package/dist/tools/renderers/BashRenderer.js +35 -0
- package/dist/tools/renderers/BashRenderer.js.map +1 -0
- package/dist/tools/renderers/CalculateRenderer.d.ts +12 -0
- package/dist/tools/renderers/CalculateRenderer.d.ts.map +1 -0
- package/dist/tools/renderers/CalculateRenderer.js +38 -0
- package/dist/tools/renderers/CalculateRenderer.js.map +1 -0
- package/dist/tools/renderers/DefaultRenderer.d.ts +8 -0
- package/dist/tools/renderers/DefaultRenderer.d.ts.map +1 -0
- package/dist/tools/renderers/DefaultRenderer.js +31 -0
- package/dist/tools/renderers/DefaultRenderer.js.map +1 -0
- package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts +12 -0
- package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts.map +1 -0
- package/dist/tools/renderers/GetCurrentTimeRenderer.js +30 -0
- package/dist/tools/renderers/GetCurrentTimeRenderer.js.map +1 -0
- package/dist/tools/types.d.ts +7 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/utils/attachment-utils.d.ts +19 -0
- package/dist/utils/attachment-utils.d.ts.map +1 -0
- package/dist/utils/attachment-utils.js +415 -0
- package/dist/utils/attachment-utils.js.map +1 -0
- package/dist/utils/auth-token.d.ts +3 -0
- package/dist/utils/auth-token.d.ts.map +1 -0
- package/dist/utils/auth-token.js +19 -0
- package/dist/utils/auth-token.js.map +1 -0
- package/dist/utils/format.d.ts +6 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +47 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/i18n.d.ts +111 -0
- package/dist/utils/i18n.d.ts.map +1 -0
- package/dist/utils/i18n.js +224 -0
- package/dist/utils/i18n.js.map +1 -0
- package/dist/utils/test-sessions.d.ts +347 -0
- package/dist/utils/test-sessions.d.ts.map +1 -0
- package/dist/utils/test-sessions.js +2215 -0
- package/dist/utils/test-sessions.js.map +1 -0
- package/example/README.md +61 -0
- package/example/index.html +13 -0
- package/example/package-lock.json +1965 -0
- package/example/package.json +22 -0
- package/example/src/app.css +1 -0
- package/example/src/main.ts +57 -0
- package/example/src/test-sessions.ts +104 -0
- package/example/tsconfig.json +15 -0
- package/example/vite.config.ts +6 -0
- package/package.json +45 -0
- package/src/ChatPanel.ts +214 -0
- package/src/app.css +44 -0
- package/src/components/AgentInterface.ts +316 -0
- package/src/components/AttachmentTile.ts +112 -0
- package/src/components/ConsoleBlock.ts +67 -0
- package/src/components/Input.ts +112 -0
- package/src/components/MessageEditor.ts +272 -0
- package/src/components/MessageList.ts +82 -0
- package/src/components/Messages.ts +310 -0
- package/src/components/ProviderKeyInput.ts +170 -0
- package/src/components/SandboxedIframe.ts +525 -0
- package/src/components/StreamingMessageContainer.ts +101 -0
- package/src/dialogs/ApiKeyPromptDialog.ts +76 -0
- package/src/dialogs/AttachmentOverlay.ts +635 -0
- package/src/dialogs/ModelSelector.ts +324 -0
- package/src/dialogs/SettingsDialog.ts +223 -0
- package/src/index.ts +63 -0
- package/src/state/agent-session.ts +311 -0
- package/src/state/transports/AppTransport.ts +363 -0
- package/src/state/transports/ProviderTransport.ts +49 -0
- package/src/state/transports/index.ts +3 -0
- package/src/state/transports/proxy-types.ts +15 -0
- package/src/state/transports/types.ts +16 -0
- package/src/state/types.ts +11 -0
- package/src/storage/app-storage.ts +53 -0
- package/src/storage/backends/chrome-storage-backend.ts +82 -0
- package/src/storage/backends/indexeddb-backend.ts +107 -0
- package/src/storage/backends/local-storage-backend.ts +74 -0
- package/src/storage/repositories/provider-keys-repository.ts +55 -0
- package/src/storage/repositories/settings-repository.ts +51 -0
- package/src/storage/types.ts +48 -0
- package/src/tools/artifacts/ArtifactElement.ts +15 -0
- package/src/tools/artifacts/HtmlArtifact.ts +221 -0
- package/src/tools/artifacts/MarkdownArtifact.ts +81 -0
- package/src/tools/artifacts/SvgArtifact.ts +77 -0
- package/src/tools/artifacts/TextArtifact.ts +148 -0
- package/src/tools/artifacts/artifacts.ts +888 -0
- package/src/tools/artifacts/index.ts +6 -0
- package/src/tools/index.ts +35 -0
- package/src/tools/javascript-repl.ts +309 -0
- package/src/tools/renderer-registry.ts +18 -0
- package/src/tools/renderers/BashRenderer.ts +45 -0
- package/src/tools/renderers/CalculateRenderer.ts +49 -0
- package/src/tools/renderers/DefaultRenderer.ts +36 -0
- package/src/tools/renderers/GetCurrentTimeRenderer.ts +39 -0
- package/src/tools/types.ts +7 -0
- package/src/utils/attachment-utils.ts +472 -0
- package/src/utils/auth-token.ts +22 -0
- package/src/utils/format.ts +42 -0
- package/src/utils/i18n.ts +343 -0
- package/src/utils/test-sessions.ts +2247 -0
- package/tsconfig.build.json +20 -0
- package/tsconfig.json +7 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { Badge, Button, DialogBase, DialogHeader, html, icon, type TemplateResult } from "@mariozechner/mini-lit";
|
|
2
|
+
import type { Model } from "@mariozechner/pi-ai";
|
|
3
|
+
import { MODELS } from "@mariozechner/pi-ai/dist/models.generated.js";
|
|
4
|
+
import type { PropertyValues } from "lit";
|
|
5
|
+
import { customElement, state } from "lit/decorators.js";
|
|
6
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
7
|
+
import { Brain, Image as ImageIcon } from "lucide";
|
|
8
|
+
import { Ollama } from "ollama/dist/browser.mjs";
|
|
9
|
+
import { Input } from "../components/Input.js";
|
|
10
|
+
import { formatModelCost } from "../utils/format.js";
|
|
11
|
+
import { i18n } from "../utils/i18n.js";
|
|
12
|
+
|
|
13
|
+
@customElement("agent-model-selector")
|
|
14
|
+
export class ModelSelector extends DialogBase {
|
|
15
|
+
@state() currentModel: Model<any> | null = null;
|
|
16
|
+
@state() searchQuery = "";
|
|
17
|
+
@state() filterThinking = false;
|
|
18
|
+
@state() filterVision = false;
|
|
19
|
+
@state() ollamaModels: Model<any>[] = [];
|
|
20
|
+
@state() ollamaError: string | null = null;
|
|
21
|
+
@state() selectedIndex = 0;
|
|
22
|
+
@state() private navigationMode: "mouse" | "keyboard" = "mouse";
|
|
23
|
+
|
|
24
|
+
private onSelectCallback?: (model: Model<any>) => void;
|
|
25
|
+
private scrollContainerRef = createRef<HTMLDivElement>();
|
|
26
|
+
private searchInputRef = createRef<HTMLInputElement>();
|
|
27
|
+
private lastMousePosition = { x: 0, y: 0 };
|
|
28
|
+
|
|
29
|
+
protected override modalWidth = "min(400px, 90vw)";
|
|
30
|
+
|
|
31
|
+
static async open(currentModel: Model<any> | null, onSelect: (model: Model<any>) => void) {
|
|
32
|
+
const selector = new ModelSelector();
|
|
33
|
+
selector.currentModel = currentModel;
|
|
34
|
+
selector.onSelectCallback = onSelect;
|
|
35
|
+
selector.open();
|
|
36
|
+
selector.fetchOllamaModels();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override async firstUpdated(changedProperties: PropertyValues): Promise<void> {
|
|
40
|
+
super.firstUpdated(changedProperties);
|
|
41
|
+
// Wait for dialog to be fully rendered
|
|
42
|
+
await this.updateComplete;
|
|
43
|
+
// Focus the search input when dialog opens
|
|
44
|
+
this.searchInputRef.value?.focus();
|
|
45
|
+
|
|
46
|
+
// Track actual mouse movement
|
|
47
|
+
this.addEventListener("mousemove", (e: MouseEvent) => {
|
|
48
|
+
// Check if mouse actually moved
|
|
49
|
+
if (e.clientX !== this.lastMousePosition.x || e.clientY !== this.lastMousePosition.y) {
|
|
50
|
+
this.lastMousePosition = { x: e.clientX, y: e.clientY };
|
|
51
|
+
// Only switch to mouse mode on actual mouse movement
|
|
52
|
+
if (this.navigationMode === "keyboard") {
|
|
53
|
+
this.navigationMode = "mouse";
|
|
54
|
+
// Update selection to the item under the mouse
|
|
55
|
+
const target = e.target as HTMLElement;
|
|
56
|
+
const modelItem = target.closest("[data-model-item]");
|
|
57
|
+
if (modelItem) {
|
|
58
|
+
const allItems = this.scrollContainerRef.value?.querySelectorAll("[data-model-item]");
|
|
59
|
+
if (allItems) {
|
|
60
|
+
const index = Array.from(allItems).indexOf(modelItem);
|
|
61
|
+
if (index !== -1) {
|
|
62
|
+
this.selectedIndex = index;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Add global keyboard handler for the dialog
|
|
71
|
+
this.addEventListener("keydown", (e: KeyboardEvent) => {
|
|
72
|
+
// Get filtered models to know the bounds
|
|
73
|
+
const filteredModels = this.getFilteredModels();
|
|
74
|
+
|
|
75
|
+
if (e.key === "ArrowDown") {
|
|
76
|
+
e.preventDefault();
|
|
77
|
+
this.navigationMode = "keyboard";
|
|
78
|
+
this.selectedIndex = Math.min(this.selectedIndex + 1, filteredModels.length - 1);
|
|
79
|
+
this.scrollToSelected();
|
|
80
|
+
} else if (e.key === "ArrowUp") {
|
|
81
|
+
e.preventDefault();
|
|
82
|
+
this.navigationMode = "keyboard";
|
|
83
|
+
this.selectedIndex = Math.max(this.selectedIndex - 1, 0);
|
|
84
|
+
this.scrollToSelected();
|
|
85
|
+
} else if (e.key === "Enter") {
|
|
86
|
+
e.preventDefault();
|
|
87
|
+
if (filteredModels[this.selectedIndex]) {
|
|
88
|
+
this.handleSelect(filteredModels[this.selectedIndex].model);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private async fetchOllamaModels() {
|
|
95
|
+
try {
|
|
96
|
+
// Create Ollama client
|
|
97
|
+
const ollama = new Ollama({ host: "http://localhost:11434" });
|
|
98
|
+
|
|
99
|
+
// Get list of available models
|
|
100
|
+
const { models } = await ollama.list();
|
|
101
|
+
|
|
102
|
+
// Fetch details for each model and convert to Model format
|
|
103
|
+
const ollamaModelPromises: Promise<Model<any> | null>[] = models
|
|
104
|
+
.map(async (model) => {
|
|
105
|
+
try {
|
|
106
|
+
// Get model details
|
|
107
|
+
const details = await ollama.show({
|
|
108
|
+
model: model.name,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Some Ollama servers don't report capabilities; don't filter on them
|
|
112
|
+
|
|
113
|
+
// Extract model info
|
|
114
|
+
const modelInfo: any = details.model_info || {};
|
|
115
|
+
|
|
116
|
+
// Get context window size - look for architecture-specific keys
|
|
117
|
+
const architecture = modelInfo["general.architecture"] || "";
|
|
118
|
+
const contextKey = `${architecture}.context_length`;
|
|
119
|
+
const contextWindow = parseInt(modelInfo[contextKey] || "8192", 10);
|
|
120
|
+
const maxTokens = 4096; // Default max output tokens
|
|
121
|
+
|
|
122
|
+
// Create Model object manually since ollama models aren't in MODELS constant
|
|
123
|
+
const ollamaModel: Model<any> = {
|
|
124
|
+
id: model.name,
|
|
125
|
+
name: model.name,
|
|
126
|
+
api: "openai-completions" as any,
|
|
127
|
+
provider: "ollama",
|
|
128
|
+
baseUrl: "http://localhost:11434/v1",
|
|
129
|
+
reasoning: false,
|
|
130
|
+
input: ["text"],
|
|
131
|
+
cost: {
|
|
132
|
+
input: 0,
|
|
133
|
+
output: 0,
|
|
134
|
+
cacheRead: 0,
|
|
135
|
+
cacheWrite: 0,
|
|
136
|
+
},
|
|
137
|
+
contextWindow: contextWindow,
|
|
138
|
+
maxTokens: maxTokens,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return ollamaModel;
|
|
142
|
+
} catch (err) {
|
|
143
|
+
console.error(`Failed to fetch details for model ${model.name}:`, err);
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
.filter((m) => m !== null);
|
|
148
|
+
|
|
149
|
+
const results = await Promise.all(ollamaModelPromises);
|
|
150
|
+
this.ollamaModels = results.filter((m): m is Model<any> => m !== null);
|
|
151
|
+
} catch (err) {
|
|
152
|
+
// Ollama not available or other error - silently ignore
|
|
153
|
+
console.debug("Ollama not available:", err);
|
|
154
|
+
this.ollamaError = err instanceof Error ? err.message : String(err);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private formatTokens(tokens: number): string {
|
|
159
|
+
if (tokens >= 1000000) return `${(tokens / 1000000).toFixed(0)}M`;
|
|
160
|
+
if (tokens >= 1000) return `${(tokens / 1000).toFixed(0)}`;
|
|
161
|
+
return String(tokens);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private handleSelect(model: Model<any>) {
|
|
165
|
+
if (model) {
|
|
166
|
+
this.onSelectCallback?.(model);
|
|
167
|
+
this.close();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private getFilteredModels(): Array<{ provider: string; id: string; model: any }> {
|
|
172
|
+
// Collect all models from all providers
|
|
173
|
+
const allModels: Array<{ provider: string; id: string; model: any }> = [];
|
|
174
|
+
for (const [provider, providerData] of Object.entries(MODELS)) {
|
|
175
|
+
for (const [modelId, model] of Object.entries(providerData)) {
|
|
176
|
+
allModels.push({ provider, id: modelId, model });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Add Ollama models
|
|
181
|
+
for (const ollamaModel of this.ollamaModels) {
|
|
182
|
+
allModels.push({
|
|
183
|
+
id: ollamaModel.id,
|
|
184
|
+
provider: "ollama",
|
|
185
|
+
model: ollamaModel,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Filter models based on search and capability filters
|
|
190
|
+
let filteredModels = allModels;
|
|
191
|
+
|
|
192
|
+
// Apply search filter
|
|
193
|
+
if (this.searchQuery) {
|
|
194
|
+
filteredModels = filteredModels.filter(({ provider, id, model }) => {
|
|
195
|
+
const searchTokens = this.searchQuery.split(/\s+/).filter((t) => t);
|
|
196
|
+
const searchText = `${provider} ${id} ${model.name}`.toLowerCase();
|
|
197
|
+
return searchTokens.every((token) => searchText.includes(token));
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Apply capability filters
|
|
202
|
+
if (this.filterThinking) {
|
|
203
|
+
filteredModels = filteredModels.filter(({ model }) => model.reasoning);
|
|
204
|
+
}
|
|
205
|
+
if (this.filterVision) {
|
|
206
|
+
filteredModels = filteredModels.filter(({ model }) => model.input.includes("image"));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Sort: current model first, then by provider
|
|
210
|
+
filteredModels.sort((a, b) => {
|
|
211
|
+
const aIsCurrent = this.currentModel?.id === a.model.id;
|
|
212
|
+
const bIsCurrent = this.currentModel?.id === b.model.id;
|
|
213
|
+
if (aIsCurrent && !bIsCurrent) return -1;
|
|
214
|
+
if (!aIsCurrent && bIsCurrent) return 1;
|
|
215
|
+
return a.provider.localeCompare(b.provider);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
return filteredModels;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private scrollToSelected() {
|
|
222
|
+
requestAnimationFrame(() => {
|
|
223
|
+
const scrollContainer = this.scrollContainerRef.value;
|
|
224
|
+
const selectedElement = scrollContainer?.querySelectorAll("[data-model-item]")[
|
|
225
|
+
this.selectedIndex
|
|
226
|
+
] as HTMLElement;
|
|
227
|
+
if (selectedElement) {
|
|
228
|
+
selectedElement.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
protected override renderContent(): TemplateResult {
|
|
234
|
+
const filteredModels = this.getFilteredModels();
|
|
235
|
+
|
|
236
|
+
return html`
|
|
237
|
+
<!-- Header and Search -->
|
|
238
|
+
<div class="p-6 pb-4 flex flex-col gap-4 border-b border-border flex-shrink-0">
|
|
239
|
+
${DialogHeader({ title: i18n("Select Model") })}
|
|
240
|
+
${Input({
|
|
241
|
+
placeholder: i18n("Search models..."),
|
|
242
|
+
value: this.searchQuery,
|
|
243
|
+
inputRef: this.searchInputRef,
|
|
244
|
+
onInput: (e: Event) => {
|
|
245
|
+
this.searchQuery = (e.target as HTMLInputElement).value;
|
|
246
|
+
this.selectedIndex = 0;
|
|
247
|
+
// Reset scroll position when search changes
|
|
248
|
+
if (this.scrollContainerRef.value) {
|
|
249
|
+
this.scrollContainerRef.value.scrollTop = 0;
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
})}
|
|
253
|
+
<div class="flex gap-2">
|
|
254
|
+
${Button({
|
|
255
|
+
variant: this.filterThinking ? "default" : "secondary",
|
|
256
|
+
size: "sm",
|
|
257
|
+
onClick: () => {
|
|
258
|
+
this.filterThinking = !this.filterThinking;
|
|
259
|
+
this.selectedIndex = 0;
|
|
260
|
+
if (this.scrollContainerRef.value) {
|
|
261
|
+
this.scrollContainerRef.value.scrollTop = 0;
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
className: "rounded-full",
|
|
265
|
+
children: html`<span class="inline-flex items-center gap-1">${icon(Brain, "sm")} ${i18n("Thinking")}</span>`,
|
|
266
|
+
})}
|
|
267
|
+
${Button({
|
|
268
|
+
variant: this.filterVision ? "default" : "secondary",
|
|
269
|
+
size: "sm",
|
|
270
|
+
onClick: () => {
|
|
271
|
+
this.filterVision = !this.filterVision;
|
|
272
|
+
this.selectedIndex = 0;
|
|
273
|
+
if (this.scrollContainerRef.value) {
|
|
274
|
+
this.scrollContainerRef.value.scrollTop = 0;
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
className: "rounded-full",
|
|
278
|
+
children: html`<span class="inline-flex items-center gap-1">${icon(ImageIcon, "sm")} ${i18n("Vision")}</span>`,
|
|
279
|
+
})}
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
282
|
+
|
|
283
|
+
<!-- Scrollable model list -->
|
|
284
|
+
<div class="flex-1 overflow-y-auto" ${ref(this.scrollContainerRef)}>
|
|
285
|
+
${filteredModels.map(({ provider, id, model }, index) => {
|
|
286
|
+
// Check if this is the current model by comparing IDs
|
|
287
|
+
const isCurrent = this.currentModel?.id === model.id;
|
|
288
|
+
const isSelected = index === this.selectedIndex;
|
|
289
|
+
return html`
|
|
290
|
+
<div
|
|
291
|
+
data-model-item
|
|
292
|
+
class="px-4 py-3 ${
|
|
293
|
+
this.navigationMode === "mouse" ? "hover:bg-muted" : ""
|
|
294
|
+
} cursor-pointer border-b border-border ${isSelected ? "bg-accent" : ""}"
|
|
295
|
+
@click=${() => this.handleSelect(model)}
|
|
296
|
+
@mouseenter=${() => {
|
|
297
|
+
// Only update selection in mouse mode
|
|
298
|
+
if (this.navigationMode === "mouse") {
|
|
299
|
+
this.selectedIndex = index;
|
|
300
|
+
}
|
|
301
|
+
}}
|
|
302
|
+
>
|
|
303
|
+
<div class="flex items-center justify-between gap-2 mb-1">
|
|
304
|
+
<div class="flex items-center gap-2 flex-1 min-w-0">
|
|
305
|
+
<span class="text-sm font-medium text-foreground truncate">${id}</span>
|
|
306
|
+
${isCurrent ? html`<span class="text-green-500">✓</span>` : ""}
|
|
307
|
+
</div>
|
|
308
|
+
${Badge(provider, "outline")}
|
|
309
|
+
</div>
|
|
310
|
+
<div class="flex items-center justify-between text-xs text-muted-foreground">
|
|
311
|
+
<div class="flex items-center gap-2">
|
|
312
|
+
<span class="${model.reasoning ? "" : "opacity-30"}">${icon(Brain, "sm")}</span>
|
|
313
|
+
<span class="${model.input.includes("image") ? "" : "opacity-30"}">${icon(ImageIcon, "sm")}</span>
|
|
314
|
+
<span>${this.formatTokens(model.contextWindow)}K/${this.formatTokens(model.maxTokens)}K</span>
|
|
315
|
+
</div>
|
|
316
|
+
<span>${formatModelCost(model.cost)}</span>
|
|
317
|
+
</div>
|
|
318
|
+
</div>
|
|
319
|
+
`;
|
|
320
|
+
})}
|
|
321
|
+
</div>
|
|
322
|
+
`;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Dialog,
|
|
3
|
+
DialogContent,
|
|
4
|
+
DialogHeader,
|
|
5
|
+
html,
|
|
6
|
+
Input,
|
|
7
|
+
i18n,
|
|
8
|
+
Label,
|
|
9
|
+
Switch,
|
|
10
|
+
type TemplateResult,
|
|
11
|
+
} from "@mariozechner/mini-lit";
|
|
12
|
+
import { getProviders } from "@mariozechner/pi-ai";
|
|
13
|
+
import { LitElement } from "lit";
|
|
14
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
15
|
+
import "../components/ProviderKeyInput.js";
|
|
16
|
+
import { getAppStorage } from "../storage/app-storage.js";
|
|
17
|
+
|
|
18
|
+
// Base class for settings tabs
|
|
19
|
+
export abstract class SettingsTab extends LitElement {
|
|
20
|
+
abstract getTabName(): string;
|
|
21
|
+
|
|
22
|
+
protected createRenderRoot() {
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// API Keys Tab
|
|
28
|
+
@customElement("api-keys-tab")
|
|
29
|
+
export class ApiKeysTab extends SettingsTab {
|
|
30
|
+
getTabName(): string {
|
|
31
|
+
return i18n("API Keys");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
render(): TemplateResult {
|
|
35
|
+
const providers = getProviders();
|
|
36
|
+
|
|
37
|
+
return html`
|
|
38
|
+
<div class="flex flex-col gap-6">
|
|
39
|
+
<p class="text-sm text-muted-foreground">
|
|
40
|
+
${i18n("Configure API keys for LLM providers. Keys are stored locally in your browser.")}
|
|
41
|
+
</p>
|
|
42
|
+
${providers.map((provider) => html`<provider-key-input .provider=${provider}></provider-key-input>`)}
|
|
43
|
+
</div>
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Proxy Tab
|
|
49
|
+
@customElement("proxy-tab")
|
|
50
|
+
export class ProxyTab extends SettingsTab {
|
|
51
|
+
@state() private proxyEnabled = false;
|
|
52
|
+
@state() private proxyUrl = "http://localhost:3001";
|
|
53
|
+
|
|
54
|
+
override async connectedCallback() {
|
|
55
|
+
super.connectedCallback();
|
|
56
|
+
// Load proxy settings when tab is connected
|
|
57
|
+
try {
|
|
58
|
+
const storage = getAppStorage();
|
|
59
|
+
const enabled = await storage.settings.get<boolean>("proxy.enabled");
|
|
60
|
+
const url = await storage.settings.get<string>("proxy.url");
|
|
61
|
+
|
|
62
|
+
if (enabled !== null) this.proxyEnabled = enabled;
|
|
63
|
+
if (url !== null) this.proxyUrl = url;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("Failed to load proxy settings:", error);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private async saveProxySettings() {
|
|
70
|
+
try {
|
|
71
|
+
const storage = getAppStorage();
|
|
72
|
+
await storage.settings.set("proxy.enabled", this.proxyEnabled);
|
|
73
|
+
await storage.settings.set("proxy.url", this.proxyUrl);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error("Failed to save proxy settings:", error);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
getTabName(): string {
|
|
80
|
+
return i18n("Proxy");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
render(): TemplateResult {
|
|
84
|
+
return html`
|
|
85
|
+
<div class="flex flex-col gap-4">
|
|
86
|
+
<p class="text-sm text-muted-foreground">
|
|
87
|
+
${i18n("The CORS proxy strips CORS headers from API responses, allowing browser-based apps to make direct calls to LLM providers without CORS restrictions. It forwards requests to providers while removing headers that would otherwise block cross-origin requests.")}
|
|
88
|
+
</p>
|
|
89
|
+
|
|
90
|
+
<div class="flex items-center justify-between">
|
|
91
|
+
<span class="text-sm font-medium text-foreground">${i18n("Use CORS Proxy")}</span>
|
|
92
|
+
${Switch({
|
|
93
|
+
checked: this.proxyEnabled,
|
|
94
|
+
onChange: (checked: boolean) => {
|
|
95
|
+
this.proxyEnabled = checked;
|
|
96
|
+
this.saveProxySettings();
|
|
97
|
+
},
|
|
98
|
+
})}
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<div class="space-y-2">
|
|
102
|
+
${Label({ children: i18n("Proxy URL") })}
|
|
103
|
+
${Input({
|
|
104
|
+
type: "text",
|
|
105
|
+
value: this.proxyUrl,
|
|
106
|
+
disabled: !this.proxyEnabled,
|
|
107
|
+
onInput: (e) => {
|
|
108
|
+
this.proxyUrl = (e.target as HTMLInputElement).value;
|
|
109
|
+
},
|
|
110
|
+
onChange: () => this.saveProxySettings(),
|
|
111
|
+
})}
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@customElement("settings-dialog")
|
|
119
|
+
export class SettingsDialog extends LitElement {
|
|
120
|
+
@property({ type: Array, attribute: false }) tabs: SettingsTab[] = [];
|
|
121
|
+
@state() private isOpen = false;
|
|
122
|
+
@state() private activeTabIndex = 0;
|
|
123
|
+
|
|
124
|
+
protected createRenderRoot() {
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static async open(tabs: SettingsTab[]) {
|
|
129
|
+
const dialog = new SettingsDialog();
|
|
130
|
+
dialog.tabs = tabs;
|
|
131
|
+
dialog.isOpen = true;
|
|
132
|
+
document.body.appendChild(dialog);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private setActiveTab(index: number) {
|
|
136
|
+
this.activeTabIndex = index;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private renderSidebarItem(tab: SettingsTab, index: number): TemplateResult {
|
|
140
|
+
const isActive = this.activeTabIndex === index;
|
|
141
|
+
return html`
|
|
142
|
+
<button
|
|
143
|
+
class="w-full text-left px-4 py-3 rounded-md transition-colors ${
|
|
144
|
+
isActive
|
|
145
|
+
? "bg-secondary text-foreground font-medium"
|
|
146
|
+
: "text-muted-foreground hover:bg-secondary/50 hover:text-foreground"
|
|
147
|
+
}"
|
|
148
|
+
@click=${() => this.setActiveTab(index)}
|
|
149
|
+
>
|
|
150
|
+
${tab.getTabName()}
|
|
151
|
+
</button>
|
|
152
|
+
`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private renderMobileTab(tab: SettingsTab, index: number): TemplateResult {
|
|
156
|
+
const isActive = this.activeTabIndex === index;
|
|
157
|
+
return html`
|
|
158
|
+
<button
|
|
159
|
+
class="px-3 py-2 text-sm font-medium transition-colors ${
|
|
160
|
+
isActive ? "border-b-2 border-primary text-foreground" : "text-muted-foreground hover:text-foreground"
|
|
161
|
+
}"
|
|
162
|
+
@click=${() => this.setActiveTab(index)}
|
|
163
|
+
>
|
|
164
|
+
${tab.getTabName()}
|
|
165
|
+
</button>
|
|
166
|
+
`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
render() {
|
|
170
|
+
if (this.tabs.length === 0) {
|
|
171
|
+
return html``;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return Dialog({
|
|
175
|
+
isOpen: this.isOpen,
|
|
176
|
+
onClose: () => {
|
|
177
|
+
this.isOpen = false;
|
|
178
|
+
this.remove();
|
|
179
|
+
},
|
|
180
|
+
width: "min(1000px, 90vw)",
|
|
181
|
+
height: "min(800px, 90vh)",
|
|
182
|
+
children: html`
|
|
183
|
+
${DialogContent({
|
|
184
|
+
className: "h-full p-6",
|
|
185
|
+
children: html`
|
|
186
|
+
<div class="flex flex-col h-full overflow-hidden">
|
|
187
|
+
<!-- Header -->
|
|
188
|
+
<div class="pb-4 flex-shrink-0">${DialogHeader({ title: i18n("Settings") })}</div>
|
|
189
|
+
|
|
190
|
+
<!-- Mobile Tabs -->
|
|
191
|
+
<div class="md:hidden flex flex-shrink-0 pb-4">
|
|
192
|
+
${this.tabs.map((tab, index) => this.renderMobileTab(tab, index))}
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<!-- Layout -->
|
|
196
|
+
<div class="flex flex-1 overflow-hidden">
|
|
197
|
+
<!-- Sidebar (desktop only) -->
|
|
198
|
+
<div class="hidden md:block w-64 flex-shrink-0 space-y-1">
|
|
199
|
+
${this.tabs.map((tab, index) => this.renderSidebarItem(tab, index))}
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
<!-- Content -->
|
|
203
|
+
<div class="flex-1 overflow-y-auto md:pl-6">
|
|
204
|
+
${this.tabs.map(
|
|
205
|
+
(tab, index) =>
|
|
206
|
+
html`<div style="display: ${this.activeTabIndex === index ? "block" : "none"}">${tab}</div>`,
|
|
207
|
+
)}
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
<!-- Footer -->
|
|
212
|
+
<div class="pt-4 flex-shrink-0">
|
|
213
|
+
<p class="text-xs text-muted-foreground text-center">
|
|
214
|
+
${i18n("Settings are stored locally in your browser")}
|
|
215
|
+
</p>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
`,
|
|
219
|
+
})}
|
|
220
|
+
`,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Main chat interface
|
|
2
|
+
export { ChatPanel } from "./ChatPanel.js";
|
|
3
|
+
|
|
4
|
+
// Components
|
|
5
|
+
export { AgentInterface } from "./components/AgentInterface.js";
|
|
6
|
+
export { AttachmentTile } from "./components/AttachmentTile.js";
|
|
7
|
+
export { ConsoleBlock } from "./components/ConsoleBlock.js";
|
|
8
|
+
export { Input } from "./components/Input.js";
|
|
9
|
+
export { MessageEditor } from "./components/MessageEditor.js";
|
|
10
|
+
export { MessageList } from "./components/MessageList.js";
|
|
11
|
+
// Message components
|
|
12
|
+
export { AssistantMessage, ToolMessage, UserMessage } from "./components/Messages.js";
|
|
13
|
+
export {
|
|
14
|
+
type SandboxFile,
|
|
15
|
+
SandboxIframe,
|
|
16
|
+
type SandboxResult,
|
|
17
|
+
type SandboxUrlProvider,
|
|
18
|
+
} from "./components/SandboxedIframe.js";
|
|
19
|
+
export { StreamingMessageContainer } from "./components/StreamingMessageContainer.js";
|
|
20
|
+
export { ApiKeyPromptDialog } from "./dialogs/ApiKeyPromptDialog.js";
|
|
21
|
+
export { AttachmentOverlay } from "./dialogs/AttachmentOverlay.js";
|
|
22
|
+
// Dialogs
|
|
23
|
+
export { ModelSelector } from "./dialogs/ModelSelector.js";
|
|
24
|
+
export { ApiKeysTab, ProxyTab, SettingsDialog, SettingsTab } from "./dialogs/SettingsDialog.js";
|
|
25
|
+
export type { AgentSessionState, ThinkingLevel } from "./state/agent-session.js";
|
|
26
|
+
// State management
|
|
27
|
+
export { AgentSession } from "./state/agent-session.js";
|
|
28
|
+
|
|
29
|
+
// Transports
|
|
30
|
+
export { AppTransport } from "./state/transports/AppTransport.js";
|
|
31
|
+
export { ProviderTransport } from "./state/transports/ProviderTransport.js";
|
|
32
|
+
export type { ProxyAssistantMessageEvent } from "./state/transports/proxy-types.js";
|
|
33
|
+
export type { AgentRunConfig, AgentTransport } from "./state/transports/types.js";
|
|
34
|
+
// Storage
|
|
35
|
+
export { AppStorage, getAppStorage, initAppStorage, setAppStorage } from "./storage/app-storage.js";
|
|
36
|
+
export { ChromeStorageBackend } from "./storage/backends/chrome-storage-backend.js";
|
|
37
|
+
export { IndexedDBBackend } from "./storage/backends/indexeddb-backend.js";
|
|
38
|
+
export { LocalStorageBackend } from "./storage/backends/local-storage-backend.js";
|
|
39
|
+
export { ProviderKeysRepository } from "./storage/repositories/provider-keys-repository.js";
|
|
40
|
+
export { SettingsRepository } from "./storage/repositories/settings-repository.js";
|
|
41
|
+
export type { AppStorageConfig, StorageBackend } from "./storage/types.js";
|
|
42
|
+
// Artifacts
|
|
43
|
+
export { ArtifactElement } from "./tools/artifacts/ArtifactElement.js";
|
|
44
|
+
export { type Artifact, ArtifactsPanel, type ArtifactsParams } from "./tools/artifacts/artifacts.js";
|
|
45
|
+
export { HtmlArtifact } from "./tools/artifacts/HtmlArtifact.js";
|
|
46
|
+
export { MarkdownArtifact } from "./tools/artifacts/MarkdownArtifact.js";
|
|
47
|
+
export { SvgArtifact } from "./tools/artifacts/SvgArtifact.js";
|
|
48
|
+
export { TextArtifact } from "./tools/artifacts/TextArtifact.js";
|
|
49
|
+
// Tools
|
|
50
|
+
export { getToolRenderer, registerToolRenderer, renderToolParams, renderToolResult } from "./tools/index.js";
|
|
51
|
+
export { createJavaScriptReplTool, javascriptReplTool } from "./tools/javascript-repl.js";
|
|
52
|
+
export { BashRenderer } from "./tools/renderers/BashRenderer.js";
|
|
53
|
+
export { CalculateRenderer } from "./tools/renderers/CalculateRenderer.js";
|
|
54
|
+
// Tool renderers
|
|
55
|
+
export { DefaultRenderer } from "./tools/renderers/DefaultRenderer.js";
|
|
56
|
+
export { GetCurrentTimeRenderer } from "./tools/renderers/GetCurrentTimeRenderer.js";
|
|
57
|
+
export type { ToolRenderer } from "./tools/types.js";
|
|
58
|
+
export type { Attachment } from "./utils/attachment-utils.js";
|
|
59
|
+
// Utils
|
|
60
|
+
export { loadAttachment } from "./utils/attachment-utils.js";
|
|
61
|
+
export { clearAuthToken, getAuthToken } from "./utils/auth-token.js";
|
|
62
|
+
export { formatCost, formatModelCost, formatTokenCount, formatUsage } from "./utils/format.js";
|
|
63
|
+
export { i18n, setLanguage } from "./utils/i18n.js";
|