feat(FN-3042): scale board typography and improve theme selector accessibil
Completes Step 2 of FN-3042 by scaling board typography styles across TaskCard and QuickEntryBox components, adding a new CustomModelDropdown stylesheet, and introducing keyboard focus-visible styles for theme selector controls. The merge includes new regression tests for board font scaling, resolve Fusion-Task-Id: FN-3042
This commit is contained in:
@@ -16,8 +16,8 @@ describe("mobile input font size CSS", () => {
|
||||
const quickEntryMatch = css.match(/\.quick-entry-input\s*\{[^}]*\}/);
|
||||
expect(quickEntryMatch).not.toBeNull();
|
||||
|
||||
// Should have 13px font-size on desktop
|
||||
expect(quickEntryMatch![0]).toContain("font-size: 13px");
|
||||
// Should keep quick entry typography below the mobile 16px override baseline
|
||||
expect(quickEntryMatch![0]).toContain("font-size: 0.8125rem");
|
||||
});
|
||||
|
||||
it("form-group textarea has desktop font-size below 16px", () => {
|
||||
|
||||
@@ -609,6 +609,12 @@ html .column.drag-over * {
|
||||
color: var(--bg);
|
||||
}
|
||||
|
||||
.theme-mode-btn:focus-visible {
|
||||
outline: none;
|
||||
border-color: var(--todo);
|
||||
box-shadow: var(--focus-ring-strong);
|
||||
}
|
||||
|
||||
.theme-section-title {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
@@ -652,6 +658,12 @@ html .column.drag-over * {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.theme-font-size-btn:focus-visible {
|
||||
outline: none;
|
||||
border-color: var(--todo);
|
||||
box-shadow: var(--focus-ring-strong);
|
||||
}
|
||||
|
||||
.theme-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
@@ -687,6 +699,12 @@ html .column.drag-over * {
|
||||
background: color-mix(in srgb, var(--todo) 14%, transparent);
|
||||
}
|
||||
|
||||
.theme-option:focus-visible {
|
||||
outline: none;
|
||||
border-color: var(--todo);
|
||||
box-shadow: var(--focus-ring-strong);
|
||||
}
|
||||
|
||||
.theme-option-swatch {
|
||||
width: calc(var(--space-2xl) + var(--space-lg));
|
||||
height: calc(var(--space-2xl) + var(--space-lg));
|
||||
@@ -1446,6 +1464,12 @@ html .column.drag-over * {
|
||||
border-color: var(--text-muted);
|
||||
}
|
||||
|
||||
.theme-reset-btn:focus-visible {
|
||||
outline: none;
|
||||
border-color: var(--todo);
|
||||
box-shadow: var(--focus-ring-strong);
|
||||
}
|
||||
|
||||
/* Theme current preview in settings */
|
||||
.theme-current-preview {
|
||||
display: flex;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--border);
|
||||
color: var(--text);
|
||||
font-size: 13px;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.4;
|
||||
font-family: inherit;
|
||||
outline: none;
|
||||
@@ -88,7 +88,7 @@
|
||||
min-height: unset;
|
||||
resize: none;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 15px;
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@@ -149,14 +149,14 @@
|
||||
.node-picker-item-status {
|
||||
margin-left: auto;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.quick-entry-subtasks-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
@@ -171,14 +171,14 @@
|
||||
}
|
||||
|
||||
.quick-entry-hint {
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
color: var(--text-dim);
|
||||
margin-left: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.quick-entry-model-trigger {
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
padding: 3px 8px;
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@
|
||||
color: var(--text-primary);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
font-size: 0.8125rem;
|
||||
transition: background-color 0.15s;
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
.model-menu-item-value {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
color: var(--text-dim);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -270,7 +270,7 @@
|
||||
border: none;
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
padding: 4px 0;
|
||||
width: fit-content;
|
||||
}
|
||||
@@ -280,7 +280,7 @@
|
||||
}
|
||||
|
||||
.model-submenu-header {
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
padding-bottom: 4px;
|
||||
@@ -292,7 +292,7 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
color: var(--text-error, #e53e3e);
|
||||
padding-top: 4px;
|
||||
}
|
||||
@@ -449,7 +449,7 @@
|
||||
}
|
||||
|
||||
.agent-list-modal .agent-state-filter-select {
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
@@ -497,7 +497,7 @@
|
||||
.agent-list-modal .agent-create-form .input,
|
||||
.agent-list-modal .agent-create-form .select {
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,14 +67,14 @@
|
||||
|
||||
.card-id {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 13px;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.4;
|
||||
word-break: break-word;
|
||||
}
|
||||
@@ -85,7 +85,7 @@
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
margin-top: var(--space-sm);
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
color: var(--text-dim);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@@ -94,7 +94,7 @@
|
||||
.card-status-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 10px;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
@@ -170,7 +170,7 @@
|
||||
.card-size-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 10px;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
@@ -199,7 +199,7 @@
|
||||
.card-priority-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 10px;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.4px;
|
||||
@@ -225,7 +225,7 @@
|
||||
.card-execution-mode-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 10px;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.4px;
|
||||
@@ -252,14 +252,14 @@
|
||||
background: color-mix(in srgb, var(--color-error) 10%, transparent);
|
||||
border: var(--btn-border-width) solid color-mix(in srgb, var(--color-error-dark) 25%, transparent);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
color: var(--color-error-dark);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.card-error-icon {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.card-error-text {
|
||||
@@ -336,7 +336,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
color: var(--triage);
|
||||
position: relative;
|
||||
cursor: default;
|
||||
@@ -363,7 +363,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
color: var(--in-progress);
|
||||
position: relative;
|
||||
cursor: default;
|
||||
@@ -380,7 +380,7 @@
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-xs) var(--space-sm);
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
white-space: nowrap;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
@@ -393,7 +393,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
font-size: 10px;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 600;
|
||||
font-family: var(--font-mono);
|
||||
color: var(--badge-mission-text);
|
||||
@@ -436,7 +436,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 10px;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
background: color-mix(in srgb, var(--text-muted) 18%, transparent);
|
||||
@@ -483,7 +483,7 @@
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
@@ -521,7 +521,7 @@
|
||||
border-radius: var(--radius-pill);
|
||||
background: color-mix(in srgb, var(--text-muted) 12%, transparent);
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
font-family: var(--font-mono);
|
||||
line-height: 1;
|
||||
@@ -543,7 +543,7 @@
|
||||
}
|
||||
|
||||
.card-progress-label {
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--font-mono);
|
||||
@@ -561,7 +561,7 @@
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: calc(var(--space-sm) + var(--space-xs) * 0.75);
|
||||
font-size: 0.6875rem;
|
||||
color: var(--text-muted);
|
||||
transition: color var(--transition-fast);
|
||||
}
|
||||
@@ -596,7 +596,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.card-step-dot {
|
||||
@@ -649,7 +649,7 @@
|
||||
padding: 0 var(--space-xs);
|
||||
border-radius: var(--radius-pill);
|
||||
border: 1px solid var(--border);
|
||||
font-size: calc(var(--space-sm) + var(--space-xs) * 0.25);
|
||||
font-size: 0.5625rem;
|
||||
color: var(--text-muted);
|
||||
background: var(--surface);
|
||||
white-space: nowrap;
|
||||
@@ -718,7 +718,7 @@
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
color: var(--text);
|
||||
font-size: 13px;
|
||||
font-size: 0.8125rem;
|
||||
font-family: inherit;
|
||||
outline: none;
|
||||
resize: none;
|
||||
@@ -823,7 +823,7 @@
|
||||
padding: calc(var(--space-xs) / 4)
|
||||
calc(var(--space-sm) - (var(--space-xs) / 2));
|
||||
margin-left: var(--space-xs);
|
||||
font-size: calc(var(--space-sm) + (var(--space-xs) / 2));
|
||||
font-size: 0.625rem;
|
||||
font-weight: 500;
|
||||
background: var(--card);
|
||||
border: 1px solid var(--border);
|
||||
@@ -865,7 +865,7 @@
|
||||
padding: calc(var(--space-xs) / 4)
|
||||
calc(var(--space-sm) - (var(--space-xs) / 2));
|
||||
margin-left: var(--space-xs);
|
||||
font-size: calc(var(--space-sm) + (var(--space-xs) / 2));
|
||||
font-size: 0.625rem;
|
||||
font-weight: 500;
|
||||
background: var(--card);
|
||||
border: 1px solid var(--border);
|
||||
@@ -909,7 +909,7 @@
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
color: var(--text);
|
||||
background: transparent;
|
||||
@@ -934,7 +934,7 @@
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
margin-top: var(--space-xs);
|
||||
font-size: calc(var(--space-sm) + var(--space-xs) * 0.75);
|
||||
font-size: 0.6875rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
@@ -948,7 +948,7 @@
|
||||
}
|
||||
|
||||
.card-edit-loading-text {
|
||||
font-size: calc(var(--space-sm) + var(--space-xs) * 0.75);
|
||||
font-size: 0.6875rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
@@ -1009,7 +1009,7 @@
|
||||
}
|
||||
|
||||
.card-progress-label {
|
||||
font-size: 10px;
|
||||
font-size: 0.625rem;
|
||||
min-width: 30px;
|
||||
}
|
||||
|
||||
@@ -1024,12 +1024,12 @@
|
||||
|
||||
.card-time-indicator {
|
||||
padding: var(--space-xs) var(--space-sm);
|
||||
font-size: 10px;
|
||||
font-size: 0.625rem;
|
||||
}
|
||||
|
||||
/* Card: smaller status badges for 280px width */
|
||||
.card-status-badge {
|
||||
font-size: 9px;
|
||||
font-size: 0.5625rem;
|
||||
padding: 1px 6px;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { describe, it, expect, beforeAll, afterAll } from "vitest";
|
||||
import { loadAllAppCss } from "../../test/cssFixture";
|
||||
|
||||
function effectivePxForFontSize(fontSize: string, rootPx: number): number {
|
||||
if (fontSize.endsWith("rem")) {
|
||||
return Number.parseFloat(fontSize) * rootPx;
|
||||
}
|
||||
return Number.parseFloat(fontSize);
|
||||
}
|
||||
|
||||
describe("board font scale", () => {
|
||||
let styleEl: HTMLStyleElement;
|
||||
|
||||
beforeAll(() => {
|
||||
styleEl = document.createElement("style");
|
||||
styleEl.textContent = loadAllAppCss();
|
||||
document.head.appendChild(styleEl);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
styleEl.remove();
|
||||
document.documentElement.style.fontSize = "";
|
||||
document.body.innerHTML = "";
|
||||
});
|
||||
|
||||
it("scales board typography when dashboard root font scale changes", () => {
|
||||
document.body.innerHTML = `
|
||||
<div class="column-header"><h2>Todo</h2></div>
|
||||
<div class="column-count">3</div>
|
||||
<div class="column-desc">work</div>
|
||||
<article class="card">
|
||||
<div class="card-id">FN-1</div>
|
||||
<div class="card-title">Task title</div>
|
||||
<div class="card-meta">meta</div>
|
||||
</article>
|
||||
<div class="quick-entry-box">
|
||||
<textarea class="quick-entry-input"></textarea>
|
||||
<span class="quick-entry-hint">Hint</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const titleEl = document.querySelector(".card-title") as Element;
|
||||
const headerEl = document.querySelector(".column-header h2") as Element;
|
||||
const quickEl = document.querySelector(".quick-entry-input") as Element;
|
||||
const countEl = document.querySelector(".column-count") as Element;
|
||||
|
||||
const getPx = (el: Element): number => {
|
||||
const fontSize = getComputedStyle(el).fontSize;
|
||||
const rootInline = document.documentElement.style.fontSize;
|
||||
const rootPx = rootInline.endsWith("%")
|
||||
? (Number.parseFloat(rootInline) / 100) * 16
|
||||
: Number.parseFloat(getComputedStyle(document.documentElement).fontSize);
|
||||
return effectivePxForFontSize(fontSize, rootPx);
|
||||
};
|
||||
|
||||
document.documentElement.style.fontSize = "85%";
|
||||
const title85 = getPx(titleEl);
|
||||
const header85 = getPx(headerEl);
|
||||
const quick85 = getPx(quickEl);
|
||||
|
||||
document.documentElement.style.fontSize = "100%";
|
||||
const title100 = getPx(titleEl);
|
||||
const header100 = getPx(headerEl);
|
||||
const quick100 = getPx(quickEl);
|
||||
const count100 = getPx(countEl);
|
||||
|
||||
document.documentElement.style.fontSize = "125%";
|
||||
const title125 = getPx(titleEl);
|
||||
const header125 = getPx(headerEl);
|
||||
const quick125 = getPx(quickEl);
|
||||
|
||||
expect(title100).toBeCloseTo(13, 2);
|
||||
expect(header100).toBeCloseTo(14, 2);
|
||||
expect(quick100).toBeCloseTo(13, 2);
|
||||
expect(count100).toBeCloseTo(12, 2);
|
||||
|
||||
expect(title85).toBeCloseTo(11.05, 2);
|
||||
expect(header85).toBeCloseTo(11.9, 2);
|
||||
expect(quick85).toBeCloseTo(11.05, 2);
|
||||
|
||||
expect(title125).toBeCloseTo(16.25, 2);
|
||||
expect(header125).toBeCloseTo(17.5, 2);
|
||||
expect(quick125).toBeCloseTo(16.25, 2);
|
||||
});
|
||||
});
|
||||
@@ -908,7 +908,7 @@
|
||||
[data-color-theme="factory"] .column-header h2 {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
[data-color-theme="factory"] .column-count,
|
||||
|
||||
@@ -821,7 +821,7 @@ body {
|
||||
}
|
||||
|
||||
.column-header h2 {
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
@@ -831,7 +831,7 @@ body {
|
||||
}
|
||||
|
||||
.column-count {
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-muted);
|
||||
background: var(--card);
|
||||
padding: calc(var(--space-xs) / 2) var(--space-sm);
|
||||
@@ -854,7 +854,7 @@ body {
|
||||
}
|
||||
|
||||
.column-desc {
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
color: var(--text-dim);
|
||||
padding: var(--space-xs) calc(var(--space-lg) - 2px) calc(var(--space-md) - 2px);
|
||||
}
|
||||
@@ -2248,7 +2248,7 @@ input[type="range"]:focus-visible {
|
||||
}
|
||||
|
||||
.step-progress-label {
|
||||
font-size: 11px;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--font-mono);
|
||||
@@ -2894,7 +2894,7 @@ input[type="range"]:focus-visible {
|
||||
}
|
||||
|
||||
.toggle-label {
|
||||
font-size: calc(var(--space-sm) + var(--space-xs) * 0.75);
|
||||
font-size: 0.6875rem;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export type AgentOnboardingStreamEvent =
|
||||
|
||||
export type AgentOnboardingStreamCallback = (event: AgentOnboardingStreamEvent, eventId?: number) => void;
|
||||
|
||||
const createFnAgent = engineCreateFnAgent;
|
||||
const createFnAgent: typeof engineCreateFnAgent = engineCreateFnAgent;
|
||||
const SESSION_TTL_MS = 30 * 60 * 1000;
|
||||
const CLEANUP_INTERVAL_MS = 5 * 60 * 1000;
|
||||
const GENERATION_TIMEOUT_MS = 120_000;
|
||||
@@ -140,23 +140,27 @@ export function parseAgentOnboardingResponse(text: string): { type: "question";
|
||||
} catch {
|
||||
parsed = JSON.parse(repairJson(candidate));
|
||||
}
|
||||
if (
|
||||
!parsed ||
|
||||
typeof parsed !== "object" ||
|
||||
!("type" in parsed) ||
|
||||
((parsed as { type?: unknown }).type !== "question" &&
|
||||
(parsed as { type?: unknown }).type !== "complete")
|
||||
) {
|
||||
if (typeof parsed !== "object" || parsed === null || !("type" in parsed)) {
|
||||
throw new Error("AI returned invalid response type");
|
||||
}
|
||||
if ((parsed as { type: string }).type === "complete") {
|
||||
const data = (parsed as { data?: Record<string, unknown> }).data ?? {};
|
||||
|
||||
const typed = parsed as { type?: unknown; data?: unknown };
|
||||
if (typed.type !== "question" && typed.type !== "complete") {
|
||||
throw new Error("AI returned invalid response type");
|
||||
}
|
||||
|
||||
if (typed.type === "complete") {
|
||||
const data = (typed.data ?? {}) as { name?: unknown; instructionsText?: unknown; maxTurns?: unknown };
|
||||
if (typeof data.name !== "string" || !data.name.trim()) throw new Error("Invalid summary.name");
|
||||
if (typeof data.instructionsText !== "string" || !data.instructionsText.trim()) throw new Error("Invalid summary.instructionsText");
|
||||
const maxTurns = data.maxTurns;
|
||||
if (!Number.isInteger(maxTurns) || (maxTurns as number) <= 0) throw new Error("Invalid summary.maxTurns");
|
||||
if (typeof maxTurns !== "number" || !Number.isInteger(maxTurns) || maxTurns <= 0) {
|
||||
throw new Error("Invalid summary.maxTurns");
|
||||
}
|
||||
return { type: "complete", data: typed.data as AgentOnboardingSummary };
|
||||
}
|
||||
return parsed as { type: "question"; data: PlanningQuestion } | { type: "complete"; data: AgentOnboardingSummary };
|
||||
|
||||
return { type: "question", data: typed.data as PlanningQuestion };
|
||||
}
|
||||
|
||||
export function createAgentOnboardingSessionPrompt(input: {
|
||||
@@ -231,8 +235,8 @@ async function runGenerationWithTimeout<T>(session: Session, operation: () => Pr
|
||||
}
|
||||
|
||||
async function continueConversation(session: Session, message: string): Promise<void> {
|
||||
if (!session.agent) throw new Error("Session agent not initialized");
|
||||
const agent = session.agent;
|
||||
if (!agent) throw new Error("Session agent not initialized");
|
||||
session.thinkingOutput = "";
|
||||
try {
|
||||
await runGenerationWithTimeout(session, async () => {
|
||||
|
||||
Reference in New Issue
Block a user