aimeat 1.16.2 → 1.18.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/.env.example +6 -1
- package/dist/locales/en.json +166 -4
- package/dist/locales/fi.json +166 -4
- package/dist/public/components/Card.js +17 -3
- package/dist/public/components/Collapsible.js +39 -0
- package/dist/public/components/CopyButton.js +55 -24
- package/dist/public/components/DataTable.js +57 -0
- package/dist/public/components/EmptyState.js +28 -0
- package/dist/public/components/KeyValueRow.js +37 -0
- package/dist/public/components/Modal.js +22 -5
- package/dist/public/components/Pagination.js +70 -0
- package/dist/public/components/SearchBar.js +44 -0
- package/dist/public/components/StatusDot.js +29 -0
- package/dist/public/components/TagList.js +53 -0
- package/dist/public/components/ToggleSwitch.js +28 -0
- package/dist/public/components/index.js +41 -1
- package/dist/public/css/components/tags.css +24 -0
- package/dist/public/css/style-testbed.css +135 -0
- package/dist/public/css/theme.css +556 -34
- package/dist/public/css/views/admin-agent-integration.css +2 -33
- package/dist/public/css/views/admin.css +730 -686
- package/dist/public/css/views/agents-detail.css +402 -14
- package/dist/public/css/views/help.css +2 -1
- package/dist/public/css/views/hobbies.css +53 -33
- package/dist/public/css/views/marketplace.css +73 -60
- package/dist/public/css/views/openclaw.css +12 -6
- package/dist/public/css/views/portal-classic.css +34 -26
- package/dist/public/css/views/portal-dev.css +41 -32
- package/dist/public/css/views/portal.css +14 -18
- package/dist/public/css/views/profile.css +252 -164
- package/dist/public/css/views/public-knowledge-viewer.css +18 -6
- package/dist/public/css/views/scheduler.css +100 -0
- package/dist/public/js/format.js +41 -0
- package/dist/public/js/services/agent-tasks.js +14 -1
- package/dist/public/js/services/generator-spec-validate.js +5 -1
- package/dist/public/js/services/schedules.js +53 -0
- package/dist/public/js/style-testbed.js +170 -0
- package/dist/public/js/theme.js +114 -0
- package/dist/public/spa.html +74 -16
- package/dist/public/style-testbed.html +420 -0
- package/dist/public/views/admin/agent-integration-tab.js +23 -38
- package/dist/public/views/admin/agent-tasks-tab.js +14 -21
- package/dist/public/views/admin/chat-instances-tab.js +1 -1
- package/dist/public/views/admin/config-tab.js +7 -2
- package/dist/public/views/admin/cortex-tab.js +20 -14
- package/dist/public/views/admin/csm-tab.js +22 -18
- package/dist/public/views/admin/directory-tab.js +3 -3
- package/dist/public/views/admin/email-tab.js +23 -28
- package/dist/public/views/admin/federation-tab.js +15 -5
- package/dist/public/views/admin/generator-debug-tab.js +10 -8
- package/dist/public/views/admin/genesis-tab.js +4 -4
- package/dist/public/views/admin/ghii-tab.js +3 -3
- package/dist/public/views/admin/knowledge-tab.js +15 -5
- package/dist/public/views/admin/matching-tab.js +3 -3
- package/dist/public/views/admin/memory-tab.js +16 -20
- package/dist/public/views/admin/msm-tab.js +30 -17
- package/dist/public/views/admin/overview-tab.js +7 -7
- package/dist/public/views/admin/packages-tab.js +10 -9
- package/dist/public/views/admin/portal-tab.js +14 -4
- package/dist/public/views/admin/prompts-tab.js +5 -5
- package/dist/public/views/admin/push-tab.js +15 -4
- package/dist/public/views/admin/realtime-tab.js +3 -3
- package/dist/public/views/admin/services-tab.js +18 -27
- package/dist/public/views/admin/shared.js +48 -58
- package/dist/public/views/admin/sharing-groups-tab.js +5 -10
- package/dist/public/views/admin/stats-tab.js +3 -3
- package/dist/public/views/guides.js +9 -13
- package/dist/public/views/help.js +3 -24
- package/dist/public/views/hobbies.js +47 -41
- package/dist/public/views/marketplace.js +42 -34
- package/dist/public/views/openclaw.js +0 -1
- package/dist/public/views/portal-classic.js +4 -15
- package/dist/public/views/portal-dev.js +28 -30
- package/dist/public/views/portal.js +16 -21
- package/dist/public/views/portfolio.js +11 -12
- package/dist/public/views/profile/access-tab.js +250 -1
- package/dist/public/views/profile/agents/agent-card.js +75 -4
- package/dist/public/views/profile/agents/tab-activity.js +15 -13
- package/dist/public/views/profile/agents/tab-agent-config.js +60 -6
- package/dist/public/views/profile/agents/tab-integration.js +37 -60
- package/dist/public/views/profile/agents/tab-messages.js +10 -1
- package/dist/public/views/profile/agents/tab-quality.js +25 -19
- package/dist/public/views/profile/agents/tab-schedules.js +110 -0
- package/dist/public/views/profile/agents-activity-subtab.js +4 -4
- package/dist/public/views/profile/agents-services-subtab.js +5 -4
- package/dist/public/views/profile/agents-tab.js +141 -37
- package/dist/public/views/profile/agents-tasks-subtab.js +221 -26
- package/dist/public/views/profile/calibrator-batch.js +5 -11
- package/dist/public/views/profile/calibrator-tab.js +4 -9
- package/dist/public/views/profile/chat-sessions-tab.js +9 -5
- package/dist/public/views/profile/email-tab.js +2 -2
- package/dist/public/views/profile/extensions-tab.js +27 -22
- package/dist/public/views/profile/federation-tab.js +4 -1
- package/dist/public/views/profile/foundry-detail.js +22 -23
- package/dist/public/views/profile/foundry-tab.js +12 -13
- package/dist/public/views/profile/generator-dashboard/DebugPanel.js +4 -7
- package/dist/public/views/profile/generator-dashboard/use-dashboard-core.js +4 -1
- package/dist/public/views/profile/generator-dashboard/use-edit-mode.js +3 -2
- package/dist/public/views/profile/generator-detail.js +26 -30
- package/dist/public/views/profile/generator-tab.js +5 -5
- package/dist/public/views/profile/knowledge-tab.js +12 -12
- package/dist/public/views/profile/landing-page.js +100 -149
- package/dist/public/views/profile/memory-tab.js +15 -11
- package/dist/public/views/profile/node-stats-tab.js +3 -3
- package/dist/public/views/profile/nodes-tab.js +10 -3
- package/dist/public/views/profile/notifications-tab.js +3 -3
- package/dist/public/views/profile/packages-tab.js +14 -14
- package/dist/public/views/profile/scheduler-tab.js +340 -0
- package/dist/public/views/profile/services-tab.js +1 -1
- package/dist/public/views/profile/shared.js +16 -12
- package/dist/public/views/profile/wallet-tab.js +27 -50
- package/dist/public/views/profile/work-tab.js +29 -31
- package/dist/public/views/profile.js +24 -0
- package/dist/public/views/public-knowledge-viewer.js +9 -18
- package/dist/src/auth/middleware.d.ts +3 -2
- package/dist/src/auth/middleware.d.ts.map +1 -1
- package/dist/src/auth/middleware.js +78 -3
- package/dist/src/auth/middleware.js.map +1 -1
- package/dist/src/cli/init-wizard.d.ts.map +1 -1
- package/dist/src/cli/init-wizard.js +13 -1
- package/dist/src/cli/init-wizard.js.map +1 -1
- package/dist/src/config.d.ts +6 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +12 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/generated/api-types.d.ts +708 -8
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/mcp/agent-schedules.d.ts +23 -0
- package/dist/src/mcp/agent-schedules.d.ts.map +1 -0
- package/dist/src/mcp/agent-schedules.js +175 -0
- package/dist/src/mcp/agent-schedules.js.map +1 -0
- package/dist/src/mcp/annotations.d.ts.map +1 -1
- package/dist/src/mcp/annotations.js +6 -0
- package/dist/src/mcp/annotations.js.map +1 -1
- package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
- package/dist/src/mcp/catalog/definitions.js +55 -0
- package/dist/src/mcp/catalog/definitions.js.map +1 -1
- package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
- package/dist/src/mcp/catalog/scopes.js +12 -0
- package/dist/src/mcp/catalog/scopes.js.map +1 -1
- package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
- package/dist/src/mcp/catalog/surfaces.js +2 -0
- package/dist/src/mcp/catalog/surfaces.js.map +1 -1
- package/dist/src/mcp/index.d.ts.map +1 -1
- package/dist/src/mcp/index.js +2 -0
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/models/agent-task-schemas.d.ts +6 -0
- package/dist/src/models/agent-task-schemas.d.ts.map +1 -1
- package/dist/src/models/agent-task-schemas.js +6 -0
- package/dist/src/models/agent-task-schemas.js.map +1 -1
- package/dist/src/models/schemas.d.ts +1 -0
- package/dist/src/models/schemas.d.ts.map +1 -1
- package/dist/src/models/schemas.js +4 -0
- package/dist/src/models/schemas.js.map +1 -1
- package/dist/src/routes/access-tokens.d.ts +17 -0
- package/dist/src/routes/access-tokens.d.ts.map +1 -0
- package/dist/src/routes/access-tokens.js +164 -0
- package/dist/src/routes/access-tokens.js.map +1 -0
- package/dist/src/routes/agent-tasks.d.ts +2 -0
- package/dist/src/routes/agent-tasks.d.ts.map +1 -1
- package/dist/src/routes/agent-tasks.js +118 -23
- package/dist/src/routes/agent-tasks.js.map +1 -1
- package/dist/src/routes/agents.d.ts.map +1 -1
- package/dist/src/routes/agents.js +46 -0
- package/dist/src/routes/agents.js.map +1 -1
- package/dist/src/routes/ai.d.ts +6 -9
- package/dist/src/routes/ai.d.ts.map +1 -1
- package/dist/src/routes/ai.js +26 -175
- package/dist/src/routes/ai.js.map +1 -1
- package/dist/src/routes/apps.d.ts.map +1 -1
- package/dist/src/routes/apps.js +104 -34
- package/dist/src/routes/apps.js.map +1 -1
- package/dist/src/routes/auth.d.ts.map +1 -1
- package/dist/src/routes/auth.js +77 -4
- package/dist/src/routes/auth.js.map +1 -1
- package/dist/src/routes/cortex.d.ts +2 -1
- package/dist/src/routes/cortex.d.ts.map +1 -1
- package/dist/src/routes/cortex.js +13 -8
- package/dist/src/routes/cortex.js.map +1 -1
- package/dist/src/routes/extensions.d.ts.map +1 -1
- package/dist/src/routes/extensions.js +85 -51
- package/dist/src/routes/extensions.js.map +1 -1
- package/dist/src/routes/generator.d.ts.map +1 -1
- package/dist/src/routes/generator.js +109 -43
- package/dist/src/routes/generator.js.map +1 -1
- package/dist/src/routes/ghii.d.ts.map +1 -1
- package/dist/src/routes/ghii.js +34 -13
- package/dist/src/routes/ghii.js.map +1 -1
- package/dist/src/routes/libs.d.ts +15 -0
- package/dist/src/routes/libs.d.ts.map +1 -1
- package/dist/src/routes/libs.js +178 -55
- package/dist/src/routes/libs.js.map +1 -1
- package/dist/src/routes/portal.d.ts.map +1 -1
- package/dist/src/routes/portal.js +1 -0
- package/dist/src/routes/portal.js.map +1 -1
- package/dist/src/routes/schedules.d.ts +33 -0
- package/dist/src/routes/schedules.d.ts.map +1 -0
- package/dist/src/routes/schedules.js +380 -0
- package/dist/src/routes/schedules.js.map +1 -0
- package/dist/src/server-bootstrap/config-init.js +2 -2
- package/dist/src/server-bootstrap/config-init.js.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.js +7 -0
- package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
- package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
- package/dist/src/server-bootstrap/service-init.js +2 -1
- package/dist/src/server-bootstrap/service-init.js.map +1 -1
- package/dist/src/services/access-token.d.ts +28 -0
- package/dist/src/services/access-token.d.ts.map +1 -0
- package/dist/src/services/access-token.js +37 -0
- package/dist/src/services/access-token.js.map +1 -0
- package/dist/src/services/ai-completion.d.ts +83 -0
- package/dist/src/services/ai-completion.d.ts.map +1 -0
- package/dist/src/services/ai-completion.js +187 -0
- package/dist/src/services/ai-completion.js.map +1 -0
- package/dist/src/services/config-schema.d.ts.map +1 -1
- package/dist/src/services/config-schema.js +3 -0
- package/dist/src/services/config-schema.js.map +1 -1
- package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -1
- package/dist/src/services/generator-prompt-seeds.js +6 -3
- package/dist/src/services/generator-prompt-seeds.js.map +1 -1
- package/dist/src/services/generator-prompts/spec-validate.d.ts.map +1 -1
- package/dist/src/services/generator-prompts/spec-validate.js +6 -2
- package/dist/src/services/generator-prompts/spec-validate.js.map +1 -1
- package/dist/src/services/generator-registration.d.ts +12 -4
- package/dist/src/services/generator-registration.d.ts.map +1 -1
- package/dist/src/services/generator-registration.js +71 -0
- package/dist/src/services/generator-registration.js.map +1 -1
- package/dist/src/services/generator-validate.d.ts +10 -0
- package/dist/src/services/generator-validate.d.ts.map +1 -1
- package/dist/src/services/generator-validate.js +180 -36
- package/dist/src/services/generator-validate.js.map +1 -1
- package/dist/src/services/owner-session.d.ts +43 -0
- package/dist/src/services/owner-session.d.ts.map +1 -0
- package/dist/src/services/owner-session.js +175 -0
- package/dist/src/services/owner-session.js.map +1 -0
- package/dist/src/services/schedule-constraints.d.ts +65 -0
- package/dist/src/services/schedule-constraints.d.ts.map +1 -0
- package/dist/src/services/schedule-constraints.js +106 -0
- package/dist/src/services/schedule-constraints.js.map +1 -0
- package/dist/src/services/scheduler.d.ts +34 -0
- package/dist/src/services/scheduler.d.ts.map +1 -1
- package/dist/src/services/scheduler.js +266 -22
- package/dist/src/services/scheduler.js.map +1 -1
- package/dist/src/services/skill-bundle/generator.js +19 -0
- package/dist/src/services/skill-bundle/generator.js.map +1 -1
- package/dist/src/storage/interface.d.ts +48 -4
- package/dist/src/storage/interface.d.ts.map +1 -1
- package/dist/src/storage/interface.js.map +1 -1
- package/dist/src/storage/providers/mongodb/index.d.ts +31 -0
- package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
- package/dist/src/storage/providers/mongodb/index.js +187 -9
- package/dist/src/storage/providers/mongodb/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/index.d.ts +31 -0
- package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/index.js +131 -8
- package/dist/src/storage/providers/sqlite/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.js +6 -4
- package/dist/src/storage/providers/sqlite/repos/agent-task.js.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.js +79 -8
- package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
- package/dist/src/storage/repositories/pat.repository.d.ts +40 -0
- package/dist/src/storage/repositories/pat.repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/pat.repository.js +14 -0
- package/dist/src/storage/repositories/pat.repository.js.map +1 -0
- package/dist/src/storage/repositories/scheduler.repository.d.ts +2 -0
- package/dist/src/storage/repositories/scheduler.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/session.repository.d.ts +51 -0
- package/dist/src/storage/repositories/session.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/session.repository.js +12 -0
- package/dist/src/storage/repositories/session.repository.js.map +1 -1
- package/dist/src/utils/env-config.d.ts.map +1 -1
- package/dist/src/utils/env-config.js +25 -1
- package/dist/src/utils/env-config.js.map +1 -1
- package/dist/src/utils/env-validator.d.ts.map +1 -1
- package/dist/src/utils/env-validator.js +4 -0
- package/dist/src/utils/env-validator.js.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.prisma +48 -0
|
@@ -9,6 +9,19 @@
|
|
|
9
9
|
* - TaskItem -- task row with expand/collapse, todo list, start button
|
|
10
10
|
* - RequestChangesModal -- inline modal for owner to send a free-text change request
|
|
11
11
|
* @version-history
|
|
12
|
+
* v4.8.3 -- 2026-06-02 -- Render non-JSON memory values (e.g. an agent's
|
|
13
|
+
* latest_output) as Markdown via the shared safe Markdown component, instead
|
|
14
|
+
* of raw monospace text.
|
|
15
|
+
* v4.8.2 -- 2026-06-01 -- Render JSON memory values as a structured key/value
|
|
16
|
+
* tree (indented nested blocks, type-coloured values) instead of raw JSON text.
|
|
17
|
+
* v4.8.1 -- 2026-06-01 -- Per-task memory entries are now collapsible; values
|
|
18
|
+
* render as pretty-printed JSON when valid (raw otherwise). Add deliverableKey
|
|
19
|
+
* as a third lookup source alongside the task:<id> tag and live-key prefix.
|
|
20
|
+
* v4.8.0 -- 2026-06-01 -- Show a task's memory entries in the expanded view:
|
|
21
|
+
* entries tagged task:<id> + the live-status key prefix, deduped by key.
|
|
22
|
+
* v4.7.0 -- 2026-06-01 -- Triage: replace status pills with Recent/Keep/Archive
|
|
23
|
+
* buckets (server-derived, with counts), on-demand search (🔍 toggle) + time
|
|
24
|
+
* chips, and per-task Keep/Archive/Restore actions. Fetches by bucket/q/time.
|
|
12
25
|
* v4.6.0 -- 2026-06-01 -- Add "max concurrent tasks" runner config (number input,
|
|
13
26
|
* default 1) that PATCHes /v1/agents/:name/max-concurrent-tasks. Consumed by
|
|
14
27
|
* the agent's runner (e.g. a CrewAI daemon) via the integration kit.
|
|
@@ -49,12 +62,24 @@ const html = htm.bind(h);
|
|
|
49
62
|
import { t } from '/js/i18n.js';
|
|
50
63
|
import { timeAgo } from '/js/utils.js';
|
|
51
64
|
import { apiGet, apiPost } from '/js/api.js';
|
|
52
|
-
import { listTasks, deleteTask, startTask, listEvents, requestChanges, createTask, rateTask } from '/js/services/agent-tasks.js';
|
|
65
|
+
import { listTasks, deleteTask, startTask, listEvents, requestChanges, createTask, rateTask, setTaskTriage } from '/js/services/agent-tasks.js';
|
|
53
66
|
import { setMaxConcurrentTasks } from '/js/services/agents.js';
|
|
54
67
|
import { useConfirm, Modal } from '/components/Modal.js';
|
|
68
|
+
import { Markdown } from '/components/Markdown.js';
|
|
55
69
|
import RateModal from './agents/rate-modal.js';
|
|
56
70
|
|
|
57
|
-
|
|
71
|
+
// Tasks-tab triage buckets (server-derived) + on-demand search time chips.
|
|
72
|
+
const BUCKETS = ['recent', 'keep', 'archive'];
|
|
73
|
+
const TIME_CHIPS = ['all', 'today', '7d', '30d'];
|
|
74
|
+
|
|
75
|
+
/** Map a time chip to an `updated_after` ISO bound (undefined = no bound). */
|
|
76
|
+
function timeChipToAfter(chip) {
|
|
77
|
+
const now = new Date();
|
|
78
|
+
if (chip === 'today') { const d = new Date(now); d.setHours(0, 0, 0, 0); return d.toISOString(); }
|
|
79
|
+
if (chip === '7d') return new Date(now.getTime() - 7 * 86400000).toISOString();
|
|
80
|
+
if (chip === '30d') return new Date(now.getTime() - 30 * 86400000).toISOString();
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
58
83
|
|
|
59
84
|
// Per-browser "blur the title" preference. Used when screen-recording the tab
|
|
60
85
|
// so sensitive task titles can be hidden without affecting other viewers or
|
|
@@ -212,6 +237,74 @@ function RequestChangesModal({ open, onClose, onSubmit, submitting }) {
|
|
|
212
237
|
<//>`;
|
|
213
238
|
}
|
|
214
239
|
|
|
240
|
+
// Parse a memory value into structured JSON when possible. Returns { json } for
|
|
241
|
+
// objects (or strings that parse as JSON), or { raw } for plain text/markdown.
|
|
242
|
+
function parseMemoryValue(value) {
|
|
243
|
+
if (value === null || value === undefined) return { raw: '' };
|
|
244
|
+
if (typeof value === 'object') return { json: value };
|
|
245
|
+
if (typeof value === 'string') {
|
|
246
|
+
const trimmed = value.trim();
|
|
247
|
+
if (trimmed && (trimmed[0] === '{' || trimmed[0] === '[')) {
|
|
248
|
+
try { return { json: JSON.parse(trimmed) }; }
|
|
249
|
+
catch { /* not JSON after all -- show raw */ }
|
|
250
|
+
}
|
|
251
|
+
return { raw: value };
|
|
252
|
+
}
|
|
253
|
+
return { raw: String(value) };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Recursive structured JSON renderer: objects/arrays become indented key/value
|
|
257
|
+
// rows, primitives get type-coloured values. Far easier to scan than raw JSON.
|
|
258
|
+
function JsonNode({ value }) {
|
|
259
|
+
if (value === null) return html`<span class="pf-agd-json-null">null</span>`;
|
|
260
|
+
const t = typeof value;
|
|
261
|
+
if (t === 'string') return html`<span class="pf-agd-json-str">${value}</span>`;
|
|
262
|
+
if (t === 'number') return html`<span class="pf-agd-json-num">${value}</span>`;
|
|
263
|
+
if (t === 'boolean') return html`<span class="pf-agd-json-bool">${value ? 'true' : 'false'}</span>`;
|
|
264
|
+
const entries = Array.isArray(value) ? value.map((v, i) => [String(i), v]) : Object.entries(value || {});
|
|
265
|
+
if (entries.length === 0) return html`<span class="pf-agd-json-empty">${Array.isArray(value) ? '[ ]' : '{ }'}</span>`;
|
|
266
|
+
return html`
|
|
267
|
+
<div class="pf-agd-json-block">
|
|
268
|
+
${entries.map(([k, v]) => {
|
|
269
|
+
const nested = v !== null && typeof v === 'object';
|
|
270
|
+
return html`
|
|
271
|
+
<div class=${`pf-agd-json-row ${nested ? 'pf-agd-json-row--nested' : ''}`} key=${k}>
|
|
272
|
+
<span class="pf-agd-json-key">${k}</span>
|
|
273
|
+
<${JsonNode} value=${v} />
|
|
274
|
+
</div>
|
|
275
|
+
`;
|
|
276
|
+
})}
|
|
277
|
+
</div>
|
|
278
|
+
`;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// One collapsible memory entry. Header (key + JSON badge) toggles the body, which
|
|
282
|
+
// renders a structured JSON view when the value is JSON, raw text otherwise.
|
|
283
|
+
function TaskMemoryEntry({ entry }) {
|
|
284
|
+
const [open, setOpen] = useState(false);
|
|
285
|
+
const { json, raw } = parseMemoryValue(entry.value);
|
|
286
|
+
const isJson = json !== undefined;
|
|
287
|
+
return html`
|
|
288
|
+
<div class="pf-agd-task-memory-entry">
|
|
289
|
+
<button class="pf-agd-task-memory-head" onClick=${(e) => { e.stopPropagation(); setOpen(o => !o); }} aria-expanded=${open}>
|
|
290
|
+
<span class="pf-agd-task-memory-caret">${open ? '▼' : '▶'}</span>
|
|
291
|
+
<code class="pf-agd-task-memory-key">${entry.key}</code>
|
|
292
|
+
${isJson && html`<span class="pf-agd-task-memory-badge">JSON</span>`}
|
|
293
|
+
</button>
|
|
294
|
+
${open && html`
|
|
295
|
+
<div class="pf-agd-task-memory-body">
|
|
296
|
+
${isJson
|
|
297
|
+
? html`<${JsonNode} value=${json} />`
|
|
298
|
+
// Non-JSON values (e.g. an agent's latest_output) are usually
|
|
299
|
+
// markdown — render them formatted via the shared safe Markdown
|
|
300
|
+
// component instead of raw text.
|
|
301
|
+
: html`<div class="pf-agd-task-memory-md"><${Markdown} text=${raw} /></div>`}
|
|
302
|
+
</div>
|
|
303
|
+
`}
|
|
304
|
+
</div>
|
|
305
|
+
`;
|
|
306
|
+
}
|
|
307
|
+
|
|
215
308
|
function TaskItem({ task, agentName, showToast, onRefresh }) {
|
|
216
309
|
const [expanded, setExpanded] = useState(false);
|
|
217
310
|
const [events, setEvents] = useState(null);
|
|
@@ -224,6 +317,8 @@ function TaskItem({ task, agentName, showToast, onRefresh }) {
|
|
|
224
317
|
const [showOutdated, setShowOutdated] = useState(false);
|
|
225
318
|
// Deliverable preview: null = not requested, {loading}|{notFound}|{value}.
|
|
226
319
|
const [deliverable, setDeliverable] = useState(null);
|
|
320
|
+
// This task's memory entries: null = not requested, {loading}|{items}.
|
|
321
|
+
const [taskMemory, setTaskMemory] = useState(null);
|
|
227
322
|
// Local-only "hide the title" toggle (for screen recordings). Persisted per
|
|
228
323
|
// task ID in localStorage; see helpers at top of file.
|
|
229
324
|
const [blurred, setBlurred] = useState(() => isTaskBlurred(task.id));
|
|
@@ -256,6 +351,43 @@ function TaskItem({ task, agentName, showToast, onRefresh }) {
|
|
|
256
351
|
}
|
|
257
352
|
}
|
|
258
353
|
|
|
354
|
+
// Fetch the memory entries that belong to this task. The canonical handle is
|
|
355
|
+
// the `task:<full-id>` tag (the runner tags every write: deliverable, live,
|
|
356
|
+
// delegated deliverable + evalctx) -- the deliverable key embeds a SHORT id so
|
|
357
|
+
// it can't be matched by key substring, which is exactly why the tag exists.
|
|
358
|
+
// Two extra fallbacks make it robust for tasks written before the tag landed:
|
|
359
|
+
// the live-status key prefix (full id) and the task's own recorded
|
|
360
|
+
// deliverableKey. Rolling/public stats (statistics.custom.*) are NOT per-task
|
|
361
|
+
// tagged, so they never appear here. Deduped by key.
|
|
362
|
+
async function fetchTaskMemory() {
|
|
363
|
+
const gaii = task.agentGaii;
|
|
364
|
+
if (!gaii) { setTaskMemory({ items: [] }); return; }
|
|
365
|
+
setTaskMemory({ loading: true });
|
|
366
|
+
try {
|
|
367
|
+
const tag = `task:${task.id}`;
|
|
368
|
+
const livePrefix = `agents.${agentName}.tasks.${task.id}.`;
|
|
369
|
+
const fetches = [
|
|
370
|
+
apiGet(`/v1/memory?agent=${encodeURIComponent(gaii)}&tags=${encodeURIComponent(tag)}&per_page=50`).catch(() => null),
|
|
371
|
+
apiGet(`/v1/memory?agent=${encodeURIComponent(gaii)}&prefix=${encodeURIComponent(livePrefix)}&per_page=20`).catch(() => null),
|
|
372
|
+
];
|
|
373
|
+
if (task.deliverableKey) {
|
|
374
|
+
fetches.push(apiGet(`/v1/memory?agent=${encodeURIComponent(gaii)}&prefix=${encodeURIComponent(task.deliverableKey)}&per_page=5`).catch(() => null));
|
|
375
|
+
}
|
|
376
|
+
const results = await Promise.all(fetches);
|
|
377
|
+
const items = [];
|
|
378
|
+
const seen = new Set();
|
|
379
|
+
for (const resp of results) {
|
|
380
|
+
const list = resp?.data?.items || resp?.data || [];
|
|
381
|
+
for (const it of (Array.isArray(list) ? list : [])) {
|
|
382
|
+
if (it.key && !seen.has(it.key)) { seen.add(it.key); items.push(it); }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
setTaskMemory({ items });
|
|
386
|
+
} catch {
|
|
387
|
+
setTaskMemory({ items: [] });
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
259
391
|
async function fetchEvents({ silent = false } = {}) {
|
|
260
392
|
if (!silent) setLoadingEvents(true);
|
|
261
393
|
try {
|
|
@@ -352,6 +484,19 @@ function TaskItem({ task, agentName, showToast, onRefresh }) {
|
|
|
352
484
|
setShowRateModal(true);
|
|
353
485
|
}
|
|
354
486
|
|
|
487
|
+
async function handleTriage(e, triage) {
|
|
488
|
+
e.stopPropagation();
|
|
489
|
+
try {
|
|
490
|
+
await setTaskTriage(agentName, task.id, triage);
|
|
491
|
+
showToast(t(triage === 'kept' ? 'profile.agents.tasks.triage.kept'
|
|
492
|
+
: triage === 'archived' ? 'profile.agents.tasks.triage.archived'
|
|
493
|
+
: 'profile.agents.tasks.triage.restored'));
|
|
494
|
+
onRefresh();
|
|
495
|
+
} catch (err) {
|
|
496
|
+
showToast(err.message || t('profile.agents.tasks.triage.error'), true);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
355
500
|
async function handleSubmitRate(body) {
|
|
356
501
|
setSendingRate(true);
|
|
357
502
|
try {
|
|
@@ -441,6 +586,21 @@ function TaskItem({ task, agentName, showToast, onRefresh }) {
|
|
|
441
586
|
`}
|
|
442
587
|
`}
|
|
443
588
|
|
|
589
|
+
<div class="pf-agd-task-memory">
|
|
590
|
+
<button class="btn-ghost btn-sm" onClick=${(e) => { e.stopPropagation(); fetchTaskMemory(); }}>
|
|
591
|
+
${t('profile.agents.tasks.memory.show')}
|
|
592
|
+
</button>
|
|
593
|
+
${taskMemory && (taskMemory.loading
|
|
594
|
+
? html`<div class="pf-agd-empty">${t('profile.loading')}</div>`
|
|
595
|
+
: taskMemory.items.length === 0
|
|
596
|
+
? html`<div class="pf-agd-empty">${t('profile.agents.tasks.memory.none')}</div>`
|
|
597
|
+
: html`
|
|
598
|
+
<div class="pf-agd-task-memory-list">
|
|
599
|
+
${taskMemory.items.map(it => html`<${TaskMemoryEntry} key=${it.key} entry=${it} />`)}
|
|
600
|
+
</div>
|
|
601
|
+
`)}
|
|
602
|
+
</div>
|
|
603
|
+
|
|
444
604
|
${isDone && html`
|
|
445
605
|
<div class="pf-agd-rate-row">
|
|
446
606
|
${rating
|
|
@@ -578,6 +738,16 @@ function TaskItem({ task, agentName, showToast, onRefresh }) {
|
|
|
578
738
|
${(isQueued || task.status === 'draft' || isRevisionRequested) && html`
|
|
579
739
|
<button class="btn-danger btn-sm" onClick=${handleDelete}>${t('profile.agents.tasks.delete')}</button>
|
|
580
740
|
`}
|
|
741
|
+
<span class="pf-agd-task-actions-spacer"></span>
|
|
742
|
+
${task.triage !== 'kept' && html`
|
|
743
|
+
<button class="btn-ghost btn-sm" onClick=${(e) => handleTriage(e, 'kept')} title=${t('profile.agents.tasks.triage.keepHint')}>★ ${t('profile.agents.tasks.triage.keep')}</button>
|
|
744
|
+
`}
|
|
745
|
+
${task.triage !== 'archived' && html`
|
|
746
|
+
<button class="btn-ghost btn-sm" onClick=${(e) => handleTriage(e, 'archived')} title=${t('profile.agents.tasks.triage.archiveHint')}>${t('profile.agents.tasks.triage.archive')}</button>
|
|
747
|
+
`}
|
|
748
|
+
${task.triage && html`
|
|
749
|
+
<button class="btn-ghost btn-sm" onClick=${(e) => handleTriage(e, null)}>${t('profile.agents.tasks.triage.restore')}</button>
|
|
750
|
+
`}
|
|
581
751
|
</div>
|
|
582
752
|
<${ConfirmUI} />
|
|
583
753
|
<${RequestChangesModal}
|
|
@@ -601,9 +771,13 @@ function TaskItem({ task, agentName, showToast, onRefresh }) {
|
|
|
601
771
|
|
|
602
772
|
export default function AgentTasksSubtab({ agent, agentName, showToast }) {
|
|
603
773
|
const [tasks, setTasks] = useState(null);
|
|
774
|
+
const [counts, setCounts] = useState({ recent: 0, keep: 0, archive: 0 });
|
|
775
|
+
const [bucket, setBucket] = useState('recent');
|
|
604
776
|
const [showCreate, setShowCreate] = useState(false);
|
|
605
777
|
const [error, setError] = useState(null);
|
|
606
|
-
const [
|
|
778
|
+
const [searchOpen, setSearchOpen] = useState(false);
|
|
779
|
+
const [q, setQ] = useState('');
|
|
780
|
+
const [timeChip, setTimeChip] = useState('all');
|
|
607
781
|
// Runner concurrency config (default 1 = serial). Saved to the agent via PATCH.
|
|
608
782
|
const [maxConcurrent, setMaxConcurrent] = useState(agent?.max_concurrent_tasks ?? 1);
|
|
609
783
|
const [savingConcurrency, setSavingConcurrency] = useState(false);
|
|
@@ -625,8 +799,14 @@ export default function AgentTasksSubtab({ agent, agentName, showToast }) {
|
|
|
625
799
|
|
|
626
800
|
async function loadTasks() {
|
|
627
801
|
try {
|
|
628
|
-
const resp = await listTasks(agentName
|
|
802
|
+
const resp = await listTasks(agentName, {
|
|
803
|
+
bucket,
|
|
804
|
+
q: q.trim() || undefined,
|
|
805
|
+
updated_after: timeChipToAfter(timeChip),
|
|
806
|
+
per_page: 100,
|
|
807
|
+
});
|
|
629
808
|
setTasks(resp?.data?.tasks || []);
|
|
809
|
+
setCounts(resp?.data?.counts || { recent: 0, keep: 0, archive: 0 });
|
|
630
810
|
setError(null);
|
|
631
811
|
} catch (err) {
|
|
632
812
|
setError(err.message);
|
|
@@ -634,7 +814,11 @@ export default function AgentTasksSubtab({ agent, agentName, showToast }) {
|
|
|
634
814
|
}
|
|
635
815
|
}
|
|
636
816
|
|
|
637
|
-
|
|
817
|
+
// Refetch on agent/bucket/time change immediately; debounce text search.
|
|
818
|
+
useEffect(() => {
|
|
819
|
+
const id = setTimeout(() => loadTasks(), q ? 300 : 0);
|
|
820
|
+
return () => clearTimeout(id);
|
|
821
|
+
}, [agentName, bucket, timeChip, q]);
|
|
638
822
|
|
|
639
823
|
const loadRef = useRef(loadTasks);
|
|
640
824
|
loadRef.current = loadTasks;
|
|
@@ -653,24 +837,13 @@ export default function AgentTasksSubtab({ agent, agentName, showToast }) {
|
|
|
653
837
|
return html`<div class="pf-agd-empty">${t('profile.loading')}</div>`;
|
|
654
838
|
}
|
|
655
839
|
|
|
656
|
-
const
|
|
657
|
-
switch (filter) {
|
|
658
|
-
case 'active': return task.status === 'active';
|
|
659
|
-
// 'revision_requested' lives under the queued filter -- the task is
|
|
660
|
-
// waiting for the agent to re-propose, which is conceptually the same
|
|
661
|
-
// "awaiting action before run" bucket the owner already monitors here.
|
|
662
|
-
case 'queued': return task.status === 'queued' || task.status === 'draft' || task.status === 'revision_requested';
|
|
663
|
-
case 'completed': return task.status === 'done';
|
|
664
|
-
case 'failed': return task.status === 'failed' || task.status === 'stalled';
|
|
665
|
-
default: return true;
|
|
666
|
-
}
|
|
667
|
-
});
|
|
840
|
+
const totalTasks = counts.recent + counts.keep + counts.archive;
|
|
668
841
|
|
|
669
842
|
return html`
|
|
670
843
|
<div>
|
|
671
844
|
<div class="pf-agd-section-header">
|
|
672
845
|
<span class="pf-agd-section-title">
|
|
673
|
-
${t('profile.agents.tasks.title')}${
|
|
846
|
+
${t('profile.agents.tasks.title')}${totalTasks > 0 ? ` (${totalTasks})` : ''}
|
|
674
847
|
</span>
|
|
675
848
|
<button class="btn-outline btn-sm" onClick=${() => setShowCreate(!showCreate)}>
|
|
676
849
|
${showCreate ? '-' : '+'} ${t('profile.agents.tasks.newTask')}
|
|
@@ -700,20 +873,42 @@ export default function AgentTasksSubtab({ agent, agentName, showToast }) {
|
|
|
700
873
|
|
|
701
874
|
${error && html`<div class="pf-agd-empty">${error}</div>`}
|
|
702
875
|
|
|
703
|
-
<div class="pf-agd-
|
|
704
|
-
${
|
|
705
|
-
<button key=${
|
|
706
|
-
class="pf-agd-
|
|
707
|
-
onClick=${() =>
|
|
708
|
-
${t(`profile.agents.
|
|
876
|
+
<div class="pf-agd-bucket-bar">
|
|
877
|
+
${BUCKETS.map(b => html`
|
|
878
|
+
<button key=${b}
|
|
879
|
+
class="pf-agd-bucket ${bucket === b ? 'pf-agd-bucket--active' : ''}"
|
|
880
|
+
onClick=${() => setBucket(b)}>
|
|
881
|
+
${t(`profile.agents.tasks.bucket.${b}`)} <span class="pf-agd-bucket-count">${counts[b] ?? 0}</span>
|
|
709
882
|
</button>
|
|
710
883
|
`)}
|
|
884
|
+
<span class="pf-agd-bucket-spacer"></span>
|
|
885
|
+
<button class="pf-agd-search-toggle ${searchOpen ? 'pf-agd-search-toggle--on' : ''}"
|
|
886
|
+
onClick=${() => setSearchOpen(o => !o)}
|
|
887
|
+
title=${t('profile.agents.tasks.search.toggle')}
|
|
888
|
+
aria-pressed=${searchOpen}>🔍</button>
|
|
711
889
|
</div>
|
|
712
890
|
|
|
713
|
-
${
|
|
891
|
+
${searchOpen && html`
|
|
892
|
+
<div class="pf-agd-search-bar">
|
|
893
|
+
<input class="pf-agd-search-input" type="search"
|
|
894
|
+
placeholder=${t('profile.agents.tasks.search.placeholder')}
|
|
895
|
+
value=${q} onInput=${e => setQ(e.target.value)} />
|
|
896
|
+
<div class="pf-agd-time-chips">
|
|
897
|
+
${TIME_CHIPS.map(c => html`
|
|
898
|
+
<button key=${c}
|
|
899
|
+
class="pf-agd-time-chip ${timeChip === c ? 'pf-agd-time-chip--on' : ''}"
|
|
900
|
+
onClick=${() => setTimeChip(c)}>
|
|
901
|
+
${t(`profile.agents.tasks.search.time.${c}`)}
|
|
902
|
+
</button>
|
|
903
|
+
`)}
|
|
904
|
+
</div>
|
|
905
|
+
</div>
|
|
906
|
+
`}
|
|
907
|
+
|
|
908
|
+
${tasks.length > 0 ? tasks.map(task => html`
|
|
714
909
|
<${TaskItem} key=${task.id} task=${task} agentName=${agentName} showToast=${showToast} onRefresh=${loadTasks} />
|
|
715
910
|
`) : html`
|
|
716
|
-
<div class="pf-agd-empty">${t('profile.agents.
|
|
911
|
+
<div class="pf-agd-empty">${q ? t('profile.agents.tasks.search.noResults') : t(`profile.agents.tasks.bucket.empty.${bucket}`)}</div>
|
|
717
912
|
`}
|
|
718
913
|
</div>
|
|
719
914
|
`;
|
|
@@ -33,6 +33,8 @@ function computeWeightedScore(dims) {
|
|
|
33
33
|
import htm from 'htm';
|
|
34
34
|
const html = htm.bind(h);
|
|
35
35
|
import { t } from '/js/i18n.js';
|
|
36
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
37
|
+
import { copyToClipboard } from '/js/utils.js';
|
|
36
38
|
import { getBatch, updateBatch, createVersion } from '/js/services/calibrator.js';
|
|
37
39
|
|
|
38
40
|
|
|
@@ -527,7 +529,7 @@ Now return the full modified instruction prompt with the fixes incorporated. Rem
|
|
|
527
529
|
}).filter(Boolean);
|
|
528
530
|
|
|
529
531
|
const text = `Here is a prompt that needs improvement:\n\n---\n${currentVersion.prompt}\n---\n\nApply these proposed fixes:\n${selectedProposals.map((p, i) => `${i + 1}. ${p}`).join('\n')}\n\nReturn ONLY the modified prompt text.`;
|
|
530
|
-
|
|
532
|
+
copyToClipboard(text).then(() => showToast?.('Copied'));
|
|
531
533
|
}
|
|
532
534
|
|
|
533
535
|
// ── Paste handlers ──
|
|
@@ -599,10 +601,6 @@ Now return the full modified instruction prompt with the fixes incorporated. Rem
|
|
|
599
601
|
.then(u => { setDetail(u || { ...detail, status: 'synthesized', step4_synthesis: synth }); onUpdate?.(); });
|
|
600
602
|
}
|
|
601
603
|
|
|
602
|
-
function copyToClipboard(text, label) {
|
|
603
|
-
navigator.clipboard.writeText(text).then(() => showToast?.(label + ' copied'));
|
|
604
|
-
}
|
|
605
|
-
|
|
606
604
|
// ── Render: Step 1 (Generation) ──
|
|
607
605
|
|
|
608
606
|
function renderStep1() {
|
|
@@ -631,9 +629,7 @@ Now return the full modified instruction prompt with the fixes incorporated. Rem
|
|
|
631
629
|
` : ''}
|
|
632
630
|
<div class="fnd-cal-run-actions">
|
|
633
631
|
${m.step1_generation?.output ? html`
|
|
634
|
-
|
|
635
|
-
${t('profile.calibrator.copy')}
|
|
636
|
-
</button>
|
|
632
|
+
<${CopyButton} text=${m.step1_generation.output} label=${t('profile.calibrator.copy')} className="btn-sm" onCopied=${() => showToast?.('Output copied')} />
|
|
637
633
|
` : ''}
|
|
638
634
|
<${PasteBack} label=${t('profile.calibrator.pasteOutput')} onSave=${text => handlePasteStep1(i, text)} />
|
|
639
635
|
</div>
|
|
@@ -700,9 +696,7 @@ Now return the full modified instruction prompt with the fixes incorporated. Rem
|
|
|
700
696
|
${a?.rawResponse ? html`<${CollapsiblePre} label=${t('profile.calibrator.viewRawResponse')} text=${a.rawResponse} />` : ''}
|
|
701
697
|
<div class="fnd-cal-run-actions">
|
|
702
698
|
${a?.analysis ? html`
|
|
703
|
-
|
|
704
|
-
${t('profile.calibrator.copy')}
|
|
705
|
-
</button>
|
|
699
|
+
<${CopyButton} text=${typeof a.analysis === 'string' ? a.analysis : JSON.stringify(a.analysis, null, 2)} label=${t('profile.calibrator.copy')} className="btn-sm" onCopied=${() => showToast?.('Analysis copied')} />
|
|
706
700
|
` : ''}
|
|
707
701
|
<${PasteBack} label=${t('profile.calibrator.pasteAnalysis')} onSave=${text => handlePasteStep2(modelIndex, text)} />
|
|
708
702
|
</div>
|
|
@@ -18,6 +18,7 @@ import htm from 'htm';
|
|
|
18
18
|
const html = htm.bind(h);
|
|
19
19
|
import { t } from '/js/i18n.js';
|
|
20
20
|
import { apiGet, apiDelete } from '/js/api.js';
|
|
21
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
21
22
|
import LlmConfigEditor from '/views/profile/calibrator-llm-editor.js';
|
|
22
23
|
import CalibrationChart from '/views/profile/calibrator-chart.js';
|
|
23
24
|
import BatchCard from '/views/profile/calibrator-batch.js';
|
|
@@ -308,10 +309,6 @@ function ProjectDetailView({ projectId, onBack, showToast }) {
|
|
|
308
309
|
}
|
|
309
310
|
}
|
|
310
311
|
|
|
311
|
-
function copyToClipboard(text, label) {
|
|
312
|
-
navigator.clipboard.writeText(text).then(() => showToast?.(label + ' copied'));
|
|
313
|
-
}
|
|
314
|
-
|
|
315
312
|
async function handleArchive() {
|
|
316
313
|
await handleUpdateProject({ status: 'archived' });
|
|
317
314
|
onBack();
|
|
@@ -388,14 +385,14 @@ function ProjectDetailView({ projectId, onBack, showToast }) {
|
|
|
388
385
|
<div class="fnd-cal-editor-label">${t('profile.calibrator.prompt')} (v${selectedVersion || 0})</div>
|
|
389
386
|
<textarea value=${prompt} onInput=${e => setPrompt(e.target.value)} disabled=${isReadOnly} />
|
|
390
387
|
<div class="fnd-cal-editor-actions">
|
|
391
|
-
|
|
388
|
+
<${CopyButton} text=${prompt} label=${t('profile.calibrator.copy')} className="btn-sm" onCopied=${() => showToast?.('Prompt copied')} />
|
|
392
389
|
</div>
|
|
393
390
|
</div>
|
|
394
391
|
<div class="fnd-cal-editor-panel">
|
|
395
392
|
<div class="fnd-cal-editor-label">${t('profile.calibrator.targetOutput')}</div>
|
|
396
393
|
<textarea value=${targetOutput} onInput=${e => setTargetOutput(e.target.value)} disabled=${isReadOnly} />
|
|
397
394
|
<div class="fnd-cal-editor-actions">
|
|
398
|
-
|
|
395
|
+
<${CopyButton} text=${targetOutput} label=${t('profile.calibrator.copy')} className="btn-sm" onCopied=${() => showToast?.('Target copied')} />
|
|
399
396
|
</div>
|
|
400
397
|
</div>
|
|
401
398
|
</div>
|
|
@@ -440,9 +437,7 @@ function ProjectDetailView({ projectId, onBack, showToast }) {
|
|
|
440
437
|
<button class="btn-ghost btn-sm" onClick=${() => handleResetTemplate(tc.field)}>
|
|
441
438
|
${t('profile.calibrator.resetTemplate')}
|
|
442
439
|
</button>
|
|
443
|
-
|
|
444
|
-
${t('profile.calibrator.copy')}
|
|
445
|
-
</button>
|
|
440
|
+
<${CopyButton} text=${templates[tc.field]} label=${t('profile.calibrator.copy')} className="btn-sm" onCopied=${() => showToast?.('Template copied')} />
|
|
446
441
|
</div>
|
|
447
442
|
</div>
|
|
448
443
|
</details>
|
|
@@ -6,14 +6,18 @@
|
|
|
6
6
|
* @version-history
|
|
7
7
|
* v1.0.0 — 2026-03-16 — Initial chat sessions tab
|
|
8
8
|
* v1.1.0 — 2026-03-17 — Replace inline styles with CSS classes; fix fallback strings
|
|
9
|
+
* v1.2.0 — 2026-06-02 — Component unification (#1): "Copy GAII" uses canonical
|
|
10
|
+
* <CopyButton> (toast preserved); prompt-copy routed through shared copyToClipboard
|
|
11
|
+
* (insecure-context fallback) instead of raw navigator.clipboard.
|
|
9
12
|
*/
|
|
10
13
|
import { h } from 'preact';
|
|
11
14
|
import { useState, useEffect, useCallback, useRef } from 'preact/hooks';
|
|
12
15
|
import htm from 'htm';
|
|
13
16
|
const html = htm.bind(h);
|
|
14
17
|
import { t } from '/js/i18n.js';
|
|
15
|
-
import { escHtml, timeAgo } from '/js/utils.js';
|
|
18
|
+
import { escHtml, timeAgo, copyToClipboard } from '/js/utils.js';
|
|
16
19
|
import { Spinner } from './shared.js';
|
|
20
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
17
21
|
import { useConfirm } from '/components/Modal.js';
|
|
18
22
|
import { listAgents, deleteAgent } from '/js/services/agents.js';
|
|
19
23
|
import { apiGet } from '/js/api.js';
|
|
@@ -75,7 +79,7 @@ export default function ChatSessionsTab({ session, showToast, onStats }) {
|
|
|
75
79
|
const resp = await apiGet(endpoint);
|
|
76
80
|
const text = resp?.data?.prompt;
|
|
77
81
|
if (text) {
|
|
78
|
-
await
|
|
82
|
+
await copyToClipboard(text);
|
|
79
83
|
showToast(t('profile.chatSessions.promptCopied'));
|
|
80
84
|
} else {
|
|
81
85
|
showToast(t('profile.chatSessions.promptError'));
|
|
@@ -165,9 +169,9 @@ export default function ChatSessionsTab({ session, showToast, onStats }) {
|
|
|
165
169
|
</div>
|
|
166
170
|
|
|
167
171
|
<div class="card-actions flex-actions">
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
</
|
|
172
|
+
<span onClick=${(e) => e.stopPropagation()}>
|
|
173
|
+
<${CopyButton} text=${s.gaii || s.name} label=${t('profile.agents.copyGaii')} className="btn-outline btn-sm" onCopied=${() => showToast('GAII copied')} />
|
|
174
|
+
</span>
|
|
171
175
|
<button class="btn-danger-solid btn-sm" onClick=${(e) => { e.stopPropagation(); handleDelete(s); }}
|
|
172
176
|
disabled=${deleting === s.name}>
|
|
173
177
|
${deleting === s.name ? '...' : t('profile.chatSessions.remove')}
|
|
@@ -130,7 +130,7 @@ export default function EmailTab({ session, showToast }) {
|
|
|
130
130
|
<p class="email-sent-text">${t('profile.email.codeSent')}</p>
|
|
131
131
|
<div class="email-form-group">
|
|
132
132
|
<label class="email-form-label">${t('profile.email.enterCode')}</label>
|
|
133
|
-
<input class="
|
|
133
|
+
<input class="input-field input-verification-code" type="text" maxlength="6" placeholder="123456"
|
|
134
134
|
value=${code} onInput=${e => setCode(e.target.value)} />
|
|
135
135
|
</div>
|
|
136
136
|
<button class="btn-primary" onClick=${handleVerifyCode} disabled=${verifying}>
|
|
@@ -147,7 +147,7 @@ export default function EmailTab({ session, showToast }) {
|
|
|
147
147
|
` : null}
|
|
148
148
|
<div class="email-form-group">
|
|
149
149
|
<label class="email-form-label">${t('profile.email.enterEmail')}</label>
|
|
150
|
-
<input class="
|
|
150
|
+
<input class="input-field" type="email" placeholder="you@example.com"
|
|
151
151
|
value=${email} onInput=${e => setEmail(e.target.value)} />
|
|
152
152
|
</div>
|
|
153
153
|
<button class="btn-primary" onClick=${handleSendCode} disabled=${sending}>
|