Spiralist AI Agent Setup Wizard - Source Excerpt 03
Back to Spiralist AI Agent Setup Wizard
Summary
This source excerpt preserves a bounded section of Spiralist/wp-content/themes/spiralist/assets/js/spiralist-ai-agent-setup-wizard.js so readers can inspect the evidence without opening the full source file.
**Source path:** Spiralist/wp-content/themes/spiralist/assets/js/spiralist-ai-agent-setup-wizard.js
const getState = () => ({
schemaVersion: draftSchemaVersion,
artifactOverrides: normalizeArtifactOverrides(artifactOverrides, [], { strict: false }),
presetId: fieldValue('preset_id', 80) || 'base',
agentName: fieldValue('agent_name', 80) || 'Spiralist Agent',
roleLabel: fieldValue('role_label', 120) || 'bounded Spiralist companion',
audience: fieldValue('audience', 160),
purposeStatement: fieldValue('purpose_statement', 700),
allowedContext: fieldValue('allowed_context', 700),
prohibitedContext: fieldValue('prohibited_context', 700),
toneRange: fieldValue('tone_range', 160),
questionFrequency: fieldValue('question_frequency', 260),
directness: fieldValue('directness', 8),
symbolicLanguage: fieldValue('symbolic_language', 8),
groundingReminders: fieldValue('grounding_reminders', 220),
clarificationRule: fieldValue('clarification_rule', 260),
declineRule: fieldValue('decline_rule', 600),
reasoningRules: checkedValues('reasoning_rules'),
evidenceMode: fieldValue('evidence_mode', 160),
reasoningSummary: fieldValue('reasoning_summary', 180),
personalityFramework: fieldValue('personality_framework', 360),
socialDynamicsLens: fieldValue('social_dynamics_lens', 360),
researchCalibration: fieldValue('research_calibration', 360),
useCaseBoundary: fieldValue('use_case_boundary', 360),
deescalationProtocol: fieldValue('deescalation_protocol', 240),
crisisRule: fieldValue('crisis_rule', 220),
responseContract: fieldValue('response_contract', 220),
allowedMoves: fieldValue('allowed_moves', 220),
fewShotNotes: fieldValue('few_shot_notes', 700),
packageName: slugify(fieldValue('package_name', 90)),
});
const defaultState = () => normalizeState({ ...presetDefaults.base, presetId: 'base' }, { strict: false }).state;
const normalizeState = (candidate, options = {}) => {
const strict = Boolean(options.strict);
const errors = [];
const source = candidate && typeof candidate === 'object' ? candidate : {};
const result = { schemaVersion: draftSchemaVersion };
const keys = Object.keys(source);
const unknown = keys.filter((key) => !allowedStateKeys.has(key));
if (strict && unknown.length) {
errors.push(`Unknown draft fields rejected: ${unknown.join(', ')}`);
}
textFields.forEach((key) => {
const raw = source[key] !== undefined ? source[key] : presetDefaults.base[key];
const value = cleanString(raw, key === 'packageName' ? 90 : 900);
const unsafe = hasBlockedPattern(raw);
if (unsafe) {
errors.push(`${key} contains instruction-override or script-like text.`);
}
const safeValue = unsafe ? cleanString(presetDefaults.base[key], key === 'packageName' ? 90 : 900) : value;
result[key] = key === 'packageName' ? slugify(safeValue) : safeValue;
});
selectFields.forEach((key) => {
const formName = key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
const allowed = optionValues(formName);
const raw = cleanString(source[key] !== undefined ? source[key] : presetDefaults.base[key], 300);
if (key === 'presetId') {
result[key] = validPresetIds.has(raw) ? raw : 'base';
if (raw && !validPresetIds.has(raw)) {
errors.push('Invalid preset ID rejected.');
}
return;
}
result[key] = allowed.size === 0 || allowed.has(raw) ? raw : cleanString(presetDefaults.base[key], 300);
if (allowed.size > 0 && raw && !allowed.has(raw)) {
errors.push(`${key} used an unsupported option and was reset.`);
}
});
numericFields.forEach((key) => {
const raw = Number.parseInt(`${source[key] !== undefined ? source[key] : presetDefaults.base[key]}`, 10);
const value = Number.isFinite(raw) ? Math.max(1, Math.min(5, raw)) : Number.parseInt(presetDefaults.base[key], 10);
result[key] = `${value}`;
});
const allowedRules = new Set(Array.from(form.querySelectorAll('input[name="reasoning_rules"]')).map((input) => input.value));
const importedRules = Array.isArray(source.reasoningRules) ? source.reasoningRules : checkedValues('reasoning_rules');
result.reasoningRules = importedRules
.map((item) => cleanString(item, 500))
.filter((item) => allowedRules.has(item));
if (result.reasoningRules.length === 0) {
result.reasoningRules = Array.from(allowedRules);
}
result.artifactOverrides = normalizeArtifactOverrides(source.artifactOverrides, errors, { strict });
return { state: result, errors };
};
const applyState = (candidate, options = {}) => {
const { state, errors } = normalizeState(candidate, options);
importValidationWarnings = options.persistImportWarnings ? [...errors] : [];
artifactOverrides = { ...state.artifactOverrides };
const map = {
preset_id: state.presetId,
agent_name: state.agentName,
role_label: state.roleLabel,
audience: state.audience,
purpose_statement: state.purposeStatement,
allowed_context: state.allowedContext,
prohibited_context: state.prohibitedContext,
tone_range: state.toneRange,
question_frequency: state.questionFrequency,
directness: state.directness,
symbolic_language: state.symbolicLanguage,
grounding_reminders: state.groundingReminders,
clarification_rule: state.clarificationRule,
decline_rule: state.declineRule,
evidence_mode: state.evidenceMode,
reasoning_summary: state.reasoningSummary,
personality_framework: state.personalityFramework,
social_dynamics_lens: state.socialDynamicsLens,
research_calibration: state.researchCalibration,
use_case_boundary: state.useCaseBoundary,
deescalation_protocol: state.deescalationProtocol,
crisis_rule: state.crisisRule,
response_contract: state.responseContract,
allowed_moves: state.allowedMoves,
few_shot_notes: state.fewShotNotes,
package_name: state.packageName,
};
Object.entries(map).forEach(([name, value]) => setFieldValue(name, value));
setCheckedValues('reasoning_rules', state.reasoningRules);
updateValidation(errors);
updatePreview();
return { state, errors };
};
const applyPreset = (presetId) => {
const normalized = validPresetIds.has(presetId) ? presetId : 'base';
const preset = { ...presetDefaults.base, ...(presetDefaults[normalized] || {}), presetId: normalized };
applyState(preset, { strict: false });
setStatus(`${normalized.replace(/-/g, ' ')} preset loaded.`);
};
const applyHashPreset = () => {
const raw = cleanString(window.location.hash.replace(/^#/, ''), 80).toLowerCase();
if (raw && validPresetIds.has(raw)) {
applyPreset(raw);
}
if (window.location.hash) {
window.history.replaceState(null, document.title, `${window.location.pathname}${window.location.search}`);
}
};
const readDraft = () => {
try {
const raw = window.localStorage.getItem(storageKey);
if (!raw || raw.length > maxImportBytes) {
return null;
}
const parsed = JSON.parse(raw);
return parsed && typeof parsed === 'object' ? parsed : null;
} catch (error) {
return null;
}
};
const saveDraft = () => {
window.clearTimeout(saveTimer);
saveTimer = window.setTimeout(() => {
try {
const state = getState();
const { errors } = normalizeState(state, { strict: false });
if (errors.length) {
updateValidation(errors);
}
window.localStorage.setItem(storageKey, JSON.stringify(state));
setStatus('Draft saved in this browser.');
} catch (error) {
setStatus('Draft could not be saved in this browser.');
}
}, 220);
};
const listLines = (items, fallback = '- Not configured.') => {
const cleanItems = Array.isArray(items) ? items.map((item) => cleanString(item, 1000)).filter(Boolean) : [];
return cleanItems.length ? cleanItems.map((item) => `- ${item}`).join('\n') : fallback;
};