Docker Docs !m.isStreaming) // Watch for store changes to focus input this.$watch('$store.gordon.isOpen', (isOpen) => { if (isOpen) { this.$nextTick(() => { this.$refs.input?.focus() }) } }) // Watch for query from store and populate input this.$watch('$store.gordon.query', (query) => { if (query) { this.currentQuestion = query const shouldAutoSubmit = this.$store.gordon.autoSubmit this.$nextTick(() => { if (shouldAutoSubmit) { this.askQuestion() } else { this.$refs.input?.focus() this.$refs.input?.select() } }) // Clear the store query and autoSubmit flag after using them this.$store.gordon.query = '' this.$store.gordon.autoSubmit = false } }) }, getTurnCount() { return this.messages.filter(m => m.role === 'user').length }, getRemainingTurns() { return this.maxTurnsPerThread - this.getTurnCount() }, isThreadLimitReached() { return this.getTurnCount() >= this.maxTurnsPerThread }, shouldShowCountdown() { const remaining = this.getRemainingTurns() return remaining > 0 && remaining { if (this.$refs.input) { this.$refs.input.style.height = 'auto' } }) this.isLoading = true this.error = null // Add placeholder for assistant response const responseIndex = this.messages.length this.messages.push({ role: 'assistant', content: '', isStreaming: true, questionAnswerId: null, feedback: null, copied: false }) this.$nextTick(() => { this.$refs.messagesContainer?.scrollTo({ top: this.$refs.messagesContainer.scrollHeight, behavior: 'smooth' }) }) try { await this.streamGordonResponse(responseIndex) } catch (err) { // Only set error if messages weren't cleared if (this.messages.length > 0) { if (err.message === 'RATE_LIMIT_EXCEEDED') { this.error = 'You\'ve exceeded your question quota for the day. Please come back tomorrow.' } else { this.error = 'Failed to get response. Please try again.' } } console.error('Gordon API error:', err) // Only try to remove message if it still exists if (this.messages[responseIndex]) { this.messages.splice(responseIndex, 1) } } finally { this.isLoading = false } }, getSessionId() { let sessionId = sessionStorage.getItem('gordon-session-id') if (!sessionId) { sessionId = `docs-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` sessionStorage.setItem('gordon-session-id', sessionId) } return sessionId }, async streamGordonResponse(responseIndex) { // Build API request from messages, excluding the streaming placeholder // The placeholder is at responseIndex, so we take everything before it const conversationMessages = this.messages.slice(0, responseIndex).map((msg, i) => { const message = { role: msg.role, content: msg.content } // Add copilot_references to the last message (most recent user question) if (i === responseIndex - 1) { message.copilot_references = [ { data: { origin: 'docs-website', email: '[email protected]', uuid: this.getSessionId(), action: 'AskGordon', ...(this.includePageContext && { page_url: window.location.href, page_title: "Home" }) } } ] } return message }) const isNewConversation = !this.threadId const payload = { messages: conversationMessages, ...(this.threadId && { thread_uuid: this.threadId }) } const response = await fetch(window.GORDON_BASE_URL + '/public/ask', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }) if (!response.ok) { if (response.status === 429) { throw new Error('RATE_LIMIT_EXCEEDED') } throw new Error(`HTTP ${response.status}: ${response.statusText}`) } const reader = response.body.getReader() const decoder = new TextDecoder() while (true) { const { done, value } = await reader.read() if (done) break const chunk = decoder.decode(value, { stream: true }) const lines = chunk.split('\n') for (const line of lines) { if (!line.trim() || !line.startsWith('data: ')) continue const data = line.slice(6) if (data === '[DONE]') continue try { const parsed = JSON.parse(data) // Capture thread_id for new conversations if (parsed.thread_id) { if (isNewConversation) { this.threadId = parsed.thread_id // $persist auto-saves to sessionStorage } else if (parsed.thread_id !== this.threadId) { console.warn('Backend returned unexpected thread_id:', parsed.thread_id) } continue } // Capture question_answer_id for feedback if (parsed.question_answer_id) { this.messages[responseIndex].questionAnswerId = parsed.question_answer_id continue } if (parsed.choices && parsed.choices[0]?.delta?.content) { const content = parsed.choices[0].delta.content this.messages[responseIndex].content += content this.$nextTick(() => { const container = this.$refs.messagesContainer if (container) { const isNearBottom = container.scrollHeight - container.scrollTop - container.clientHeight { setTimeout(() => { message.copied = false }, 2000) }) } catch (err) { console.error('Failed to copy:', err) } } }" x-cloak @keydown.escape.window=$store.gordon.close()> 0">Start a new chat 0" class="relative flex flex-col gap-4"> Answers are generated based on the documentation. How can we help? How do I get started with Docker? Can I run my AI agent in a sandbox? What is a container? What are Docker Hardened Images? Why should I use Docker Compose? Get started Learn Docker basics. Guides Optimize your development workflows with Docker. Manuals Install, set up, configure, and use Docker products. Reference Browse the CLI and API documentation. Aug 10 Docker Desktop Aug 10 Use Docker VMM on Mac and Windows Run Docker Desktop with Docker's container-optimized hypervisor on supported Mac and Windows systems. Aug 6 Docker Sandboxes Aug 6 Connect sandboxes through an MCP gateway Register local or remote MCP servers on the host, reuse them across sandboxes, and govern server and tool access with Cedar policies. Aug 6 Docker Sandboxes Aug 6 Author version 2 sandbox kits Define kit setup, permissions, networking, and API key or OAuth credential requirements with the version 2 kit schema. Aug 6 Docker Sandboxes Aug 6 Run Claude Code with local models Route Claude Code sandbox requests to the bundled local-model server or an existing Ollama installation. Aug 3 Docker AI Governance Aug 3 Search and forward audit events Search and export policy decisions from Docker Cloud, or forward events to Splunk, Dynatrace, and custom HTTPS endpoints. Aug 3 Docker Desktop Aug 3 Install from the Microsoft Store without administrator privileges Fresh Microsoft Store installations on Windows use per-user mode by default. Jul 24 Docker Sandboxes Jul 24 Share agent skills across sandboxes Import skills from supported host agents into a persistent store that sandboxes can share. Jul 24 Docker Sandboxes Jul 24 Connect editors and desktop apps over SSH Use a sandbox from VS Code, Cursor, Claude Desktop, ChatGPT, or another SSH-capable tool. Jul 23 Docker Hardened Images Jul 23 Query the DHI catalog from AI assistants Search DHI repositories, inspect images, retrieve SBOMs, check CVEs, and manage mirrors through the DHI MCP server. Jul 21 Docker Enterprise Jul 21 Authenticate GitHub Actions with OIDC connections Exchange GitHub OIDC tokens for short-lived access to Docker resources without storing long-lived workflow credentials. Show more