@mariozechner/pi-web-ui 0.5.48 → 0.7.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.
Files changed (222) hide show
  1. package/dist/ChatPanel.d.ts +1 -0
  2. package/dist/ChatPanel.d.ts.map +1 -1
  3. package/dist/ChatPanel.js +3 -2
  4. package/dist/ChatPanel.js.map +1 -1
  5. package/dist/agent/transports/ProviderTransport.d.ts +1 -1
  6. package/dist/agent/transports/ProviderTransport.d.ts.map +1 -1
  7. package/dist/agent/transports/ProviderTransport.js +5 -10
  8. package/dist/agent/transports/ProviderTransport.js.map +1 -1
  9. package/dist/app.css +4188 -2
  10. package/dist/components/AgentInterface.d.ts +1 -0
  11. package/dist/components/AgentInterface.d.ts.map +1 -1
  12. package/dist/components/AgentInterface.js +13 -3
  13. package/dist/components/AgentInterface.js.map +1 -1
  14. package/dist/components/AttachmentTile.d.ts.map +1 -1
  15. package/dist/components/AttachmentTile.js +2 -1
  16. package/dist/components/AttachmentTile.js.map +1 -1
  17. package/dist/components/ConsoleBlock.d.ts.map +1 -1
  18. package/dist/components/ConsoleBlock.js +2 -1
  19. package/dist/components/ConsoleBlock.js.map +1 -1
  20. package/dist/components/CustomProviderCard.d.ts +17 -0
  21. package/dist/components/CustomProviderCard.d.ts.map +1 -0
  22. package/dist/components/CustomProviderCard.js +110 -0
  23. package/dist/components/CustomProviderCard.js.map +1 -0
  24. package/dist/components/Input.d.ts +2 -2
  25. package/dist/components/Input.d.ts.map +1 -1
  26. package/dist/components/Input.js +2 -1
  27. package/dist/components/Input.js.map +1 -1
  28. package/dist/components/MessageEditor.d.ts +1 -3
  29. package/dist/components/MessageEditor.d.ts.map +1 -1
  30. package/dist/components/MessageEditor.js +6 -31
  31. package/dist/components/MessageEditor.js.map +1 -1
  32. package/dist/components/MessageList.d.ts +1 -0
  33. package/dist/components/MessageList.d.ts.map +1 -1
  34. package/dist/components/MessageList.js +6 -3
  35. package/dist/components/MessageList.js.map +1 -1
  36. package/dist/components/Messages.d.ts +2 -0
  37. package/dist/components/Messages.d.ts.map +1 -1
  38. package/dist/components/Messages.js +25 -14
  39. package/dist/components/Messages.js.map +1 -1
  40. package/dist/components/ProviderKeyInput.d.ts +1 -1
  41. package/dist/components/ProviderKeyInput.d.ts.map +1 -1
  42. package/dist/components/ProviderKeyInput.js +22 -36
  43. package/dist/components/ProviderKeyInput.js.map +1 -1
  44. package/dist/components/StreamingMessageContainer.d.ts +1 -0
  45. package/dist/components/StreamingMessageContainer.d.ts.map +1 -1
  46. package/dist/components/StreamingMessageContainer.js +5 -2
  47. package/dist/components/StreamingMessageContainer.js.map +1 -1
  48. package/dist/components/ThinkingBlock.d.ts +11 -0
  49. package/dist/components/ThinkingBlock.d.ts.map +1 -0
  50. package/dist/components/ThinkingBlock.js +58 -0
  51. package/dist/components/ThinkingBlock.js.map +1 -0
  52. package/dist/dialogs/ApiKeyPromptDialog.d.ts +1 -1
  53. package/dist/dialogs/ApiKeyPromptDialog.d.ts.map +1 -1
  54. package/dist/dialogs/ApiKeyPromptDialog.js +3 -1
  55. package/dist/dialogs/ApiKeyPromptDialog.js.map +1 -1
  56. package/dist/dialogs/AttachmentOverlay.d.ts.map +1 -1
  57. package/dist/dialogs/AttachmentOverlay.js +3 -2
  58. package/dist/dialogs/AttachmentOverlay.js.map +1 -1
  59. package/dist/dialogs/CustomProviderDialog.d.ts +25 -0
  60. package/dist/dialogs/CustomProviderDialog.d.ts.map +1 -0
  61. package/dist/dialogs/CustomProviderDialog.js +270 -0
  62. package/dist/dialogs/CustomProviderDialog.js.map +1 -0
  63. package/dist/dialogs/ModelSelector.d.ts +6 -6
  64. package/dist/dialogs/ModelSelector.d.ts.map +1 -1
  65. package/dist/dialogs/ModelSelector.js +60 -74
  66. package/dist/dialogs/ModelSelector.js.map +1 -1
  67. package/dist/dialogs/PersistentStorageDialog.d.ts +1 -1
  68. package/dist/dialogs/PersistentStorageDialog.d.ts.map +1 -1
  69. package/dist/dialogs/PersistentStorageDialog.js +4 -1
  70. package/dist/dialogs/PersistentStorageDialog.js.map +1 -1
  71. package/dist/dialogs/ProvidersModelsTab.d.ts +20 -0
  72. package/dist/dialogs/ProvidersModelsTab.d.ts.map +1 -0
  73. package/dist/dialogs/ProvidersModelsTab.js +191 -0
  74. package/dist/dialogs/ProvidersModelsTab.js.map +1 -0
  75. package/dist/dialogs/SessionListDialog.d.ts +1 -1
  76. package/dist/dialogs/SessionListDialog.d.ts.map +1 -1
  77. package/dist/dialogs/SessionListDialog.js +3 -1
  78. package/dist/dialogs/SessionListDialog.js.map +1 -1
  79. package/dist/dialogs/SettingsDialog.d.ts +1 -2
  80. package/dist/dialogs/SettingsDialog.d.ts.map +1 -1
  81. package/dist/dialogs/SettingsDialog.js +10 -3
  82. package/dist/dialogs/SettingsDialog.js.map +1 -1
  83. package/dist/index.d.ts +4 -0
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +3 -0
  86. package/dist/index.js.map +1 -1
  87. package/dist/storage/app-storage.d.ts +3 -1
  88. package/dist/storage/app-storage.d.ts.map +1 -1
  89. package/dist/storage/app-storage.js +2 -1
  90. package/dist/storage/app-storage.js.map +1 -1
  91. package/dist/storage/stores/custom-providers-store.d.ts +25 -0
  92. package/dist/storage/stores/custom-providers-store.d.ts.map +1 -0
  93. package/dist/storage/stores/custom-providers-store.js +35 -0
  94. package/dist/storage/stores/custom-providers-store.js.map +1 -0
  95. package/dist/storage/stores/sessions-store.d.ts.map +1 -1
  96. package/dist/storage/stores/sessions-store.js +0 -1
  97. package/dist/storage/stores/sessions-store.js.map +1 -1
  98. package/dist/storage/types.d.ts +0 -2
  99. package/dist/storage/types.d.ts.map +1 -1
  100. package/dist/tools/artifacts/ArtifactPill.d.ts +1 -1
  101. package/dist/tools/artifacts/ArtifactPill.d.ts.map +1 -1
  102. package/dist/tools/artifacts/ArtifactPill.js +2 -1
  103. package/dist/tools/artifacts/ArtifactPill.js.map +1 -1
  104. package/dist/tools/artifacts/DocxArtifact.js +1 -1
  105. package/dist/tools/artifacts/DocxArtifact.js.map +1 -1
  106. package/dist/tools/artifacts/ExcelArtifact.js +1 -1
  107. package/dist/tools/artifacts/ExcelArtifact.js.map +1 -1
  108. package/dist/tools/artifacts/GenericArtifact.js +1 -1
  109. package/dist/tools/artifacts/GenericArtifact.js.map +1 -1
  110. package/dist/tools/artifacts/HtmlArtifact.d.ts.map +1 -1
  111. package/dist/tools/artifacts/HtmlArtifact.js +5 -1
  112. package/dist/tools/artifacts/HtmlArtifact.js.map +1 -1
  113. package/dist/tools/artifacts/ImageArtifact.js +1 -1
  114. package/dist/tools/artifacts/ImageArtifact.js.map +1 -1
  115. package/dist/tools/artifacts/MarkdownArtifact.d.ts.map +1 -1
  116. package/dist/tools/artifacts/MarkdownArtifact.js +3 -1
  117. package/dist/tools/artifacts/MarkdownArtifact.js.map +1 -1
  118. package/dist/tools/artifacts/PdfArtifact.js +1 -1
  119. package/dist/tools/artifacts/PdfArtifact.js.map +1 -1
  120. package/dist/tools/artifacts/SvgArtifact.d.ts.map +1 -1
  121. package/dist/tools/artifacts/SvgArtifact.js +3 -1
  122. package/dist/tools/artifacts/SvgArtifact.js.map +1 -1
  123. package/dist/tools/artifacts/TextArtifact.d.ts.map +1 -1
  124. package/dist/tools/artifacts/TextArtifact.js +2 -1
  125. package/dist/tools/artifacts/TextArtifact.js.map +1 -1
  126. package/dist/tools/artifacts/artifacts-tool-renderer.d.ts.map +1 -1
  127. package/dist/tools/artifacts/artifacts-tool-renderer.js +18 -8
  128. package/dist/tools/artifacts/artifacts-tool-renderer.js.map +1 -1
  129. package/dist/tools/artifacts/artifacts.d.ts.map +1 -1
  130. package/dist/tools/artifacts/artifacts.js +3 -2
  131. package/dist/tools/artifacts/artifacts.js.map +1 -1
  132. package/dist/tools/extract-document.d.ts.map +1 -1
  133. package/dist/tools/extract-document.js +78 -58
  134. package/dist/tools/extract-document.js.map +1 -1
  135. package/dist/tools/javascript-repl.d.ts.map +1 -1
  136. package/dist/tools/javascript-repl.js +7 -3
  137. package/dist/tools/javascript-repl.js.map +1 -1
  138. package/dist/tools/renderer-registry.d.ts +1 -1
  139. package/dist/tools/renderer-registry.d.ts.map +1 -1
  140. package/dist/tools/renderer-registry.js +20 -6
  141. package/dist/tools/renderer-registry.js.map +1 -1
  142. package/dist/tools/renderers/BashRenderer.d.ts.map +1 -1
  143. package/dist/tools/renderers/BashRenderer.js +5 -2
  144. package/dist/tools/renderers/BashRenderer.js.map +1 -1
  145. package/dist/tools/renderers/CalculateRenderer.d.ts.map +1 -1
  146. package/dist/tools/renderers/CalculateRenderer.js +5 -2
  147. package/dist/tools/renderers/CalculateRenderer.js.map +1 -1
  148. package/dist/tools/renderers/DefaultRenderer.d.ts.map +1 -1
  149. package/dist/tools/renderers/DefaultRenderer.js +5 -2
  150. package/dist/tools/renderers/DefaultRenderer.js.map +1 -1
  151. package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts.map +1 -1
  152. package/dist/tools/renderers/GetCurrentTimeRenderer.js +9 -3
  153. package/dist/tools/renderers/GetCurrentTimeRenderer.js.map +1 -1
  154. package/dist/utils/auth-token.js +1 -1
  155. package/dist/utils/auth-token.js.map +1 -1
  156. package/dist/utils/i18n.d.ts +105 -3
  157. package/dist/utils/i18n.d.ts.map +1 -1
  158. package/dist/utils/i18n.js +72 -2
  159. package/dist/utils/i18n.js.map +1 -1
  160. package/dist/utils/model-discovery.d.ts +38 -0
  161. package/dist/utils/model-discovery.d.ts.map +1 -0
  162. package/dist/utils/model-discovery.js +243 -0
  163. package/dist/utils/model-discovery.js.map +1 -0
  164. package/dist/utils/proxy-utils.d.ts +37 -0
  165. package/dist/utils/proxy-utils.d.ts.map +1 -0
  166. package/dist/utils/proxy-utils.js +97 -0
  167. package/dist/utils/proxy-utils.js.map +1 -0
  168. package/example/package.json +2 -2
  169. package/example/src/custom-messages.ts +1 -1
  170. package/example/src/main.ts +17 -6
  171. package/package.json +9 -8
  172. package/src/ChatPanel.ts +4 -2
  173. package/src/agent/transports/ProviderTransport.ts +5 -10
  174. package/src/app.css +24 -0
  175. package/src/components/AgentInterface.ts +14 -3
  176. package/src/components/AttachmentTile.ts +2 -1
  177. package/src/components/ConsoleBlock.ts +2 -1
  178. package/src/components/CustomProviderCard.ts +100 -0
  179. package/src/components/Input.ts +2 -1
  180. package/src/components/MessageEditor.ts +6 -33
  181. package/src/components/MessageList.ts +4 -3
  182. package/src/components/Messages.ts +32 -20
  183. package/src/components/ProviderKeyInput.ts +19 -38
  184. package/src/components/StreamingMessageContainer.ts +3 -2
  185. package/src/components/ThinkingBlock.ts +43 -0
  186. package/src/dialogs/ApiKeyPromptDialog.ts +3 -1
  187. package/src/dialogs/AttachmentOverlay.ts +3 -2
  188. package/src/dialogs/CustomProviderDialog.ts +274 -0
  189. package/src/dialogs/ModelSelector.ts +61 -75
  190. package/src/dialogs/PersistentStorageDialog.ts +4 -1
  191. package/src/dialogs/ProvidersModelsTab.ts +212 -0
  192. package/src/dialogs/SessionListDialog.ts +3 -1
  193. package/src/dialogs/SettingsDialog.ts +10 -13
  194. package/src/index.ts +8 -0
  195. package/src/storage/app-storage.ts +4 -0
  196. package/src/storage/stores/custom-providers-store.ts +62 -0
  197. package/src/storage/stores/sessions-store.ts +0 -1
  198. package/src/storage/types.ts +0 -3
  199. package/src/tools/artifacts/ArtifactPill.ts +2 -1
  200. package/src/tools/artifacts/DocxArtifact.ts +1 -1
  201. package/src/tools/artifacts/ExcelArtifact.ts +1 -1
  202. package/src/tools/artifacts/GenericArtifact.ts +1 -1
  203. package/src/tools/artifacts/HtmlArtifact.ts +5 -1
  204. package/src/tools/artifacts/ImageArtifact.ts +1 -1
  205. package/src/tools/artifacts/MarkdownArtifact.ts +3 -1
  206. package/src/tools/artifacts/PdfArtifact.ts +1 -1
  207. package/src/tools/artifacts/SvgArtifact.ts +3 -1
  208. package/src/tools/artifacts/TextArtifact.ts +2 -1
  209. package/src/tools/artifacts/artifacts-tool-renderer.ts +20 -8
  210. package/src/tools/artifacts/artifacts.ts +3 -2
  211. package/src/tools/extract-document.ts +82 -61
  212. package/src/tools/javascript-repl.ts +8 -3
  213. package/src/tools/renderer-registry.ts +20 -6
  214. package/src/tools/renderers/BashRenderer.ts +6 -2
  215. package/src/tools/renderers/CalculateRenderer.ts +6 -2
  216. package/src/tools/renderers/DefaultRenderer.ts +6 -2
  217. package/src/tools/renderers/GetCurrentTimeRenderer.ts +11 -3
  218. package/src/utils/auth-token.ts +1 -1
  219. package/src/utils/i18n.ts +120 -5
  220. package/src/utils/model-discovery.ts +277 -0
  221. package/src/utils/proxy-utils.ts +112 -0
  222. package/example/package-lock.json +0 -1965
@@ -0,0 +1,243 @@
1
+ import { LMStudioClient } from "@lmstudio/sdk";
2
+ import { Ollama } from "ollama/browser";
3
+ /**
4
+ * Discover models from an Ollama server.
5
+ * @param baseUrl - Base URL of the Ollama server (e.g., "http://localhost:11434")
6
+ * @param apiKey - Optional API key (currently unused by Ollama)
7
+ * @returns Array of discovered models
8
+ */
9
+ export async function discoverOllamaModels(baseUrl, _apiKey) {
10
+ try {
11
+ // Create Ollama client
12
+ const ollama = new Ollama({ host: baseUrl });
13
+ // Get list of available models
14
+ const { models } = await ollama.list();
15
+ // Fetch details for each model and convert to Model format
16
+ const ollamaModelPromises = models.map(async (model) => {
17
+ try {
18
+ // Get model details
19
+ const details = await ollama.show({
20
+ model: model.name,
21
+ });
22
+ // Check capabilities - filter out models that don't support tools
23
+ const capabilities = details.capabilities || [];
24
+ if (!capabilities.includes("tools")) {
25
+ console.debug(`Skipping model ${model.name}: does not support tools`);
26
+ return null;
27
+ }
28
+ // Extract model info
29
+ const modelInfo = details.model_info || {};
30
+ // Get context window size - look for architecture-specific keys
31
+ const architecture = modelInfo["general.architecture"] || "";
32
+ const contextKey = `${architecture}.context_length`;
33
+ const contextWindow = parseInt(modelInfo[contextKey] || "8192", 10);
34
+ // Ollama caps max tokens at 10x context length
35
+ const maxTokens = contextWindow * 10;
36
+ // Ollama only supports completions API
37
+ const ollamaModel = {
38
+ id: model.name,
39
+ name: model.name,
40
+ api: "openai-completions",
41
+ provider: "", // Will be set by caller
42
+ baseUrl: `${baseUrl}/v1`,
43
+ reasoning: capabilities.includes("thinking"),
44
+ input: ["text"],
45
+ cost: {
46
+ input: 0,
47
+ output: 0,
48
+ cacheRead: 0,
49
+ cacheWrite: 0,
50
+ },
51
+ contextWindow: contextWindow,
52
+ maxTokens: maxTokens,
53
+ };
54
+ return ollamaModel;
55
+ }
56
+ catch (err) {
57
+ console.error(`Failed to fetch details for model ${model.name}:`, err);
58
+ return null;
59
+ }
60
+ });
61
+ const results = await Promise.all(ollamaModelPromises);
62
+ return results.filter((m) => m !== null);
63
+ }
64
+ catch (err) {
65
+ console.error("Failed to discover Ollama models:", err);
66
+ throw new Error(`Ollama discovery failed: ${err instanceof Error ? err.message : String(err)}`);
67
+ }
68
+ }
69
+ /**
70
+ * Discover models from a llama.cpp server via OpenAI-compatible /v1/models endpoint.
71
+ * @param baseUrl - Base URL of the llama.cpp server (e.g., "http://localhost:8080")
72
+ * @param apiKey - Optional API key
73
+ * @returns Array of discovered models
74
+ */
75
+ export async function discoverLlamaCppModels(baseUrl, apiKey) {
76
+ try {
77
+ const headers = {
78
+ "Content-Type": "application/json",
79
+ };
80
+ if (apiKey) {
81
+ headers.Authorization = `Bearer ${apiKey}`;
82
+ }
83
+ const response = await fetch(`${baseUrl}/v1/models`, {
84
+ method: "GET",
85
+ headers,
86
+ });
87
+ if (!response.ok) {
88
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
89
+ }
90
+ const data = await response.json();
91
+ if (!data.data || !Array.isArray(data.data)) {
92
+ throw new Error("Invalid response format from llama.cpp server");
93
+ }
94
+ return data.data.map((model) => {
95
+ // llama.cpp doesn't always provide context window info
96
+ const contextWindow = model.context_length || 8192;
97
+ const maxTokens = model.max_tokens || 4096;
98
+ const llamaModel = {
99
+ id: model.id,
100
+ name: model.id,
101
+ api: "openai-completions",
102
+ provider: "", // Will be set by caller
103
+ baseUrl: `${baseUrl}/v1`,
104
+ reasoning: false,
105
+ input: ["text"],
106
+ cost: {
107
+ input: 0,
108
+ output: 0,
109
+ cacheRead: 0,
110
+ cacheWrite: 0,
111
+ },
112
+ contextWindow: contextWindow,
113
+ maxTokens: maxTokens,
114
+ };
115
+ return llamaModel;
116
+ });
117
+ }
118
+ catch (err) {
119
+ console.error("Failed to discover llama.cpp models:", err);
120
+ throw new Error(`llama.cpp discovery failed: ${err instanceof Error ? err.message : String(err)}`);
121
+ }
122
+ }
123
+ /**
124
+ * Discover models from a vLLM server via OpenAI-compatible /v1/models endpoint.
125
+ * @param baseUrl - Base URL of the vLLM server (e.g., "http://localhost:8000")
126
+ * @param apiKey - Optional API key
127
+ * @returns Array of discovered models
128
+ */
129
+ export async function discoverVLLMModels(baseUrl, apiKey) {
130
+ try {
131
+ const headers = {
132
+ "Content-Type": "application/json",
133
+ };
134
+ if (apiKey) {
135
+ headers.Authorization = `Bearer ${apiKey}`;
136
+ }
137
+ const response = await fetch(`${baseUrl}/v1/models`, {
138
+ method: "GET",
139
+ headers,
140
+ });
141
+ if (!response.ok) {
142
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
143
+ }
144
+ const data = await response.json();
145
+ if (!data.data || !Array.isArray(data.data)) {
146
+ throw new Error("Invalid response format from vLLM server");
147
+ }
148
+ return data.data.map((model) => {
149
+ // vLLM provides max_model_len which is the context window
150
+ const contextWindow = model.max_model_len || 8192;
151
+ const maxTokens = Math.min(contextWindow, 4096); // Cap max tokens
152
+ const vllmModel = {
153
+ id: model.id,
154
+ name: model.id,
155
+ api: "openai-completions",
156
+ provider: "", // Will be set by caller
157
+ baseUrl: `${baseUrl}/v1`,
158
+ reasoning: false,
159
+ input: ["text"],
160
+ cost: {
161
+ input: 0,
162
+ output: 0,
163
+ cacheRead: 0,
164
+ cacheWrite: 0,
165
+ },
166
+ contextWindow: contextWindow,
167
+ maxTokens: maxTokens,
168
+ };
169
+ return vllmModel;
170
+ });
171
+ }
172
+ catch (err) {
173
+ console.error("Failed to discover vLLM models:", err);
174
+ throw new Error(`vLLM discovery failed: ${err instanceof Error ? err.message : String(err)}`);
175
+ }
176
+ }
177
+ /**
178
+ * Discover models from an LM Studio server using the LM Studio SDK.
179
+ * @param baseUrl - Base URL of the LM Studio server (e.g., "http://localhost:1234")
180
+ * @param apiKey - Optional API key (unused for LM Studio SDK)
181
+ * @returns Array of discovered models
182
+ */
183
+ export async function discoverLMStudioModels(baseUrl, _apiKey) {
184
+ try {
185
+ // Extract host and port from baseUrl
186
+ const url = new URL(baseUrl);
187
+ const port = url.port ? parseInt(url.port, 10) : 1234;
188
+ // Create LM Studio client
189
+ const client = new LMStudioClient({ baseUrl: `ws://${url.hostname}:${port}` });
190
+ // List all downloaded models
191
+ const models = await client.system.listDownloadedModels();
192
+ // Filter to only LLM models and map to our Model format
193
+ return models
194
+ .filter((model) => model.type === "llm")
195
+ .map((model) => {
196
+ const contextWindow = model.maxContextLength;
197
+ // Use 10x context length like Ollama does
198
+ const maxTokens = contextWindow;
199
+ const lmStudioModel = {
200
+ id: model.path,
201
+ name: model.displayName || model.path,
202
+ api: "openai-completions",
203
+ provider: "", // Will be set by caller
204
+ baseUrl: `${baseUrl}/v1`,
205
+ reasoning: model.trainedForToolUse || false,
206
+ input: model.vision ? ["text", "image"] : ["text"],
207
+ cost: {
208
+ input: 0,
209
+ output: 0,
210
+ cacheRead: 0,
211
+ cacheWrite: 0,
212
+ },
213
+ contextWindow: contextWindow,
214
+ maxTokens: maxTokens,
215
+ };
216
+ return lmStudioModel;
217
+ });
218
+ }
219
+ catch (err) {
220
+ console.error("Failed to discover LM Studio models:", err);
221
+ throw new Error(`LM Studio discovery failed: ${err instanceof Error ? err.message : String(err)}`);
222
+ }
223
+ }
224
+ /**
225
+ * Convenience function to discover models based on provider type.
226
+ * @param type - Provider type
227
+ * @param baseUrl - Base URL of the server
228
+ * @param apiKey - Optional API key
229
+ * @returns Array of discovered models
230
+ */
231
+ export async function discoverModels(type, baseUrl, apiKey) {
232
+ switch (type) {
233
+ case "ollama":
234
+ return discoverOllamaModels(baseUrl, apiKey);
235
+ case "llama.cpp":
236
+ return discoverLlamaCppModels(baseUrl, apiKey);
237
+ case "vllm":
238
+ return discoverVLLMModels(baseUrl, apiKey);
239
+ case "lmstudio":
240
+ return discoverLMStudioModels(baseUrl, apiKey);
241
+ }
242
+ }
243
+ //# sourceMappingURL=model-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-discovery.js","sourceRoot":"","sources":["../../src/utils/model-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { Api, Model } from "@mariozechner/pi-ai";
2
+ /**
3
+ * Centralized proxy decision logic.
4
+ *
5
+ * Determines whether to use a CORS proxy for LLM API requests based on:
6
+ * - Provider name
7
+ * - API key pattern (for providers where it matters)
8
+ */
9
+ /**
10
+ * Check if a provider/API key combination requires a CORS proxy.
11
+ *
12
+ * @param provider - Provider name (e.g., "anthropic", "openai", "zai")
13
+ * @param apiKey - API key for the provider
14
+ * @returns true if proxy is required, false otherwise
15
+ */
16
+ export declare function shouldUseProxyForProvider(provider: string, apiKey: string): boolean;
17
+ /**
18
+ * Apply CORS proxy to a model's baseUrl if needed.
19
+ *
20
+ * @param model - The model to potentially proxy
21
+ * @param apiKey - API key for the provider
22
+ * @param proxyUrl - CORS proxy URL (e.g., "https://proxy.mariozechner.at/proxy")
23
+ * @returns Model with modified baseUrl if proxy is needed, otherwise original model
24
+ */
25
+ export declare function applyProxyIfNeeded<T extends Api>(model: Model<T>, apiKey: string, proxyUrl?: string): Model<T>;
26
+ /**
27
+ * Check if an error is likely a CORS error.
28
+ *
29
+ * CORS errors in browsers typically manifest as:
30
+ * - TypeError with message "Failed to fetch"
31
+ * - NetworkError
32
+ *
33
+ * @param error - The error to check
34
+ * @returns true if error is likely a CORS error
35
+ */
36
+ export declare function isCorsError(error: unknown): boolean;
37
+ //# sourceMappingURL=proxy-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-utils.d.ts","sourceRoot":"","sources":["../../src/utils/proxy-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;;;;;GAMG;AAEH;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CA2BnF;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAqB9G;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAwBnD"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Centralized proxy decision logic.
3
+ *
4
+ * Determines whether to use a CORS proxy for LLM API requests based on:
5
+ * - Provider name
6
+ * - API key pattern (for providers where it matters)
7
+ */
8
+ /**
9
+ * Check if a provider/API key combination requires a CORS proxy.
10
+ *
11
+ * @param provider - Provider name (e.g., "anthropic", "openai", "zai")
12
+ * @param apiKey - API key for the provider
13
+ * @returns true if proxy is required, false otherwise
14
+ */
15
+ export function shouldUseProxyForProvider(provider, apiKey) {
16
+ switch (provider.toLowerCase()) {
17
+ case "zai":
18
+ // Z-AI always requires proxy
19
+ return true;
20
+ case "anthropic":
21
+ // Anthropic OAuth tokens (sk-ant-oat-*) require proxy
22
+ // Regular API keys (sk-ant-api-*) do NOT require proxy
23
+ return apiKey.startsWith("sk-ant-oat");
24
+ // These providers work without proxy
25
+ case "openai":
26
+ case "google":
27
+ case "groq":
28
+ case "openrouter":
29
+ case "cerebras":
30
+ case "xai":
31
+ case "ollama":
32
+ case "lmstudio":
33
+ return false;
34
+ // Unknown providers - assume no proxy needed
35
+ // This allows new providers to work by default
36
+ default:
37
+ return false;
38
+ }
39
+ }
40
+ /**
41
+ * Apply CORS proxy to a model's baseUrl if needed.
42
+ *
43
+ * @param model - The model to potentially proxy
44
+ * @param apiKey - API key for the provider
45
+ * @param proxyUrl - CORS proxy URL (e.g., "https://proxy.mariozechner.at/proxy")
46
+ * @returns Model with modified baseUrl if proxy is needed, otherwise original model
47
+ */
48
+ export function applyProxyIfNeeded(model, apiKey, proxyUrl) {
49
+ // If no proxy URL configured, return original model
50
+ if (!proxyUrl) {
51
+ return model;
52
+ }
53
+ // If model has no baseUrl, can't proxy it
54
+ if (!model.baseUrl) {
55
+ return model;
56
+ }
57
+ // Check if this provider/key needs proxy
58
+ if (!shouldUseProxyForProvider(model.provider, apiKey)) {
59
+ return model;
60
+ }
61
+ // Apply proxy to baseUrl
62
+ return {
63
+ ...model,
64
+ baseUrl: `${proxyUrl}/?url=${encodeURIComponent(model.baseUrl)}`,
65
+ };
66
+ }
67
+ /**
68
+ * Check if an error is likely a CORS error.
69
+ *
70
+ * CORS errors in browsers typically manifest as:
71
+ * - TypeError with message "Failed to fetch"
72
+ * - NetworkError
73
+ *
74
+ * @param error - The error to check
75
+ * @returns true if error is likely a CORS error
76
+ */
77
+ export function isCorsError(error) {
78
+ if (!(error instanceof Error)) {
79
+ return false;
80
+ }
81
+ // Check for common CORS error patterns
82
+ const message = error.message.toLowerCase();
83
+ // "Failed to fetch" is the standard CORS error in most browsers
84
+ if (error.name === "TypeError" && message.includes("failed to fetch")) {
85
+ return true;
86
+ }
87
+ // Some browsers report "NetworkError"
88
+ if (error.name === "NetworkError") {
89
+ return true;
90
+ }
91
+ // CORS-specific messages
92
+ if (message.includes("cors") || message.includes("cross-origin")) {
93
+ return true;
94
+ }
95
+ return false;
96
+ }
97
+ //# sourceMappingURL=proxy-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-utils.js","sourceRoot":"","sources":["../../src/utils/proxy-utils.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAgB,EAAE,MAAc;IACzE,QAAQ,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QAChC,KAAK,KAAK;YACT,6BAA6B;YAC7B,OAAO,IAAI,CAAC;QAEb,KAAK,WAAW;YACf,sDAAsD;YACtD,uDAAuD;YACvD,OAAO,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAExC,qCAAqC;QACrC,KAAK,QAAQ,CAAC;QACd,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM,CAAC;QACZ,KAAK,YAAY,CAAC;QAClB,KAAK,UAAU,CAAC;QAChB,KAAK,KAAK,CAAC;QACX,KAAK,QAAQ,CAAC;QACd,KAAK,UAAU;YACd,OAAO,KAAK,CAAC;QAEd,6CAA6C;QAC7C,+CAA+C;QAC/C;YACC,OAAO,KAAK,CAAC;IACf,CAAC;AACF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAgB,KAAe,EAAE,MAAc,EAAE,QAAiB;IACnG,oDAAoD;IACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,OAAO,KAAK,CAAC;IACd,CAAC;IAED,0CAA0C;IAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC;IACd,CAAC;IAED,yCAAyC;IACzC,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,yBAAyB;IACzB,OAAO;QACN,GAAG,KAAK;QACR,OAAO,EAAE,GAAG,QAAQ,SAAS,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;KAChE,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACzC,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,uCAAuC;IACvC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IAE5C,gEAAgE;IAChE,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACvE,OAAO,IAAI,CAAC;IACb,CAAC;IAED,sCAAsC;IACtC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,yBAAyB;IACzB,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QAClE,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC"}
@@ -9,10 +9,10 @@
9
9
  "check": "tsc --noEmit"
10
10
  },
11
11
  "dependencies": {
12
- "@mariozechner/mini-lit": "^0.1.7",
12
+ "@mariozechner/mini-lit": "^0.2.0",
13
13
  "@mariozechner/pi-ai": "file:../../ai",
14
14
  "@mariozechner/pi-web-ui": "file:../",
15
- "@tailwindcss/vite": "^4.1.13",
15
+ "@tailwindcss/vite": "^4.1.17",
16
16
  "lit": "^3.3.1",
17
17
  "lucide": "^0.544.0"
18
18
  },
@@ -1,8 +1,8 @@
1
- import { Alert } from "@mariozechner/mini-lit";
2
1
  import type { Message } from "@mariozechner/pi-ai";
3
2
  import { html } from "lit";
4
3
  import { registerMessageRenderer } from "@mariozechner/pi-web-ui";
5
4
  import type { AppMessage, MessageRenderer } from "@mariozechner/pi-web-ui";
5
+ import { Alert } from "@mariozechner/mini-lit/dist/Alert.js";
6
6
 
7
7
  // ============================================================================
8
8
  // 1. EXTEND AppMessage TYPE VIA DECLARATION MERGING
@@ -1,19 +1,19 @@
1
- import { Button, icon, Input } from "@mariozechner/mini-lit";
2
1
  import "@mariozechner/mini-lit/dist/ThemeToggle.js";
3
2
  import { getModel } from "@mariozechner/pi-ai";
4
3
  import {
5
4
  Agent,
6
5
  type AgentState,
7
6
  ApiKeyPromptDialog,
8
- ApiKeysTab,
9
7
  type AppMessage,
10
8
  AppStorage,
11
9
  ChatPanel,
12
10
  createJavaScriptReplTool,
11
+ CustomProvidersStore,
13
12
  IndexedDBStorageBackend,
14
13
  // PersistentStorageDialog, // TODO: Fix - currently broken
15
14
  ProviderKeysStore,
16
15
  ProviderTransport,
16
+ ProvidersModelsTab,
17
17
  ProxyTab,
18
18
  SessionListDialog,
19
19
  SessionsStore,
@@ -25,6 +25,9 @@ import { html, render } from "lit";
25
25
  import { Bell, History, Plus, Settings } from "lucide";
26
26
  import "./app.css";
27
27
  import { createSystemNotification, customMessageTransformer, registerCustomMessageRenderers } from "./custom-messages.js";
28
+ import { Button } from "@mariozechner/mini-lit/dist/Button.js";
29
+ import { icon } from "@mariozechner/mini-lit";
30
+ import { Input } from "@mariozechner/mini-lit/dist/Input.js";
28
31
 
29
32
  // Register custom message renderers
30
33
  registerCustomMessageRenderers();
@@ -33,24 +36,32 @@ registerCustomMessageRenderers();
33
36
  const settings = new SettingsStore();
34
37
  const providerKeys = new ProviderKeysStore();
35
38
  const sessions = new SessionsStore();
39
+ const customProviders = new CustomProvidersStore();
36
40
 
37
41
  // Gather configs
38
- const configs = [settings.getConfig(), SessionsStore.getMetadataConfig(), providerKeys.getConfig(), sessions.getConfig()];
42
+ const configs = [
43
+ settings.getConfig(),
44
+ SessionsStore.getMetadataConfig(),
45
+ providerKeys.getConfig(),
46
+ customProviders.getConfig(),
47
+ sessions.getConfig(),
48
+ ];
39
49
 
40
50
  // Create backend
41
51
  const backend = new IndexedDBStorageBackend({
42
52
  dbName: "pi-web-ui-example",
43
- version: 1,
53
+ version: 2, // Incremented for custom-providers store
44
54
  stores: configs,
45
55
  });
46
56
 
47
57
  // Wire backend to stores
48
58
  settings.setBackend(backend);
49
59
  providerKeys.setBackend(backend);
60
+ customProviders.setBackend(backend);
50
61
  sessions.setBackend(backend);
51
62
 
52
63
  // Create and set app storage
53
- const storage = new AppStorage(settings, providerKeys, sessions, backend);
64
+ const storage = new AppStorage(settings, providerKeys, sessions, customProviders, backend);
54
65
  setAppStorage(storage);
55
66
 
56
67
  let currentSessionId: string | undefined;
@@ -349,7 +360,7 @@ const renderApp = () => {
349
360
  variant: "ghost",
350
361
  size: "sm",
351
362
  children: icon(Settings, "sm"),
352
- onClick: () => SettingsDialog.open([new ApiKeysTab(), new ProxyTab()]),
363
+ onClick: () => SettingsDialog.open([new ProvidersModelsTab(), new ProxyTab()]),
353
364
  title: "Settings",
354
365
  })}
355
366
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mariozechner/pi-web-ui",
3
- "version": "0.5.48",
3
+ "version": "0.7.1",
4
4
  "description": "Reusable web UI components for AI chat interfaces powered by @mariozechner/pi-ai",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -13,25 +13,26 @@
13
13
  "clean": "rm -rf dist",
14
14
  "build": "tsc -p tsconfig.build.json && tailwindcss -i ./src/app.css -o ./dist/app.css --minify",
15
15
  "dev": "concurrently --names \"build,example\" --prefix-colors \"cyan,green\" \"tsc -p tsconfig.build.json --watch --preserveWatchOutput\" \"tailwindcss -i ./src/app.css -o ./dist/app.css --watch\" \"npm run dev --prefix example\"",
16
- "typecheck": "tsc --noEmit && cd example && tsc --noEmit",
17
- "check": "npm run typecheck"
16
+ "dev:tsc": "concurrently --names \"build\" --prefix-colors \"cyan\" \"tsc -p tsconfig.build.json --watch --preserveWatchOutput\" \"tailwindcss -i ./src/app.css -o ./dist/app.css --watch\"",
17
+ "check": "tsc --noEmit && cd example && tsc --noEmit"
18
18
  },
19
19
  "dependencies": {
20
- "@mariozechner/pi-ai": "^0.5.43",
21
- "@mariozechner/pi-tui": "^0.5.48",
20
+ "@lmstudio/sdk": "^1.5.0",
21
+ "@mariozechner/pi-ai": "^0.6.0",
22
+ "@mariozechner/pi-tui": "^0.7.1",
22
23
  "docx-preview": "^0.3.7",
23
24
  "jszip": "^3.10.1",
24
- "lit": "^3.3.1",
25
25
  "lucide": "^0.544.0",
26
26
  "ollama": "^0.6.0",
27
27
  "pdfjs-dist": "^5.4.296",
28
28
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
29
29
  },
30
30
  "peerDependencies": {
31
- "@mariozechner/mini-lit": "^0.1.10"
31
+ "@mariozechner/mini-lit": "^0.2.0",
32
+ "lit": "^3.3.1"
32
33
  },
33
34
  "devDependencies": {
34
- "@mariozechner/mini-lit": "^0.1.10",
35
+ "@mariozechner/mini-lit": "^0.2.0",
35
36
  "@tailwindcss/cli": "^4.0.0-beta.14",
36
37
  "concurrently": "^9.2.1",
37
38
  "typescript": "^5.7.3"
package/src/ChatPanel.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Badge, html } from "@mariozechner/mini-lit";
2
- import { LitElement } from "lit";
1
+ import { Badge } from "@mariozechner/mini-lit/dist/Badge.js";
2
+ import { html, LitElement } from "lit";
3
3
  import { customElement, state } from "lit/decorators.js";
4
4
  import type { Agent } from "./agent/agent.js";
5
5
  import "./components/AgentInterface.js";
@@ -59,6 +59,7 @@ export class ChatPanel extends LitElement {
59
59
  config?: {
60
60
  onApiKeyRequired?: (provider: string) => Promise<boolean>;
61
61
  onBeforeSend?: () => void | Promise<void>;
62
+ onCostClick?: () => void;
62
63
  sandboxUrlProvider?: () => string;
63
64
  toolsFactory?: (
64
65
  agent: Agent,
@@ -79,6 +80,7 @@ export class ChatPanel extends LitElement {
79
80
  this.agentInterface.showThemeToggle = false;
80
81
  this.agentInterface.onApiKeyRequired = config?.onApiKeyRequired;
81
82
  this.agentInterface.onBeforeSend = config?.onBeforeSend;
83
+ this.agentInterface.onCostClick = config?.onCostClick;
82
84
 
83
85
  // Set up artifacts panel
84
86
  this.artifactsPanel = new ArtifactsPanel();
@@ -6,11 +6,12 @@ import {
6
6
  type UserMessage,
7
7
  } from "@mariozechner/pi-ai";
8
8
  import { getAppStorage } from "../../storage/app-storage.js";
9
+ import { applyProxyIfNeeded } from "../../utils/proxy-utils.js";
9
10
  import type { AgentRunConfig, AgentTransport } from "./types.js";
10
11
 
11
12
  /**
12
13
  * Transport that calls LLM providers directly.
13
- * Optionally routes calls through a CORS proxy if enabled in settings.
14
+ * Uses CORS proxy only for providers that require it (Anthropic OAuth, Z-AI).
14
15
  */
15
16
  export class ProviderTransport implements AgentTransport {
16
17
  async *run(messages: Message[], userMessage: Message, cfg: AgentRunConfig, signal?: AbortSignal) {
@@ -20,18 +21,12 @@ export class ProviderTransport implements AgentTransport {
20
21
  throw new Error("no-api-key");
21
22
  }
22
23
 
23
- // Check if CORS proxy is enabled
24
+ // Get proxy URL from settings (if available)
24
25
  const proxyEnabled = await getAppStorage().settings.get<boolean>("proxy.enabled");
25
26
  const proxyUrl = await getAppStorage().settings.get<string>("proxy.url");
26
27
 
27
- // Clone model and modify baseUrl if proxy is enabled
28
- let model = cfg.model;
29
- if (proxyEnabled && proxyUrl && cfg.model.baseUrl) {
30
- model = {
31
- ...cfg.model,
32
- baseUrl: `${proxyUrl}/?url=${encodeURIComponent(cfg.model.baseUrl)}`,
33
- };
34
- }
28
+ // Apply proxy only if this provider/key combination requires it
29
+ const model = applyProxyIfNeeded(cfg.model, apiKey, proxyEnabled ? proxyUrl || undefined : undefined);
35
30
 
36
31
  // Messages are already LLM-compatible (filtered by Agent)
37
32
  const context: AgentContext = {
package/src/app.css CHANGED
@@ -42,3 +42,27 @@ body {
42
42
  .fixed.inset-0 button[type="button"] {
43
43
  cursor: pointer;
44
44
  }
45
+
46
+ /* Shimmer animation for thinking text */
47
+ @keyframes shimmer {
48
+ 0% {
49
+ background-position: -200% 0;
50
+ }
51
+ 100% {
52
+ background-position: 200% 0;
53
+ }
54
+ }
55
+
56
+ .animate-shimmer {
57
+ animation: shimmer 2s ease-in-out infinite;
58
+ }
59
+
60
+ /* User message with fancy pill styling */
61
+ .user-message-container {
62
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
63
+ position: relative;
64
+ background: linear-gradient(135deg, rgba(217, 79, 0, 0.12), rgba(255, 107, 0, 0.12), rgba(212, 165, 0, 0.12));
65
+ border: 1px solid rgba(255, 107, 0, 0.25);
66
+ backdrop-filter: blur(10px);
67
+ max-width: 100%;
68
+ }