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
32 changes: 27 additions & 5 deletions nx2/blocks/chat/chat.css
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
padding: 0 var(--s2-spacing-300);
box-sizing: border-box;
justify-content: flex-end;
gap: var(--s2-spacing-300);
gap: var(--s2-spacing-100);

.chat-header-btn {
display: inline-flex;
Expand All @@ -98,7 +98,7 @@
color: var(--s2-gray-800);
cursor: pointer;
font-family: inherit;
font-size: var(--s2-body-size-s);
font-size: var(--s2-body-size-xs);

&.clear-btn {
padding: 0 var(--s2-spacing-100);
Expand Down Expand Up @@ -190,6 +190,10 @@
color: var(--s2-gray-500);
overflow-wrap: break-word;
}

&.tool-card-detail {
margin-left: 14px;
}
}

.directive {
Expand All @@ -203,6 +207,7 @@

.directive-checklist ul {
list-style: none;
padding: 0;
}

.directive-toggle-list {
Expand Down Expand Up @@ -306,8 +311,25 @@
gap: var(--s2-spacing-75);
}

.message-content p {
margin: 0;
.message-content {
p {
margin: 0;
}

code {
background: var(--s2-gray-75);
border-radius: var(--s2-corner-radius-75);
padding: var(--s2-spacing-50);
overflow-x: auto;
margin: 0;
font-size: var(--s2-body-size-xs);
}

hr {
border: none;
height: 1px;
background: var(--s2-gray-200);
}
}

.message-content code {
Expand All @@ -320,7 +342,7 @@
}

.message-action-copy {
align-self: flex-end;
align-self: flex-start;
visibility: hidden;
box-sizing: border-box;
width: 20px;
Expand Down
13 changes: 11 additions & 2 deletions nx2/blocks/chat/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,19 @@ class NxChat extends LitElement {
}));
},
onUpdate: ({ messages, thinking, streamingText, connected, toolCards }) => {
this.messages = streamingText
const newMessages = streamingText
? [...(messages ?? []), { role: ROLE.ASSISTANT, content: streamingText, streaming: true }]
: messages;
this.thinking = thinking;
this.connected = connected;
this.toolCards = toolCards;
cancelAnimationFrame(this._updateRaf);
this._updateRaf = requestAnimationFrame(() => {
this.messages = newMessages;
this.thinking = thinking;
this.connected = connected;
this.toolCards = toolCards;
});
},
});
if (this._context) this._controller.setContext(this._context);
Expand All @@ -209,6 +216,7 @@ class NxChat extends LitElement {

disconnectedCallback() {
super.disconnectedCallback();
cancelAnimationFrame(this._updateRaf);
(this._items ?? []).forEach((item) => {
if (item.thumbnail) URL.revokeObjectURL(item.thumbnail);
});
Expand Down Expand Up @@ -252,7 +260,8 @@ class NxChat extends LitElement {
if (changed.has('messages')) {
const log = this.shadowRoot.querySelector('.chat-scroll-container');
if (log && this._wasNearBottom) {
requestAnimationFrame(() => { log.scrollTop = log.scrollHeight; });
cancelAnimationFrame(this._scrollRaf);
this._scrollRaf = requestAnimationFrame(() => { log.scrollTop = log.scrollHeight; });
}
}
if (changed.has('thinking') && !this.thinking && changed.get('thinking')) {
Expand Down
11 changes: 3 additions & 8 deletions nx2/blocks/chat/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,14 @@ const MENU_OPTIONS = {

const ADD_MENU_ITEMS = [
{ section: 'Add' },
{ id: 'files', label: 'Files or images', icon: 'link' },
{ id: MENU_OPTIONS.PROMPT, label: 'Prompt' },
{ id: 'command', label: '"/" Command' },
{ id: MENU_OPTIONS.FILES, label: 'Files or images', icon: 'link' },
{ id: MENU_OPTIONS.PROMPT, label: 'Prompt', icon: 'commentremove' },
{ id: MENU_OPTIONS.COMMAND, label: '"/" Command', icon: 'prompt' },
{ divider: true },
{ id: 'prompts', label: 'Manage Prompts' },
{ id: 'skills', label: 'Manage Skills' },
];

const CHAT_ICONS = {
add: 'Add', clear: 'RemoveCircle', close: 'SplitLeft', send: 'ArrowUpSend', stop: 'Stop', up: 'ChevronUp',
};

/**
* Agent stream event types.
* Source: Vercel AI SDK v6 UIMessageStream format, as emitted by da-agent.
Expand Down Expand Up @@ -96,7 +92,6 @@ export {
ADOBE_AI_GUIDELINES_URL,
ADD_MENU_ITEMS,
AGENT_EVENT,
CHAT_ICONS,
MENU_OPTIONS,
ROLE,
TOOL_INPUT,
Expand Down
18 changes: 10 additions & 8 deletions nx2/blocks/chat/renderers.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,35 @@ function renderMessageContent(text) {
if (!text) return nothing;

return parseDirectives(text).map(({ kind, type, content }) => {
if (!content) return nothing;
const dom = toDOM(mdast2hast(parser.parse(content)));
return kind === 'directive' ? html`<div class="directive directive-${type}">${dom}</div>` : dom;
});
}

function approvalSummary(input) {
function approvalSummary(input, { json = false } = {}) {
if (!input) return null;
const {
HUMAN_READABLE_SUMMARY, SOURCE_PATH, DESTINATION_PATH, PATH, SKILL_ID, NAME,
} = TOOL_INPUT;
return input[HUMAN_READABLE_SUMMARY]
?? (input[SOURCE_PATH] && input[DESTINATION_PATH] ? `${input[SOURCE_PATH]} → ${input[DESTINATION_PATH]}` : null)
?? input[PATH] ?? input[SKILL_ID] ?? input[NAME] ?? null;
?? input[PATH] ?? input[SKILL_ID] ?? input[NAME]
?? (json ? JSON.stringify(input, null, 2) : null);
}

function renderToolCard(toolCallId, toolCards) {
const card = toolCards?.get(toolCallId);
if (!card || card.state === TOOL_STATE.APPROVAL_REQUESTED) return nothing;
const { toolName, state, input } = card;
const detail = approvalSummary(input);
const detail = approvalSummary(input, { json: true });
const failed = state === TOOL_STATE.ERROR || state === TOOL_STATE.REJECTED;
return html`
const status = failed ? html`<span class="tool-card-status">${state}</span>` : nothing;
return detail ? html`
<details class="tool-card tool-card-${state}">
<summary>${toolName}${failed ? html`<span class="tool-card-status">${state}</span>` : nothing}</summary>
${detail ? html`<span class="tool-card-detail">${detail}</span>` : nothing}
</details>
`;
<summary>${toolName}${status}</summary>
<span class="tool-card-detail">${detail}</span>
</details>` : html`<span class="tool-card-detail">${toolName}${status}</span>`;
}

function renderApprovalCard(pending, onApprove) {
Expand Down
8 changes: 4 additions & 4 deletions nx2/blocks/shared/menu/menu.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
display: block;
padding: var(--s2-spacing-75) var(--s2-spacing-100);
color: light-dark(var(--s2-gray-600), var(--s2-gray-700));
font-size: var(--s2-body-size-xs);
font-weight: var(--s2-heading-font-weight);
font-size: var(--s2-body-size-xxs);
line-height: var(--s2-component-xs-regular-line-height);
cursor: default;
}

Expand All @@ -29,8 +29,8 @@
background: none;
color: var(--s2-gray-900);
font-family: inherit;
font-size: var(--s2-body-size-s);
margin-bottom: 2px;
font-size: var(--s2-body-size-xs);
line-height: var(--s2-component-s-regular-line-height);
cursor: pointer;
box-sizing: border-box;
outline: none;
Expand Down
Loading