@meshmakers/octo-ai-console 3.4.180 → 3.4.200
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.
|
@@ -161,10 +161,10 @@ class AiAdapterClientService {
|
|
|
161
161
|
tenantBase() {
|
|
162
162
|
return `${this.options.baseUrl}/${encodeURIComponent(this.options.tenantId)}/v1`;
|
|
163
163
|
}
|
|
164
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
165
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
164
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiAdapterClientService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
165
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiAdapterClientService });
|
|
166
166
|
}
|
|
167
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
167
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiAdapterClientService, decorators: [{
|
|
168
168
|
type: Injectable
|
|
169
169
|
}] });
|
|
170
170
|
|
|
@@ -308,10 +308,10 @@ class AiSessionStreamService {
|
|
|
308
308
|
: `/${this.options.hubPath}`;
|
|
309
309
|
return `${this.options.baseUrl}/${this.options.tenantId}${trimmed}`;
|
|
310
310
|
}
|
|
311
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
312
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
311
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiSessionStreamService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
312
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiSessionStreamService });
|
|
313
313
|
}
|
|
314
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
314
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiSessionStreamService, decorators: [{
|
|
315
315
|
type: Injectable
|
|
316
316
|
}] });
|
|
317
317
|
|
|
@@ -362,7 +362,8 @@ function provideOctoAiConsole(options) {
|
|
|
362
362
|
* `--mm-ai-status-*` custom properties.
|
|
363
363
|
*/
|
|
364
364
|
class AiJobStatusBadgeComponent {
|
|
365
|
-
status = input.required(
|
|
365
|
+
status = input.required(/* @ts-ignore */
|
|
366
|
+
...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
366
367
|
variant = computed(() => {
|
|
367
368
|
switch (this.status()) {
|
|
368
369
|
case 'Running':
|
|
@@ -382,11 +383,12 @@ class AiJobStatusBadgeComponent {
|
|
|
382
383
|
default:
|
|
383
384
|
return 'queued';
|
|
384
385
|
}
|
|
385
|
-
},
|
|
386
|
-
|
|
387
|
-
static
|
|
386
|
+
}, /* @ts-ignore */
|
|
387
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
388
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiJobStatusBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
389
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: AiJobStatusBadgeComponent, isStandalone: true, selector: "mm-ai-job-status-badge", inputs: { status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<span class=\"mm-ai-status-badge mm-ai-status-badge--{{ variant() }}\">\n {{ status() }}\n</span>\n", styles: [":host{display:inline-block;--mm-ai-status-running-bg: #1f6feb;--mm-ai-status-running-fg: #ffffff;--mm-ai-status-queued-bg: #6e7681;--mm-ai-status-queued-fg: #ffffff;--mm-ai-status-paused-bg: #d29922;--mm-ai-status-paused-fg: #1c1c1c;--mm-ai-status-completed-bg: #2ea44f;--mm-ai-status-completed-fg: #ffffff;--mm-ai-status-failed-bg: #d73a49;--mm-ai-status-failed-fg: #ffffff;--mm-ai-status-blocked-bg: #8957e5;--mm-ai-status-blocked-fg: #ffffff}.mm-ai-status-badge{display:inline-block;padding:.15rem .65rem;border-radius:9999px;font-size:.8rem;font-weight:600;line-height:1.2;letter-spacing:.01em}.mm-ai-status-badge--running{background:var(--mm-ai-status-running-bg);color:var(--mm-ai-status-running-fg)}.mm-ai-status-badge--queued{background:var(--mm-ai-status-queued-bg);color:var(--mm-ai-status-queued-fg)}.mm-ai-status-badge--paused{background:var(--mm-ai-status-paused-bg);color:var(--mm-ai-status-paused-fg)}.mm-ai-status-badge--completed{background:var(--mm-ai-status-completed-bg);color:var(--mm-ai-status-completed-fg)}.mm-ai-status-badge--failed{background:var(--mm-ai-status-failed-bg);color:var(--mm-ai-status-failed-fg)}.mm-ai-status-badge--blocked{background:var(--mm-ai-status-blocked-bg);color:var(--mm-ai-status-blocked-fg)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
388
390
|
}
|
|
389
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
391
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiJobStatusBadgeComponent, decorators: [{
|
|
390
392
|
type: Component,
|
|
391
393
|
args: [{ selector: 'mm-ai-job-status-badge', imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<span class=\"mm-ai-status-badge mm-ai-status-badge--{{ variant() }}\">\n {{ status() }}\n</span>\n", styles: [":host{display:inline-block;--mm-ai-status-running-bg: #1f6feb;--mm-ai-status-running-fg: #ffffff;--mm-ai-status-queued-bg: #6e7681;--mm-ai-status-queued-fg: #ffffff;--mm-ai-status-paused-bg: #d29922;--mm-ai-status-paused-fg: #1c1c1c;--mm-ai-status-completed-bg: #2ea44f;--mm-ai-status-completed-fg: #ffffff;--mm-ai-status-failed-bg: #d73a49;--mm-ai-status-failed-fg: #ffffff;--mm-ai-status-blocked-bg: #8957e5;--mm-ai-status-blocked-fg: #ffffff}.mm-ai-status-badge{display:inline-block;padding:.15rem .65rem;border-radius:9999px;font-size:.8rem;font-weight:600;line-height:1.2;letter-spacing:.01em}.mm-ai-status-badge--running{background:var(--mm-ai-status-running-bg);color:var(--mm-ai-status-running-fg)}.mm-ai-status-badge--queued{background:var(--mm-ai-status-queued-bg);color:var(--mm-ai-status-queued-fg)}.mm-ai-status-badge--paused{background:var(--mm-ai-status-paused-bg);color:var(--mm-ai-status-paused-fg)}.mm-ai-status-badge--completed{background:var(--mm-ai-status-completed-bg);color:var(--mm-ai-status-completed-fg)}.mm-ai-status-badge--failed{background:var(--mm-ai-status-failed-bg);color:var(--mm-ai-status-failed-fg)}.mm-ai-status-badge--blocked{background:var(--mm-ai-status-blocked-bg);color:var(--mm-ai-status-blocked-fg)}\n"] }]
|
|
392
394
|
}], propDecorators: { status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: true }] }] } });
|
|
@@ -404,12 +406,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
404
406
|
* never offers Cancel.
|
|
405
407
|
*/
|
|
406
408
|
class AiSessionListComponent {
|
|
407
|
-
sessions = input.required(
|
|
408
|
-
|
|
409
|
+
sessions = input.required(/* @ts-ignore */
|
|
410
|
+
...(ngDevMode ? [{ debugName: "sessions" }] : /* istanbul ignore next */ []));
|
|
411
|
+
selectedSessionId = input(null, /* @ts-ignore */
|
|
412
|
+
...(ngDevMode ? [{ debugName: "selectedSessionId" }] : /* istanbul ignore next */ []));
|
|
409
413
|
sessionSelected = output();
|
|
410
414
|
cancelRequested = output();
|
|
411
415
|
deleteRequested = output();
|
|
412
|
-
orderedSessions = computed(() => [...this.sessions()].sort((a, b) => b.startedAt.localeCompare(a.startedAt)),
|
|
416
|
+
orderedSessions = computed(() => [...this.sessions()].sort((a, b) => b.startedAt.localeCompare(a.startedAt)), /* @ts-ignore */
|
|
417
|
+
...(ngDevMode ? [{ debugName: "orderedSessions" }] : /* istanbul ignore next */ []));
|
|
413
418
|
/**
|
|
414
419
|
* Terminal status set, kept in sync with the C# `AiAgentSessionService.IsTerminal`
|
|
415
420
|
* predicate. Delete is gated to this set; Cancel is gated to its complement.
|
|
@@ -458,10 +463,10 @@ class AiSessionListComponent {
|
|
|
458
463
|
const days = Math.floor(hours / 24);
|
|
459
464
|
return `${days}d ago`;
|
|
460
465
|
}
|
|
461
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
462
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
466
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiSessionListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
467
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: AiSessionListComponent, isStandalone: true, selector: "mm-ai-session-list", inputs: { sessions: { classPropertyName: "sessions", publicName: "sessions", isSignal: true, isRequired: true, transformFunction: null }, selectedSessionId: { classPropertyName: "selectedSessionId", publicName: "selectedSessionId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sessionSelected: "sessionSelected", cancelRequested: "cancelRequested", deleteRequested: "deleteRequested" }, ngImport: i0, template: "<ul class=\"mm-ai-session-list\">\n @for (session of orderedSessions(); track session.sessionRtId) {\n <li\n class=\"mm-ai-session-list__row\"\n [class.mm-ai-session-list__row--selected]=\"\n session.sessionRtId === selectedSessionId()\n \"\n >\n <button\n type=\"button\"\n class=\"mm-ai-session-list__button\"\n (click)=\"onSelect(session.sessionRtId)\"\n >\n <!--\n Row layout: goal + status badge on top, meta + actions on the\n bottom. The two-line shape lets a narrow sidebar (Refinery\n Studio caps the column at 18rem) breathe \u2014 the previous\n horizontal cram had the goal text overlap the action buttons\n on every row.\n -->\n <div class=\"mm-ai-session-list__top\">\n <span class=\"mm-ai-session-list__goal\">{{ session.goalSummary }}</span>\n <mm-ai-job-status-badge [status]=\"session.status\" />\n </div>\n <div class=\"mm-ai-session-list__bottom\">\n <span class=\"mm-ai-session-list__meta\">\n {{ age(session.startedAt) }}\n <span class=\"mm-ai-session-list__dot\">\u00B7</span>\n {{ session.tokensConsumed }} tok\n </span>\n @if (session.previewUrl) {\n <!--\n #4136 \u2014 preview-deploy URL the server surfaces when the\n worker pod's nginx sidecar has a build to serve. Opens in\n a new tab so the sidebar scroll position survives.\n stopPropagation prevents the row click from also firing.\n -->\n <a\n class=\"mm-ai-session-list__preview\"\n [href]=\"session.previewUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"$event.stopPropagation()\"\n >\n Preview\n </a>\n }\n <span class=\"mm-ai-session-list__spacer\"></span>\n <span class=\"mm-ai-session-list__actions\">\n @if (canCancel(session.status)) {\n <button\n type=\"button\"\n class=\"mm-ai-session-list__action mm-ai-session-list__action--cancel\"\n [attr.aria-label]=\"'Cancel session ' + session.goalSummary\"\n (click)=\"onCancel(session.sessionRtId, $event)\"\n >\n Cancel\n </button>\n }\n @if (canDelete(session.status)) {\n <button\n type=\"button\"\n class=\"mm-ai-session-list__action mm-ai-session-list__action--delete\"\n [attr.aria-label]=\"'Delete session ' + session.goalSummary\"\n (click)=\"onDelete(session.sessionRtId, $event)\"\n >\n Delete\n </button>\n }\n </span>\n </div>\n </button>\n </li>\n } @empty {\n <li class=\"mm-ai-session-list__empty\">No sessions yet.</li>\n }\n</ul>\n", styles: [":host{display:block;--mm-ai-list-bg: #16191d;--mm-ai-list-row-bg: #1f2227;--mm-ai-list-row-selected: #2a3142;--mm-ai-list-border: #2f343b;--mm-ai-list-text: #e6e6e6;--mm-ai-list-muted: #9aa0a6;--mm-ai-list-accent: #64ceb9;--mm-ai-list-action-cancel: #da9162;--mm-ai-list-action-delete: #ec658f}.mm-ai-session-list{list-style:none;margin:0;padding:0;background:var(--mm-ai-list-bg);border-radius:.5rem;display:flex;flex-direction:column;gap:.25rem;padding:.25rem}.mm-ai-session-list__row{background:var(--mm-ai-list-row-bg);border:1px solid var(--mm-ai-list-border);border-radius:.4rem}.mm-ai-session-list__row--selected{background:var(--mm-ai-list-row-selected)}.mm-ai-session-list__button{width:100%;display:flex;flex-direction:column;gap:.3rem;padding:.5rem .75rem;background:transparent;color:var(--mm-ai-list-text);border:none;cursor:pointer;text-align:left;font-family:inherit;min-width:0}.mm-ai-session-list__button:hover{background:#ffffff08}.mm-ai-session-list__top{display:flex;align-items:center;gap:.5rem;min-width:0}.mm-ai-session-list__goal{flex:1;min-width:0;font-size:.85rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mm-ai-session-list__bottom{display:flex;align-items:center;gap:.5rem;font-size:.7rem;color:var(--mm-ai-list-muted);font-variant-numeric:tabular-nums;min-width:0}.mm-ai-session-list__meta{display:inline-flex;align-items:baseline;gap:.35rem;flex-shrink:0}.mm-ai-session-list__dot{opacity:.5}.mm-ai-session-list__spacer{flex:1}.mm-ai-session-list__preview{color:var(--mm-ai-list-accent);font-size:.7rem;text-decoration:underline;text-underline-offset:2px;flex-shrink:0}.mm-ai-session-list__preview:hover{text-decoration-thickness:2px}.mm-ai-session-list__empty{padding:1rem;text-align:center;color:var(--mm-ai-list-muted);font-style:italic}.mm-ai-session-list__actions{display:flex;gap:.25rem;flex-shrink:0;opacity:.45;transition:opacity .15s ease}.mm-ai-session-list__row:hover .mm-ai-session-list__actions,.mm-ai-session-list__row--selected .mm-ai-session-list__actions{opacity:1}.mm-ai-session-list__action{padding:.15rem .5rem;background:transparent;border:1px solid var(--mm-ai-list-border);border-radius:.25rem;color:var(--mm-ai-list-text);font-family:inherit;font-size:.65rem;letter-spacing:.04em;text-transform:uppercase;cursor:pointer;transition:border-color .15s ease,color .15s ease,background-color .15s ease}.mm-ai-session-list__action:hover{background:#ffffff0a}.mm-ai-session-list__action--cancel{color:var(--mm-ai-list-action-cancel);border-color:color-mix(in srgb,var(--mm-ai-list-action-cancel) 40%,transparent)}.mm-ai-session-list__action--cancel:hover{border-color:var(--mm-ai-list-action-cancel)}.mm-ai-session-list__action--delete{color:var(--mm-ai-list-action-delete);border-color:color-mix(in srgb,var(--mm-ai-list-action-delete) 40%,transparent)}.mm-ai-session-list__action--delete:hover{border-color:var(--mm-ai-list-action-delete)}\n"], dependencies: [{ kind: "component", type: AiJobStatusBadgeComponent, selector: "mm-ai-job-status-badge", inputs: ["status"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
463
468
|
}
|
|
464
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
469
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiSessionListComponent, decorators: [{
|
|
465
470
|
type: Component,
|
|
466
471
|
args: [{ selector: 'mm-ai-session-list', imports: [AiJobStatusBadgeComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ul class=\"mm-ai-session-list\">\n @for (session of orderedSessions(); track session.sessionRtId) {\n <li\n class=\"mm-ai-session-list__row\"\n [class.mm-ai-session-list__row--selected]=\"\n session.sessionRtId === selectedSessionId()\n \"\n >\n <button\n type=\"button\"\n class=\"mm-ai-session-list__button\"\n (click)=\"onSelect(session.sessionRtId)\"\n >\n <!--\n Row layout: goal + status badge on top, meta + actions on the\n bottom. The two-line shape lets a narrow sidebar (Refinery\n Studio caps the column at 18rem) breathe \u2014 the previous\n horizontal cram had the goal text overlap the action buttons\n on every row.\n -->\n <div class=\"mm-ai-session-list__top\">\n <span class=\"mm-ai-session-list__goal\">{{ session.goalSummary }}</span>\n <mm-ai-job-status-badge [status]=\"session.status\" />\n </div>\n <div class=\"mm-ai-session-list__bottom\">\n <span class=\"mm-ai-session-list__meta\">\n {{ age(session.startedAt) }}\n <span class=\"mm-ai-session-list__dot\">\u00B7</span>\n {{ session.tokensConsumed }} tok\n </span>\n @if (session.previewUrl) {\n <!--\n #4136 \u2014 preview-deploy URL the server surfaces when the\n worker pod's nginx sidecar has a build to serve. Opens in\n a new tab so the sidebar scroll position survives.\n stopPropagation prevents the row click from also firing.\n -->\n <a\n class=\"mm-ai-session-list__preview\"\n [href]=\"session.previewUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"$event.stopPropagation()\"\n >\n Preview\n </a>\n }\n <span class=\"mm-ai-session-list__spacer\"></span>\n <span class=\"mm-ai-session-list__actions\">\n @if (canCancel(session.status)) {\n <button\n type=\"button\"\n class=\"mm-ai-session-list__action mm-ai-session-list__action--cancel\"\n [attr.aria-label]=\"'Cancel session ' + session.goalSummary\"\n (click)=\"onCancel(session.sessionRtId, $event)\"\n >\n Cancel\n </button>\n }\n @if (canDelete(session.status)) {\n <button\n type=\"button\"\n class=\"mm-ai-session-list__action mm-ai-session-list__action--delete\"\n [attr.aria-label]=\"'Delete session ' + session.goalSummary\"\n (click)=\"onDelete(session.sessionRtId, $event)\"\n >\n Delete\n </button>\n }\n </span>\n </div>\n </button>\n </li>\n } @empty {\n <li class=\"mm-ai-session-list__empty\">No sessions yet.</li>\n }\n</ul>\n", styles: [":host{display:block;--mm-ai-list-bg: #16191d;--mm-ai-list-row-bg: #1f2227;--mm-ai-list-row-selected: #2a3142;--mm-ai-list-border: #2f343b;--mm-ai-list-text: #e6e6e6;--mm-ai-list-muted: #9aa0a6;--mm-ai-list-accent: #64ceb9;--mm-ai-list-action-cancel: #da9162;--mm-ai-list-action-delete: #ec658f}.mm-ai-session-list{list-style:none;margin:0;padding:0;background:var(--mm-ai-list-bg);border-radius:.5rem;display:flex;flex-direction:column;gap:.25rem;padding:.25rem}.mm-ai-session-list__row{background:var(--mm-ai-list-row-bg);border:1px solid var(--mm-ai-list-border);border-radius:.4rem}.mm-ai-session-list__row--selected{background:var(--mm-ai-list-row-selected)}.mm-ai-session-list__button{width:100%;display:flex;flex-direction:column;gap:.3rem;padding:.5rem .75rem;background:transparent;color:var(--mm-ai-list-text);border:none;cursor:pointer;text-align:left;font-family:inherit;min-width:0}.mm-ai-session-list__button:hover{background:#ffffff08}.mm-ai-session-list__top{display:flex;align-items:center;gap:.5rem;min-width:0}.mm-ai-session-list__goal{flex:1;min-width:0;font-size:.85rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mm-ai-session-list__bottom{display:flex;align-items:center;gap:.5rem;font-size:.7rem;color:var(--mm-ai-list-muted);font-variant-numeric:tabular-nums;min-width:0}.mm-ai-session-list__meta{display:inline-flex;align-items:baseline;gap:.35rem;flex-shrink:0}.mm-ai-session-list__dot{opacity:.5}.mm-ai-session-list__spacer{flex:1}.mm-ai-session-list__preview{color:var(--mm-ai-list-accent);font-size:.7rem;text-decoration:underline;text-underline-offset:2px;flex-shrink:0}.mm-ai-session-list__preview:hover{text-decoration-thickness:2px}.mm-ai-session-list__empty{padding:1rem;text-align:center;color:var(--mm-ai-list-muted);font-style:italic}.mm-ai-session-list__actions{display:flex;gap:.25rem;flex-shrink:0;opacity:.45;transition:opacity .15s ease}.mm-ai-session-list__row:hover .mm-ai-session-list__actions,.mm-ai-session-list__row--selected .mm-ai-session-list__actions{opacity:1}.mm-ai-session-list__action{padding:.15rem .5rem;background:transparent;border:1px solid var(--mm-ai-list-border);border-radius:.25rem;color:var(--mm-ai-list-text);font-family:inherit;font-size:.65rem;letter-spacing:.04em;text-transform:uppercase;cursor:pointer;transition:border-color .15s ease,color .15s ease,background-color .15s ease}.mm-ai-session-list__action:hover{background:#ffffff0a}.mm-ai-session-list__action--cancel{color:var(--mm-ai-list-action-cancel);border-color:color-mix(in srgb,var(--mm-ai-list-action-cancel) 40%,transparent)}.mm-ai-session-list__action--cancel:hover{border-color:var(--mm-ai-list-action-cancel)}.mm-ai-session-list__action--delete{color:var(--mm-ai-list-action-delete);border-color:color-mix(in srgb,var(--mm-ai-list-action-delete) 40%,transparent)}.mm-ai-session-list__action--delete:hover{border-color:var(--mm-ai-list-action-delete)}\n"] }]
|
|
467
472
|
}], propDecorators: { sessions: [{ type: i0.Input, args: [{ isSignal: true, alias: "sessions", required: true }] }], selectedSessionId: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedSessionId", required: false }] }], sessionSelected: [{ type: i0.Output, args: ["sessionSelected"] }], cancelRequested: [{ type: i0.Output, args: ["cancelRequested"] }], deleteRequested: [{ type: i0.Output, args: ["deleteRequested"] }] } });
|
|
@@ -791,18 +796,21 @@ function stringifyToolContent(content) {
|
|
|
791
796
|
* marked) is gated on a CSP review and a markdown-corpus regression test.
|
|
792
797
|
*/
|
|
793
798
|
class AiChatStreamComponent {
|
|
794
|
-
events = input.required(
|
|
799
|
+
events = input.required(/* @ts-ignore */
|
|
800
|
+
...(ngDevMode ? [{ debugName: "events" }] : /* istanbul ignore next */ []));
|
|
795
801
|
/**
|
|
796
802
|
* Sorted + parsed. Recomputes whenever the input signal changes; the sort
|
|
797
803
|
* is stable so live appends from SignalR keep prior render positions.
|
|
798
804
|
*/
|
|
799
|
-
parsedEvents = computed(() => parseAndOrder(this.events()),
|
|
805
|
+
parsedEvents = computed(() => parseAndOrder(this.events()), /* @ts-ignore */
|
|
806
|
+
...(ngDevMode ? [{ debugName: "parsedEvents" }] : /* istanbul ignore next */ []));
|
|
800
807
|
/**
|
|
801
808
|
* Per-event "show raw JSON" toggle. Keyed by sequence so live appends
|
|
802
809
|
* don't flicker existing toggles closed. A `Set<number>` rather than a
|
|
803
810
|
* record so add / delete avoids `keyof` shenanigans.
|
|
804
811
|
*/
|
|
805
|
-
expandedSet = signal(new Set(),
|
|
812
|
+
expandedSet = signal(new Set(), /* @ts-ignore */
|
|
813
|
+
...(ngDevMode ? [{ debugName: "expandedSet" }] : /* istanbul ignore next */ []));
|
|
806
814
|
isExpanded(sequence) {
|
|
807
815
|
return this.expandedSet().has(sequence);
|
|
808
816
|
}
|
|
@@ -866,10 +874,10 @@ class AiChatStreamComponent {
|
|
|
866
874
|
return String(value);
|
|
867
875
|
}
|
|
868
876
|
}
|
|
869
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
870
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AiChatStreamComponent, isStandalone: true, selector: "mm-ai-chat-stream", inputs: { events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"mm-ai-chat\">\n @for (parsed of parsedEvents(); track parsed.event.sequence) {\n @switch (parsed.view.kind) {\n @case ('assistant') {\n <article class=\"mm-ai-chat__bubble mm-ai-chat__bubble--assistant\">\n <header class=\"mm-ai-chat__bubble-header\">\n <span class=\"mm-ai-chat__role\">Assistant</span>\n @if (parsed.view.model; as model) {\n <span class=\"mm-ai-chat__meta\">{{ model }}</span>\n }\n @if (parsed.view.usage; as usage) {\n <span class=\"mm-ai-chat__meta\">\n {{ formatTokenCount(usage.input + usage.output) }}\n </span>\n }\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </header>\n @for (part of parsed.view.parts; track $index) {\n @switch (part.type) {\n @case ('text') {\n <p class=\"mm-ai-chat__text\">{{ part.text }}</p>\n }\n @case ('tool_use') {\n <div class=\"mm-ai-chat__tool-use\">\n <header class=\"mm-ai-chat__tool-use-header\">\n <span class=\"mm-ai-chat__tool-badge\">tool</span>\n <span class=\"mm-ai-chat__tool-name\">{{ part.toolName }}</span>\n </header>\n <pre class=\"mm-ai-chat__tool-input\">{{ formatRaw(part.input) }}</pre>\n </div>\n }\n }\n }\n </article>\n }\n\n @case ('tool-result') {\n <article\n class=\"mm-ai-chat__tool-result\"\n [class.mm-ai-chat__tool-result--error]=\"parsed.view.isError\"\n >\n <header class=\"mm-ai-chat__tool-result-header\">\n <span class=\"mm-ai-chat__role\">Tool result</span>\n @if (parsed.view.isError) {\n <span class=\"mm-ai-chat__error-badge\">error</span>\n }\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </header>\n <pre class=\"mm-ai-chat__tool-result-body\">{{ parsed.view.content }}</pre>\n </article>\n }\n\n @case ('result') {\n <article class=\"mm-ai-chat__result\"\n [class.mm-ai-chat__result--error]=\"parsed.view.isError\">\n <header class=\"mm-ai-chat__result-header\">\n <span class=\"mm-ai-chat__role\">{{ parsed.view.reason }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </header>\n @if (parsed.view.text) {\n <p class=\"mm-ai-chat__result-text\">{{ parsed.view.text }}</p>\n }\n <dl class=\"mm-ai-chat__result-stats\">\n <div>\n <dt>Duration</dt>\n <dd>{{ formatDuration(parsed.view.durationMs) }}</dd>\n </div>\n <div>\n <dt>Tokens (in/out)</dt>\n <dd>\n @if (parsed.view.usage) {\n {{ formatTokenCount(parsed.view.usage.input) }}\n /\n {{ formatTokenCount(parsed.view.usage.output) }}\n } @else {\n \u2014\n }\n </dd>\n </div>\n <div>\n <dt>Cost</dt>\n <dd>{{ formatCost(parsed.view.costUsd) }}</dd>\n </div>\n </dl>\n </article>\n }\n\n @case ('system') {\n <button\n type=\"button\"\n class=\"mm-ai-chat__system\"\n [class.mm-ai-chat__system--init]=\"parsed.view.subKind === 'init'\"\n [class.mm-ai-chat__system--hook]=\"parsed.view.subKind === 'hook'\"\n [class.mm-ai-chat__system--rate]=\"parsed.view.subKind === 'rate-limit'\"\n [attr.aria-expanded]=\"isExpanded(parsed.event.sequence)\"\n (click)=\"toggleRaw(parsed.event.sequence)\"\n >\n <span class=\"mm-ai-chat__system-chevron\">\n {{ isExpanded(parsed.event.sequence) ? '\u25BE' : '\u25B8' }}\n </span>\n <span class=\"mm-ai-chat__system-summary\">{{ parsed.view.summary }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </button>\n @if (isExpanded(parsed.event.sequence)) {\n <pre class=\"mm-ai-chat__system-detail\">{{ formatRaw(parsed.view.raw) }}</pre>\n }\n }\n\n @case ('status-change') {\n <div class=\"mm-ai-chat__status\">\n <span class=\"mm-ai-chat__status-label\">Status</span>\n <span class=\"mm-ai-chat__status-value\">{{ parsed.view.status }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </div>\n }\n\n @case ('unknown') {\n <button\n type=\"button\"\n class=\"mm-ai-chat__system mm-ai-chat__system--unknown\"\n [attr.aria-expanded]=\"isExpanded(parsed.event.sequence)\"\n (click)=\"toggleRaw(parsed.event.sequence)\"\n >\n <span class=\"mm-ai-chat__system-chevron\">\n {{ isExpanded(parsed.event.sequence) ? '\u25BE' : '\u25B8' }}\n </span>\n <span class=\"mm-ai-chat__system-summary\">{{ parsed.view.summary }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </button>\n @if (isExpanded(parsed.event.sequence)) {\n <pre class=\"mm-ai-chat__system-detail\">{{ formatRaw(parsed.view.raw) }}</pre>\n }\n }\n }\n } @empty {\n <div class=\"mm-ai-chat__empty\">\n No events yet \u2014 the worker hasn't emitted anything.\n </div>\n }\n</div>\n", styles: [":host{display:block;--mm-ai-chat-bg: transparent;--mm-ai-chat-card-bg: rgba(31, 46, 64, .55);--mm-ai-chat-card-bg-elevated: rgba(31, 46, 64, .85);--mm-ai-chat-border: rgba(100, 206, 185, .18);--mm-ai-chat-border-strong: rgba(100, 206, 185, .4);--mm-ai-chat-text: #e6e6e6;--mm-ai-chat-muted: #9292a6;--mm-ai-chat-accent-assistant: #64ceb9;--mm-ai-chat-accent-tool: #00a8dc;--mm-ai-chat-accent-tool-result: #00a8dc;--mm-ai-chat-accent-system: #6c4da8;--mm-ai-chat-accent-rate-limit: #da9162;--mm-ai-chat-accent-result: #64ceb9;--mm-ai-chat-accent-error: #ec658f}.mm-ai-chat{display:flex;flex-direction:column;gap:.5rem;padding:.25rem;background:var(--mm-ai-chat-bg);color:var(--mm-ai-chat-text);font-size:.85rem;line-height:1.45}.mm-ai-chat__empty{color:var(--mm-ai-chat-muted);text-align:center;padding:1.5rem;font-style:italic}.mm-ai-chat__bubble{background:var(--mm-ai-chat-card-bg);border:1px solid var(--mm-ai-chat-border);border-left:3px solid var(--mm-ai-chat-accent-assistant);border-radius:.5rem;padding:.6rem .75rem;display:flex;flex-direction:column;gap:.5rem}.mm-ai-chat__bubble-header{display:flex;align-items:baseline;gap:.5rem;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__role{font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--mm-ai-chat-accent-assistant)}.mm-ai-chat__meta{font-family:Roboto Mono,monospace;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__time{margin-left:auto;font-variant-numeric:tabular-nums;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__text{margin:0;white-space:pre-wrap;word-break:break-word}.mm-ai-chat__tool-use{border:1px solid var(--mm-ai-chat-border);border-left:2px solid var(--mm-ai-chat-accent-tool);border-radius:.35rem;background:var(--mm-ai-chat-card-bg-elevated);padding:.4rem .5rem}.mm-ai-chat__tool-use-header{display:flex;align-items:baseline;gap:.4rem;font-size:.7rem}.mm-ai-chat__tool-badge{background:var(--mm-ai-chat-accent-tool);color:#07172b;padding:0 6px;border-radius:.25rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;font-size:.65rem}.mm-ai-chat__tool-name{font-family:Roboto Mono,monospace;color:var(--mm-ai-chat-text);font-weight:600}.mm-ai-chat__tool-input{margin:.35rem 0 0;font-family:Roboto Mono,monospace;font-size:.75rem;white-space:pre-wrap;word-break:break-word;color:var(--mm-ai-chat-muted);max-height:14rem;overflow-y:auto}.mm-ai-chat__tool-result{background:var(--mm-ai-chat-card-bg);border:1px solid var(--mm-ai-chat-border);border-left:3px solid var(--mm-ai-chat-accent-tool-result);border-radius:.5rem;padding:.55rem .75rem;margin-left:1.25rem}.mm-ai-chat__tool-result--error{border-left-color:var(--mm-ai-chat-accent-error)}.mm-ai-chat__tool-result-header{display:flex;align-items:baseline;gap:.5rem;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__tool-result-header .mm-ai-chat__role{color:var(--mm-ai-chat-accent-tool-result)}.mm-ai-chat__error-badge{background:var(--mm-ai-chat-accent-error);color:#07172b;padding:0 6px;border-radius:.25rem;font-size:.6rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase}.mm-ai-chat__tool-result-body{margin:.4rem 0 0;font-family:Roboto Mono,monospace;font-size:.75rem;white-space:pre-wrap;word-break:break-word;max-height:18rem;overflow-y:auto}.mm-ai-chat__result{background:var(--mm-ai-chat-card-bg-elevated);border:1px solid var(--mm-ai-chat-border-strong);border-top:3px solid var(--mm-ai-chat-accent-result);border-radius:.5rem;padding:.7rem .85rem;display:flex;flex-direction:column;gap:.5rem}.mm-ai-chat__result--error{border-top-color:var(--mm-ai-chat-accent-error)}.mm-ai-chat__result-header{display:flex;align-items:baseline;gap:.5rem;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__result-header .mm-ai-chat__role{color:var(--mm-ai-chat-accent-result);text-transform:uppercase}.mm-ai-chat__result-text{margin:0;white-space:pre-wrap;word-break:break-word;font-style:italic;color:var(--mm-ai-chat-text)}.mm-ai-chat__result-stats{margin:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));gap:.5rem;font-family:Roboto Mono,monospace;font-size:.75rem}.mm-ai-chat__result-stats div{display:flex;flex-direction:column;gap:.2rem;padding:.4rem .5rem;background:#64ceb90f;border-radius:.3rem}.mm-ai-chat__result-stats dt{font-size:.62rem;text-transform:uppercase;letter-spacing:.08em;color:var(--mm-ai-chat-muted)}.mm-ai-chat__result-stats dd{margin:0;color:var(--mm-ai-chat-text);font-variant-numeric:tabular-nums}.mm-ai-chat__system{all:unset;cursor:pointer;display:flex;align-items:center;gap:.5rem;padding:.35rem .6rem;background:#64ceb908;border:1px solid var(--mm-ai-chat-border);border-left:2px solid var(--mm-ai-chat-accent-system);border-radius:.4rem;font-size:.78rem;color:var(--mm-ai-chat-muted);transition:background-color .15s ease}.mm-ai-chat__system:hover{background:#64ceb90f}.mm-ai-chat__system:focus-visible{outline:2px solid var(--mm-ai-chat-accent-assistant);outline-offset:1px}.mm-ai-chat__system--init{border-left-color:var(--mm-ai-chat-accent-tool)}.mm-ai-chat__system--hook{border-left-color:var(--mm-ai-chat-accent-system)}.mm-ai-chat__system--rate{border-left-color:var(--mm-ai-chat-accent-rate-limit)}.mm-ai-chat__system--unknown{border-left-color:var(--mm-ai-chat-accent-error)}.mm-ai-chat__system-chevron{font-size:.7rem;width:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__system-summary{flex:1;color:var(--mm-ai-chat-text);font-variant-numeric:tabular-nums}.mm-ai-chat__system-detail{margin:-.25rem 0 0 1.5rem;padding:.5rem .6rem;background:#00000040;border-radius:.35rem;font-family:Roboto Mono,monospace;font-size:.7rem;white-space:pre-wrap;word-break:break-word;max-height:22rem;overflow-y:auto;color:var(--mm-ai-chat-muted)}.mm-ai-chat__status{display:flex;align-items:baseline;gap:.5rem;padding:.25rem .5rem;font-size:.7rem;color:var(--mm-ai-chat-muted);text-transform:uppercase;letter-spacing:.06em}.mm-ai-chat__status-label{color:var(--mm-ai-chat-muted)}.mm-ai-chat__status-value{color:var(--mm-ai-chat-text);font-weight:600}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
877
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiChatStreamComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
878
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: AiChatStreamComponent, isStandalone: true, selector: "mm-ai-chat-stream", inputs: { events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"mm-ai-chat\">\n @for (parsed of parsedEvents(); track parsed.event.sequence) {\n @switch (parsed.view.kind) {\n @case ('assistant') {\n <article class=\"mm-ai-chat__bubble mm-ai-chat__bubble--assistant\">\n <header class=\"mm-ai-chat__bubble-header\">\n <span class=\"mm-ai-chat__role\">Assistant</span>\n @if (parsed.view.model; as model) {\n <span class=\"mm-ai-chat__meta\">{{ model }}</span>\n }\n @if (parsed.view.usage; as usage) {\n <span class=\"mm-ai-chat__meta\">\n {{ formatTokenCount(usage.input + usage.output) }}\n </span>\n }\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </header>\n @for (part of parsed.view.parts; track $index) {\n @switch (part.type) {\n @case ('text') {\n <p class=\"mm-ai-chat__text\">{{ part.text }}</p>\n }\n @case ('tool_use') {\n <div class=\"mm-ai-chat__tool-use\">\n <header class=\"mm-ai-chat__tool-use-header\">\n <span class=\"mm-ai-chat__tool-badge\">tool</span>\n <span class=\"mm-ai-chat__tool-name\">{{ part.toolName }}</span>\n </header>\n <pre class=\"mm-ai-chat__tool-input\">{{ formatRaw(part.input) }}</pre>\n </div>\n }\n }\n }\n </article>\n }\n\n @case ('tool-result') {\n <article\n class=\"mm-ai-chat__tool-result\"\n [class.mm-ai-chat__tool-result--error]=\"parsed.view.isError\"\n >\n <header class=\"mm-ai-chat__tool-result-header\">\n <span class=\"mm-ai-chat__role\">Tool result</span>\n @if (parsed.view.isError) {\n <span class=\"mm-ai-chat__error-badge\">error</span>\n }\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </header>\n <pre class=\"mm-ai-chat__tool-result-body\">{{ parsed.view.content }}</pre>\n </article>\n }\n\n @case ('result') {\n <article class=\"mm-ai-chat__result\"\n [class.mm-ai-chat__result--error]=\"parsed.view.isError\">\n <header class=\"mm-ai-chat__result-header\">\n <span class=\"mm-ai-chat__role\">{{ parsed.view.reason }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </header>\n @if (parsed.view.text) {\n <p class=\"mm-ai-chat__result-text\">{{ parsed.view.text }}</p>\n }\n <dl class=\"mm-ai-chat__result-stats\">\n <div>\n <dt>Duration</dt>\n <dd>{{ formatDuration(parsed.view.durationMs) }}</dd>\n </div>\n <div>\n <dt>Tokens (in/out)</dt>\n <dd>\n @if (parsed.view.usage) {\n {{ formatTokenCount(parsed.view.usage.input) }}\n /\n {{ formatTokenCount(parsed.view.usage.output) }}\n } @else {\n \u2014\n }\n </dd>\n </div>\n <div>\n <dt>Cost</dt>\n <dd>{{ formatCost(parsed.view.costUsd) }}</dd>\n </div>\n </dl>\n </article>\n }\n\n @case ('system') {\n <button\n type=\"button\"\n class=\"mm-ai-chat__system\"\n [class.mm-ai-chat__system--init]=\"parsed.view.subKind === 'init'\"\n [class.mm-ai-chat__system--hook]=\"parsed.view.subKind === 'hook'\"\n [class.mm-ai-chat__system--rate]=\"parsed.view.subKind === 'rate-limit'\"\n [attr.aria-expanded]=\"isExpanded(parsed.event.sequence)\"\n (click)=\"toggleRaw(parsed.event.sequence)\"\n >\n <span class=\"mm-ai-chat__system-chevron\">\n {{ isExpanded(parsed.event.sequence) ? '\u25BE' : '\u25B8' }}\n </span>\n <span class=\"mm-ai-chat__system-summary\">{{ parsed.view.summary }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </button>\n @if (isExpanded(parsed.event.sequence)) {\n <pre class=\"mm-ai-chat__system-detail\">{{ formatRaw(parsed.view.raw) }}</pre>\n }\n }\n\n @case ('status-change') {\n <div class=\"mm-ai-chat__status\">\n <span class=\"mm-ai-chat__status-label\">Status</span>\n <span class=\"mm-ai-chat__status-value\">{{ parsed.view.status }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </div>\n }\n\n @case ('unknown') {\n <button\n type=\"button\"\n class=\"mm-ai-chat__system mm-ai-chat__system--unknown\"\n [attr.aria-expanded]=\"isExpanded(parsed.event.sequence)\"\n (click)=\"toggleRaw(parsed.event.sequence)\"\n >\n <span class=\"mm-ai-chat__system-chevron\">\n {{ isExpanded(parsed.event.sequence) ? '\u25BE' : '\u25B8' }}\n </span>\n <span class=\"mm-ai-chat__system-summary\">{{ parsed.view.summary }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </button>\n @if (isExpanded(parsed.event.sequence)) {\n <pre class=\"mm-ai-chat__system-detail\">{{ formatRaw(parsed.view.raw) }}</pre>\n }\n }\n }\n } @empty {\n <div class=\"mm-ai-chat__empty\">\n No events yet \u2014 the worker hasn't emitted anything.\n </div>\n }\n</div>\n", styles: [":host{display:block;--mm-ai-chat-bg: transparent;--mm-ai-chat-card-bg: rgba(31, 46, 64, .55);--mm-ai-chat-card-bg-elevated: rgba(31, 46, 64, .85);--mm-ai-chat-border: rgba(100, 206, 185, .18);--mm-ai-chat-border-strong: rgba(100, 206, 185, .4);--mm-ai-chat-text: #e6e6e6;--mm-ai-chat-muted: #9292a6;--mm-ai-chat-accent-assistant: #64ceb9;--mm-ai-chat-accent-tool: #00a8dc;--mm-ai-chat-accent-tool-result: #00a8dc;--mm-ai-chat-accent-system: #6c4da8;--mm-ai-chat-accent-rate-limit: #da9162;--mm-ai-chat-accent-result: #64ceb9;--mm-ai-chat-accent-error: #ec658f}.mm-ai-chat{display:flex;flex-direction:column;gap:.5rem;padding:.25rem;background:var(--mm-ai-chat-bg);color:var(--mm-ai-chat-text);font-size:.85rem;line-height:1.45}.mm-ai-chat__empty{color:var(--mm-ai-chat-muted);text-align:center;padding:1.5rem;font-style:italic}.mm-ai-chat__bubble{background:var(--mm-ai-chat-card-bg);border:1px solid var(--mm-ai-chat-border);border-left:3px solid var(--mm-ai-chat-accent-assistant);border-radius:.5rem;padding:.6rem .75rem;display:flex;flex-direction:column;gap:.5rem}.mm-ai-chat__bubble-header{display:flex;align-items:baseline;gap:.5rem;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__role{font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--mm-ai-chat-accent-assistant)}.mm-ai-chat__meta{font-family:Roboto Mono,monospace;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__time{margin-left:auto;font-variant-numeric:tabular-nums;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__text{margin:0;white-space:pre-wrap;word-break:break-word}.mm-ai-chat__tool-use{border:1px solid var(--mm-ai-chat-border);border-left:2px solid var(--mm-ai-chat-accent-tool);border-radius:.35rem;background:var(--mm-ai-chat-card-bg-elevated);padding:.4rem .5rem}.mm-ai-chat__tool-use-header{display:flex;align-items:baseline;gap:.4rem;font-size:.7rem}.mm-ai-chat__tool-badge{background:var(--mm-ai-chat-accent-tool);color:#07172b;padding:0 6px;border-radius:.25rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;font-size:.65rem}.mm-ai-chat__tool-name{font-family:Roboto Mono,monospace;color:var(--mm-ai-chat-text);font-weight:600}.mm-ai-chat__tool-input{margin:.35rem 0 0;font-family:Roboto Mono,monospace;font-size:.75rem;white-space:pre-wrap;word-break:break-word;color:var(--mm-ai-chat-muted);max-height:14rem;overflow-y:auto}.mm-ai-chat__tool-result{background:var(--mm-ai-chat-card-bg);border:1px solid var(--mm-ai-chat-border);border-left:3px solid var(--mm-ai-chat-accent-tool-result);border-radius:.5rem;padding:.55rem .75rem;margin-left:1.25rem}.mm-ai-chat__tool-result--error{border-left-color:var(--mm-ai-chat-accent-error)}.mm-ai-chat__tool-result-header{display:flex;align-items:baseline;gap:.5rem;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__tool-result-header .mm-ai-chat__role{color:var(--mm-ai-chat-accent-tool-result)}.mm-ai-chat__error-badge{background:var(--mm-ai-chat-accent-error);color:#07172b;padding:0 6px;border-radius:.25rem;font-size:.6rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase}.mm-ai-chat__tool-result-body{margin:.4rem 0 0;font-family:Roboto Mono,monospace;font-size:.75rem;white-space:pre-wrap;word-break:break-word;max-height:18rem;overflow-y:auto}.mm-ai-chat__result{background:var(--mm-ai-chat-card-bg-elevated);border:1px solid var(--mm-ai-chat-border-strong);border-top:3px solid var(--mm-ai-chat-accent-result);border-radius:.5rem;padding:.7rem .85rem;display:flex;flex-direction:column;gap:.5rem}.mm-ai-chat__result--error{border-top-color:var(--mm-ai-chat-accent-error)}.mm-ai-chat__result-header{display:flex;align-items:baseline;gap:.5rem;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__result-header .mm-ai-chat__role{color:var(--mm-ai-chat-accent-result);text-transform:uppercase}.mm-ai-chat__result-text{margin:0;white-space:pre-wrap;word-break:break-word;font-style:italic;color:var(--mm-ai-chat-text)}.mm-ai-chat__result-stats{margin:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));gap:.5rem;font-family:Roboto Mono,monospace;font-size:.75rem}.mm-ai-chat__result-stats div{display:flex;flex-direction:column;gap:.2rem;padding:.4rem .5rem;background:#64ceb90f;border-radius:.3rem}.mm-ai-chat__result-stats dt{font-size:.62rem;text-transform:uppercase;letter-spacing:.08em;color:var(--mm-ai-chat-muted)}.mm-ai-chat__result-stats dd{margin:0;color:var(--mm-ai-chat-text);font-variant-numeric:tabular-nums}.mm-ai-chat__system{all:unset;cursor:pointer;display:flex;align-items:center;gap:.5rem;padding:.35rem .6rem;background:#64ceb908;border:1px solid var(--mm-ai-chat-border);border-left:2px solid var(--mm-ai-chat-accent-system);border-radius:.4rem;font-size:.78rem;color:var(--mm-ai-chat-muted);transition:background-color .15s ease}.mm-ai-chat__system:hover{background:#64ceb90f}.mm-ai-chat__system:focus-visible{outline:2px solid var(--mm-ai-chat-accent-assistant);outline-offset:1px}.mm-ai-chat__system--init{border-left-color:var(--mm-ai-chat-accent-tool)}.mm-ai-chat__system--hook{border-left-color:var(--mm-ai-chat-accent-system)}.mm-ai-chat__system--rate{border-left-color:var(--mm-ai-chat-accent-rate-limit)}.mm-ai-chat__system--unknown{border-left-color:var(--mm-ai-chat-accent-error)}.mm-ai-chat__system-chevron{font-size:.7rem;width:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__system-summary{flex:1;color:var(--mm-ai-chat-text);font-variant-numeric:tabular-nums}.mm-ai-chat__system-detail{margin:-.25rem 0 0 1.5rem;padding:.5rem .6rem;background:#00000040;border-radius:.35rem;font-family:Roboto Mono,monospace;font-size:.7rem;white-space:pre-wrap;word-break:break-word;max-height:22rem;overflow-y:auto;color:var(--mm-ai-chat-muted)}.mm-ai-chat__status{display:flex;align-items:baseline;gap:.5rem;padding:.25rem .5rem;font-size:.7rem;color:var(--mm-ai-chat-muted);text-transform:uppercase;letter-spacing:.06em}.mm-ai-chat__status-label{color:var(--mm-ai-chat-muted)}.mm-ai-chat__status-value{color:var(--mm-ai-chat-text);font-weight:600}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
871
879
|
}
|
|
872
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
880
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiChatStreamComponent, decorators: [{
|
|
873
881
|
type: Component,
|
|
874
882
|
args: [{ selector: 'mm-ai-chat-stream', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"mm-ai-chat\">\n @for (parsed of parsedEvents(); track parsed.event.sequence) {\n @switch (parsed.view.kind) {\n @case ('assistant') {\n <article class=\"mm-ai-chat__bubble mm-ai-chat__bubble--assistant\">\n <header class=\"mm-ai-chat__bubble-header\">\n <span class=\"mm-ai-chat__role\">Assistant</span>\n @if (parsed.view.model; as model) {\n <span class=\"mm-ai-chat__meta\">{{ model }}</span>\n }\n @if (parsed.view.usage; as usage) {\n <span class=\"mm-ai-chat__meta\">\n {{ formatTokenCount(usage.input + usage.output) }}\n </span>\n }\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </header>\n @for (part of parsed.view.parts; track $index) {\n @switch (part.type) {\n @case ('text') {\n <p class=\"mm-ai-chat__text\">{{ part.text }}</p>\n }\n @case ('tool_use') {\n <div class=\"mm-ai-chat__tool-use\">\n <header class=\"mm-ai-chat__tool-use-header\">\n <span class=\"mm-ai-chat__tool-badge\">tool</span>\n <span class=\"mm-ai-chat__tool-name\">{{ part.toolName }}</span>\n </header>\n <pre class=\"mm-ai-chat__tool-input\">{{ formatRaw(part.input) }}</pre>\n </div>\n }\n }\n }\n </article>\n }\n\n @case ('tool-result') {\n <article\n class=\"mm-ai-chat__tool-result\"\n [class.mm-ai-chat__tool-result--error]=\"parsed.view.isError\"\n >\n <header class=\"mm-ai-chat__tool-result-header\">\n <span class=\"mm-ai-chat__role\">Tool result</span>\n @if (parsed.view.isError) {\n <span class=\"mm-ai-chat__error-badge\">error</span>\n }\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </header>\n <pre class=\"mm-ai-chat__tool-result-body\">{{ parsed.view.content }}</pre>\n </article>\n }\n\n @case ('result') {\n <article class=\"mm-ai-chat__result\"\n [class.mm-ai-chat__result--error]=\"parsed.view.isError\">\n <header class=\"mm-ai-chat__result-header\">\n <span class=\"mm-ai-chat__role\">{{ parsed.view.reason }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </header>\n @if (parsed.view.text) {\n <p class=\"mm-ai-chat__result-text\">{{ parsed.view.text }}</p>\n }\n <dl class=\"mm-ai-chat__result-stats\">\n <div>\n <dt>Duration</dt>\n <dd>{{ formatDuration(parsed.view.durationMs) }}</dd>\n </div>\n <div>\n <dt>Tokens (in/out)</dt>\n <dd>\n @if (parsed.view.usage) {\n {{ formatTokenCount(parsed.view.usage.input) }}\n /\n {{ formatTokenCount(parsed.view.usage.output) }}\n } @else {\n \u2014\n }\n </dd>\n </div>\n <div>\n <dt>Cost</dt>\n <dd>{{ formatCost(parsed.view.costUsd) }}</dd>\n </div>\n </dl>\n </article>\n }\n\n @case ('system') {\n <button\n type=\"button\"\n class=\"mm-ai-chat__system\"\n [class.mm-ai-chat__system--init]=\"parsed.view.subKind === 'init'\"\n [class.mm-ai-chat__system--hook]=\"parsed.view.subKind === 'hook'\"\n [class.mm-ai-chat__system--rate]=\"parsed.view.subKind === 'rate-limit'\"\n [attr.aria-expanded]=\"isExpanded(parsed.event.sequence)\"\n (click)=\"toggleRaw(parsed.event.sequence)\"\n >\n <span class=\"mm-ai-chat__system-chevron\">\n {{ isExpanded(parsed.event.sequence) ? '\u25BE' : '\u25B8' }}\n </span>\n <span class=\"mm-ai-chat__system-summary\">{{ parsed.view.summary }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </button>\n @if (isExpanded(parsed.event.sequence)) {\n <pre class=\"mm-ai-chat__system-detail\">{{ formatRaw(parsed.view.raw) }}</pre>\n }\n }\n\n @case ('status-change') {\n <div class=\"mm-ai-chat__status\">\n <span class=\"mm-ai-chat__status-label\">Status</span>\n <span class=\"mm-ai-chat__status-value\">{{ parsed.view.status }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </div>\n }\n\n @case ('unknown') {\n <button\n type=\"button\"\n class=\"mm-ai-chat__system mm-ai-chat__system--unknown\"\n [attr.aria-expanded]=\"isExpanded(parsed.event.sequence)\"\n (click)=\"toggleRaw(parsed.event.sequence)\"\n >\n <span class=\"mm-ai-chat__system-chevron\">\n {{ isExpanded(parsed.event.sequence) ? '\u25BE' : '\u25B8' }}\n </span>\n <span class=\"mm-ai-chat__system-summary\">{{ parsed.view.summary }}</span>\n <time class=\"mm-ai-chat__time\">{{ formatTime(parsed.event.at) }}</time>\n </button>\n @if (isExpanded(parsed.event.sequence)) {\n <pre class=\"mm-ai-chat__system-detail\">{{ formatRaw(parsed.view.raw) }}</pre>\n }\n }\n }\n } @empty {\n <div class=\"mm-ai-chat__empty\">\n No events yet \u2014 the worker hasn't emitted anything.\n </div>\n }\n</div>\n", styles: [":host{display:block;--mm-ai-chat-bg: transparent;--mm-ai-chat-card-bg: rgba(31, 46, 64, .55);--mm-ai-chat-card-bg-elevated: rgba(31, 46, 64, .85);--mm-ai-chat-border: rgba(100, 206, 185, .18);--mm-ai-chat-border-strong: rgba(100, 206, 185, .4);--mm-ai-chat-text: #e6e6e6;--mm-ai-chat-muted: #9292a6;--mm-ai-chat-accent-assistant: #64ceb9;--mm-ai-chat-accent-tool: #00a8dc;--mm-ai-chat-accent-tool-result: #00a8dc;--mm-ai-chat-accent-system: #6c4da8;--mm-ai-chat-accent-rate-limit: #da9162;--mm-ai-chat-accent-result: #64ceb9;--mm-ai-chat-accent-error: #ec658f}.mm-ai-chat{display:flex;flex-direction:column;gap:.5rem;padding:.25rem;background:var(--mm-ai-chat-bg);color:var(--mm-ai-chat-text);font-size:.85rem;line-height:1.45}.mm-ai-chat__empty{color:var(--mm-ai-chat-muted);text-align:center;padding:1.5rem;font-style:italic}.mm-ai-chat__bubble{background:var(--mm-ai-chat-card-bg);border:1px solid var(--mm-ai-chat-border);border-left:3px solid var(--mm-ai-chat-accent-assistant);border-radius:.5rem;padding:.6rem .75rem;display:flex;flex-direction:column;gap:.5rem}.mm-ai-chat__bubble-header{display:flex;align-items:baseline;gap:.5rem;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__role{font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--mm-ai-chat-accent-assistant)}.mm-ai-chat__meta{font-family:Roboto Mono,monospace;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__time{margin-left:auto;font-variant-numeric:tabular-nums;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__text{margin:0;white-space:pre-wrap;word-break:break-word}.mm-ai-chat__tool-use{border:1px solid var(--mm-ai-chat-border);border-left:2px solid var(--mm-ai-chat-accent-tool);border-radius:.35rem;background:var(--mm-ai-chat-card-bg-elevated);padding:.4rem .5rem}.mm-ai-chat__tool-use-header{display:flex;align-items:baseline;gap:.4rem;font-size:.7rem}.mm-ai-chat__tool-badge{background:var(--mm-ai-chat-accent-tool);color:#07172b;padding:0 6px;border-radius:.25rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;font-size:.65rem}.mm-ai-chat__tool-name{font-family:Roboto Mono,monospace;color:var(--mm-ai-chat-text);font-weight:600}.mm-ai-chat__tool-input{margin:.35rem 0 0;font-family:Roboto Mono,monospace;font-size:.75rem;white-space:pre-wrap;word-break:break-word;color:var(--mm-ai-chat-muted);max-height:14rem;overflow-y:auto}.mm-ai-chat__tool-result{background:var(--mm-ai-chat-card-bg);border:1px solid var(--mm-ai-chat-border);border-left:3px solid var(--mm-ai-chat-accent-tool-result);border-radius:.5rem;padding:.55rem .75rem;margin-left:1.25rem}.mm-ai-chat__tool-result--error{border-left-color:var(--mm-ai-chat-accent-error)}.mm-ai-chat__tool-result-header{display:flex;align-items:baseline;gap:.5rem;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__tool-result-header .mm-ai-chat__role{color:var(--mm-ai-chat-accent-tool-result)}.mm-ai-chat__error-badge{background:var(--mm-ai-chat-accent-error);color:#07172b;padding:0 6px;border-radius:.25rem;font-size:.6rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase}.mm-ai-chat__tool-result-body{margin:.4rem 0 0;font-family:Roboto Mono,monospace;font-size:.75rem;white-space:pre-wrap;word-break:break-word;max-height:18rem;overflow-y:auto}.mm-ai-chat__result{background:var(--mm-ai-chat-card-bg-elevated);border:1px solid var(--mm-ai-chat-border-strong);border-top:3px solid var(--mm-ai-chat-accent-result);border-radius:.5rem;padding:.7rem .85rem;display:flex;flex-direction:column;gap:.5rem}.mm-ai-chat__result--error{border-top-color:var(--mm-ai-chat-accent-error)}.mm-ai-chat__result-header{display:flex;align-items:baseline;gap:.5rem;font-size:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__result-header .mm-ai-chat__role{color:var(--mm-ai-chat-accent-result);text-transform:uppercase}.mm-ai-chat__result-text{margin:0;white-space:pre-wrap;word-break:break-word;font-style:italic;color:var(--mm-ai-chat-text)}.mm-ai-chat__result-stats{margin:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));gap:.5rem;font-family:Roboto Mono,monospace;font-size:.75rem}.mm-ai-chat__result-stats div{display:flex;flex-direction:column;gap:.2rem;padding:.4rem .5rem;background:#64ceb90f;border-radius:.3rem}.mm-ai-chat__result-stats dt{font-size:.62rem;text-transform:uppercase;letter-spacing:.08em;color:var(--mm-ai-chat-muted)}.mm-ai-chat__result-stats dd{margin:0;color:var(--mm-ai-chat-text);font-variant-numeric:tabular-nums}.mm-ai-chat__system{all:unset;cursor:pointer;display:flex;align-items:center;gap:.5rem;padding:.35rem .6rem;background:#64ceb908;border:1px solid var(--mm-ai-chat-border);border-left:2px solid var(--mm-ai-chat-accent-system);border-radius:.4rem;font-size:.78rem;color:var(--mm-ai-chat-muted);transition:background-color .15s ease}.mm-ai-chat__system:hover{background:#64ceb90f}.mm-ai-chat__system:focus-visible{outline:2px solid var(--mm-ai-chat-accent-assistant);outline-offset:1px}.mm-ai-chat__system--init{border-left-color:var(--mm-ai-chat-accent-tool)}.mm-ai-chat__system--hook{border-left-color:var(--mm-ai-chat-accent-system)}.mm-ai-chat__system--rate{border-left-color:var(--mm-ai-chat-accent-rate-limit)}.mm-ai-chat__system--unknown{border-left-color:var(--mm-ai-chat-accent-error)}.mm-ai-chat__system-chevron{font-size:.7rem;width:.7rem;color:var(--mm-ai-chat-muted)}.mm-ai-chat__system-summary{flex:1;color:var(--mm-ai-chat-text);font-variant-numeric:tabular-nums}.mm-ai-chat__system-detail{margin:-.25rem 0 0 1.5rem;padding:.5rem .6rem;background:#00000040;border-radius:.35rem;font-family:Roboto Mono,monospace;font-size:.7rem;white-space:pre-wrap;word-break:break-word;max-height:22rem;overflow-y:auto;color:var(--mm-ai-chat-muted)}.mm-ai-chat__status{display:flex;align-items:baseline;gap:.5rem;padding:.25rem .5rem;font-size:.7rem;color:var(--mm-ai-chat-muted);text-transform:uppercase;letter-spacing:.06em}.mm-ai-chat__status-label{color:var(--mm-ai-chat-muted)}.mm-ai-chat__status-value{color:var(--mm-ai-chat-text);font-weight:600}\n"] }]
|
|
875
883
|
}], propDecorators: { events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: true }] }] } });
|
|
@@ -880,8 +888,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
880
888
|
* pretty-printed JSON so the host doesn't need its own json formatter.
|
|
881
889
|
*/
|
|
882
890
|
class AiToolCallComponent {
|
|
883
|
-
call = input.required(
|
|
884
|
-
|
|
891
|
+
call = input.required(/* @ts-ignore */
|
|
892
|
+
...(ngDevMode ? [{ debugName: "call" }] : /* istanbul ignore next */ []));
|
|
893
|
+
expanded = signal(false, /* @ts-ignore */
|
|
894
|
+
...(ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []));
|
|
885
895
|
statusVariant = computed(() => {
|
|
886
896
|
const status = this.call().status;
|
|
887
897
|
switch (status) {
|
|
@@ -897,12 +907,15 @@ class AiToolCallComponent {
|
|
|
897
907
|
default:
|
|
898
908
|
return 'pending';
|
|
899
909
|
}
|
|
900
|
-
},
|
|
901
|
-
|
|
910
|
+
}, /* @ts-ignore */
|
|
911
|
+
...(ngDevMode ? [{ debugName: "statusVariant" }] : /* istanbul ignore next */ []));
|
|
912
|
+
argumentsJson = computed(() => this.format(this.call().arguments), /* @ts-ignore */
|
|
913
|
+
...(ngDevMode ? [{ debugName: "argumentsJson" }] : /* istanbul ignore next */ []));
|
|
902
914
|
resultJson = computed(() => {
|
|
903
915
|
const result = this.call().result;
|
|
904
916
|
return result === undefined ? null : this.format(result);
|
|
905
|
-
},
|
|
917
|
+
}, /* @ts-ignore */
|
|
918
|
+
...(ngDevMode ? [{ debugName: "resultJson" }] : /* istanbul ignore next */ []));
|
|
906
919
|
toggleExpanded() {
|
|
907
920
|
this.expanded.update((v) => !v);
|
|
908
921
|
}
|
|
@@ -917,10 +930,10 @@ class AiToolCallComponent {
|
|
|
917
930
|
return String(value);
|
|
918
931
|
}
|
|
919
932
|
}
|
|
920
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
921
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
933
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiToolCallComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
934
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: AiToolCallComponent, isStandalone: true, selector: "mm-ai-tool-call", inputs: { call: { classPropertyName: "call", publicName: "call", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"mm-ai-tool-call mm-ai-tool-call--{{ statusVariant() }}\">\n <button\n type=\"button\"\n class=\"mm-ai-tool-call__header\"\n (click)=\"toggleExpanded()\"\n [attr.aria-expanded]=\"expanded()\"\n >\n <span class=\"mm-ai-tool-call__chevron\">\n {{ expanded() ? '\u25BE' : '\u25B8' }}\n </span>\n <span class=\"mm-ai-tool-call__name\">{{ call().toolName }}</span>\n <span class=\"mm-ai-tool-call__status\">{{ call().status }}</span>\n @if (call().durationMs != null) {\n <span class=\"mm-ai-tool-call__duration\">\n {{ call().durationMs }}ms\n </span>\n }\n </button>\n\n @if (expanded()) {\n <div class=\"mm-ai-tool-call__body\">\n <div class=\"mm-ai-tool-call__section\">\n <h4 class=\"mm-ai-tool-call__heading\">Arguments</h4>\n <pre class=\"mm-ai-tool-call__code\">{{ argumentsJson() }}</pre>\n </div>\n\n @if (resultJson() !== null) {\n <div class=\"mm-ai-tool-call__section\">\n <h4 class=\"mm-ai-tool-call__heading\">Result</h4>\n <pre class=\"mm-ai-tool-call__code\">{{ resultJson() }}</pre>\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block;--mm-ai-tool-bg: #1f2227;--mm-ai-tool-border: #2f343b;--mm-ai-tool-text: #e6e6e6;--mm-ai-tool-muted: #9aa0a6;--mm-ai-tool-success: #2ea44f;--mm-ai-tool-failed: #d73a49;--mm-ai-tool-rejected: #d29922;--mm-ai-tool-pending: #6e7681;--mm-ai-tool-code-bg: #16191d}.mm-ai-tool-call{border:1px solid var(--mm-ai-tool-border);border-radius:.5rem;background:var(--mm-ai-tool-bg);color:var(--mm-ai-tool-text);margin:.4rem 0;overflow:hidden}.mm-ai-tool-call--succeeded{border-left:3px solid var(--mm-ai-tool-success)}.mm-ai-tool-call--failed{border-left:3px solid var(--mm-ai-tool-failed)}.mm-ai-tool-call--rejected{border-left:3px solid var(--mm-ai-tool-rejected)}.mm-ai-tool-call--pending{border-left:3px solid var(--mm-ai-tool-pending)}.mm-ai-tool-call__header{width:100%;display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:transparent;color:inherit;border:none;cursor:pointer;text-align:left;font-family:inherit;font-size:.9rem}.mm-ai-tool-call__header:hover{background:#ffffff0a}.mm-ai-tool-call__chevron{width:1rem;text-align:center;color:var(--mm-ai-tool-muted)}.mm-ai-tool-call__name{font-weight:600;flex:1}.mm-ai-tool-call__status,.mm-ai-tool-call__duration{font-size:.75rem;color:var(--mm-ai-tool-muted);font-variant-numeric:tabular-nums}.mm-ai-tool-call__body{border-top:1px solid var(--mm-ai-tool-border);padding:.5rem .75rem}.mm-ai-tool-call__section+.mm-ai-tool-call__section{margin-top:.75rem}.mm-ai-tool-call__heading{margin:0 0 .25rem;font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;color:var(--mm-ai-tool-muted)}.mm-ai-tool-call__code{margin:0;padding:.5rem .6rem;background:var(--mm-ai-tool-code-bg);border-radius:.3rem;font-size:.8rem;overflow-x:auto;white-space:pre-wrap;word-break:break-word}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
922
935
|
}
|
|
923
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
936
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiToolCallComponent, decorators: [{
|
|
924
937
|
type: Component,
|
|
925
938
|
args: [{ selector: 'mm-ai-tool-call', imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"mm-ai-tool-call mm-ai-tool-call--{{ statusVariant() }}\">\n <button\n type=\"button\"\n class=\"mm-ai-tool-call__header\"\n (click)=\"toggleExpanded()\"\n [attr.aria-expanded]=\"expanded()\"\n >\n <span class=\"mm-ai-tool-call__chevron\">\n {{ expanded() ? '\u25BE' : '\u25B8' }}\n </span>\n <span class=\"mm-ai-tool-call__name\">{{ call().toolName }}</span>\n <span class=\"mm-ai-tool-call__status\">{{ call().status }}</span>\n @if (call().durationMs != null) {\n <span class=\"mm-ai-tool-call__duration\">\n {{ call().durationMs }}ms\n </span>\n }\n </button>\n\n @if (expanded()) {\n <div class=\"mm-ai-tool-call__body\">\n <div class=\"mm-ai-tool-call__section\">\n <h4 class=\"mm-ai-tool-call__heading\">Arguments</h4>\n <pre class=\"mm-ai-tool-call__code\">{{ argumentsJson() }}</pre>\n </div>\n\n @if (resultJson() !== null) {\n <div class=\"mm-ai-tool-call__section\">\n <h4 class=\"mm-ai-tool-call__heading\">Result</h4>\n <pre class=\"mm-ai-tool-call__code\">{{ resultJson() }}</pre>\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block;--mm-ai-tool-bg: #1f2227;--mm-ai-tool-border: #2f343b;--mm-ai-tool-text: #e6e6e6;--mm-ai-tool-muted: #9aa0a6;--mm-ai-tool-success: #2ea44f;--mm-ai-tool-failed: #d73a49;--mm-ai-tool-rejected: #d29922;--mm-ai-tool-pending: #6e7681;--mm-ai-tool-code-bg: #16191d}.mm-ai-tool-call{border:1px solid var(--mm-ai-tool-border);border-radius:.5rem;background:var(--mm-ai-tool-bg);color:var(--mm-ai-tool-text);margin:.4rem 0;overflow:hidden}.mm-ai-tool-call--succeeded{border-left:3px solid var(--mm-ai-tool-success)}.mm-ai-tool-call--failed{border-left:3px solid var(--mm-ai-tool-failed)}.mm-ai-tool-call--rejected{border-left:3px solid var(--mm-ai-tool-rejected)}.mm-ai-tool-call--pending{border-left:3px solid var(--mm-ai-tool-pending)}.mm-ai-tool-call__header{width:100%;display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:transparent;color:inherit;border:none;cursor:pointer;text-align:left;font-family:inherit;font-size:.9rem}.mm-ai-tool-call__header:hover{background:#ffffff0a}.mm-ai-tool-call__chevron{width:1rem;text-align:center;color:var(--mm-ai-tool-muted)}.mm-ai-tool-call__name{font-weight:600;flex:1}.mm-ai-tool-call__status,.mm-ai-tool-call__duration{font-size:.75rem;color:var(--mm-ai-tool-muted);font-variant-numeric:tabular-nums}.mm-ai-tool-call__body{border-top:1px solid var(--mm-ai-tool-border);padding:.5rem .75rem}.mm-ai-tool-call__section+.mm-ai-tool-call__section{margin-top:.75rem}.mm-ai-tool-call__heading{margin:0 0 .25rem;font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;color:var(--mm-ai-tool-muted)}.mm-ai-tool-call__code{margin:0;padding:.5rem .6rem;background:var(--mm-ai-tool-code-bg);border-radius:.3rem;font-size:.8rem;overflow-x:auto;white-space:pre-wrap;word-break:break-word}\n"] }]
|
|
926
939
|
}], propDecorators: { call: [{ type: i0.Input, args: [{ isSignal: true, alias: "call", required: true }] }] } });
|
|
@@ -936,10 +949,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
936
949
|
* window, ng-bootstrap, …) — each host shop already has one.
|
|
937
950
|
*/
|
|
938
951
|
class AiApprovalModalComponent {
|
|
939
|
-
request = input.required(
|
|
952
|
+
request = input.required(/* @ts-ignore */
|
|
953
|
+
...(ngDevMode ? [{ debugName: "request" }] : /* istanbul ignore next */ []));
|
|
940
954
|
decide = output();
|
|
941
955
|
dismiss = output();
|
|
942
|
-
comment = signal('',
|
|
956
|
+
comment = signal('', /* @ts-ignore */
|
|
957
|
+
...(ngDevMode ? [{ debugName: "comment" }] : /* istanbul ignore next */ []));
|
|
943
958
|
prettyPayload = computed(() => {
|
|
944
959
|
try {
|
|
945
960
|
return JSON.stringify(JSON.parse(this.request().payload), null, 2);
|
|
@@ -947,7 +962,8 @@ class AiApprovalModalComponent {
|
|
|
947
962
|
catch {
|
|
948
963
|
return this.request().payload;
|
|
949
964
|
}
|
|
950
|
-
},
|
|
965
|
+
}, /* @ts-ignore */
|
|
966
|
+
...(ngDevMode ? [{ debugName: "prettyPayload" }] : /* istanbul ignore next */ []));
|
|
951
967
|
approve() {
|
|
952
968
|
this.decide.emit({
|
|
953
969
|
outcome: 'Approved',
|
|
@@ -967,10 +983,10 @@ class AiApprovalModalComponent {
|
|
|
967
983
|
const trimmed = this.comment().trim();
|
|
968
984
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
969
985
|
}
|
|
970
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
971
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "
|
|
986
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiApprovalModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
987
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: AiApprovalModalComponent, isStandalone: true, selector: "mm-ai-approval-modal", inputs: { request: { classPropertyName: "request", publicName: "request", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { decide: "decide", dismiss: "dismiss" }, ngImport: i0, template: "<div class=\"mm-ai-approval\">\n <header class=\"mm-ai-approval__header\">\n <h3 class=\"mm-ai-approval__title\">Approve tool call</h3>\n <button\n type=\"button\"\n class=\"mm-ai-approval__close\"\n (click)=\"onDismiss()\"\n aria-label=\"Dismiss\"\n >\n \u00D7\n </button>\n </header>\n\n <div class=\"mm-ai-approval__meta\">\n <div><span>Tool:</span> <code>{{ request().toolName }}</code></div>\n <div><span>Reason:</span> <code>{{ request().reason }}</code></div>\n <div><span>Session:</span> <code>{{ request().sessionId }}</code></div>\n </div>\n\n <div class=\"mm-ai-approval__section\">\n <h4 class=\"mm-ai-approval__heading\">Payload</h4>\n <pre class=\"mm-ai-approval__code\">{{ prettyPayload() }}</pre>\n </div>\n\n <div class=\"mm-ai-approval__section\">\n <h4 class=\"mm-ai-approval__heading\">Comment <span>(optional)</span></h4>\n <textarea\n class=\"mm-ai-approval__comment\"\n [ngModel]=\"comment()\"\n (ngModelChange)=\"comment.set($event)\"\n rows=\"3\"\n placeholder=\"Why is this approved or rejected?\"\n ></textarea>\n </div>\n\n <footer class=\"mm-ai-approval__actions\">\n <button\n type=\"button\"\n class=\"mm-ai-approval__btn mm-ai-approval__btn--reject\"\n (click)=\"reject()\"\n >\n Reject\n </button>\n <button\n type=\"button\"\n class=\"mm-ai-approval__btn mm-ai-approval__btn--approve\"\n (click)=\"approve()\"\n >\n Approve\n </button>\n </footer>\n</div>\n", styles: [":host{display:block;--mm-ai-approval-bg: #1f2227;--mm-ai-approval-border: #2f343b;--mm-ai-approval-text: #e6e6e6;--mm-ai-approval-muted: #9aa0a6;--mm-ai-approval-approve: #2ea44f;--mm-ai-approval-reject: #d73a49;--mm-ai-approval-code-bg: #16191d}.mm-ai-approval{background:var(--mm-ai-approval-bg);color:var(--mm-ai-approval-text);border:1px solid var(--mm-ai-approval-border);border-radius:.6rem;padding:1rem 1.25rem;width:min(36rem,100%)}.mm-ai-approval__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.mm-ai-approval__title{margin:0;font-size:1rem}.mm-ai-approval__close{background:transparent;color:var(--mm-ai-approval-muted);border:none;font-size:1.4rem;cursor:pointer;line-height:1;padding:0 .25rem}.mm-ai-approval__close:hover{color:var(--mm-ai-approval-text)}.mm-ai-approval__meta{display:grid;gap:.25rem;font-size:.85rem;margin-bottom:.75rem}.mm-ai-approval__meta span{color:var(--mm-ai-approval-muted);margin-right:.35rem}.mm-ai-approval__meta code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.mm-ai-approval__section{margin-bottom:.75rem}.mm-ai-approval__heading{margin:0 0 .3rem;font-size:.75rem;color:var(--mm-ai-approval-muted);text-transform:uppercase;letter-spacing:.04em}.mm-ai-approval__heading span{text-transform:none;letter-spacing:0;opacity:.6}.mm-ai-approval__code{margin:0;padding:.5rem .6rem;background:var(--mm-ai-approval-code-bg);border-radius:.3rem;font-size:.8rem;overflow-x:auto;white-space:pre-wrap;word-break:break-word;max-height:14rem}.mm-ai-approval__comment{width:100%;box-sizing:border-box;padding:.5rem .6rem;background:var(--mm-ai-approval-code-bg);color:inherit;border:1px solid var(--mm-ai-approval-border);border-radius:.3rem;font-family:inherit;font-size:.85rem;resize:vertical}.mm-ai-approval__actions{display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem}.mm-ai-approval__btn{padding:.45rem 1rem;border-radius:.3rem;font-weight:600;border:none;cursor:pointer;font-size:.85rem}.mm-ai-approval__btn--approve{background:var(--mm-ai-approval-approve);color:#fff}.mm-ai-approval__btn--reject{background:var(--mm-ai-approval-reject);color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
972
988
|
}
|
|
973
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
989
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiApprovalModalComponent, decorators: [{
|
|
974
990
|
type: Component,
|
|
975
991
|
args: [{ selector: 'mm-ai-approval-modal', imports: [FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"mm-ai-approval\">\n <header class=\"mm-ai-approval__header\">\n <h3 class=\"mm-ai-approval__title\">Approve tool call</h3>\n <button\n type=\"button\"\n class=\"mm-ai-approval__close\"\n (click)=\"onDismiss()\"\n aria-label=\"Dismiss\"\n >\n \u00D7\n </button>\n </header>\n\n <div class=\"mm-ai-approval__meta\">\n <div><span>Tool:</span> <code>{{ request().toolName }}</code></div>\n <div><span>Reason:</span> <code>{{ request().reason }}</code></div>\n <div><span>Session:</span> <code>{{ request().sessionId }}</code></div>\n </div>\n\n <div class=\"mm-ai-approval__section\">\n <h4 class=\"mm-ai-approval__heading\">Payload</h4>\n <pre class=\"mm-ai-approval__code\">{{ prettyPayload() }}</pre>\n </div>\n\n <div class=\"mm-ai-approval__section\">\n <h4 class=\"mm-ai-approval__heading\">Comment <span>(optional)</span></h4>\n <textarea\n class=\"mm-ai-approval__comment\"\n [ngModel]=\"comment()\"\n (ngModelChange)=\"comment.set($event)\"\n rows=\"3\"\n placeholder=\"Why is this approved or rejected?\"\n ></textarea>\n </div>\n\n <footer class=\"mm-ai-approval__actions\">\n <button\n type=\"button\"\n class=\"mm-ai-approval__btn mm-ai-approval__btn--reject\"\n (click)=\"reject()\"\n >\n Reject\n </button>\n <button\n type=\"button\"\n class=\"mm-ai-approval__btn mm-ai-approval__btn--approve\"\n (click)=\"approve()\"\n >\n Approve\n </button>\n </footer>\n</div>\n", styles: [":host{display:block;--mm-ai-approval-bg: #1f2227;--mm-ai-approval-border: #2f343b;--mm-ai-approval-text: #e6e6e6;--mm-ai-approval-muted: #9aa0a6;--mm-ai-approval-approve: #2ea44f;--mm-ai-approval-reject: #d73a49;--mm-ai-approval-code-bg: #16191d}.mm-ai-approval{background:var(--mm-ai-approval-bg);color:var(--mm-ai-approval-text);border:1px solid var(--mm-ai-approval-border);border-radius:.6rem;padding:1rem 1.25rem;width:min(36rem,100%)}.mm-ai-approval__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.mm-ai-approval__title{margin:0;font-size:1rem}.mm-ai-approval__close{background:transparent;color:var(--mm-ai-approval-muted);border:none;font-size:1.4rem;cursor:pointer;line-height:1;padding:0 .25rem}.mm-ai-approval__close:hover{color:var(--mm-ai-approval-text)}.mm-ai-approval__meta{display:grid;gap:.25rem;font-size:.85rem;margin-bottom:.75rem}.mm-ai-approval__meta span{color:var(--mm-ai-approval-muted);margin-right:.35rem}.mm-ai-approval__meta code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.mm-ai-approval__section{margin-bottom:.75rem}.mm-ai-approval__heading{margin:0 0 .3rem;font-size:.75rem;color:var(--mm-ai-approval-muted);text-transform:uppercase;letter-spacing:.04em}.mm-ai-approval__heading span{text-transform:none;letter-spacing:0;opacity:.6}.mm-ai-approval__code{margin:0;padding:.5rem .6rem;background:var(--mm-ai-approval-code-bg);border-radius:.3rem;font-size:.8rem;overflow-x:auto;white-space:pre-wrap;word-break:break-word;max-height:14rem}.mm-ai-approval__comment{width:100%;box-sizing:border-box;padding:.5rem .6rem;background:var(--mm-ai-approval-code-bg);color:inherit;border:1px solid var(--mm-ai-approval-border);border-radius:.3rem;font-family:inherit;font-size:.85rem;resize:vertical}.mm-ai-approval__actions{display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem}.mm-ai-approval__btn{padding:.45rem 1rem;border-radius:.3rem;font-weight:600;border:none;cursor:pointer;font-size:.85rem}.mm-ai-approval__btn--approve{background:var(--mm-ai-approval-approve);color:#fff}.mm-ai-approval__btn--reject{background:var(--mm-ai-approval-reject);color:#fff}\n"] }]
|
|
976
992
|
}], propDecorators: { request: [{ type: i0.Input, args: [{ isSignal: true, alias: "request", required: true }] }], decide: [{ type: i0.Output, args: ["decide"] }], dismiss: [{ type: i0.Output, args: ["dismiss"] }] } });
|
|
@@ -982,11 +998,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
982
998
|
* adapter already aggregated.
|
|
983
999
|
*/
|
|
984
1000
|
class AiQuotaIndicatorComponent {
|
|
985
|
-
dailyConsumed = input.required(
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1001
|
+
dailyConsumed = input.required(/* @ts-ignore */
|
|
1002
|
+
...(ngDevMode ? [{ debugName: "dailyConsumed" }] : /* istanbul ignore next */ []));
|
|
1003
|
+
dailyCap = input.required(/* @ts-ignore */
|
|
1004
|
+
...(ngDevMode ? [{ debugName: "dailyCap" }] : /* istanbul ignore next */ []));
|
|
1005
|
+
monthlyConsumed = input(null, /* @ts-ignore */
|
|
1006
|
+
...(ngDevMode ? [{ debugName: "monthlyConsumed" }] : /* istanbul ignore next */ []));
|
|
1007
|
+
monthlyCap = input(null, /* @ts-ignore */
|
|
1008
|
+
...(ngDevMode ? [{ debugName: "monthlyCap" }] : /* istanbul ignore next */ []));
|
|
1009
|
+
dailyPercent = computed(() => this.percent(this.dailyConsumed(), this.dailyCap()), /* @ts-ignore */
|
|
1010
|
+
...(ngDevMode ? [{ debugName: "dailyPercent" }] : /* istanbul ignore next */ []));
|
|
990
1011
|
monthlyPercent = computed(() => {
|
|
991
1012
|
const consumed = this.monthlyConsumed();
|
|
992
1013
|
const cap = this.monthlyCap();
|
|
@@ -994,12 +1015,15 @@ class AiQuotaIndicatorComponent {
|
|
|
994
1015
|
return null;
|
|
995
1016
|
}
|
|
996
1017
|
return this.percent(consumed, cap);
|
|
997
|
-
},
|
|
998
|
-
|
|
1018
|
+
}, /* @ts-ignore */
|
|
1019
|
+
...(ngDevMode ? [{ debugName: "monthlyPercent" }] : /* istanbul ignore next */ []));
|
|
1020
|
+
dailyState = computed(() => this.toState(this.dailyPercent()), /* @ts-ignore */
|
|
1021
|
+
...(ngDevMode ? [{ debugName: "dailyState" }] : /* istanbul ignore next */ []));
|
|
999
1022
|
monthlyState = computed(() => {
|
|
1000
1023
|
const pct = this.monthlyPercent();
|
|
1001
1024
|
return pct == null ? null : this.toState(pct);
|
|
1002
|
-
},
|
|
1025
|
+
}, /* @ts-ignore */
|
|
1026
|
+
...(ngDevMode ? [{ debugName: "monthlyState" }] : /* istanbul ignore next */ []));
|
|
1003
1027
|
percent(consumed, cap) {
|
|
1004
1028
|
if (cap <= 0) {
|
|
1005
1029
|
return 0;
|
|
@@ -1015,10 +1039,10 @@ class AiQuotaIndicatorComponent {
|
|
|
1015
1039
|
}
|
|
1016
1040
|
return 'ok';
|
|
1017
1041
|
}
|
|
1018
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1019
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1042
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiQuotaIndicatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1043
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: AiQuotaIndicatorComponent, isStandalone: true, selector: "mm-ai-quota-indicator", inputs: { dailyConsumed: { classPropertyName: "dailyConsumed", publicName: "dailyConsumed", isSignal: true, isRequired: true, transformFunction: null }, dailyCap: { classPropertyName: "dailyCap", publicName: "dailyCap", isSignal: true, isRequired: true, transformFunction: null }, monthlyConsumed: { classPropertyName: "monthlyConsumed", publicName: "monthlyConsumed", isSignal: true, isRequired: false, transformFunction: null }, monthlyCap: { classPropertyName: "monthlyCap", publicName: "monthlyCap", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"mm-ai-quota\">\n <div class=\"mm-ai-quota__row\">\n <span class=\"mm-ai-quota__label\">Daily</span>\n <div class=\"mm-ai-quota__bar mm-ai-quota__bar--{{ dailyState() }}\">\n <div class=\"mm-ai-quota__fill\" [style.width.%]=\"dailyPercent()\"></div>\n </div>\n <span class=\"mm-ai-quota__count\">\n {{ dailyConsumed() }} / {{ dailyCap() }} ({{ dailyPercent() }}%)\n </span>\n </div>\n\n @if (monthlyPercent() !== null) {\n <div class=\"mm-ai-quota__row\">\n <span class=\"mm-ai-quota__label\">Monthly</span>\n <div class=\"mm-ai-quota__bar mm-ai-quota__bar--{{ monthlyState() }}\">\n <div class=\"mm-ai-quota__fill\" [style.width.%]=\"monthlyPercent()\"></div>\n </div>\n <span class=\"mm-ai-quota__count\">\n {{ monthlyConsumed() }} / {{ monthlyCap() }} ({{ monthlyPercent() }}%)\n </span>\n </div>\n }\n</div>\n", styles: [":host{display:block;--mm-ai-quota-track-bg: #2a2a2a;--mm-ai-quota-ok: #2ea44f;--mm-ai-quota-warning: #d29922;--mm-ai-quota-critical: #d73a49}.mm-ai-quota{display:flex;flex-direction:column;gap:.5rem;font-size:.85rem}.mm-ai-quota__row{display:grid;grid-template-columns:4.5rem 1fr auto;align-items:center;gap:.5rem}.mm-ai-quota__label{font-weight:600;opacity:.7}.mm-ai-quota__bar{height:.5rem;border-radius:9999px;background:var(--mm-ai-quota-track-bg);overflow:hidden}.mm-ai-quota__bar--ok .mm-ai-quota__fill{background:var(--mm-ai-quota-ok)}.mm-ai-quota__bar--warning .mm-ai-quota__fill{background:var(--mm-ai-quota-warning)}.mm-ai-quota__bar--critical .mm-ai-quota__fill{background:var(--mm-ai-quota-critical)}.mm-ai-quota__fill{height:100%;transition:width .2s ease}.mm-ai-quota__count{font-variant-numeric:tabular-nums;opacity:.8}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1020
1044
|
}
|
|
1021
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1045
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiQuotaIndicatorComponent, decorators: [{
|
|
1022
1046
|
type: Component,
|
|
1023
1047
|
args: [{ selector: 'mm-ai-quota-indicator', imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"mm-ai-quota\">\n <div class=\"mm-ai-quota__row\">\n <span class=\"mm-ai-quota__label\">Daily</span>\n <div class=\"mm-ai-quota__bar mm-ai-quota__bar--{{ dailyState() }}\">\n <div class=\"mm-ai-quota__fill\" [style.width.%]=\"dailyPercent()\"></div>\n </div>\n <span class=\"mm-ai-quota__count\">\n {{ dailyConsumed() }} / {{ dailyCap() }} ({{ dailyPercent() }}%)\n </span>\n </div>\n\n @if (monthlyPercent() !== null) {\n <div class=\"mm-ai-quota__row\">\n <span class=\"mm-ai-quota__label\">Monthly</span>\n <div class=\"mm-ai-quota__bar mm-ai-quota__bar--{{ monthlyState() }}\">\n <div class=\"mm-ai-quota__fill\" [style.width.%]=\"monthlyPercent()\"></div>\n </div>\n <span class=\"mm-ai-quota__count\">\n {{ monthlyConsumed() }} / {{ monthlyCap() }} ({{ monthlyPercent() }}%)\n </span>\n </div>\n }\n</div>\n", styles: [":host{display:block;--mm-ai-quota-track-bg: #2a2a2a;--mm-ai-quota-ok: #2ea44f;--mm-ai-quota-warning: #d29922;--mm-ai-quota-critical: #d73a49}.mm-ai-quota{display:flex;flex-direction:column;gap:.5rem;font-size:.85rem}.mm-ai-quota__row{display:grid;grid-template-columns:4.5rem 1fr auto;align-items:center;gap:.5rem}.mm-ai-quota__label{font-weight:600;opacity:.7}.mm-ai-quota__bar{height:.5rem;border-radius:9999px;background:var(--mm-ai-quota-track-bg);overflow:hidden}.mm-ai-quota__bar--ok .mm-ai-quota__fill{background:var(--mm-ai-quota-ok)}.mm-ai-quota__bar--warning .mm-ai-quota__fill{background:var(--mm-ai-quota-warning)}.mm-ai-quota__bar--critical .mm-ai-quota__fill{background:var(--mm-ai-quota-critical)}.mm-ai-quota__fill{height:100%;transition:width .2s ease}.mm-ai-quota__count{font-variant-numeric:tabular-nums;opacity:.8}\n"] }]
|
|
1024
1048
|
}], propDecorators: { dailyConsumed: [{ type: i0.Input, args: [{ isSignal: true, alias: "dailyConsumed", required: true }] }], dailyCap: [{ type: i0.Input, args: [{ isSignal: true, alias: "dailyCap", required: true }] }], monthlyConsumed: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthlyConsumed", required: false }] }], monthlyCap: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthlyCap", required: false }] }] } });
|
|
@@ -1036,12 +1060,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
1036
1060
|
*/
|
|
1037
1061
|
class AiCredentialTicketIssueComponent {
|
|
1038
1062
|
client = inject(AiAdapterClientService);
|
|
1039
|
-
scope = signal('CredentialRegister',
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1063
|
+
scope = signal('CredentialRegister', /* @ts-ignore */
|
|
1064
|
+
...(ngDevMode ? [{ debugName: "scope" }] : /* istanbul ignore next */ []));
|
|
1065
|
+
ttlMinutes = signal(5, /* @ts-ignore */
|
|
1066
|
+
...(ngDevMode ? [{ debugName: "ttlMinutes" }] : /* istanbul ignore next */ []));
|
|
1067
|
+
issuing = signal(false, /* @ts-ignore */
|
|
1068
|
+
...(ngDevMode ? [{ debugName: "issuing" }] : /* istanbul ignore next */ []));
|
|
1069
|
+
issued = signal(null, /* @ts-ignore */
|
|
1070
|
+
...(ngDevMode ? [{ debugName: "issued" }] : /* istanbul ignore next */ []));
|
|
1071
|
+
error = signal(null, /* @ts-ignore */
|
|
1072
|
+
...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
1073
|
+
copied = signal(false, /* @ts-ignore */
|
|
1074
|
+
...(ngDevMode ? [{ debugName: "copied" }] : /* istanbul ignore next */ []));
|
|
1045
1075
|
/** Available scope choices — kept in sync with `AiCredentialTicketScope`. */
|
|
1046
1076
|
scopes = [
|
|
1047
1077
|
{
|
|
@@ -1124,10 +1154,10 @@ class AiCredentialTicketIssueComponent {
|
|
|
1124
1154
|
}
|
|
1125
1155
|
return 'Failed to reach the AI Adapter — check the network.';
|
|
1126
1156
|
}
|
|
1127
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1128
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1157
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiCredentialTicketIssueComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1158
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: AiCredentialTicketIssueComponent, isStandalone: true, selector: "mm-ai-credential-ticket-issue", ngImport: i0, template: "<section class=\"mm-ai-ticket\">\n <header class=\"mm-ai-ticket__header\">\n <div class=\"mm-ai-ticket__title\">Issue credential ticket</div>\n <div class=\"mm-ai-ticket__subtitle\">\n Mint a one-time code an operator redeems on their own machine.\n </div>\n </header>\n\n @if (!issued()) {\n <form\n class=\"mm-ai-ticket__form\"\n (ngSubmit)=\"onIssue()\"\n #issueForm=\"ngForm\"\n >\n <label class=\"mm-ai-ticket__field\">\n <span class=\"mm-ai-ticket__label\">Scope</span>\n <select\n class=\"mm-ai-ticket__select\"\n [ngModel]=\"scope()\"\n (ngModelChange)=\"scope.set($event)\"\n name=\"scope\"\n [disabled]=\"issuing()\"\n >\n @for (s of scopes; track s.value) {\n <option [value]=\"s.value\">{{ s.label }}</option>\n }\n </select>\n </label>\n <p class=\"mm-ai-ticket__hint\">\n @for (s of scopes; track s.value) {\n @if (s.value === scope()) {\n {{ s.hint }}\n }\n }\n </p>\n\n <label class=\"mm-ai-ticket__field\">\n <span class=\"mm-ai-ticket__label\">TTL (minutes)</span>\n <input\n class=\"mm-ai-ticket__input\"\n type=\"number\"\n min=\"1\"\n max=\"60\"\n step=\"1\"\n [ngModel]=\"ttlMinutes()\"\n (ngModelChange)=\"ttlMinutes.set(+$event)\"\n name=\"ttlMinutes\"\n [disabled]=\"issuing()\"\n />\n </label>\n <p class=\"mm-ai-ticket__hint\">\n Default 5 minutes. Server clamps to 60 \u2014 long TTLs leak.\n </p>\n\n <div class=\"mm-ai-ticket__actions\">\n <button\n class=\"mm-ai-ticket__button mm-ai-ticket__button--primary\"\n type=\"submit\"\n [disabled]=\"issuing()\"\n >\n @if (issuing()) {\n Issuing\u2026\n } @else {\n Issue ticket\n }\n </button>\n </div>\n\n @if (error()) {\n <p class=\"mm-ai-ticket__error\">{{ error() }}</p>\n }\n </form>\n } @else {\n <div class=\"mm-ai-ticket__result\">\n <p class=\"mm-ai-ticket__result-label\">\n One-time code (copy now \u2014 not shown again):\n </p>\n <div class=\"mm-ai-ticket__code-row\">\n <code class=\"mm-ai-ticket__code\">{{ issued()!.code }}</code>\n <button\n class=\"mm-ai-ticket__button mm-ai-ticket__button--secondary\"\n type=\"button\"\n (click)=\"onCopy()\"\n >\n @if (copied()) {\n Copied\n } @else {\n Copy\n }\n </button>\n </div>\n <dl class=\"mm-ai-ticket__meta\">\n <div>\n <dt>Scope</dt>\n <dd>{{ issued()!.scope }}</dd>\n </div>\n <div>\n <dt>Expires at</dt>\n <dd>{{ issued()!.expiresAt }}</dd>\n </div>\n <div>\n <dt>Ticket rtId</dt>\n <dd><code>{{ issued()!.rtId }}</code></dd>\n </div>\n </dl>\n <div class=\"mm-ai-ticket__actions\">\n <button\n class=\"mm-ai-ticket__button\"\n type=\"button\"\n (click)=\"onClear()\"\n >\n Issue another\n </button>\n </div>\n </div>\n }\n</section>\n", styles: [":host{display:block;--mm-ai-ticket-bg: #16191d;--mm-ai-ticket-surface: #1f2227;--mm-ai-ticket-border: #2f343b;--mm-ai-ticket-text: #e6e6e6;--mm-ai-ticket-muted: #9aa0a6;--mm-ai-ticket-accent: #64ceb9;--mm-ai-ticket-error: #ec658f;--mm-ai-ticket-code-bg: #0f1115}.mm-ai-ticket{background:var(--mm-ai-ticket-bg);color:var(--mm-ai-ticket-text);border:1px solid var(--mm-ai-ticket-border);border-radius:.5rem;padding:1rem 1.25rem;display:flex;flex-direction:column;gap:.85rem;font-family:inherit}.mm-ai-ticket__header{display:flex;flex-direction:column;gap:.15rem}.mm-ai-ticket__title{font-size:1rem;font-weight:600}.mm-ai-ticket__subtitle{font-size:.8rem;color:var(--mm-ai-ticket-muted)}.mm-ai-ticket__form,.mm-ai-ticket__result{display:flex;flex-direction:column;gap:.6rem}.mm-ai-ticket__field{display:flex;flex-direction:column;gap:.25rem}.mm-ai-ticket__label{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:var(--mm-ai-ticket-muted)}.mm-ai-ticket__select,.mm-ai-ticket__input{background:var(--mm-ai-ticket-surface);color:var(--mm-ai-ticket-text);border:1px solid var(--mm-ai-ticket-border);border-radius:.3rem;padding:.4rem .55rem;font-family:inherit;font-size:.9rem}.mm-ai-ticket__select:focus,.mm-ai-ticket__input:focus{outline:2px solid var(--mm-ai-ticket-accent);outline-offset:1px}.mm-ai-ticket__select:disabled,.mm-ai-ticket__input:disabled{opacity:.6;cursor:not-allowed}.mm-ai-ticket__hint{margin:0;font-size:.75rem;color:var(--mm-ai-ticket-muted)}.mm-ai-ticket__actions{display:flex;gap:.5rem;margin-top:.25rem}.mm-ai-ticket__button{background:var(--mm-ai-ticket-surface);color:var(--mm-ai-ticket-text);border:1px solid var(--mm-ai-ticket-border);border-radius:.3rem;padding:.4rem .85rem;font-family:inherit;font-size:.85rem;cursor:pointer}.mm-ai-ticket__button:hover:not(:disabled){border-color:var(--mm-ai-ticket-accent)}.mm-ai-ticket__button:disabled{opacity:.5;cursor:not-allowed}.mm-ai-ticket__button--primary{background:var(--mm-ai-ticket-accent);color:#0a0c0f;border-color:var(--mm-ai-ticket-accent)}.mm-ai-ticket__error{margin:0;font-size:.8rem;color:var(--mm-ai-ticket-error)}.mm-ai-ticket__result-label{margin:0;font-size:.85rem;color:var(--mm-ai-ticket-muted)}.mm-ai-ticket__code-row{display:flex;align-items:center;gap:.5rem}.mm-ai-ticket__code{flex:1;background:var(--mm-ai-ticket-code-bg);color:var(--mm-ai-ticket-accent);padding:.5rem .75rem;border-radius:.3rem;font-family:Roboto Mono,ui-monospace,monospace;font-size:1.05rem;letter-spacing:.1em;-webkit-user-select:all;user-select:all}.mm-ai-ticket__meta{display:grid;grid-template-columns:max-content 1fr;gap:.2rem .75rem;margin:0;font-size:.8rem}.mm-ai-ticket__meta>div{display:contents}.mm-ai-ticket__meta dt{color:var(--mm-ai-ticket-muted);text-transform:uppercase;letter-spacing:.05em;font-size:.7rem}.mm-ai-ticket__meta dd{margin:0;font-family:Roboto Mono,ui-monospace,monospace}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number]:not([ngNoCva])[formControlName],input[type=number]:not([ngNoCva])[formControl],input[type=number]:not([ngNoCva])[ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple]):not([ngNoCva])[formControlName],select:not([multiple]):not([ngNoCva])[formControl],select:not([multiple]):not([ngNoCva])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1129
1159
|
}
|
|
1130
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1160
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiCredentialTicketIssueComponent, decorators: [{
|
|
1131
1161
|
type: Component,
|
|
1132
1162
|
args: [{ selector: 'mm-ai-credential-ticket-issue', imports: [CommonModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"mm-ai-ticket\">\n <header class=\"mm-ai-ticket__header\">\n <div class=\"mm-ai-ticket__title\">Issue credential ticket</div>\n <div class=\"mm-ai-ticket__subtitle\">\n Mint a one-time code an operator redeems on their own machine.\n </div>\n </header>\n\n @if (!issued()) {\n <form\n class=\"mm-ai-ticket__form\"\n (ngSubmit)=\"onIssue()\"\n #issueForm=\"ngForm\"\n >\n <label class=\"mm-ai-ticket__field\">\n <span class=\"mm-ai-ticket__label\">Scope</span>\n <select\n class=\"mm-ai-ticket__select\"\n [ngModel]=\"scope()\"\n (ngModelChange)=\"scope.set($event)\"\n name=\"scope\"\n [disabled]=\"issuing()\"\n >\n @for (s of scopes; track s.value) {\n <option [value]=\"s.value\">{{ s.label }}</option>\n }\n </select>\n </label>\n <p class=\"mm-ai-ticket__hint\">\n @for (s of scopes; track s.value) {\n @if (s.value === scope()) {\n {{ s.hint }}\n }\n }\n </p>\n\n <label class=\"mm-ai-ticket__field\">\n <span class=\"mm-ai-ticket__label\">TTL (minutes)</span>\n <input\n class=\"mm-ai-ticket__input\"\n type=\"number\"\n min=\"1\"\n max=\"60\"\n step=\"1\"\n [ngModel]=\"ttlMinutes()\"\n (ngModelChange)=\"ttlMinutes.set(+$event)\"\n name=\"ttlMinutes\"\n [disabled]=\"issuing()\"\n />\n </label>\n <p class=\"mm-ai-ticket__hint\">\n Default 5 minutes. Server clamps to 60 \u2014 long TTLs leak.\n </p>\n\n <div class=\"mm-ai-ticket__actions\">\n <button\n class=\"mm-ai-ticket__button mm-ai-ticket__button--primary\"\n type=\"submit\"\n [disabled]=\"issuing()\"\n >\n @if (issuing()) {\n Issuing\u2026\n } @else {\n Issue ticket\n }\n </button>\n </div>\n\n @if (error()) {\n <p class=\"mm-ai-ticket__error\">{{ error() }}</p>\n }\n </form>\n } @else {\n <div class=\"mm-ai-ticket__result\">\n <p class=\"mm-ai-ticket__result-label\">\n One-time code (copy now \u2014 not shown again):\n </p>\n <div class=\"mm-ai-ticket__code-row\">\n <code class=\"mm-ai-ticket__code\">{{ issued()!.code }}</code>\n <button\n class=\"mm-ai-ticket__button mm-ai-ticket__button--secondary\"\n type=\"button\"\n (click)=\"onCopy()\"\n >\n @if (copied()) {\n Copied\n } @else {\n Copy\n }\n </button>\n </div>\n <dl class=\"mm-ai-ticket__meta\">\n <div>\n <dt>Scope</dt>\n <dd>{{ issued()!.scope }}</dd>\n </div>\n <div>\n <dt>Expires at</dt>\n <dd>{{ issued()!.expiresAt }}</dd>\n </div>\n <div>\n <dt>Ticket rtId</dt>\n <dd><code>{{ issued()!.rtId }}</code></dd>\n </div>\n </dl>\n <div class=\"mm-ai-ticket__actions\">\n <button\n class=\"mm-ai-ticket__button\"\n type=\"button\"\n (click)=\"onClear()\"\n >\n Issue another\n </button>\n </div>\n </div>\n }\n</section>\n", styles: [":host{display:block;--mm-ai-ticket-bg: #16191d;--mm-ai-ticket-surface: #1f2227;--mm-ai-ticket-border: #2f343b;--mm-ai-ticket-text: #e6e6e6;--mm-ai-ticket-muted: #9aa0a6;--mm-ai-ticket-accent: #64ceb9;--mm-ai-ticket-error: #ec658f;--mm-ai-ticket-code-bg: #0f1115}.mm-ai-ticket{background:var(--mm-ai-ticket-bg);color:var(--mm-ai-ticket-text);border:1px solid var(--mm-ai-ticket-border);border-radius:.5rem;padding:1rem 1.25rem;display:flex;flex-direction:column;gap:.85rem;font-family:inherit}.mm-ai-ticket__header{display:flex;flex-direction:column;gap:.15rem}.mm-ai-ticket__title{font-size:1rem;font-weight:600}.mm-ai-ticket__subtitle{font-size:.8rem;color:var(--mm-ai-ticket-muted)}.mm-ai-ticket__form,.mm-ai-ticket__result{display:flex;flex-direction:column;gap:.6rem}.mm-ai-ticket__field{display:flex;flex-direction:column;gap:.25rem}.mm-ai-ticket__label{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:var(--mm-ai-ticket-muted)}.mm-ai-ticket__select,.mm-ai-ticket__input{background:var(--mm-ai-ticket-surface);color:var(--mm-ai-ticket-text);border:1px solid var(--mm-ai-ticket-border);border-radius:.3rem;padding:.4rem .55rem;font-family:inherit;font-size:.9rem}.mm-ai-ticket__select:focus,.mm-ai-ticket__input:focus{outline:2px solid var(--mm-ai-ticket-accent);outline-offset:1px}.mm-ai-ticket__select:disabled,.mm-ai-ticket__input:disabled{opacity:.6;cursor:not-allowed}.mm-ai-ticket__hint{margin:0;font-size:.75rem;color:var(--mm-ai-ticket-muted)}.mm-ai-ticket__actions{display:flex;gap:.5rem;margin-top:.25rem}.mm-ai-ticket__button{background:var(--mm-ai-ticket-surface);color:var(--mm-ai-ticket-text);border:1px solid var(--mm-ai-ticket-border);border-radius:.3rem;padding:.4rem .85rem;font-family:inherit;font-size:.85rem;cursor:pointer}.mm-ai-ticket__button:hover:not(:disabled){border-color:var(--mm-ai-ticket-accent)}.mm-ai-ticket__button:disabled{opacity:.5;cursor:not-allowed}.mm-ai-ticket__button--primary{background:var(--mm-ai-ticket-accent);color:#0a0c0f;border-color:var(--mm-ai-ticket-accent)}.mm-ai-ticket__error{margin:0;font-size:.8rem;color:var(--mm-ai-ticket-error)}.mm-ai-ticket__result-label{margin:0;font-size:.85rem;color:var(--mm-ai-ticket-muted)}.mm-ai-ticket__code-row{display:flex;align-items:center;gap:.5rem}.mm-ai-ticket__code{flex:1;background:var(--mm-ai-ticket-code-bg);color:var(--mm-ai-ticket-accent);padding:.5rem .75rem;border-radius:.3rem;font-family:Roboto Mono,ui-monospace,monospace;font-size:1.05rem;letter-spacing:.1em;-webkit-user-select:all;user-select:all}.mm-ai-ticket__meta{display:grid;grid-template-columns:max-content 1fr;gap:.2rem .75rem;margin:0;font-size:.8rem}.mm-ai-ticket__meta>div{display:contents}.mm-ai-ticket__meta dt{color:var(--mm-ai-ticket-muted);text-transform:uppercase;letter-spacing:.05em;font-size:.7rem}.mm-ai-ticket__meta dd{margin:0;font-family:Roboto Mono,ui-monospace,monospace}\n"] }]
|
|
1133
1163
|
}] });
|
|
@@ -1150,9 +1180,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
1150
1180
|
*/
|
|
1151
1181
|
class AiNewAppDialogComponent {
|
|
1152
1182
|
/** Available templates from the adapter — typically 3 in Phase 1. */
|
|
1153
|
-
templates = input.required(
|
|
1183
|
+
templates = input.required(/* @ts-ignore */
|
|
1184
|
+
...(ngDevMode ? [{ debugName: "templates" }] : /* istanbul ignore next */ []));
|
|
1154
1185
|
/** Tenant name shown in the dialog header so the operator confirms the scope. */
|
|
1155
|
-
tenantName = input('',
|
|
1186
|
+
tenantName = input('', /* @ts-ignore */
|
|
1187
|
+
...(ngDevMode ? [{ debugName: "tenantName" }] : /* istanbul ignore next */ []));
|
|
1156
1188
|
/**
|
|
1157
1189
|
* Emitted on Submit with the fully interpolated Goal + the picked template id.
|
|
1158
1190
|
* Named `confirmed` (not `submit`) because Angular flags native-event collisions
|
|
@@ -1165,13 +1197,17 @@ class AiNewAppDialogComponent {
|
|
|
1165
1197
|
*/
|
|
1166
1198
|
cancelled = output();
|
|
1167
1199
|
/** rtId-style id of the picked template, or empty until the operator picks one. */
|
|
1168
|
-
selectedTemplateId = signal('',
|
|
1169
|
-
|
|
1170
|
-
|
|
1200
|
+
selectedTemplateId = signal('', /* @ts-ignore */
|
|
1201
|
+
...(ngDevMode ? [{ debugName: "selectedTemplateId" }] : /* istanbul ignore next */ []));
|
|
1202
|
+
projectName = signal('', /* @ts-ignore */
|
|
1203
|
+
...(ngDevMode ? [{ debugName: "projectName" }] : /* istanbul ignore next */ []));
|
|
1204
|
+
primaryEntity = signal('', /* @ts-ignore */
|
|
1205
|
+
...(ngDevMode ? [{ debugName: "primaryEntity" }] : /* istanbul ignore next */ []));
|
|
1171
1206
|
selectedTemplate = computed(() => {
|
|
1172
1207
|
const id = this.selectedTemplateId();
|
|
1173
1208
|
return this.templates().find((t) => t.id === id) ?? null;
|
|
1174
|
-
},
|
|
1209
|
+
}, /* @ts-ignore */
|
|
1210
|
+
...(ngDevMode ? [{ debugName: "selectedTemplate" }] : /* istanbul ignore next */ []));
|
|
1175
1211
|
/**
|
|
1176
1212
|
* Rendered Goal string the operator sees in the preview block. Stays empty
|
|
1177
1213
|
* until a template is picked AND every required placeholder has a value, so
|
|
@@ -1186,7 +1222,8 @@ class AiNewAppDialogComponent {
|
|
|
1186
1222
|
return '';
|
|
1187
1223
|
}
|
|
1188
1224
|
return this.interpolate(template.goalTemplate);
|
|
1189
|
-
},
|
|
1225
|
+
}, /* @ts-ignore */
|
|
1226
|
+
...(ngDevMode ? [{ debugName: "renderedGoal" }] : /* istanbul ignore next */ []));
|
|
1190
1227
|
/** True when every placeholder the picked template declares has a non-empty value. */
|
|
1191
1228
|
allRequiredFilled = computed(() => {
|
|
1192
1229
|
const template = this.selectedTemplate();
|
|
@@ -1197,7 +1234,8 @@ class AiNewAppDialogComponent {
|
|
|
1197
1234
|
const value = this.valueFor(key);
|
|
1198
1235
|
return value !== null && value.trim().length > 0;
|
|
1199
1236
|
});
|
|
1200
|
-
},
|
|
1237
|
+
}, /* @ts-ignore */
|
|
1238
|
+
...(ngDevMode ? [{ debugName: "allRequiredFilled" }] : /* istanbul ignore next */ []));
|
|
1201
1239
|
onSubmit() {
|
|
1202
1240
|
const template = this.selectedTemplate();
|
|
1203
1241
|
if (!template || !this.allRequiredFilled()) {
|
|
@@ -1233,10 +1271,10 @@ class AiNewAppDialogComponent {
|
|
|
1233
1271
|
return value !== null ? value.trim() : full;
|
|
1234
1272
|
});
|
|
1235
1273
|
}
|
|
1236
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1237
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1274
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiNewAppDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1275
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: AiNewAppDialogComponent, isStandalone: true, selector: "mm-ai-new-app-dialog", inputs: { templates: { classPropertyName: "templates", publicName: "templates", isSignal: true, isRequired: true, transformFunction: null }, tenantName: { classPropertyName: "tenantName", publicName: "tenantName", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirmed: "confirmed", cancelled: "cancelled" }, ngImport: i0, template: "<div class=\"mm-ai-new-app\">\n <header class=\"mm-ai-new-app__header\">\n <h3 class=\"mm-ai-new-app__title\">\n New App\n @if (tenantName(); as tenant) {\n <span class=\"mm-ai-new-app__tenant\"> \u00B7 {{ tenant }}</span>\n }\n </h3>\n <button\n type=\"button\"\n class=\"mm-ai-new-app__close\"\n (click)=\"onCancel()\"\n aria-label=\"Dismiss\"\n >\n \u00D7\n </button>\n </header>\n\n <div class=\"mm-ai-new-app__section\">\n <h4 class=\"mm-ai-new-app__heading\">Template</h4>\n <ul class=\"mm-ai-new-app__templates\" role=\"radiogroup\" aria-label=\"Template\">\n @for (template of templates(); track template.id) {\n <li>\n <label\n class=\"mm-ai-new-app__template\"\n [class.mm-ai-new-app__template--active]=\"\n selectedTemplateId() === template.id\n \"\n >\n <input\n type=\"radio\"\n name=\"mm-ai-new-app-template\"\n [value]=\"template.id\"\n [checked]=\"selectedTemplateId() === template.id\"\n (change)=\"selectedTemplateId.set(template.id)\"\n />\n <span class=\"mm-ai-new-app__template-body\">\n <strong class=\"mm-ai-new-app__template-name\">{{ template.name }}</strong>\n <span class=\"mm-ai-new-app__template-description\">\n {{ template.description }}\n </span>\n </span>\n </label>\n </li>\n }\n </ul>\n </div>\n\n @if (selectedTemplate(); as template) {\n <div class=\"mm-ai-new-app__section\">\n <h4 class=\"mm-ai-new-app__heading\">Parameters</h4>\n <div class=\"mm-ai-new-app__field\">\n <label for=\"mm-ai-new-app-project-name\">Project name</label>\n <input\n id=\"mm-ai-new-app-project-name\"\n type=\"text\"\n [ngModel]=\"projectName()\"\n (ngModelChange)=\"projectName.set($event)\"\n placeholder=\"e.g. customer-list\"\n autocomplete=\"off\"\n />\n </div>\n <div class=\"mm-ai-new-app__field\">\n <label for=\"mm-ai-new-app-primary-entity\">Primary entity (CK type)</label>\n <input\n id=\"mm-ai-new-app-primary-entity\"\n type=\"text\"\n [ngModel]=\"primaryEntity()\"\n (ngModelChange)=\"primaryEntity.set($event)\"\n placeholder=\"e.g. Customer\"\n autocomplete=\"off\"\n />\n </div>\n </div>\n\n <div class=\"mm-ai-new-app__section\">\n <h4 class=\"mm-ai-new-app__heading\">\n Generated Goal <span>(this is what Claude will see)</span>\n </h4>\n <pre class=\"mm-ai-new-app__preview\">{{\n renderedGoal() ||\n 'Fill in every field above to preview the Goal that will be sent.'\n }}</pre>\n </div>\n }\n\n <footer class=\"mm-ai-new-app__actions\">\n <button\n type=\"button\"\n class=\"mm-ai-new-app__btn mm-ai-new-app__btn--cancel\"\n (click)=\"onCancel()\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"mm-ai-new-app__btn mm-ai-new-app__btn--submit\"\n [disabled]=\"!allRequiredFilled()\"\n (click)=\"onSubmit()\"\n >\n Create App Session\n </button>\n </footer>\n</div>\n", styles: [":host{display:block;--mm-ai-new-app-bg: #1f2227;--mm-ai-new-app-border: #2f343b;--mm-ai-new-app-text: #e6e6e6;--mm-ai-new-app-muted: #9aa0a6;--mm-ai-new-app-accent: #2ea44f;--mm-ai-new-app-accent-soft: rgba(46, 164, 79, .15);--mm-ai-new-app-cancel: #44494f;--mm-ai-new-app-code-bg: #16191d}.mm-ai-new-app{background:var(--mm-ai-new-app-bg);color:var(--mm-ai-new-app-text);border:1px solid var(--mm-ai-new-app-border);border-radius:.6rem;padding:1rem 1.25rem;width:min(40rem,100%)}.mm-ai-new-app__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.mm-ai-new-app__title{margin:0;font-size:1rem}.mm-ai-new-app__tenant{color:var(--mm-ai-new-app-muted);font-weight:400}.mm-ai-new-app__close{background:transparent;color:var(--mm-ai-new-app-muted);border:none;font-size:1.4rem;cursor:pointer;line-height:1;padding:0 .25rem}.mm-ai-new-app__close:hover{color:var(--mm-ai-new-app-text)}.mm-ai-new-app__section{margin-bottom:.75rem}.mm-ai-new-app__heading{margin:0 0 .35rem;font-size:.75rem;color:var(--mm-ai-new-app-muted);text-transform:uppercase;letter-spacing:.04em}.mm-ai-new-app__heading span{text-transform:none;letter-spacing:0;opacity:.6}.mm-ai-new-app__templates{list-style:none;margin:0;padding:0;display:grid;gap:.4rem}.mm-ai-new-app__template{display:flex;gap:.6rem;padding:.55rem .7rem;border:1px solid var(--mm-ai-new-app-border);border-radius:.35rem;cursor:pointer;align-items:flex-start}.mm-ai-new-app__template--active{background:var(--mm-ai-new-app-accent-soft);border-color:var(--mm-ai-new-app-accent)}.mm-ai-new-app__template input[type=radio]{margin-top:.2rem}.mm-ai-new-app__template-body{display:grid;gap:.2rem}.mm-ai-new-app__template-name{font-size:.9rem}.mm-ai-new-app__template-description{font-size:.8rem;color:var(--mm-ai-new-app-muted)}.mm-ai-new-app__field{display:grid;gap:.25rem;margin-bottom:.5rem;font-size:.85rem}.mm-ai-new-app__field label{color:var(--mm-ai-new-app-muted)}.mm-ai-new-app__field input{padding:.45rem .55rem;background:var(--mm-ai-new-app-code-bg);color:inherit;border:1px solid var(--mm-ai-new-app-border);border-radius:.3rem;font-family:inherit;font-size:.9rem}.mm-ai-new-app__preview{margin:0;padding:.5rem .6rem;background:var(--mm-ai-new-app-code-bg);border-radius:.3rem;font-size:.8rem;white-space:pre-wrap;word-break:break-word;max-height:12rem;overflow-y:auto}.mm-ai-new-app__actions{display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem}.mm-ai-new-app__btn{padding:.45rem 1rem;border-radius:.3rem;font-weight:600;border:none;cursor:pointer;font-size:.85rem}.mm-ai-new-app__btn--submit{background:var(--mm-ai-new-app-accent);color:#fff}.mm-ai-new-app__btn--submit:disabled{opacity:.5;cursor:not-allowed}.mm-ai-new-app__btn--cancel{background:var(--mm-ai-new-app-cancel);color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1238
1276
|
}
|
|
1239
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1277
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AiNewAppDialogComponent, decorators: [{
|
|
1240
1278
|
type: Component,
|
|
1241
1279
|
args: [{ selector: 'mm-ai-new-app-dialog', imports: [FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"mm-ai-new-app\">\n <header class=\"mm-ai-new-app__header\">\n <h3 class=\"mm-ai-new-app__title\">\n New App\n @if (tenantName(); as tenant) {\n <span class=\"mm-ai-new-app__tenant\"> \u00B7 {{ tenant }}</span>\n }\n </h3>\n <button\n type=\"button\"\n class=\"mm-ai-new-app__close\"\n (click)=\"onCancel()\"\n aria-label=\"Dismiss\"\n >\n \u00D7\n </button>\n </header>\n\n <div class=\"mm-ai-new-app__section\">\n <h4 class=\"mm-ai-new-app__heading\">Template</h4>\n <ul class=\"mm-ai-new-app__templates\" role=\"radiogroup\" aria-label=\"Template\">\n @for (template of templates(); track template.id) {\n <li>\n <label\n class=\"mm-ai-new-app__template\"\n [class.mm-ai-new-app__template--active]=\"\n selectedTemplateId() === template.id\n \"\n >\n <input\n type=\"radio\"\n name=\"mm-ai-new-app-template\"\n [value]=\"template.id\"\n [checked]=\"selectedTemplateId() === template.id\"\n (change)=\"selectedTemplateId.set(template.id)\"\n />\n <span class=\"mm-ai-new-app__template-body\">\n <strong class=\"mm-ai-new-app__template-name\">{{ template.name }}</strong>\n <span class=\"mm-ai-new-app__template-description\">\n {{ template.description }}\n </span>\n </span>\n </label>\n </li>\n }\n </ul>\n </div>\n\n @if (selectedTemplate(); as template) {\n <div class=\"mm-ai-new-app__section\">\n <h4 class=\"mm-ai-new-app__heading\">Parameters</h4>\n <div class=\"mm-ai-new-app__field\">\n <label for=\"mm-ai-new-app-project-name\">Project name</label>\n <input\n id=\"mm-ai-new-app-project-name\"\n type=\"text\"\n [ngModel]=\"projectName()\"\n (ngModelChange)=\"projectName.set($event)\"\n placeholder=\"e.g. customer-list\"\n autocomplete=\"off\"\n />\n </div>\n <div class=\"mm-ai-new-app__field\">\n <label for=\"mm-ai-new-app-primary-entity\">Primary entity (CK type)</label>\n <input\n id=\"mm-ai-new-app-primary-entity\"\n type=\"text\"\n [ngModel]=\"primaryEntity()\"\n (ngModelChange)=\"primaryEntity.set($event)\"\n placeholder=\"e.g. Customer\"\n autocomplete=\"off\"\n />\n </div>\n </div>\n\n <div class=\"mm-ai-new-app__section\">\n <h4 class=\"mm-ai-new-app__heading\">\n Generated Goal <span>(this is what Claude will see)</span>\n </h4>\n <pre class=\"mm-ai-new-app__preview\">{{\n renderedGoal() ||\n 'Fill in every field above to preview the Goal that will be sent.'\n }}</pre>\n </div>\n }\n\n <footer class=\"mm-ai-new-app__actions\">\n <button\n type=\"button\"\n class=\"mm-ai-new-app__btn mm-ai-new-app__btn--cancel\"\n (click)=\"onCancel()\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"mm-ai-new-app__btn mm-ai-new-app__btn--submit\"\n [disabled]=\"!allRequiredFilled()\"\n (click)=\"onSubmit()\"\n >\n Create App Session\n </button>\n </footer>\n</div>\n", styles: [":host{display:block;--mm-ai-new-app-bg: #1f2227;--mm-ai-new-app-border: #2f343b;--mm-ai-new-app-text: #e6e6e6;--mm-ai-new-app-muted: #9aa0a6;--mm-ai-new-app-accent: #2ea44f;--mm-ai-new-app-accent-soft: rgba(46, 164, 79, .15);--mm-ai-new-app-cancel: #44494f;--mm-ai-new-app-code-bg: #16191d}.mm-ai-new-app{background:var(--mm-ai-new-app-bg);color:var(--mm-ai-new-app-text);border:1px solid var(--mm-ai-new-app-border);border-radius:.6rem;padding:1rem 1.25rem;width:min(40rem,100%)}.mm-ai-new-app__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.mm-ai-new-app__title{margin:0;font-size:1rem}.mm-ai-new-app__tenant{color:var(--mm-ai-new-app-muted);font-weight:400}.mm-ai-new-app__close{background:transparent;color:var(--mm-ai-new-app-muted);border:none;font-size:1.4rem;cursor:pointer;line-height:1;padding:0 .25rem}.mm-ai-new-app__close:hover{color:var(--mm-ai-new-app-text)}.mm-ai-new-app__section{margin-bottom:.75rem}.mm-ai-new-app__heading{margin:0 0 .35rem;font-size:.75rem;color:var(--mm-ai-new-app-muted);text-transform:uppercase;letter-spacing:.04em}.mm-ai-new-app__heading span{text-transform:none;letter-spacing:0;opacity:.6}.mm-ai-new-app__templates{list-style:none;margin:0;padding:0;display:grid;gap:.4rem}.mm-ai-new-app__template{display:flex;gap:.6rem;padding:.55rem .7rem;border:1px solid var(--mm-ai-new-app-border);border-radius:.35rem;cursor:pointer;align-items:flex-start}.mm-ai-new-app__template--active{background:var(--mm-ai-new-app-accent-soft);border-color:var(--mm-ai-new-app-accent)}.mm-ai-new-app__template input[type=radio]{margin-top:.2rem}.mm-ai-new-app__template-body{display:grid;gap:.2rem}.mm-ai-new-app__template-name{font-size:.9rem}.mm-ai-new-app__template-description{font-size:.8rem;color:var(--mm-ai-new-app-muted)}.mm-ai-new-app__field{display:grid;gap:.25rem;margin-bottom:.5rem;font-size:.85rem}.mm-ai-new-app__field label{color:var(--mm-ai-new-app-muted)}.mm-ai-new-app__field input{padding:.45rem .55rem;background:var(--mm-ai-new-app-code-bg);color:inherit;border:1px solid var(--mm-ai-new-app-border);border-radius:.3rem;font-family:inherit;font-size:.9rem}.mm-ai-new-app__preview{margin:0;padding:.5rem .6rem;background:var(--mm-ai-new-app-code-bg);border-radius:.3rem;font-size:.8rem;white-space:pre-wrap;word-break:break-word;max-height:12rem;overflow-y:auto}.mm-ai-new-app__actions{display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem}.mm-ai-new-app__btn{padding:.45rem 1rem;border-radius:.3rem;font-weight:600;border:none;cursor:pointer;font-size:.85rem}.mm-ai-new-app__btn--submit{background:var(--mm-ai-new-app-accent);color:#fff}.mm-ai-new-app__btn--submit:disabled{opacity:.5;cursor:not-allowed}.mm-ai-new-app__btn--cancel{background:var(--mm-ai-new-app-cancel);color:#fff}\n"] }]
|
|
1242
1280
|
}], propDecorators: { templates: [{ type: i0.Input, args: [{ isSignal: true, alias: "templates", required: true }] }], tenantName: [{ type: i0.Input, args: [{ isSignal: true, alias: "tenantName", required: false }] }], confirmed: [{ type: i0.Output, args: ["confirmed"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }] } });
|