feat: initial public release (MAESTRO)
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
import { HelpText } from './HelpText';
|
||||
import { FieldLabel, FieldInput } from './formUtils';
|
||||
import type { SectionFormProps } from './types';
|
||||
|
||||
/**
|
||||
* Reflection (Hermes mode) settings.
|
||||
*
|
||||
* Toggle + caps for the per-job reflection loop that auto-updates a user's
|
||||
* persistent memory. See `src/engine/reflection/` and the design doc at
|
||||
* docs/superpowers/specs/2026-05-11-self-improving-memory-design.md.
|
||||
*
|
||||
* For Reflection to actually run, a worker with `roles: [reflection]` must
|
||||
* exist in the LLM Workers tab. Otherwise (with the default `worker_required`)
|
||||
* jobs are silently skipped.
|
||||
*/
|
||||
export function ReflectionForm({ config, onChange }: SectionFormProps) {
|
||||
const reflection = config.reflection ?? {};
|
||||
// Step 7 (design 2026-05-21): read v2 `llm.workers`. The v2 API contract
|
||||
// already strips the legacy `provider` block from GET /api/config, so
|
||||
// falling back to it would always be empty. Kept as a defensive `?? []`
|
||||
// for the brief window where draft state may still be undefined.
|
||||
const workers = config.llm?.workers ?? [];
|
||||
const hasReflectionWorker = workers.some(
|
||||
(w: { roles?: string[] }) => Array.isArray(w.roles) && w.roles.includes('reflection'),
|
||||
);
|
||||
const enabled = reflection.enabled === true;
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<h2 className="text-base font-semibold text-slate-800">Reflection (Hermes mode)</h2>
|
||||
|
||||
<p className="text-xs text-slate-600 leading-relaxed">
|
||||
通常ジョブが完了するたびに LLM がそのジョブから学んだ教訓を抽出し、ユーザーの memory
|
||||
(<code className="font-mono text-2xs">data/users/{'{userId}'}/memory/</code>)
|
||||
と必要に応じて custom piece を自動更新します。全変更は snapshot として保存され、
|
||||
Memory & Learning タブから revert 可能です。
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<label className="flex items-center gap-2 text-sm text-slate-700">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={enabled}
|
||||
onChange={e => onChange('reflection.enabled', e.target.checked)}
|
||||
className="rounded"
|
||||
/>
|
||||
<span className="font-semibold">Reflection を有効化(自動適用)</span>
|
||||
</label>
|
||||
<HelpText>
|
||||
ON にすると、エージェントジョブが終わるたびに reflection ジョブが裏で走り、memory
|
||||
を自動で書き換えます。デフォルト: 無効。
|
||||
</HelpText>
|
||||
</div>
|
||||
|
||||
{enabled && !hasReflectionWorker && (
|
||||
<div className="rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-900">
|
||||
<div className="font-semibold mb-1">⚠ Reflection worker が未設定です</div>
|
||||
<div>
|
||||
Reflection を有効化しても、<code className="font-mono">roles</code> に
|
||||
<code className="font-mono">reflection</code> を含む worker が無いとジョブは
|
||||
enqueue されません。<strong>LLM → Workers</strong> タブで以下のような worker
|
||||
を追加してください:
|
||||
</div>
|
||||
<pre className="mt-2 text-2xs font-mono bg-white border border-amber-200 rounded p-2 overflow-auto">{`id: reflection-1
|
||||
connection_type: direct
|
||||
endpoint: http://localhost:11434/v1
|
||||
model: qwen2.5:3b # cheap モデル推奨
|
||||
roles: [reflection]
|
||||
max_concurrency: 1`}</pre>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<label className="flex items-center gap-2 text-sm text-slate-700">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={reflection.workerRequired !== false}
|
||||
onChange={e => onChange('reflection.workerRequired', e.target.checked)}
|
||||
className="rounded"
|
||||
/>
|
||||
専用 reflection worker を必須にする
|
||||
</label>
|
||||
<HelpText>
|
||||
ON: <code className="font-mono">roles: [reflection]</code> を持つ worker が無い場合、
|
||||
reflection ジョブを enqueue せずスキップします (デフォルト)。OFF にすると enabled
|
||||
のみで他 worker に拾われる可能性あり。
|
||||
</HelpText>
|
||||
</div>
|
||||
|
||||
<h3 className="text-sm font-medium text-slate-600 mt-4 pt-3 border-t border-slate-200">Caps</h3>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Max memory changes per job</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={reflection.maxMemoryChangesPerJob ?? 3}
|
||||
onChange={v => onChange('reflection.maxMemoryChangesPerJob', Number(v))}
|
||||
/>
|
||||
<HelpText>1 ジョブの reflection で書き込める memory entry の上限。デフォルト: 3</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Max entry body bytes</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={reflection.maxEntryBodyBytes ?? 8192}
|
||||
onChange={v => onChange('reflection.maxEntryBodyBytes', Number(v))}
|
||||
/>
|
||||
<HelpText>memory entry body の最大バイト数。これを超えると semantic validator が reject。デフォルト: 8192</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Piece edit cooldown (hours)</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={reflection.pieceEditCooldownHours ?? 24}
|
||||
onChange={v => onChange('reflection.pieceEditCooldownHours', Number(v))}
|
||||
/>
|
||||
<HelpText>同じ piece への連続編集を抑制する cooldown。デフォルト: 24 (24h 以内に 2 回編集されたら 3 回目以降はスキップ)</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Activity log max bytes</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={reflection.activityLogMaxBytes ?? 4096}
|
||||
onChange={v => onChange('reflection.activityLogMaxBytes', Number(v))}
|
||||
/>
|
||||
<HelpText>reflection LLM に渡す activity log の圧縮上限。デフォルト: 4096</HelpText>
|
||||
</div>
|
||||
|
||||
<h3 className="text-sm font-medium text-slate-600 mt-4 pt-3 border-t border-slate-200">Budget</h3>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Per-user daily budget (tokens)</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={reflection.perUserDailyBudgetTokens ?? 200000}
|
||||
onChange={v => onChange('reflection.perUserDailyBudgetTokens', Number(v))}
|
||||
/>
|
||||
<HelpText>1 ユーザーが 1 日に reflection で消費できる token 合計。超えた以降の reflection は enqueue されません。デフォルト: 200000</HelpText>
|
||||
</div>
|
||||
|
||||
<h3 className="text-sm font-medium text-slate-600 mt-4 pt-3 border-t border-slate-200">Snapshot & Retention</h3>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Snapshot retention (days)</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={reflection.snapshotRetentionDays ?? 90}
|
||||
onChange={v => onChange('reflection.snapshotRetentionDays', Number(v))}
|
||||
/>
|
||||
<HelpText>reflection-history snapshot の保持日数。デフォルト: 90</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Snapshot max bytes per user</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={reflection.snapshotMaxBytesPerUser ?? 100 * 1024 * 1024}
|
||||
onChange={v => onChange('reflection.snapshotMaxBytesPerUser', Number(v))}
|
||||
/>
|
||||
<HelpText>1 ユーザーあたりの snapshot ディレクトリ合計サイズ上限 (bytes)。超えると古い順に削除。デフォルト: 100 MiB</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Snapshot max bytes per entry</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={reflection.snapshotMaxBytesPerEntry ?? 1 * 1024 * 1024}
|
||||
onChange={v => onChange('reflection.snapshotMaxBytesPerEntry', Number(v))}
|
||||
/>
|
||||
<HelpText>1 snapshot エントリの最大サイズ (bytes)。デフォルト: 1 MiB</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="flex items-center gap-2 text-sm text-slate-700">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={reflection.storeLlmRaw === true}
|
||||
onChange={e => onChange('reflection.storeLlmRaw', e.target.checked)}
|
||||
className="rounded"
|
||||
/>
|
||||
スナップショットに LLM の生レスポンスを保存する
|
||||
</label>
|
||||
<HelpText>
|
||||
ON にすると <code className="font-mono">llm-raw.json</code> を snapshot に含めます。
|
||||
デバッグ用途、デフォルトは OFF (ディスク節約)。
|
||||
</HelpText>
|
||||
</div>
|
||||
|
||||
<h3 className="text-sm font-medium text-slate-600 mt-4 pt-3 border-t border-slate-200">Monitoring</h3>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Abstain rate floor</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={reflection.abstainRateFloor ?? 0.3}
|
||||
onChange={v => onChange('reflection.abstainRateFloor', v ? Number(v) : undefined)}
|
||||
/>
|
||||
<HelpText>
|
||||
abstain (学ぶことなし) 率がこれを下回ると過剰学習サインとして警告 (運用シグナル)。
|
||||
デフォルト: 0.3。この値を下回った場合はシステムログに warn が出ます。
|
||||
反映率が高すぎる場合は max_memory_changes_per_job を下げることを検討してください。
|
||||
</HelpText>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user