Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions api/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7068,6 +7068,19 @@ components:
- ModelOutputStopReasonRefusal
- ModelOutputStopReasonContentFilter
- ModelOutputStopReasonError
ContentBlockMetadata:
Comment thread
asherdale marked this conversation as resolved.
type: object
description: >-
String key-value metadata. Maximum 16 pairs, keys up to 64 characters,
and values up to 512 characters. Keys beginning with `omnara_` are
reserved for Omnara and may affect product behavior; use them only when
intentionally invoking Omnara-defined behavior.
x-go-type: json.RawMessage
x-go-type-skip-optional-pointer: true
maxProperties: 16
additionalProperties:
type: string
maxLength: 512
TextContentBlock:
type: object
additionalProperties: false
Expand All @@ -7078,6 +7091,8 @@ components:
enum: [text]
text:
type: string
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
InlineMediaContentBlock:
type: object
additionalProperties: false
Expand Down Expand Up @@ -7108,6 +7123,8 @@ components:
type: string
format: byte
minLength: 1
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
MediaRefContentBlock:
type: object
additionalProperties: false
Expand All @@ -7118,6 +7135,8 @@ components:
enum: [media_ref]
artifact_id:
$ref: '#/components/schemas/ArtifactID'
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
ReasoningContentBlock:
type: object
additionalProperties: false
Expand All @@ -7128,6 +7147,8 @@ components:
enum: [reasoning]
text:
type: string
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
ErrorContentBlock:
type: object
additionalProperties: false
Expand All @@ -7138,6 +7159,8 @@ components:
enum: [error]
text:
type: string
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
StructuredDataContentBlock:
type: object
additionalProperties: false
Expand All @@ -7148,6 +7171,8 @@ components:
enum: [structured_data]
value:
$ref: '#/components/schemas/JSONBlob'
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
ModelToolCallContentBlock:
type: object
additionalProperties: false
Expand All @@ -7164,6 +7189,8 @@ components:
type: string
input:
$ref: '#/components/schemas/ToolInput'
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
CreateAgentInputContentBlock:
oneOf:
- $ref: '#/components/schemas/TextContentBlock'
Expand Down
27 changes: 27 additions & 0 deletions docs/api-reference/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7069,6 +7069,19 @@ components:
- ModelOutputStopReasonRefusal
- ModelOutputStopReasonContentFilter
- ModelOutputStopReasonError
ContentBlockMetadata:
type: object
description: >-
String key-value metadata. Maximum 16 pairs, keys up to 64 characters,
and values up to 512 characters. Keys beginning with `omnara_` are
reserved for Omnara and may affect product behavior; use them only when
intentionally invoking Omnara-defined behavior.
x-go-type: json.RawMessage
x-go-type-skip-optional-pointer: true
maxProperties: 16
additionalProperties:
type: string
maxLength: 512
TextContentBlock:
type: object
additionalProperties: false
Expand All @@ -7079,6 +7092,8 @@ components:
enum: [text]
text:
type: string
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
InlineMediaContentBlock:
type: object
additionalProperties: false
Expand Down Expand Up @@ -7109,6 +7124,8 @@ components:
type: string
format: byte
minLength: 1
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
MediaRefContentBlock:
type: object
additionalProperties: false
Expand All @@ -7119,6 +7136,8 @@ components:
enum: [media_ref]
artifact_id:
$ref: '#/components/schemas/ArtifactID'
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
ReasoningContentBlock:
type: object
additionalProperties: false
Expand All @@ -7129,6 +7148,8 @@ components:
enum: [reasoning]
text:
type: string
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
ErrorContentBlock:
type: object
additionalProperties: false
Expand All @@ -7139,6 +7160,8 @@ components:
enum: [error]
text:
type: string
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
StructuredDataContentBlock:
type: object
additionalProperties: false
Expand All @@ -7149,6 +7172,8 @@ components:
enum: [structured_data]
value:
$ref: '#/components/schemas/JSONBlob'
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
ModelToolCallContentBlock:
type: object
additionalProperties: false
Expand All @@ -7165,6 +7190,8 @@ components:
type: string
input:
$ref: '#/components/schemas/ToolInput'
metadata:
$ref: '#/components/schemas/ContentBlockMetadata'
CreateAgentInputContentBlock:
oneOf:
- $ref: '#/components/schemas/TextContentBlock'
Expand Down
37 changes: 35 additions & 2 deletions frontend/apps/web/src/components/agents/AgentChatMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
import type { OmnaraUIMessage } from '@omnara/react'
import { type OmnaraUIMessage, useOmnaraClient } from '@omnara/react'
import { getActorOptions } from '@omnara/sdk/tanstack'
import { useQuery } from '@tanstack/react-query'
import { Brain, Check, ChevronRight, CircleDashed, Terminal } from 'lucide-react'
import { Streamdown } from 'streamdown'

import { AgentAttachment } from '@/components/agents/AgentAttachment'
import { Bubble, BubbleContent } from '@/components/ui/bubble'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
import { Message, MessageContent } from '@/components/ui/message'
import { Message, MessageContent, MessageHeader } from '@/components/ui/message'

function ActorLabel({
actorID,
orgID,
projectID,
}: {
actorID: string
orgID: string
projectID: string
}) {
const client = useOmnaraClient()
const { data: actor } = useQuery(getActorOptions({ path: { orgID, projectID, actorID }, client }))
if (actor == null) return null

const displayName = actor.display_name?.trim()
const provider =
actor.provider === 'slack' ? 'Slack' : actor.provider === 'external' ? 'External' : 'Omnara'
return (
<MessageHeader>
{displayName == null || displayName === '' ? actor.provider_user_id : displayName}
{` · ${provider}`}
</MessageHeader>
)
}

function JsonValue({ value }: { value: unknown }) {
return (
Expand Down Expand Up @@ -82,9 +108,13 @@ function ToolPart({
export function AgentChatMessage({
message,
currentActorId,
orgID,
projectID,
}: {
message: OmnaraUIMessage
currentActorId?: string
orgID: string
projectID: string
}) {
const metadata = message.metadata
const mine =
Expand All @@ -94,6 +124,9 @@ export function AgentChatMessage({
return (
<Message align={mine ? 'end' : 'start'}>
<MessageContent>
{message.role === 'user' && !mine && metadata?.actorId != null ? (
<ActorLabel actorID={metadata.actorId} orgID={orgID} projectID={projectID} />
) : null}
{message.parts.map((part, index) => {
if (part.type === 'text') {
if (message.role === 'assistant') {
Expand Down
11 changes: 10 additions & 1 deletion frontend/apps/web/src/components/agents/AgentConversation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ import { Spinner } from '@/components/ui/spinner'
export function AgentConversation({
chat,
currentActorId,
orgID,
projectID,
}: {
chat: UseAgentChatResult
currentActorId?: string
orgID: string
projectID: string
}) {
return (
<MessageScrollerProvider>
Expand Down Expand Up @@ -69,7 +73,12 @@ export function AgentConversation({
messageId={message.id}
scrollAnchor={index === chat.messages.length - 1}
>
<AgentChatMessage message={message} currentActorId={currentActorId} />
<AgentChatMessage
message={message}
currentActorId={currentActorId}
orgID={orgID}
projectID={projectID}
/>
</MessageScrollerItem>
))}
</>
Expand Down
7 changes: 6 additions & 1 deletion frontend/apps/web/src/routes/AgentView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ export function AgentView() {
</header>

<main className="min-h-0 flex-1">
<AgentConversation chat={chat} currentActorId={currentActorId} />
<AgentConversation
chat={chat}
currentActorId={currentActorId}
orgID={activeOrg.id}
projectID={projectId}
/>
</main>

<div className="mx-auto grid w-full max-w-3xl shrink-0 gap-3">
Expand Down
15 changes: 13 additions & 2 deletions frontend/packages/react/src/domains/agent-chat-messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,21 @@ function mediaPart(block: MediaRefContentBlock): OmnaraUIMessage['parts'][number
}
}

function isHiddenContentBlock(block: { metadata?: Record<string, unknown> }): boolean {
return block.metadata?.omnara_hidden === 'true'
}

function agentInputParts(event: AgentInputEvent): OmnaraUIMessage['parts'] {
const parts: OmnaraUIMessage['parts'] = []
for (const block of event.content_blocks) {
if (isHiddenContentBlock(block)) continue
if (block.type === 'text') {
parts.push({ type: 'text', text: block.text, state: 'done' })
const displayText = block.metadata?.omnara_display_text
parts.push({
type: 'text',
text: typeof displayText === 'string' ? displayText : block.text,
state: 'done',
})
}
if (block.type === 'media_ref') {
parts.push(mediaPart(block))
Expand All @@ -86,6 +96,7 @@ function agentInputParts(event: AgentInputEvent): OmnaraUIMessage['parts'] {
function modelOutputParts(event: ModelOutputEvent): OmnaraUIMessage['parts'] {
const parts: OmnaraUIMessage['parts'] = []
for (const block of event.content_blocks) {
if (isHiddenContentBlock(block)) continue
if (block.type === 'text') {
parts.push({ type: 'text', text: block.text, state: 'done' })
}
Expand Down Expand Up @@ -189,7 +200,7 @@ export function agentEventsToMessages(
input: part.input,
output: {
outcome: event.outcome,
contentBlocks: event.content_blocks,
contentBlocks: event.content_blocks.filter((block) => !isHiddenContentBlock(block)),
},
}
message.metadata = eventMetadata(event)
Expand Down
Loading
Loading