mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 01:04:36 +00:00
Artifacts tool, V1, htmlartifact broken due to CSP
This commit is contained in:
parent
51f5448a5c
commit
4b0703cd5b
10 changed files with 1861 additions and 39 deletions
|
|
@ -1,15 +1,30 @@
|
|||
import { html } from "@mariozechner/mini-lit";
|
||||
import { calculateTool, getCurrentTimeTool, getModel } from "@mariozechner/pi-ai";
|
||||
import { LitElement } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import "./AgentInterface.js";
|
||||
import { AgentSession } from "./state/agent-session.js";
|
||||
import { ArtifactsPanel } from "./tools/artifacts/index.js";
|
||||
import { browserJavaScriptTool, createJavaScriptReplTool } from "./tools/index.js";
|
||||
import { registerToolRenderer } from "./tools/renderer-registry.js";
|
||||
import { getAuthToken } from "./utils/auth-token.js";
|
||||
|
||||
const BREAKPOINT = 800; // px - switch between overlay and side-by-side
|
||||
|
||||
@customElement("pi-chat-panel")
|
||||
export class ChatPanel extends LitElement {
|
||||
@state() private session!: AgentSession;
|
||||
@state() private artifactsPanel!: ArtifactsPanel;
|
||||
@state() private hasArtifacts = false;
|
||||
@state() private artifactCount = 0;
|
||||
@state() private showArtifactsPanel = true;
|
||||
@state() private windowWidth = window.innerWidth;
|
||||
@property({ type: String }) systemPrompt = "You are a helpful AI assistant.";
|
||||
|
||||
private resizeHandler = () => {
|
||||
this.windowWidth = window.innerWidth;
|
||||
this.requestUpdate();
|
||||
};
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
|
|
@ -18,6 +33,9 @@ export class ChatPanel extends LitElement {
|
|||
override async connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
// Listen to window resize
|
||||
window.addEventListener("resize", this.resizeHandler);
|
||||
|
||||
// Ensure panel fills height and allows flex layout
|
||||
this.style.display = "flex";
|
||||
this.style.flexDirection = "column";
|
||||
|
|
@ -27,21 +45,12 @@ export class ChatPanel extends LitElement {
|
|||
// Create JavaScript REPL tool with attachments provider
|
||||
const javascriptReplTool = createJavaScriptReplTool();
|
||||
|
||||
// Create agent session with default settings
|
||||
this.session = new AgentSession({
|
||||
initialState: {
|
||||
systemPrompt: "You are a helpful AI assistant.",
|
||||
model: getModel("anthropic", "claude-3-5-haiku-20241022"),
|
||||
tools: [calculateTool, getCurrentTimeTool, browserJavaScriptTool, javascriptReplTool],
|
||||
thinkingLevel: "off",
|
||||
},
|
||||
authTokenProvider: async () => getAuthToken(),
|
||||
transportMode: "direct", // Use direct mode by default (API keys from KeyStore)
|
||||
});
|
||||
// Set up artifacts panel
|
||||
this.artifactsPanel = new ArtifactsPanel();
|
||||
registerToolRenderer("artifacts", this.artifactsPanel);
|
||||
|
||||
// Wire up attachments provider for JavaScript REPL tool
|
||||
// We'll need to get attachments from the AgentInterface
|
||||
javascriptReplTool.attachmentsProvider = () => {
|
||||
// Attachments provider for both REPL and artifacts
|
||||
const getAttachments = () => {
|
||||
// Get all attachments from conversation messages
|
||||
const attachments: any[] = [];
|
||||
for (const message of this.session.state.messages) {
|
||||
|
|
@ -62,6 +71,66 @@ export class ChatPanel extends LitElement {
|
|||
}
|
||||
return attachments;
|
||||
};
|
||||
|
||||
javascriptReplTool.attachmentsProvider = getAttachments;
|
||||
this.artifactsPanel.attachmentsProvider = getAttachments;
|
||||
|
||||
this.artifactsPanel.onArtifactsChange = () => {
|
||||
const count = this.artifactsPanel.artifacts?.size ?? 0;
|
||||
const created = count > this.artifactCount;
|
||||
this.hasArtifacts = count > 0;
|
||||
this.artifactCount = count;
|
||||
|
||||
// Auto-open when new artifacts are created
|
||||
if (this.hasArtifacts && created) {
|
||||
this.showArtifactsPanel = true;
|
||||
}
|
||||
this.requestUpdate();
|
||||
};
|
||||
|
||||
this.artifactsPanel.onClose = () => {
|
||||
this.showArtifactsPanel = false;
|
||||
this.requestUpdate();
|
||||
};
|
||||
|
||||
this.artifactsPanel.onOpen = () => {
|
||||
this.showArtifactsPanel = true;
|
||||
this.requestUpdate();
|
||||
};
|
||||
|
||||
// Create agent session with default settings
|
||||
this.session = new AgentSession({
|
||||
initialState: {
|
||||
systemPrompt: this.systemPrompt,
|
||||
model: getModel("anthropic", "claude-3-5-haiku-20241022"),
|
||||
tools: [
|
||||
calculateTool,
|
||||
getCurrentTimeTool,
|
||||
browserJavaScriptTool,
|
||||
javascriptReplTool,
|
||||
this.artifactsPanel.tool,
|
||||
],
|
||||
thinkingLevel: "off",
|
||||
},
|
||||
authTokenProvider: async () => getAuthToken(),
|
||||
transportMode: "direct", // Use direct mode by default (API keys from KeyStore)
|
||||
});
|
||||
}
|
||||
|
||||
override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
window.removeEventListener("resize", this.resizeHandler);
|
||||
}
|
||||
|
||||
// Expose method to toggle artifacts panel
|
||||
public toggleArtifactsPanel() {
|
||||
this.showArtifactsPanel = !this.showArtifactsPanel;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
// Check if artifacts panel is currently visible
|
||||
public get artifactsPanelVisible(): boolean {
|
||||
return this.showArtifactsPanel;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
@ -71,15 +140,49 @@ export class ChatPanel extends LitElement {
|
|||
</div>`;
|
||||
}
|
||||
|
||||
const isMobile = this.windowWidth < BREAKPOINT;
|
||||
|
||||
// Set panel modes: collapsed when not showing, overlay on mobile
|
||||
if (this.artifactsPanel) {
|
||||
this.artifactsPanel.collapsed = !this.showArtifactsPanel;
|
||||
this.artifactsPanel.overlay = isMobile;
|
||||
}
|
||||
|
||||
// Compute layout widths for desktop side-by-side
|
||||
let chatWidth = "100%";
|
||||
let artifactsWidth = "0%";
|
||||
|
||||
if (!isMobile && this.hasArtifacts && this.showArtifactsPanel) {
|
||||
chatWidth = "50%";
|
||||
artifactsWidth = "50%";
|
||||
}
|
||||
|
||||
return html`
|
||||
<agent-interface
|
||||
.session=${this.session}
|
||||
.enableAttachments=${true}
|
||||
.enableModelSelector=${true}
|
||||
.enableThinking=${true}
|
||||
.showThemeToggle=${false}
|
||||
.showDebugToggle=${false}
|
||||
></agent-interface>
|
||||
<div class="relative w-full h-full overflow-hidden flex">
|
||||
<!-- Chat interface -->
|
||||
<div class="h-full ${isMobile ? "w-full" : ""}" style="${!isMobile ? `width: ${chatWidth};` : ""}">
|
||||
<agent-interface
|
||||
.session=${this.session}
|
||||
.enableAttachments=${true}
|
||||
.enableModelSelector=${true}
|
||||
.enableThinking=${true}
|
||||
.showThemeToggle=${false}
|
||||
.showDebugToggle=${false}
|
||||
></agent-interface>
|
||||
</div>
|
||||
|
||||
<!-- Artifacts panel (desktop side-by-side) -->
|
||||
${
|
||||
!isMobile
|
||||
? html`<div class="h-full" style="${this.hasArtifacts && this.showArtifactsPanel ? `width: ${artifactsWidth};` : "width: 0;"}">
|
||||
${this.artifactsPanel}
|
||||
</div>`
|
||||
: ""
|
||||
}
|
||||
|
||||
<!-- Mobile: artifacts panel always rendered (shows pill when collapsed) -->
|
||||
${isMobile ? html`<div class="absolute inset-0 pointer-events-none">${this.artifactsPanel}</div>` : ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue