Portal Community

Message Types and Rendering

Message RoleWidget DisplayAlignment
userText bubble in primary colorRight
assistantText bubble with markdown renderingLeft
tool_callSmall inline card showing tool name and parametersLeft, indented
tool_resultCollapsed summary; expandable for full JSONLeft, indented
systemNot displayed in the widget (filtered out)

Loading Conversation History

// GET /api/chat/{sessionId}/history — returns paginated message list
{
  "session_id":   "sess-abc123",
  "agent_id":     "hr-assistant",
  "started_at":   "2024-06-15T09:00:00Z",
  "messages": [
    {
      "id":         "msg-001",
      "role":       "user",
      "content":    "How many leave days do I have left?",
      "created_at": "2024-06-15T09:00:12Z"
    },
    {
      "id":         "msg-002",
      "role":       "tool_call",
      "tool_name":  "get_leave_balance",
      "tool_input": { "employee_id": "EMP-1234" },
      "created_at": "2024-06-15T09:00:13Z"
    },
    {
      "id":         "msg-003",
      "role":       "tool_result",
      "tool_name":  "get_leave_balance",
      "content":    "{\"annual_days\":15,\"sick_days\":8}",
      "created_at": "2024-06-15T09:00:13Z"
    },
    {
      "id":         "msg-004",
      "role":       "assistant",
      "content":    "You have **15 annual leave days** and **8 sick days** remaining.",
      "created_at": "2024-06-15T09:00:14Z"
    }
  ],
  "has_more":   false,
  "next_cursor": null
}

Markdown Rendering

Agent responses are rendered as Markdown. The widget supports a safe subset of Markdown:

Markdown FeatureRendered As
**bold**Bold text
*italic*Italic text
`code`Inline monospace code
Triple backtick code blocksSyntax-highlighted code block with copy button
- list itemUnordered list
1. itemOrdered list
[link](url)Clickable link (opens in new tab)
Raw HTMLStripped — not rendered (XSS prevention)

Session Persistence

When persistSession: true, the widget stores the conversation session ID in localStorage. On reload or re-open, the stored session ID is sent with the history request to restore the previous conversation:

// Widget startup logic (TypeScript)
const STORAGE_KEY = `octopus-session-${agentId}`;

async function initWidget() {
  const savedSessionId = localStorage.getItem(STORAGE_KEY);

  if (savedSessionId) {
    try {
      const history = await fetchHistory(savedSessionId);
      renderMessages(history.messages);
      currentSessionId = savedSessionId;
      return;
    } catch {
      // Session expired — start fresh
      localStorage.removeItem(STORAGE_KEY);
    }
  }

  // Start a new session
  currentSessionId = await createSession(agentId);
  localStorage.setItem(STORAGE_KEY, currentSessionId);
}