@mariozechner/pi-web-ui 0.30.2 → 0.31.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 (242) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +420 -150
  3. package/dist/ChatPanel.d.ts +1 -2
  4. package/dist/ChatPanel.d.ts.map +1 -1
  5. package/dist/ChatPanel.js +22 -45
  6. package/dist/ChatPanel.js.map +1 -1
  7. package/dist/components/AgentInterface.d.ts +1 -1
  8. package/dist/components/AgentInterface.d.ts.map +1 -1
  9. package/dist/components/AgentInterface.js +113 -91
  10. package/dist/components/AgentInterface.js.map +1 -1
  11. package/dist/components/AttachmentTile.d.ts.map +1 -1
  12. package/dist/components/AttachmentTile.js +12 -28
  13. package/dist/components/AttachmentTile.js.map +1 -1
  14. package/dist/components/ConsoleBlock.d.ts.map +1 -1
  15. package/dist/components/ConsoleBlock.js +6 -21
  16. package/dist/components/ConsoleBlock.js.map +1 -1
  17. package/dist/components/CustomProviderCard.d.ts.map +1 -1
  18. package/dist/components/CustomProviderCard.js +15 -34
  19. package/dist/components/CustomProviderCard.js.map +1 -1
  20. package/dist/components/ExpandableSection.d.ts.map +1 -1
  21. package/dist/components/ExpandableSection.js +10 -27
  22. package/dist/components/ExpandableSection.js.map +1 -1
  23. package/dist/components/Input.js.map +1 -1
  24. package/dist/components/MessageEditor.d.ts +2 -1
  25. package/dist/components/MessageEditor.d.ts.map +1 -1
  26. package/dist/components/MessageEditor.js +147 -190
  27. package/dist/components/MessageEditor.js.map +1 -1
  28. package/dist/components/MessageList.d.ts +2 -3
  29. package/dist/components/MessageList.d.ts.map +1 -1
  30. package/dist/components/MessageList.js +11 -28
  31. package/dist/components/MessageList.js.map +1 -1
  32. package/dist/components/Messages.d.ts +37 -7
  33. package/dist/components/Messages.d.ts.map +1 -1
  34. package/dist/components/Messages.js +127 -103
  35. package/dist/components/Messages.js.map +1 -1
  36. package/dist/components/ProviderKeyInput.d.ts.map +1 -1
  37. package/dist/components/ProviderKeyInput.js +15 -39
  38. package/dist/components/ProviderKeyInput.js.map +1 -1
  39. package/dist/components/SandboxedIframe.d.ts.map +1 -1
  40. package/dist/components/SandboxedIframe.js +11 -15
  41. package/dist/components/SandboxedIframe.js.map +1 -1
  42. package/dist/components/StreamingMessageContainer.d.ts +3 -2
  43. package/dist/components/StreamingMessageContainer.d.ts.map +1 -1
  44. package/dist/components/StreamingMessageContainer.js +16 -34
  45. package/dist/components/StreamingMessageContainer.js.map +1 -1
  46. package/dist/components/ThinkingBlock.d.ts.map +1 -1
  47. package/dist/components/ThinkingBlock.js +9 -26
  48. package/dist/components/ThinkingBlock.js.map +1 -1
  49. package/dist/components/message-renderer-registry.d.ts +5 -5
  50. package/dist/components/message-renderer-registry.d.ts.map +1 -1
  51. package/dist/components/message-renderer-registry.js.map +1 -1
  52. package/dist/components/sandbox/ArtifactsRuntimeProvider.d.ts.map +1 -1
  53. package/dist/components/sandbox/ArtifactsRuntimeProvider.js +3 -0
  54. package/dist/components/sandbox/ArtifactsRuntimeProvider.js.map +1 -1
  55. package/dist/components/sandbox/AttachmentsRuntimeProvider.d.ts.map +1 -1
  56. package/dist/components/sandbox/AttachmentsRuntimeProvider.js +1 -0
  57. package/dist/components/sandbox/AttachmentsRuntimeProvider.js.map +1 -1
  58. package/dist/components/sandbox/ConsoleRuntimeProvider.d.ts.map +1 -1
  59. package/dist/components/sandbox/ConsoleRuntimeProvider.js +3 -5
  60. package/dist/components/sandbox/ConsoleRuntimeProvider.js.map +1 -1
  61. package/dist/components/sandbox/FileDownloadRuntimeProvider.d.ts.map +1 -1
  62. package/dist/components/sandbox/FileDownloadRuntimeProvider.js +1 -3
  63. package/dist/components/sandbox/FileDownloadRuntimeProvider.js.map +1 -1
  64. package/dist/components/sandbox/RuntimeMessageBridge.d.ts.map +1 -1
  65. package/dist/components/sandbox/RuntimeMessageBridge.js.map +1 -1
  66. package/dist/components/sandbox/RuntimeMessageRouter.d.ts.map +1 -1
  67. package/dist/components/sandbox/RuntimeMessageRouter.js +3 -5
  68. package/dist/components/sandbox/RuntimeMessageRouter.js.map +1 -1
  69. package/dist/dialogs/ApiKeyPromptDialog.d.ts.map +1 -1
  70. package/dist/dialogs/ApiKeyPromptDialog.js +10 -23
  71. package/dist/dialogs/ApiKeyPromptDialog.js.map +1 -1
  72. package/dist/dialogs/AttachmentOverlay.d.ts.map +1 -1
  73. package/dist/dialogs/AttachmentOverlay.js +34 -46
  74. package/dist/dialogs/AttachmentOverlay.js.map +1 -1
  75. package/dist/dialogs/CustomProviderDialog.d.ts.map +1 -1
  76. package/dist/dialogs/CustomProviderDialog.js +19 -39
  77. package/dist/dialogs/CustomProviderDialog.js.map +1 -1
  78. package/dist/dialogs/ModelSelector.d.ts.map +1 -1
  79. package/dist/dialogs/ModelSelector.js +25 -53
  80. package/dist/dialogs/ModelSelector.js.map +1 -1
  81. package/dist/dialogs/PersistentStorageDialog.d.ts.map +1 -1
  82. package/dist/dialogs/PersistentStorageDialog.js +9 -23
  83. package/dist/dialogs/PersistentStorageDialog.js.map +1 -1
  84. package/dist/dialogs/ProvidersModelsTab.d.ts.map +1 -1
  85. package/dist/dialogs/ProvidersModelsTab.js +7 -23
  86. package/dist/dialogs/ProvidersModelsTab.js.map +1 -1
  87. package/dist/dialogs/SessionListDialog.d.ts.map +1 -1
  88. package/dist/dialogs/SessionListDialog.js +14 -29
  89. package/dist/dialogs/SessionListDialog.js.map +1 -1
  90. package/dist/dialogs/SettingsDialog.d.ts.map +1 -1
  91. package/dist/dialogs/SettingsDialog.js +20 -52
  92. package/dist/dialogs/SettingsDialog.js.map +1 -1
  93. package/dist/index.d.ts +5 -8
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +2 -6
  96. package/dist/index.js.map +1 -1
  97. package/dist/prompts/prompts.d.ts.map +1 -1
  98. package/dist/storage/app-storage.d.ts.map +1 -1
  99. package/dist/storage/app-storage.js +5 -0
  100. package/dist/storage/app-storage.js.map +1 -1
  101. package/dist/storage/backends/indexeddb-storage-backend.d.ts.map +1 -1
  102. package/dist/storage/backends/indexeddb-storage-backend.js +2 -1
  103. package/dist/storage/backends/indexeddb-storage-backend.js.map +1 -1
  104. package/dist/storage/store.d.ts.map +1 -1
  105. package/dist/storage/store.js +1 -3
  106. package/dist/storage/store.js.map +1 -1
  107. package/dist/storage/stores/custom-providers-store.d.ts.map +1 -1
  108. package/dist/storage/stores/custom-providers-store.js.map +1 -1
  109. package/dist/storage/stores/provider-keys-store.d.ts.map +1 -1
  110. package/dist/storage/stores/provider-keys-store.js.map +1 -1
  111. package/dist/storage/stores/sessions-store.d.ts +1 -1
  112. package/dist/storage/stores/sessions-store.d.ts.map +1 -1
  113. package/dist/storage/stores/sessions-store.js.map +1 -1
  114. package/dist/storage/stores/settings-store.d.ts.map +1 -1
  115. package/dist/storage/stores/settings-store.js.map +1 -1
  116. package/dist/storage/types.d.ts +2 -3
  117. package/dist/storage/types.d.ts.map +1 -1
  118. package/dist/tools/artifacts/ArtifactElement.d.ts.map +1 -1
  119. package/dist/tools/artifacts/ArtifactElement.js +1 -4
  120. package/dist/tools/artifacts/ArtifactElement.js.map +1 -1
  121. package/dist/tools/artifacts/ArtifactPill.js.map +1 -1
  122. package/dist/tools/artifacts/Console.d.ts.map +1 -1
  123. package/dist/tools/artifacts/Console.js +10 -28
  124. package/dist/tools/artifacts/Console.js.map +1 -1
  125. package/dist/tools/artifacts/DocxArtifact.d.ts.map +1 -1
  126. package/dist/tools/artifacts/DocxArtifact.js +7 -23
  127. package/dist/tools/artifacts/DocxArtifact.js.map +1 -1
  128. package/dist/tools/artifacts/ExcelArtifact.d.ts.map +1 -1
  129. package/dist/tools/artifacts/ExcelArtifact.js +7 -23
  130. package/dist/tools/artifacts/ExcelArtifact.js.map +1 -1
  131. package/dist/tools/artifacts/GenericArtifact.d.ts.map +1 -1
  132. package/dist/tools/artifacts/GenericArtifact.js +5 -19
  133. package/dist/tools/artifacts/GenericArtifact.js.map +1 -1
  134. package/dist/tools/artifacts/HtmlArtifact.d.ts.map +1 -1
  135. package/dist/tools/artifacts/HtmlArtifact.js +16 -35
  136. package/dist/tools/artifacts/HtmlArtifact.js.map +1 -1
  137. package/dist/tools/artifacts/ImageArtifact.d.ts.map +1 -1
  138. package/dist/tools/artifacts/ImageArtifact.js +5 -19
  139. package/dist/tools/artifacts/ImageArtifact.js.map +1 -1
  140. package/dist/tools/artifacts/MarkdownArtifact.d.ts.map +1 -1
  141. package/dist/tools/artifacts/MarkdownArtifact.js +8 -24
  142. package/dist/tools/artifacts/MarkdownArtifact.js.map +1 -1
  143. package/dist/tools/artifacts/PdfArtifact.d.ts.map +1 -1
  144. package/dist/tools/artifacts/PdfArtifact.js +8 -24
  145. package/dist/tools/artifacts/PdfArtifact.js.map +1 -1
  146. package/dist/tools/artifacts/SvgArtifact.d.ts.map +1 -1
  147. package/dist/tools/artifacts/SvgArtifact.js +8 -24
  148. package/dist/tools/artifacts/SvgArtifact.js.map +1 -1
  149. package/dist/tools/artifacts/TextArtifact.d.ts.map +1 -1
  150. package/dist/tools/artifacts/TextArtifact.js +6 -20
  151. package/dist/tools/artifacts/TextArtifact.js.map +1 -1
  152. package/dist/tools/artifacts/artifacts-tool-renderer.d.ts.map +1 -1
  153. package/dist/tools/artifacts/artifacts-tool-renderer.js +1 -0
  154. package/dist/tools/artifacts/artifacts-tool-renderer.js.map +1 -1
  155. package/dist/tools/artifacts/artifacts.d.ts +2 -3
  156. package/dist/tools/artifacts/artifacts.d.ts.map +1 -1
  157. package/dist/tools/artifacts/artifacts.js +30 -52
  158. package/dist/tools/artifacts/artifacts.js.map +1 -1
  159. package/dist/tools/extract-document.d.ts +2 -2
  160. package/dist/tools/extract-document.d.ts.map +1 -1
  161. package/dist/tools/extract-document.js.map +1 -1
  162. package/dist/tools/index.js.map +1 -1
  163. package/dist/tools/javascript-repl.d.ts +3 -3
  164. package/dist/tools/javascript-repl.d.ts.map +1 -1
  165. package/dist/tools/javascript-repl.js.map +1 -1
  166. package/dist/tools/renderer-registry.js.map +1 -1
  167. package/dist/tools/renderers/BashRenderer.d.ts.map +1 -1
  168. package/dist/tools/renderers/BashRenderer.js.map +1 -1
  169. package/dist/tools/renderers/CalculateRenderer.d.ts.map +1 -1
  170. package/dist/tools/renderers/CalculateRenderer.js.map +1 -1
  171. package/dist/tools/renderers/DefaultRenderer.d.ts.map +1 -1
  172. package/dist/tools/renderers/DefaultRenderer.js.map +1 -1
  173. package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts.map +1 -1
  174. package/dist/tools/renderers/GetCurrentTimeRenderer.js.map +1 -1
  175. package/dist/utils/attachment-utils.js.map +1 -1
  176. package/dist/utils/auth-token.js.map +1 -1
  177. package/dist/utils/format.js.map +1 -1
  178. package/dist/utils/i18n.d.ts +14 -14
  179. package/dist/utils/i18n.d.ts.map +1 -1
  180. package/dist/utils/i18n.js.map +1 -1
  181. package/dist/utils/model-discovery.js.map +1 -1
  182. package/dist/utils/proxy-utils.d.ts +9 -1
  183. package/dist/utils/proxy-utils.d.ts.map +1 -1
  184. package/dist/utils/proxy-utils.js +19 -0
  185. package/dist/utils/proxy-utils.js.map +1 -1
  186. package/dist/utils/test-sessions.d.ts +47 -47
  187. package/dist/utils/test-sessions.js.map +1 -1
  188. package/example/package.json +1 -1
  189. package/example/src/custom-messages.ts +26 -36
  190. package/example/src/main.ts +11 -20
  191. package/example/tsconfig.json +1 -0
  192. package/package.json +4 -4
  193. package/src/ChatPanel.ts +2 -3
  194. package/src/components/AgentInterface.ts +57 -13
  195. package/src/components/MessageEditor.ts +2 -1
  196. package/src/components/MessageList.ts +3 -4
  197. package/src/components/Messages.ts +108 -19
  198. package/src/components/StreamingMessageContainer.ts +6 -5
  199. package/src/components/message-renderer-registry.ts +5 -5
  200. package/src/index.ts +13 -10
  201. package/src/storage/stores/sessions-store.ts +1 -1
  202. package/src/storage/types.ts +2 -3
  203. package/src/tools/artifacts/artifacts.ts +4 -4
  204. package/src/tools/extract-document.ts +2 -1
  205. package/src/tools/javascript-repl.ts +2 -1
  206. package/src/utils/proxy-utils.ts +23 -1
  207. package/dist/agent/agent.d.ts +0 -62
  208. package/dist/agent/agent.d.ts.map +0 -1
  209. package/dist/agent/agent.js +0 -274
  210. package/dist/agent/agent.js.map +0 -1
  211. package/dist/agent/transports/AppTransport.d.ts +0 -15
  212. package/dist/agent/transports/AppTransport.d.ts.map +0 -1
  213. package/dist/agent/transports/AppTransport.js +0 -327
  214. package/dist/agent/transports/AppTransport.js.map +0 -1
  215. package/dist/agent/transports/ProviderTransport.d.ts +0 -14
  216. package/dist/agent/transports/ProviderTransport.d.ts.map +0 -1
  217. package/dist/agent/transports/ProviderTransport.js +0 -55
  218. package/dist/agent/transports/ProviderTransport.js.map +0 -1
  219. package/dist/agent/transports/index.d.ts +0 -4
  220. package/dist/agent/transports/index.d.ts.map +0 -1
  221. package/dist/agent/transports/index.js +0 -4
  222. package/dist/agent/transports/index.js.map +0 -1
  223. package/dist/agent/transports/proxy-types.d.ts +0 -48
  224. package/dist/agent/transports/proxy-types.d.ts.map +0 -1
  225. package/dist/agent/transports/proxy-types.js +0 -2
  226. package/dist/agent/transports/proxy-types.js.map +0 -1
  227. package/dist/agent/transports/types.d.ts +0 -15
  228. package/dist/agent/transports/types.d.ts.map +0 -1
  229. package/dist/agent/transports/types.js +0 -2
  230. package/dist/agent/transports/types.js.map +0 -1
  231. package/dist/agent/types.d.ts +0 -15
  232. package/dist/agent/types.d.ts.map +0 -1
  233. package/dist/agent/types.js +0 -2
  234. package/dist/agent/types.js.map +0 -1
  235. package/example/src/test-sessions.ts +0 -104
  236. package/src/agent/agent.ts +0 -341
  237. package/src/agent/transports/AppTransport.ts +0 -371
  238. package/src/agent/transports/ProviderTransport.ts +0 -71
  239. package/src/agent/transports/index.ts +0 -3
  240. package/src/agent/transports/proxy-types.ts +0 -15
  241. package/src/agent/transports/types.ts +0 -26
  242. package/src/agent/types.ts +0 -11
@@ -1,4 +1,4 @@
1
- import type { ToolResultMessage, Usage } from "@mariozechner/pi-ai";
1
+ import { streamSimple, type ToolResultMessage, type Usage } from "@mariozechner/pi-ai";
2
2
  import { html, LitElement } from "lit";
3
3
  import { customElement, property, query } from "lit/decorators.js";
4
4
  import { ModelSelector } from "../dialogs/ModelSelector.js";
@@ -6,12 +6,14 @@ import type { MessageEditor } from "./MessageEditor.js";
6
6
  import "./MessageEditor.js";
7
7
  import "./MessageList.js";
8
8
  import "./Messages.js"; // Import for side effects to register the custom elements
9
- import type { Agent, AgentEvent } from "../agent/agent.js";
10
9
  import { getAppStorage } from "../storage/app-storage.js";
11
10
  import "./StreamingMessageContainer.js";
11
+ import type { Agent, AgentEvent } from "@mariozechner/pi-agent-core";
12
12
  import type { Attachment } from "../utils/attachment-utils.js";
13
13
  import { formatUsage } from "../utils/format.js";
14
14
  import { i18n } from "../utils/i18n.js";
15
+ import { createStreamFn } from "../utils/proxy-utils.js";
16
+ import type { UserMessageWithAttachments } from "./Messages.js";
15
17
  import type { StreamingMessageContainer } from "./StreamingMessageContainer.js";
16
18
 
17
19
  @customElement("agent-interface")
@@ -129,17 +131,48 @@ export class AgentInterface extends LitElement {
129
131
  this._unsubscribeSession = undefined;
130
132
  }
131
133
  if (!this.session) return;
134
+
135
+ // Set default streamFn with proxy support if not already set
136
+ if (this.session.streamFn === streamSimple) {
137
+ this.session.streamFn = createStreamFn(async () => {
138
+ const enabled = await getAppStorage().settings.get<boolean>("proxy.enabled");
139
+ return enabled ? (await getAppStorage().settings.get<string>("proxy.url")) || undefined : undefined;
140
+ });
141
+ }
142
+
143
+ // Set default getApiKey if not already set
144
+ if (!this.session.getApiKey) {
145
+ this.session.getApiKey = async (provider: string) => {
146
+ const key = await getAppStorage().providerKeys.get(provider);
147
+ return key ?? undefined;
148
+ };
149
+ }
150
+
132
151
  this._unsubscribeSession = this.session.subscribe(async (ev: AgentEvent) => {
133
- if (ev.type === "state-update") {
134
- if (this._streamingContainer) {
135
- this._streamingContainer.isStreaming = ev.state.isStreaming;
136
- this._streamingContainer.setMessage(ev.state.streamMessage, !ev.state.isStreaming);
137
- }
138
- this.requestUpdate();
139
- } else if (ev.type === "error-no-model") {
140
- // TODO show some UI feedback
141
- } else if (ev.type === "error-no-api-key") {
142
- // Handled by onApiKeyRequired callback
152
+ switch (ev.type) {
153
+ case "message_start":
154
+ case "message_end":
155
+ case "turn_start":
156
+ case "turn_end":
157
+ case "agent_start":
158
+ this.requestUpdate();
159
+ break;
160
+ case "agent_end":
161
+ // Clear streaming container when agent finishes
162
+ if (this._streamingContainer) {
163
+ this._streamingContainer.isStreaming = false;
164
+ this._streamingContainer.setMessage(null, true);
165
+ }
166
+ this.requestUpdate();
167
+ break;
168
+ case "message_update":
169
+ if (this._streamingContainer) {
170
+ const isStreaming = this.session?.state.isStreaming || false;
171
+ this._streamingContainer.isStreaming = isStreaming;
172
+ this._streamingContainer.setMessage(ev.message, !isStreaming);
173
+ }
174
+ this.requestUpdate();
175
+ break;
143
176
  }
144
177
  });
145
178
  }
@@ -205,7 +238,18 @@ export class AgentInterface extends LitElement {
205
238
  this._messageEditor.attachments = [];
206
239
  this._autoScroll = true; // Enable auto-scroll when sending a message
207
240
 
208
- await this.session?.prompt(input, attachments);
241
+ // Compose message with attachments if any
242
+ if (attachments && attachments.length > 0) {
243
+ const message: UserMessageWithAttachments = {
244
+ role: "user-with-attachments",
245
+ content: input,
246
+ attachments,
247
+ timestamp: Date.now(),
248
+ };
249
+ await this.session?.prompt(message);
250
+ } else {
251
+ await this.session?.prompt(input);
252
+ }
209
253
  }
210
254
 
211
255
  private renderMessages() {
@@ -9,6 +9,7 @@ import { Brain, Loader2, Paperclip, Send, Sparkles, Square } from "lucide";
9
9
  import { type Attachment, loadAttachment } from "../utils/attachment-utils.js";
10
10
  import { i18n } from "../utils/i18n.js";
11
11
  import "./AttachmentTile.js";
12
+ import type { ThinkingLevel } from "@mariozechner/pi-agent-core";
12
13
 
13
14
  @customElement("message-editor")
14
15
  export class MessageEditor extends LitElement {
@@ -28,7 +29,7 @@ export class MessageEditor extends LitElement {
28
29
 
29
30
  @property() isStreaming = false;
30
31
  @property() currentModel?: Model<any>;
31
- @property() thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" = "off";
32
+ @property() thinkingLevel: ThinkingLevel = "off";
32
33
  @property() showAttachmentButton = true;
33
34
  @property() showModelSelector = true;
34
35
  @property() showThinkingSelector = true;
@@ -1,16 +1,15 @@
1
+ import type { AgentMessage, AgentTool } from "@mariozechner/pi-agent-core";
1
2
  import type {
2
- AgentTool,
3
3
  AssistantMessage as AssistantMessageType,
4
4
  ToolResultMessage as ToolResultMessageType,
5
5
  } from "@mariozechner/pi-ai";
6
6
  import { html, LitElement, type TemplateResult } from "lit";
7
7
  import { property } from "lit/decorators.js";
8
8
  import { repeat } from "lit/directives/repeat.js";
9
- import type { AppMessage } from "./Messages.js";
10
9
  import { renderMessage } from "./message-renderer-registry.js";
11
10
 
12
11
  export class MessageList extends LitElement {
13
- @property({ type: Array }) messages: AppMessage[] = [];
12
+ @property({ type: Array }) messages: AgentMessage[] = [];
14
13
  @property({ type: Array }) tools: AgentTool[] = [];
15
14
  @property({ type: Object }) pendingToolCalls?: Set<string>;
16
15
  @property({ type: Boolean }) isStreaming: boolean = false;
@@ -51,7 +50,7 @@ export class MessageList extends LitElement {
51
50
  }
52
51
 
53
52
  // Fall back to built-in renderers
54
- if (msg.role === "user") {
53
+ if (msg.role === "user" || msg.role === "user-with-attachments") {
55
54
  items.push({
56
55
  key: `msg:${index}`,
57
56
  template: html`<user-message .message=${msg}></user-message>`,
@@ -1,6 +1,7 @@
1
1
  import type {
2
- AgentTool,
3
2
  AssistantMessage as AssistantMessageType,
3
+ ImageContent,
4
+ TextContent,
4
5
  ToolCall,
5
6
  ToolResultMessage as ToolResultMessageType,
6
7
  UserMessage as UserMessageType,
@@ -12,8 +13,14 @@ import type { Attachment } from "../utils/attachment-utils.js";
12
13
  import { formatUsage } from "../utils/format.js";
13
14
  import { i18n } from "../utils/i18n.js";
14
15
  import "./ThinkingBlock.js";
16
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
15
17
 
16
- export type UserMessageWithAttachments = UserMessageType & { attachments?: Attachment[] };
18
+ export type UserMessageWithAttachments = {
19
+ role: "user-with-attachments";
20
+ content: string | (TextContent | ImageContent)[];
21
+ timestamp: number;
22
+ attachments?: Attachment[];
23
+ };
17
24
 
18
25
  // Artifact message type for session persistence
19
26
  export interface ArtifactMessage {
@@ -25,26 +32,16 @@ export interface ArtifactMessage {
25
32
  timestamp: string;
26
33
  }
27
34
 
28
- // Base message union
29
- type BaseMessage = AssistantMessageType | UserMessageWithAttachments | ToolResultMessageType | ArtifactMessage;
30
-
31
- // Extensible interface - apps can extend via declaration merging
32
- // Example:
33
- // declare module "@mariozechner/pi-web-ui" {
34
- // interface CustomMessages {
35
- // "system-notification": SystemNotificationMessage;
36
- // }
37
- // }
38
- export interface CustomMessages {
39
- // Empty by default - apps extend via declaration merging
35
+ declare module "@mariozechner/pi-agent-core" {
36
+ interface CustomAgentMessages {
37
+ "user-with-attachments": UserMessageWithAttachments;
38
+ artifact: ArtifactMessage;
39
+ }
40
40
  }
41
41
 
42
- // AppMessage is union of base messages + custom messages
43
- export type AppMessage = BaseMessage | CustomMessages[keyof CustomMessages];
44
-
45
42
  @customElement("user-message")
46
43
  export class UserMessage extends LitElement {
47
- @property({ type: Object }) message!: UserMessageWithAttachments;
44
+ @property({ type: Object }) message!: UserMessageWithAttachments | UserMessageType;
48
45
 
49
46
  protected override createRenderRoot(): HTMLElement | DocumentFragment {
50
47
  return this;
@@ -66,7 +63,9 @@ export class UserMessage extends LitElement {
66
63
  <div class="user-message-container py-2 px-4 rounded-xl">
67
64
  <markdown-block .content=${content}></markdown-block>
68
65
  ${
69
- this.message.attachments && this.message.attachments.length > 0
66
+ this.message.role === "user-with-attachments" &&
67
+ this.message.attachments &&
68
+ this.message.attachments.length > 0
70
69
  ? html`
71
70
  <div class="mt-3 flex flex-wrap gap-2">
72
71
  ${this.message.attachments.map(
@@ -286,3 +285,93 @@ export class AbortedMessage extends LitElement {
286
285
  return html`<span class="text-sm text-destructive italic">${i18n("Request aborted")}</span>`;
287
286
  }
288
287
  }
288
+
289
+ // ============================================================================
290
+ // Default Message Transformer
291
+ // ============================================================================
292
+
293
+ import type { AgentMessage } from "@mariozechner/pi-agent-core";
294
+ import type { Message } from "@mariozechner/pi-ai";
295
+
296
+ /**
297
+ * Convert attachments to content blocks for LLM.
298
+ * - Images become ImageContent blocks
299
+ * - Documents with extractedText become TextContent blocks with filename header
300
+ */
301
+ export function convertAttachments(attachments: Attachment[]): (TextContent | ImageContent)[] {
302
+ const content: (TextContent | ImageContent)[] = [];
303
+ for (const attachment of attachments) {
304
+ if (attachment.type === "image") {
305
+ content.push({
306
+ type: "image",
307
+ data: attachment.content,
308
+ mimeType: attachment.mimeType,
309
+ } as ImageContent);
310
+ } else if (attachment.type === "document" && attachment.extractedText) {
311
+ content.push({
312
+ type: "text",
313
+ text: `\n\n[Document: ${attachment.fileName}]\n${attachment.extractedText}`,
314
+ } as TextContent);
315
+ }
316
+ }
317
+ return content;
318
+ }
319
+
320
+ /**
321
+ * Check if a message is a UserMessageWithAttachments.
322
+ */
323
+ export function isUserMessageWithAttachments(msg: AgentMessage): msg is UserMessageWithAttachments {
324
+ return (msg as UserMessageWithAttachments).role === "user-with-attachments";
325
+ }
326
+
327
+ /**
328
+ * Check if a message is an ArtifactMessage.
329
+ */
330
+ export function isArtifactMessage(msg: AgentMessage): msg is ArtifactMessage {
331
+ return (msg as ArtifactMessage).role === "artifact";
332
+ }
333
+
334
+ /**
335
+ * Default convertToLlm for web-ui apps.
336
+ *
337
+ * Handles:
338
+ * - UserMessageWithAttachments: converts to user message with content blocks
339
+ * - ArtifactMessage: filtered out (UI-only, for session reconstruction)
340
+ * - Standard LLM messages (user, assistant, toolResult): passed through
341
+ */
342
+ export function defaultConvertToLlm(messages: AgentMessage[]): Message[] {
343
+ return messages
344
+ .filter((m) => {
345
+ // Filter out artifact messages - they're for session reconstruction only
346
+ if (isArtifactMessage(m)) {
347
+ return false;
348
+ }
349
+ return true;
350
+ })
351
+ .map((m): Message | null => {
352
+ // Convert user-with-attachments to user message with content blocks
353
+ if (isUserMessageWithAttachments(m)) {
354
+ const textContent: (TextContent | ImageContent)[] =
355
+ typeof m.content === "string" ? [{ type: "text", text: m.content }] : [...m.content];
356
+
357
+ if (m.attachments) {
358
+ textContent.push(...convertAttachments(m.attachments));
359
+ }
360
+
361
+ return {
362
+ role: "user",
363
+ content: textContent,
364
+ timestamp: m.timestamp,
365
+ } as Message;
366
+ }
367
+
368
+ // Pass through standard LLM roles
369
+ if (m.role === "user" || m.role === "assistant" || m.role === "toolResult") {
370
+ return m as Message;
371
+ }
372
+
373
+ // Filter out unknown message types
374
+ return null;
375
+ })
376
+ .filter((m): m is Message => m !== null);
377
+ }
@@ -1,4 +1,5 @@
1
- import type { AgentTool, Message, ToolResultMessage } from "@mariozechner/pi-ai";
1
+ import type { AgentMessage, AgentTool } from "@mariozechner/pi-agent-core";
2
+ import type { ToolResultMessage } from "@mariozechner/pi-ai";
2
3
  import { html, LitElement } from "lit";
3
4
  import { property, state } from "lit/decorators.js";
4
5
 
@@ -9,8 +10,8 @@ export class StreamingMessageContainer extends LitElement {
9
10
  @property({ type: Object }) toolResultsById?: Map<string, ToolResultMessage>;
10
11
  @property({ attribute: false }) onCostClick?: () => void;
11
12
 
12
- @state() private _message: Message | null = null;
13
- private _pendingMessage: Message | null = null;
13
+ @state() private _message: AgentMessage | null = null;
14
+ private _pendingMessage: AgentMessage | null = null;
14
15
  private _updateScheduled = false;
15
16
  private _immediateUpdate = false;
16
17
 
@@ -24,7 +25,7 @@ export class StreamingMessageContainer extends LitElement {
24
25
  }
25
26
 
26
27
  // Public method to update the message with batching for performance
27
- public setMessage(message: Message | null, immediate = false) {
28
+ public setMessage(message: AgentMessage | null, immediate = false) {
28
29
  // Store the latest message
29
30
  this._pendingMessage = message;
30
31
 
@@ -73,7 +74,7 @@ export class StreamingMessageContainer extends LitElement {
73
74
  if (msg.role === "toolResult") {
74
75
  // Skip standalone tool result in streaming; the stable list will render paired tool-message
75
76
  return html``;
76
- } else if (msg.role === "user") {
77
+ } else if (msg.role === "user" || msg.role === "user-with-attachments") {
77
78
  // Skip standalone tool result in streaming; the stable list will render it immediiately
78
79
  return html``;
79
80
  } else if (msg.role === "assistant") {
@@ -1,11 +1,11 @@
1
+ import type { AgentMessage } from "@mariozechner/pi-agent-core";
1
2
  import type { TemplateResult } from "lit";
2
- import type { AppMessage } from "./Messages.js";
3
3
 
4
4
  // Extract role type from AppMessage union
5
- export type MessageRole = AppMessage["role"];
5
+ export type MessageRole = AgentMessage["role"];
6
6
 
7
7
  // Generic message renderer typed to specific message type
8
- export interface MessageRenderer<TMessage extends AppMessage = AppMessage> {
8
+ export interface MessageRenderer<TMessage extends AgentMessage = AgentMessage> {
9
9
  render(message: TMessage): TemplateResult;
10
10
  }
11
11
 
@@ -14,7 +14,7 @@ const messageRenderers = new Map<MessageRole, MessageRenderer<any>>();
14
14
 
15
15
  export function registerMessageRenderer<TRole extends MessageRole>(
16
16
  role: TRole,
17
- renderer: MessageRenderer<Extract<AppMessage, { role: TRole }>>,
17
+ renderer: MessageRenderer<Extract<AgentMessage, { role: TRole }>>,
18
18
  ): void {
19
19
  messageRenderers.set(role, renderer);
20
20
  }
@@ -23,6 +23,6 @@ export function getMessageRenderer(role: MessageRole): MessageRenderer | undefin
23
23
  return messageRenderers.get(role);
24
24
  }
25
25
 
26
- export function renderMessage(message: AppMessage): TemplateResult | undefined {
26
+ export function renderMessage(message: AgentMessage): TemplateResult | undefined {
27
27
  return messageRenderers.get(message.role)?.render(message);
28
28
  }
package/src/index.ts CHANGED
@@ -1,13 +1,7 @@
1
1
  // Main chat interface
2
2
 
3
- export type { AgentState, ThinkingLevel } from "./agent/agent.js";
4
- // State management
5
- export { Agent } from "./agent/agent.js";
6
- // Transports
7
- export { AppTransport } from "./agent/transports/AppTransport.js";
8
- export { ProviderTransport } from "./agent/transports/ProviderTransport.js";
9
- export type { ProxyAssistantMessageEvent } from "./agent/transports/proxy-types.js";
10
- export type { AgentRunConfig, AgentTransport } from "./agent/transports/types.js";
3
+ export type { Agent, AgentMessage, AgentState, ThinkingLevel } from "@mariozechner/pi-agent-core";
4
+ export type { Model } from "@mariozechner/pi-ai";
11
5
  export { ChatPanel } from "./ChatPanel.js";
12
6
  // Components
13
7
  export { AgentInterface } from "./components/AgentInterface.js";
@@ -18,8 +12,16 @@ export { Input } from "./components/Input.js";
18
12
  export { MessageEditor } from "./components/MessageEditor.js";
19
13
  export { MessageList } from "./components/MessageList.js";
20
14
  // Message components
21
- export type { AppMessage, CustomMessages, UserMessageWithAttachments } from "./components/Messages.js";
22
- export { AssistantMessage, ToolMessage, UserMessage } from "./components/Messages.js";
15
+ export type { ArtifactMessage, UserMessageWithAttachments } from "./components/Messages.js";
16
+ export {
17
+ AssistantMessage,
18
+ convertAttachments,
19
+ defaultConvertToLlm,
20
+ isArtifactMessage,
21
+ isUserMessageWithAttachments,
22
+ ToolMessage,
23
+ UserMessage,
24
+ } from "./components/Messages.js";
23
25
  // Message renderer registry
24
26
  export {
25
27
  getMessageRenderer,
@@ -110,3 +112,4 @@ export { loadAttachment } from "./utils/attachment-utils.js";
110
112
  export { clearAuthToken, getAuthToken } from "./utils/auth-token.js";
111
113
  export { formatCost, formatModelCost, formatTokenCount, formatUsage } from "./utils/format.js";
112
114
  export { i18n, setLanguage, translations } from "./utils/i18n.js";
115
+ export { applyProxyIfNeeded, createStreamFn, isCorsError, shouldUseProxyForProvider } from "./utils/proxy-utils.js";
@@ -1,4 +1,4 @@
1
- import type { AgentState } from "../../agent/agent.js";
1
+ import type { AgentState } from "@mariozechner/pi-agent-core";
2
2
  import { Store } from "../store.js";
3
3
  import type { SessionData, SessionMetadata, StoreConfig } from "../types.js";
4
4
 
@@ -1,6 +1,5 @@
1
+ import type { AgentMessage, ThinkingLevel } from "@mariozechner/pi-agent-core";
1
2
  import type { Model } from "@mariozechner/pi-ai";
2
- import type { ThinkingLevel } from "../agent/agent.js";
3
- import type { AppMessage } from "../components/Messages.js";
4
3
 
5
4
  /**
6
5
  * Transaction interface for atomic operations across stores.
@@ -159,7 +158,7 @@ export interface SessionData {
159
158
  thinkingLevel: ThinkingLevel;
160
159
 
161
160
  /** Full conversation history (with attachments inline) */
162
- messages: AppMessage[];
161
+ messages: AgentMessage[];
163
162
 
164
163
  /** ISO 8601 UTC timestamp of creation */
165
164
  createdAt: string;
@@ -1,13 +1,13 @@
1
1
  import { icon } from "@mariozechner/mini-lit";
2
2
  import "@mariozechner/mini-lit/dist/MarkdownBlock.js";
3
3
  import { Button } from "@mariozechner/mini-lit/dist/Button.js";
4
- import { type AgentTool, type Message, StringEnum, type ToolCall } from "@mariozechner/pi-ai";
4
+ import type { Agent, AgentMessage, AgentTool } from "@mariozechner/pi-agent-core";
5
+ import { StringEnum, type ToolCall } from "@mariozechner/pi-ai";
5
6
  import { type Static, Type } from "@sinclair/typebox";
6
7
  import { html, LitElement, type TemplateResult } from "lit";
7
8
  import { customElement, property, state } from "lit/decorators.js";
8
9
  import { createRef, type Ref, ref } from "lit/directives/ref.js";
9
10
  import { X } from "lucide";
10
- import type { Agent } from "../../agent/agent.js";
11
11
  import type { ArtifactMessage } from "../../components/Messages.js";
12
12
  import { ArtifactsRuntimeProvider } from "../../components/sandbox/ArtifactsRuntimeProvider.js";
13
13
  import { AttachmentsRuntimeProvider } from "../../components/sandbox/AttachmentsRuntimeProvider.js";
@@ -85,7 +85,7 @@ export class ArtifactsPanel extends LitElement {
85
85
  if (this.agent) {
86
86
  const attachments: Attachment[] = [];
87
87
  for (const message of this.agent.state.messages) {
88
- if (message.role === "user" && message.attachments) {
88
+ if (message.role === "user-with-attachments" && message.attachments) {
89
89
  attachments.push(...message.attachments);
90
90
  }
91
91
  }
@@ -292,7 +292,7 @@ export class ArtifactsPanel extends LitElement {
292
292
 
293
293
  // Re-apply artifacts by scanning a message list (optional utility)
294
294
  public async reconstructFromMessages(
295
- messages: Array<Message | { role: "aborted" } | { role: "artifact" }>,
295
+ messages: Array<AgentMessage | { role: "aborted" } | { role: "artifact" }>,
296
296
  ): Promise<void> {
297
297
  const toolCalls = new Map<string, ToolCall>();
298
298
  const artifactToolName = "artifacts";
@@ -1,4 +1,5 @@
1
- import type { AgentTool, ToolResultMessage } from "@mariozechner/pi-ai";
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import type { ToolResultMessage } from "@mariozechner/pi-ai";
2
3
  import { type Static, Type } from "@sinclair/typebox";
3
4
  import { html } from "lit";
4
5
  import { createRef, ref } from "lit/directives/ref.js";
@@ -1,5 +1,6 @@
1
1
  import { i18n } from "@mariozechner/mini-lit";
2
- import type { AgentTool, ToolResultMessage } from "@mariozechner/pi-ai";
2
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
3
+ import type { ToolResultMessage } from "@mariozechner/pi-ai";
3
4
  import { type Static, Type } from "@sinclair/typebox";
4
5
  import { html } from "lit";
5
6
  import { createRef, ref } from "lit/directives/ref.js";
@@ -1,4 +1,5 @@
1
- import type { Api, Model } from "@mariozechner/pi-ai";
1
+ import type { Api, Context, Model, SimpleStreamOptions } from "@mariozechner/pi-ai";
2
+ import { streamSimple } from "@mariozechner/pi-ai";
2
3
 
3
4
  /**
4
5
  * Centralized proxy decision logic.
@@ -110,3 +111,24 @@ export function isCorsError(error: unknown): boolean {
110
111
 
111
112
  return false;
112
113
  }
114
+
115
+ /**
116
+ * Create a streamFn that applies CORS proxy when needed.
117
+ * Reads proxy settings from storage on each call.
118
+ *
119
+ * @param getProxyUrl - Async function to get current proxy URL (or undefined if disabled)
120
+ * @returns A streamFn compatible with Agent's streamFn option
121
+ */
122
+ export function createStreamFn(getProxyUrl: () => Promise<string | undefined>) {
123
+ return async (model: Model<any>, context: Context, options?: SimpleStreamOptions) => {
124
+ const apiKey = options?.apiKey;
125
+ const proxyUrl = await getProxyUrl();
126
+
127
+ if (!apiKey || !proxyUrl) {
128
+ return streamSimple(model, context, options);
129
+ }
130
+
131
+ const proxiedModel = applyProxyIfNeeded(model, apiKey, proxyUrl);
132
+ return streamSimple(proxiedModel, context, options);
133
+ };
134
+ }
@@ -1,62 +0,0 @@
1
- import { type AgentTool, type Message, type Model } from "@mariozechner/pi-ai";
2
- import type { AppMessage } from "../components/Messages.js";
3
- import type { Attachment } from "../utils/attachment-utils.js";
4
- import type { AgentTransport } from "./transports/types.js";
5
- import type { DebugLogEntry } from "./types.js";
6
- export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high";
7
- export interface AgentState {
8
- systemPrompt: string;
9
- model: Model<any>;
10
- thinkingLevel: ThinkingLevel;
11
- tools: AgentTool<any>[];
12
- messages: AppMessage[];
13
- isStreaming: boolean;
14
- streamMessage: Message | null;
15
- pendingToolCalls: Set<string>;
16
- error?: string;
17
- }
18
- export type AgentEvent = {
19
- type: "state-update";
20
- state: AgentState;
21
- } | {
22
- type: "error-no-model";
23
- } | {
24
- type: "error-no-api-key";
25
- provider: string;
26
- } | {
27
- type: "started";
28
- } | {
29
- type: "completed";
30
- };
31
- export interface AgentOptions {
32
- initialState?: Partial<AgentState>;
33
- debugListener?: (entry: DebugLogEntry) => void;
34
- transport: AgentTransport;
35
- messageTransformer?: (messages: AppMessage[]) => Message[] | Promise<Message[]>;
36
- }
37
- export declare class Agent {
38
- private _state;
39
- private listeners;
40
- private abortController?;
41
- private transport;
42
- private debugListener?;
43
- private messageTransformer;
44
- private messageQueue;
45
- constructor(opts: AgentOptions);
46
- get state(): AgentState;
47
- subscribe(fn: (e: AgentEvent) => void): () => void;
48
- setSystemPrompt(v: string): void;
49
- setModel(m: Model<any>): void;
50
- setThinkingLevel(l: ThinkingLevel): void;
51
- setTools(t: AgentTool<any>[]): void;
52
- replaceMessages(ms: AppMessage[]): void;
53
- appendMessage(m: AppMessage): void;
54
- queueMessage(m: AppMessage): Promise<void>;
55
- clearMessages(): void;
56
- abort(): void;
57
- private logState;
58
- prompt(input: string, attachments?: Attachment[]): Promise<void>;
59
- private patch;
60
- private emit;
61
- }
62
- //# sourceMappingURL=agent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/agent/agent.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,SAAS,EAId,KAAK,OAAO,EACZ,KAAK,KAAK,EAEV,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,KAAK,EAAkB,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAqBhD,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1E,MAAM,WAAW,UAAU;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;IACxB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,UAAU,GACnB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAEzB,MAAM,WAAW,YAAY;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,SAAS,EAAE,cAAc,CAAC;IAE1B,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CAChF;AAED,qBAAa,KAAK;IACjB,OAAO,CAAC,MAAM,CAUZ;IACF,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,aAAa,CAAC,CAAiC;IACvD,OAAO,CAAC,kBAAkB,CAA6D;IACvF,OAAO,CAAC,YAAY,CAAwC;gBAEhD,IAAI,EAAE,YAAY;IAO9B,IAAI,KAAK,IAAI,UAAU,CAEtB;IAED,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI;IAOlD,eAAe,CAAC,CAAC,EAAE,MAAM;IAGzB,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC;IAGtB,gBAAgB,CAAC,CAAC,EAAE,aAAa;IAGjC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE;IAG5B,eAAe,CAAC,EAAE,EAAE,UAAU,EAAE;IAGhC,aAAa,CAAC,CAAC,EAAE,UAAU;IAGrB,YAAY,CAAC,CAAC,EAAE,UAAU;IAQhC,aAAa;IAIb,KAAK;IAIL,OAAO,CAAC,QAAQ;IAKV,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,UAAU,EAAE;IA+LtD,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,IAAI;CAKZ"}