@design.estate/dees-catalog 3.93.0 → 3.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_bundle/bundle.js +1936 -1376
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.d.ts +6 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.js +34 -4
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.js +49 -45
- package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.d.ts +13 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.demo.js +5 -2
- package/dist_ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.js +118 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.d.ts +25 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.js +156 -48
- package/dist_ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.d.ts +2 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.js +9 -5
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.d.ts +31 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.demo.d.ts +1 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.demo.js +69 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.js +382 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/index.d.ts +1 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/index.js +2 -0
- package/dist_ts_web/elements/00group-harness/index.d.ts +1 -0
- package/dist_ts_web/elements/00group-harness/index.js +2 -1
- package/dist_ts_web/elements/00group-harness/interfaces.d.ts +33 -0
- package/dist_ts_web/elements/00group-harness/toolregistry.js +9 -1
- package/dist_ts_web/elements/00theme.js +6 -1
- package/dist_watch/bundle.js +1937 -1377
- package/dist_watch/bundle.js.map +4 -4
- package/package.json +1 -1
- package/readme.md +13 -5
- package/readme.playbook.md +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.ts +37 -3
- package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.ts +31 -44
- package/ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.demo.ts +4 -1
- package/ts_web/elements/00group-harness/dees-harness-composer/dees-harness-composer.ts +99 -0
- package/ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.ts +148 -46
- package/ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.ts +9 -4
- package/ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.demo.ts +70 -0
- package/ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.ts +319 -0
- package/ts_web/elements/00group-harness/dees-harness-question-card/index.ts +1 -0
- package/ts_web/elements/00group-harness/index.ts +1 -0
- package/ts_web/elements/00group-harness/interfaces.ts +36 -0
- package/ts_web/elements/00group-harness/toolregistry.ts +8 -0
- package/ts_web/elements/00theme.ts +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@design.estate/dees-catalog",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.94.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.",
|
|
6
6
|
"main": "dist_ts_web/index.js",
|
package/readme.md
CHANGED
|
@@ -64,7 +64,7 @@ For developers working on this library, please refer to the [UI Components Playb
|
|
|
64
64
|
| **Dialogs & Overlays** | [`DeesModal`](#deesmodal), [`DeesContextmenu`](#deescontextmenu), [`DeesSpeechbubble`](#deesspeechbubble), [`DeesWindowlayer`](#deeswindowlayer) |
|
|
65
65
|
| **Navigation** | [`DeesStepper`](#deesstepper), [`DeesProgressbar`](#deesprogressbar) |
|
|
66
66
|
| **Workspace / IDE** | [`DeesWorkspace`](#deesworkspace), [`DeesWorkspaceMonaco`](#deesworkspacemonaco), [`DeesWorkspaceDiffEditor`](#deesworkspacediffeditor), [`DeesWorkspaceFiletree`](#deesworkspacefiletree), [`DeesWorkspaceTerminal`](#deesworkspaceterminal), [`DeesWorkspaceTerminalPreview`](#deesworkspaceterminalpreview), [`DeesWorkspaceMarkdown`](#deesworkspacemarkdown), [`DeesWorkspaceMarkdownoutlet`](#deesworkspacemarkdownoutlet), [`DeesWorkspaceBottombar`](#deesworkspacebottombar) |
|
|
67
|
-
| **Agentic Chat** | [`DeesHarnessChat`](#deesharnesschat), [`DeesHarnessMessageList`](#deesharnessmessagelist), [`DeesHarnessMessage`](#deesharnessmessage), [`DeesHarnessReasoning`](#deesharnessreasoning), [`DeesHarnessToolCard`](#deesharnesstoolcard), [`DeesHarnessContentBlocks`](#deesharnesscontentblocks), [`DeesHarnessPermissionCard`](#deesharnesspermissioncard), [`DeesHarnessComposer`](#deesharnesscomposer), [`DeesHarnessStatus`](#deesharnessstatus), [`DeesHarnessTodos`](#deesharnesstodos), [`DeesHarnessUsage`](#deesharnessusage), [`DeesHarnessSessionList`](#deesharnesssessionlist) |
|
|
67
|
+
| **Agentic Chat** | [`DeesHarnessChat`](#deesharnesschat), [`DeesHarnessMessageList`](#deesharnessmessagelist), [`DeesHarnessMessage`](#deesharnessmessage), [`DeesHarnessReasoning`](#deesharnessreasoning), [`DeesHarnessToolCard`](#deesharnesstoolcard), [`DeesHarnessContentBlocks`](#deesharnesscontentblocks), [`DeesHarnessPermissionCard`](#deesharnesspermissioncard), [`DeesHarnessQuestionCard`](#deesharnessquestioncard), [`DeesHarnessComposer`](#deesharnesscomposer), [`DeesHarnessStatus`](#deesharnessstatus), [`DeesHarnessTodos`](#deesharnesstodos), [`DeesHarnessUsage`](#deesharnessusage), [`DeesHarnessSessionList`](#deesharnesssessionlist) |
|
|
68
68
|
| **Theming** | [`DeesTheme`](#deestheme), [`DeesUpdater`](#deesupdater) |
|
|
69
69
|
| **Pre-built Templates** | [`DeesSimpleAppdash`](#deessimpleappdash), [`DeesSimpleLogin`](#deessimplelogin) |
|
|
70
70
|
| **Shopping** | [`DeesShoppingProductcard`](#deesshoppingproductcard) |
|
|
@@ -1699,7 +1699,7 @@ The `00group-harness` family renders what an agent harness produces — streamin
|
|
|
1699
1699
|
|
|
1700
1700
|
#### `DeesHarnessChat`
|
|
1701
1701
|
|
|
1702
|
-
The assembled chat: optional toolbar (heading, usage chip, history/new-session buttons), streaming message list
|
|
1702
|
+
The assembled chat: optional toolbar (heading, usage chip, history/new-session buttons), streaming message list with inline permission cards, transcript status line, and docked composer.
|
|
1703
1703
|
|
|
1704
1704
|
```typescript
|
|
1705
1705
|
const chat = document.querySelector('dees-harness-chat');
|
|
@@ -1721,13 +1721,13 @@ chat.applyDelta({ type: 'text', messageId: 'm1', delta: 'chunk' });
|
|
|
1721
1721
|
chat.applyDelta({ type: 'message-end', messageId: 'm1', usage: { totalTokens: 1200 } });
|
|
1722
1722
|
```
|
|
1723
1723
|
|
|
1724
|
-
Key props: `messages`, `permissions`, `status`, `usage`, `todos`/`showTodosPanel`, `heading`, `subheading`, `showToolbar`, `busy`, `queuedCount`, `disabled`, `model`/`modelOptions`, `reasoningEffort`/`effortOptions`, `toolRegistry`.
|
|
1724
|
+
Key props: `messages`, `permissions`, `questions`, `status`, `usage`, `todos`/`showTodosPanel`, `heading`, `subheading`, `showToolbar`, `busy`, `queuedCount`, `disabled`, `model`/`modelOptions`, `reasoningEffort`/`effortOptions`, `mode`/`modeOptions`, `toolRegistry`. The status line renders inside the transcript column (it never pushes between the Tasks panel and the composer), and both the toolbar and the docked composer cast a subtle shadow over the scrolling messages.
|
|
1725
1725
|
|
|
1726
|
-
A **Tasks side panel** (OpenCode-style) shows the current todo list next to the transcript: set `.todos` explicitly, or leave it empty and the chat derives it from the newest todo tool call in `messages`. The panel hides itself in narrow containers (< 520px) where the transcript's todo cards carry the same information; `showTodosPanel={false}` disables it entirely. Methods: `applyDelta()`, `focusComposer()`, `clearComposer()`, `scrollToBottom()`. Events (also from children, all composed): `harness-send`, `harness-steer`, `harness-abort`, `harness-input`, `harness-attachments-change`, `harness-attachment-error`, `harness-model-change`, `harness-permission-response`, `harness-new-session`, `harness-open-sessions`.
|
|
1726
|
+
A **Tasks side panel** (OpenCode-style) shows the current todo list next to the transcript: set `.todos` explicitly, or leave it empty and the chat derives it from the newest todo tool call in `messages`. The panel hides itself in narrow containers (< 520px) where the transcript's todo cards carry the same information; `showTodosPanel={false}` disables it entirely. Methods: `applyDelta()`, `focusComposer()`, `clearComposer()`, `scrollToBottom()`. Events (also from children, all composed): `harness-send`, `harness-steer`, `harness-abort`, `harness-input`, `harness-attachments-change`, `harness-attachment-error`, `harness-model-change`, `harness-mode-change`, `harness-permission-response`, `harness-question-response`, `harness-new-session`, `harness-open-sessions`.
|
|
1727
1727
|
|
|
1728
1728
|
#### `DeesHarnessMessageList`
|
|
1729
1729
|
|
|
1730
|
-
Scrollable streaming-safe log. Keyed repeat
|
|
1730
|
+
Scrollable streaming-safe log. Keyed repeat keeps DOM identity stable; `applyDelta()` routes updates to the affected message element only. Auto-follows the bottom while pinned; otherwise raises a "Jump to latest" chip instead of yanking the scroll. Permission requests and agent questions render inline in the flow, and while pinned the list follows content growth frame-by-frame (ResizeObserver), so a new box growing into place and the scroll move as one motion. Props: `messages`, `permissions`/`permissionsBusy`, `questions`, `status`, `autoFollow`, `showRoles`, `showTimestamps`, `emptyTitle`/`emptyText` (+ `slot="empty"`).
|
|
1731
1731
|
|
|
1732
1732
|
#### `DeesHarnessMessage`
|
|
1733
1733
|
|
|
@@ -1764,12 +1764,20 @@ Renders MCP `CallToolResult` content structurally: text, base64 images, audio wi
|
|
|
1764
1764
|
|
|
1765
1765
|
Permission prompt: title, type badge (shell/delete → error tone, write/browser → warning), metadata key/values, Allow Once / Always Allow / Reject, and a "remember" checkbox (`always` implies remember). Emits `harness-permission-response`; disables itself once answered or while `busy`.
|
|
1766
1766
|
|
|
1767
|
+
Inside the chat, permission cards render **inline with the messages**: pending requests pin to the end of the transcript (action required), and answered ones freeze at their response time in the flow. Set `response`/`respondedAt` on the request after handling it and keep it in the array — the card stays in the transcript showing what was granted or rejected.
|
|
1768
|
+
|
|
1769
|
+
#### `DeesHarnessQuestionCard`
|
|
1770
|
+
|
|
1771
|
+
A question the agent asks mid-run: option buttons with descriptions (single-select answers on click; `multiSelect` collects then confirms) plus an optional free-text answer (`allowCustom`, default on — Enter or "Send Answer" submits, combining selections with the text). Emits `harness-question-response` with `{ requestId, answers, request }`. Questions flow through `dees-harness-chat`'s `questions` property and render inline like permissions: pending ones pin to the end of the transcript, and answered ones persist showing the chosen answers once the host sets `response`/`respondedAt`.
|
|
1772
|
+
|
|
1767
1773
|
#### `DeesHarnessComposer`
|
|
1768
1774
|
|
|
1769
1775
|
Prompt input: autogrow textarea, attachment picker/paste/drag-drop with per-file (10 MB) and total (30 MB) limits and MIME allowlist, optional model + reasoning-effort dropdowns, Cmd/Ctrl+Enter to send. Controlled component — the host owns `value` and `attachments`.
|
|
1770
1776
|
|
|
1771
1777
|
While `busy`, Stop renders as an additional button and Send stays available so hosts can queue messages. With an empty prompt and `queuedCount > 0`, the primary action becomes **Steer now** (`harness-steer` event) to force the agent to continue with the queued messages immediately.
|
|
1772
1778
|
|
|
1779
|
+
Set `modeOptions` (e.g. `['Planning', 'Building']`) to render a segmented **mode switcher**; the active `mode` changes on click — or **Shift+Tab** inside the prompt cycles it — and emits `harness-mode-change`. Inside `dees-harness-chat` the composer renders `docked` — flush edge-to-edge with a top border and an upward shadow (`--dees-shadow-up-sm`) so it meets the transcript and the Tasks panel like the toolbar does; standalone composers keep the floating-card chrome.
|
|
1780
|
+
|
|
1773
1781
|
#### `DeesHarnessTodos`
|
|
1774
1782
|
|
|
1775
1783
|
Agent task list for `IHarnessTodoItem[]` — completed items dim with a check and strikethrough, the in-progress item leads with a pulsing accent marker, and an optional heading shows `completed/total` progress. Used automatically as the todo tool-card body (`harnessParseTodos` normalizes tool input shapes) and standalone for a "current tasks" sidebar panel fed from the latest `todowrite` call.
|
package/readme.playbook.md
CHANGED
|
@@ -439,7 +439,7 @@ Components that render continuously arriving data (agent chat, logs) follow the
|
|
|
439
439
|
- **Props are the source of truth; deltas are the fast path.** The host owns the array (e.g. `.messages`). Incremental updates go through `applyDelta()`, which mutates the same object instance held in the array and calls `requestUpdate()` on the one affected child element. A later wholesale re-assignment of the array is therefore idempotent — no divergence between streamed and re-set state.
|
|
440
440
|
- **Keyed `repeat` for identity.** List children render via `directives.repeat` keyed by a stable id so streaming never recreates sibling DOM (which would drop scroll position, expansion state, and selection).
|
|
441
441
|
- **Cheap while streaming, rich when done.** While `streaming` is set, text renders as pre-wrap with a cursor; expensive work (markdown parse) is throttled (≥150 ms, token-guarded like the codebox highlight pattern) and syntax highlighting waits for the final parse.
|
|
442
|
-
- **Scroll follow with user override.** Auto-scroll only when the user is already pinned to the bottom (`scrollHeight - scrollTop - clientHeight < threshold`); otherwise show a "jump to latest" chip.
|
|
442
|
+
- **Scroll follow with user override.** Auto-scroll only when the user is already pinned to the bottom (`scrollHeight - scrollTop - clientHeight < threshold`); otherwise show a "jump to latest" chip. While pinned, a content change opens a short follow window and a `ResizeObserver` on the scroll content re-pins the bottom on every layout change (post-layout, pre-paint), so a growing box and the scroll move as one motion; an external upward scroll ends the window before the next pin so following never fights the user. Disconnect the observer in `disconnectedCallback`.
|
|
443
443
|
- **Interaction state lives on the child.** Expand/collapse (reasoning, tool cards) is element-local state seeded from data (`expanded ?? isStreaming`), so parent re-renders can't reset what the user opened.
|
|
444
444
|
|
|
445
445
|
## Performance Optimization
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@design.estate/dees-catalog',
|
|
6
|
-
version: '3.
|
|
6
|
+
version: '3.94.0',
|
|
7
7
|
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
|
|
8
8
|
}
|
|
@@ -223,6 +223,23 @@ const simulate = (event: MouseEvent) => {
|
|
|
223
223
|
});
|
|
224
224
|
};
|
|
225
225
|
|
|
226
|
+
const askQuestion = (event: MouseEvent) => {
|
|
227
|
+
const chat = chatOf(event);
|
|
228
|
+
if (!chat) return;
|
|
229
|
+
chat.questions = [
|
|
230
|
+
...chat.questions,
|
|
231
|
+
{
|
|
232
|
+
id: `question-${Date.now()}`,
|
|
233
|
+
question: 'Which cache-key strategy should I roll out?',
|
|
234
|
+
createdAt: Date.now(),
|
|
235
|
+
options: [
|
|
236
|
+
{ label: 'Route manifest hash', description: 'Deterministic, invalidates on route changes' },
|
|
237
|
+
{ label: 'Content hash', description: 'Fine-grained, more churn' },
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
];
|
|
241
|
+
};
|
|
242
|
+
|
|
226
243
|
const askPermission = (event: MouseEvent) => {
|
|
227
244
|
const chat = chatOf(event);
|
|
228
245
|
if (!chat) return;
|
|
@@ -274,9 +291,23 @@ export const demoFunc = () => html`
|
|
|
274
291
|
console.log('harness-permission-response', event.detail);
|
|
275
292
|
const chat = (event.target as HTMLElement).closest('.chatDemo')?.querySelector('dees-harness-chat');
|
|
276
293
|
if (chat) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
294
|
+
// answered cards stay in the transcript showing the outcome
|
|
295
|
+
chat.permissions = chat.permissions.map((request) =>
|
|
296
|
+
request.id === event.detail.requestId
|
|
297
|
+
? { ...request, response: event.detail.response, respondedAt: Date.now() }
|
|
298
|
+
: request,
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
}}
|
|
302
|
+
@harness-question-response=${(event: CustomEvent) => {
|
|
303
|
+
console.log('harness-question-response', event.detail);
|
|
304
|
+
const chat = (event.target as HTMLElement).closest('.chatDemo')?.querySelector('dees-harness-chat');
|
|
305
|
+
if (chat) {
|
|
306
|
+
chat.questions = chat.questions.map((request) =>
|
|
307
|
+
request.id === event.detail.requestId
|
|
308
|
+
? { ...request, response: event.detail.answers, respondedAt: Date.now() }
|
|
309
|
+
: request,
|
|
310
|
+
);
|
|
280
311
|
}
|
|
281
312
|
}}
|
|
282
313
|
@harness-new-session=${() => console.log('harness-new-session')}
|
|
@@ -289,6 +320,7 @@ export const demoFunc = () => html`
|
|
|
289
320
|
<div class="controls">
|
|
290
321
|
<dees-button type="accent" @clicked=${simulate}>Simulate streaming</dees-button>
|
|
291
322
|
<dees-button @clicked=${askPermission}>Ask permission</dees-button>
|
|
323
|
+
<dees-button @clicked=${askQuestion}>Ask a question</dees-button>
|
|
292
324
|
<dees-button @clicked=${toggleError}>Toggle error status</dees-button>
|
|
293
325
|
<dees-button type="ghost" @clicked=${resetChat}>Reset</dees-button>
|
|
294
326
|
</div>
|
|
@@ -297,6 +329,8 @@ export const demoFunc = () => html`
|
|
|
297
329
|
subheading="acme-app · main · connected"
|
|
298
330
|
model="gpt-5.5"
|
|
299
331
|
reasoningEffort="high"
|
|
332
|
+
mode="Building"
|
|
333
|
+
.modeOptions=${['Planning', 'Building']}
|
|
300
334
|
.modelOptions=${['gpt-5.5', 'gpt-5', 'o4-mini']}
|
|
301
335
|
.effortOptions=${['xhigh', 'high', 'medium', 'low']}
|
|
302
336
|
.usage=${{ inputTokens: 18_400, outputTokens: 3_100, totalTokens: 21_500 }}
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
IHarnessAttachment,
|
|
14
14
|
IHarnessMessage,
|
|
15
15
|
IHarnessPermissionRequest,
|
|
16
|
+
IHarnessQuestionRequest,
|
|
16
17
|
IHarnessStatus,
|
|
17
18
|
IHarnessTodoItem,
|
|
18
19
|
IHarnessUsage,
|
|
@@ -22,8 +23,6 @@ import { harnessParseTodos } from '../harness.helpers.js';
|
|
|
22
23
|
import { DeesHarnessToolRegistry } from '../toolregistry.js';
|
|
23
24
|
import { DeesHarnessMessageList } from '../dees-harness-message-list/dees-harness-message-list.js';
|
|
24
25
|
import { DeesHarnessComposer } from '../dees-harness-composer/dees-harness-composer.js';
|
|
25
|
-
import '../dees-harness-permission-card/dees-harness-permission-card.js';
|
|
26
|
-
import '../dees-harness-status/dees-harness-status.js';
|
|
27
26
|
import '../dees-harness-todos/dees-harness-todos.js';
|
|
28
27
|
import '../dees-harness-usage/dees-harness-usage.js';
|
|
29
28
|
import '../../00group-button/dees-button/dees-button.js';
|
|
@@ -35,9 +34,6 @@ declare global {
|
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
// stable idle binding for the embedded list — a fresh object literal per
|
|
39
|
-
// render would re-trigger its follow logic on every chat render
|
|
40
|
-
const idleStatus: IHarnessStatus = { type: 'idle' };
|
|
41
37
|
|
|
42
38
|
/**
|
|
43
39
|
* The assembled agent chat: optional toolbar, streaming message list,
|
|
@@ -58,6 +54,10 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
58
54
|
@property({ attribute: false })
|
|
59
55
|
accessor permissions: IHarnessPermissionRequest[] = [];
|
|
60
56
|
|
|
57
|
+
/** agent questions render inline like permissions; answered ones persist */
|
|
58
|
+
@property({ attribute: false })
|
|
59
|
+
accessor questions: IHarnessQuestionRequest[] = [];
|
|
60
|
+
|
|
61
61
|
@property({ attribute: false })
|
|
62
62
|
accessor status: IHarnessStatus = { type: 'idle' };
|
|
63
63
|
|
|
@@ -115,6 +115,13 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
115
115
|
@property({ attribute: false })
|
|
116
116
|
accessor effortOptions: string[] = [];
|
|
117
117
|
|
|
118
|
+
/** agent mode switcher (e.g. Planning / Building); empty hides it */
|
|
119
|
+
@property()
|
|
120
|
+
accessor mode: string = '';
|
|
121
|
+
|
|
122
|
+
@property({ attribute: false })
|
|
123
|
+
accessor modeOptions: string[] = [];
|
|
124
|
+
|
|
118
125
|
@property({ attribute: false })
|
|
119
126
|
accessor toolRegistry: DeesHarnessToolRegistry = DeesHarnessToolRegistry.default;
|
|
120
127
|
|
|
@@ -166,6 +173,10 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
166
173
|
padding: var(--dees-spacing-sm) var(--dees-spacing-md);
|
|
167
174
|
border-bottom: 1px solid var(--dees-color-border-subtle);
|
|
168
175
|
background: var(--dees-color-bg-secondary);
|
|
176
|
+
/* chrome floats above the scrolling transcript */
|
|
177
|
+
position: relative;
|
|
178
|
+
z-index: 1;
|
|
179
|
+
box-shadow: var(--dees-shadow-sm);
|
|
169
180
|
}
|
|
170
181
|
|
|
171
182
|
.headingBlock {
|
|
@@ -203,32 +214,13 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
203
214
|
min-height: 0;
|
|
204
215
|
}
|
|
205
216
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
padding: 0 var(--dees-spacing-md);
|
|
210
|
-
max-height: 40%;
|
|
211
|
-
overflow-y: auto;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
.permissionQueue > * + * {
|
|
215
|
-
margin-top: var(--dees-spacing-xs);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/* always mounted so the status leave transition can play; the status
|
|
219
|
-
element renders empty when idle, collapsing the row to zero height */
|
|
220
|
-
.statusRow {
|
|
221
|
-
flex: 0 0 auto;
|
|
222
|
-
padding: 0 var(--dees-spacing-md);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
.statusRow dees-harness-status {
|
|
226
|
-
margin: 0;
|
|
227
|
-
}
|
|
228
|
-
|
|
217
|
+
/* the composer docks edge-to-edge like the toolbar, so the tasks
|
|
218
|
+
panel's border meets its top border cleanly; z-order keeps its
|
|
219
|
+
upward shadow above the transcript */
|
|
229
220
|
.composerRow {
|
|
230
221
|
flex: 0 0 auto;
|
|
231
|
-
|
|
222
|
+
position: relative;
|
|
223
|
+
z-index: 1;
|
|
232
224
|
}
|
|
233
225
|
`,
|
|
234
226
|
];
|
|
@@ -285,7 +277,10 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
285
277
|
<div class="chatBody">
|
|
286
278
|
<dees-harness-message-list
|
|
287
279
|
.messages=${this.messages}
|
|
288
|
-
.
|
|
280
|
+
.permissions=${this.permissions}
|
|
281
|
+
.permissionsBusy=${this.disabled}
|
|
282
|
+
.questions=${this.questions}
|
|
283
|
+
.status=${this.status}
|
|
289
284
|
.showRoles=${this.showRoles}
|
|
290
285
|
.toolRegistry=${this.toolRegistry}
|
|
291
286
|
></dees-harness-message-list>
|
|
@@ -297,22 +292,9 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
297
292
|
`
|
|
298
293
|
: ''}
|
|
299
294
|
</div>
|
|
300
|
-
${this.permissions.length
|
|
301
|
-
? html`
|
|
302
|
-
<div class="permissionQueue">
|
|
303
|
-
${this.permissions.map(
|
|
304
|
-
(request) => html`
|
|
305
|
-
<dees-harness-permission-card .request=${request} .busy=${this.disabled}></dees-harness-permission-card>
|
|
306
|
-
`,
|
|
307
|
-
)}
|
|
308
|
-
</div>
|
|
309
|
-
`
|
|
310
|
-
: ''}
|
|
311
|
-
<div class="statusRow">
|
|
312
|
-
<dees-harness-status .status=${this.status}></dees-harness-status>
|
|
313
|
-
</div>
|
|
314
295
|
<div class="composerRow">
|
|
315
296
|
<dees-harness-composer
|
|
297
|
+
docked
|
|
316
298
|
.value=${this.composerValue}
|
|
317
299
|
.attachments=${this.attachments}
|
|
318
300
|
.disabled=${this.disabled}
|
|
@@ -322,6 +304,8 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
322
304
|
.modelOptions=${this.modelOptions}
|
|
323
305
|
.reasoningEffort=${this.reasoningEffort}
|
|
324
306
|
.effortOptions=${this.effortOptions}
|
|
307
|
+
.mode=${this.mode}
|
|
308
|
+
.modeOptions=${this.modeOptions}
|
|
325
309
|
@harness-input=${(event: CustomEvent<{ value: string }>) => {
|
|
326
310
|
this.composerValue = event.detail?.value ?? '';
|
|
327
311
|
}}
|
|
@@ -332,6 +316,9 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
332
316
|
if (event.detail?.model) this.model = event.detail.model;
|
|
333
317
|
if (event.detail?.reasoningEffort) this.reasoningEffort = event.detail.reasoningEffort;
|
|
334
318
|
}}
|
|
319
|
+
@harness-mode-change=${(event: CustomEvent<{ mode?: string }>) => {
|
|
320
|
+
if (event.detail?.mode) this.mode = event.detail.mode;
|
|
321
|
+
}}
|
|
335
322
|
></dees-harness-composer>
|
|
336
323
|
</div>
|
|
337
324
|
`;
|
|
@@ -30,11 +30,14 @@ export const demoFunc = () => html`
|
|
|
30
30
|
@harness-attachments-change=${logEvent}
|
|
31
31
|
@harness-attachment-error=${logEvent}
|
|
32
32
|
@harness-model-change=${logEvent}
|
|
33
|
+
@harness-mode-change=${logEvent}
|
|
33
34
|
>
|
|
34
|
-
<div class="label">default with model controls (events log to console)</div>
|
|
35
|
+
<div class="label">default with mode switcher + model controls (events log to console)</div>
|
|
35
36
|
<dees-harness-composer
|
|
36
37
|
model="gpt-5.5"
|
|
37
38
|
reasoningEffort="high"
|
|
39
|
+
mode="Planning"
|
|
40
|
+
.modeOptions=${['Planning', 'Building']}
|
|
38
41
|
.modelOptions=${['gpt-5.5', 'gpt-5', 'o4-mini']}
|
|
39
42
|
.effortOptions=${['xhigh', 'high', 'medium', 'low']}
|
|
40
43
|
></dees-harness-composer>
|
|
@@ -57,6 +57,15 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
57
57
|
@property()
|
|
58
58
|
accessor placeholder: string = 'Message the agent — drop or paste files to attach…';
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Docked composers sit flush against their container edge-to-edge (a
|
|
62
|
+
* top border instead of the floating card chrome) — used by
|
|
63
|
+
* dees-harness-chat so the bar meets the transcript and the tasks panel
|
|
64
|
+
* without a gap.
|
|
65
|
+
*/
|
|
66
|
+
@property({ type: Boolean, reflect: true })
|
|
67
|
+
accessor docked: boolean = false;
|
|
68
|
+
|
|
60
69
|
@property({ type: Boolean })
|
|
61
70
|
accessor disabled: boolean = false;
|
|
62
71
|
|
|
@@ -94,6 +103,16 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
94
103
|
@property({ attribute: false })
|
|
95
104
|
accessor effortOptions: string[] = [];
|
|
96
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Agent mode switcher (e.g. Planning / Building). Renders a segmented
|
|
108
|
+
* control when modeOptions is set; emits harness-mode-change.
|
|
109
|
+
*/
|
|
110
|
+
@property()
|
|
111
|
+
accessor mode: string = '';
|
|
112
|
+
|
|
113
|
+
@property({ attribute: false })
|
|
114
|
+
accessor modeOptions: string[] = [];
|
|
115
|
+
|
|
97
116
|
@property({ type: Boolean })
|
|
98
117
|
accessor showModelControls: boolean = true;
|
|
99
118
|
|
|
@@ -121,6 +140,19 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
121
140
|
box-shadow: 0 0 0 3px var(--dees-color-focus-ring);
|
|
122
141
|
}
|
|
123
142
|
|
|
143
|
+
:host([docked]) .composer {
|
|
144
|
+
border: 0;
|
|
145
|
+
border-top: 1px solid var(--dees-color-border-subtle);
|
|
146
|
+
border-radius: 0;
|
|
147
|
+
padding: var(--dees-spacing-sm) var(--dees-spacing-md) var(--dees-spacing-md);
|
|
148
|
+
box-shadow: var(--dees-shadow-up-sm);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
:host([docked]) .composer.dragOver {
|
|
152
|
+
border-top-color: var(--dees-color-accent-primary);
|
|
153
|
+
box-shadow: inset 0 3px 0 0 var(--dees-color-focus-ring);
|
|
154
|
+
}
|
|
155
|
+
|
|
124
156
|
.fileInput {
|
|
125
157
|
display: none;
|
|
126
158
|
}
|
|
@@ -214,6 +246,44 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
214
246
|
gap: var(--dees-spacing-sm);
|
|
215
247
|
}
|
|
216
248
|
|
|
249
|
+
/* segmented mode switcher (Planning / Building) */
|
|
250
|
+
.modeSwitch {
|
|
251
|
+
display: inline-flex;
|
|
252
|
+
flex: 0 0 auto;
|
|
253
|
+
padding: 2px;
|
|
254
|
+
border-radius: var(--dees-radius-md);
|
|
255
|
+
corner-shape: var(--dees-corner-shape);
|
|
256
|
+
background: var(--dees-color-fill-secondary);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.modeSwitch button {
|
|
260
|
+
height: calc(var(--dees-control-height-sm) - 4px);
|
|
261
|
+
padding: 0 10px;
|
|
262
|
+
border: 0;
|
|
263
|
+
border-radius: calc(var(--dees-radius-md) - 2px);
|
|
264
|
+
corner-shape: var(--dees-corner-shape);
|
|
265
|
+
background: transparent;
|
|
266
|
+
color: var(--dees-color-text-secondary);
|
|
267
|
+
cursor: pointer;
|
|
268
|
+
font-family: inherit;
|
|
269
|
+
font-size: var(--dees-font-control-size-sm, 12px);
|
|
270
|
+
font-weight: 500;
|
|
271
|
+
transition:
|
|
272
|
+
background var(--dees-transition-fast) var(--dees-ease-standard),
|
|
273
|
+
color var(--dees-transition-fast) var(--dees-ease-standard);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.modeSwitch button.active {
|
|
277
|
+
background: var(--dees-color-bg-primary);
|
|
278
|
+
color: var(--dees-color-text-primary);
|
|
279
|
+
box-shadow: var(--dees-shadow-xs);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.modeSwitch button:disabled {
|
|
283
|
+
cursor: default;
|
|
284
|
+
opacity: 0.55;
|
|
285
|
+
}
|
|
286
|
+
|
|
217
287
|
.modelControls {
|
|
218
288
|
display: flex;
|
|
219
289
|
gap: var(--dees-spacing-xs);
|
|
@@ -289,6 +359,26 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
289
359
|
>
|
|
290
360
|
<dees-icon icon="lucide:Paperclip" iconSize="14"></dees-icon>
|
|
291
361
|
</dees-button>
|
|
362
|
+
${this.modeOptions.length
|
|
363
|
+
? html`
|
|
364
|
+
<div class="modeSwitch" role="radiogroup" aria-label="Agent mode">
|
|
365
|
+
${this.modeOptions.map((option) => html`
|
|
366
|
+
<button
|
|
367
|
+
type="button"
|
|
368
|
+
role="radio"
|
|
369
|
+
aria-checked=${option === this.mode ? 'true' : 'false'}
|
|
370
|
+
class=${option === this.mode ? 'active' : ''}
|
|
371
|
+
?disabled=${this.disabled}
|
|
372
|
+
@click=${() => {
|
|
373
|
+
if (this.mode === option) return;
|
|
374
|
+
this.mode = option;
|
|
375
|
+
this.emit('harness-mode-change', { mode: option });
|
|
376
|
+
}}
|
|
377
|
+
>${option}</button>
|
|
378
|
+
`)}
|
|
379
|
+
</div>
|
|
380
|
+
`
|
|
381
|
+
: ''}
|
|
292
382
|
${this.showModelControls && (this.modelOptions.length || this.effortOptions.length)
|
|
293
383
|
? html`
|
|
294
384
|
<div class="modelControls">
|
|
@@ -391,6 +481,15 @@ export class DeesHarnessComposer extends DeesElement {
|
|
|
391
481
|
if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
|
|
392
482
|
event.preventDefault();
|
|
393
483
|
this.send();
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
// Shift+Tab cycles the agent mode without leaving the prompt
|
|
487
|
+
if (event.key === 'Tab' && event.shiftKey && this.modeOptions.length) {
|
|
488
|
+
event.preventDefault();
|
|
489
|
+
const currentIndex = this.modeOptions.indexOf(this.mode);
|
|
490
|
+
const nextMode = this.modeOptions[(currentIndex + 1) % this.modeOptions.length];
|
|
491
|
+
this.mode = nextMode;
|
|
492
|
+
this.emit('harness-mode-change', { mode: nextMode });
|
|
394
493
|
}
|
|
395
494
|
};
|
|
396
495
|
|