@fonlan/dsh-gitmemo 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -4
- package/README.zh.md +83 -3
- package/lib/client.js +721 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +266 -15
- package/lib/index.js +377 -10
- package/lib/mem.d.ts +37 -1
- package/lib/mem.js +74 -10
- package/lib/systemone.d.ts +250 -0
- package/lib/systemone.js +359 -0
- package/package.json +37 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":["Tag","Button","Switch","SettingsForm","SettingsValueField","SettingsSecretField"],"sources":["../../../src/client/card.tsx","../../../src/client/form-model.tsx","../../../src/client/controller.tsx","../../../src/client/locales.tsx","../../../src/client/index.tsx"],"sourcesContent":["/**\n * The gitmemo settings page's card: the gate's master switch, the System-one\n * endpoint, its model, and the API key — written through the credentials domain,\n * never into the settings section, so the literal never rides a response.\n *\n * The form chrome (read-only notice, unavailable notice, save, and the staged\n * save semantics) is the shared `SettingsForm`/`SettingsValueField`/\n * `SettingsSecretField` kit, so this page behaves exactly like a shipped one.\n */\n\nimport { Button, SettingsForm, SettingsSecretField, SettingsValueField, Switch, Tag } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { SettingsFieldProps, SettingsFormLabels } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport { LOCALE_NS } from './locales'\nimport type { GitMemoSettingsFace } from './controller'\n\n/**\n * The boolean control of this page: the gate's master switch.\n *\n * `dsh-client-ui-primitives` ships no boolean settings field (only\n * `SettingsValueField`, whose control is a text input, and `SettingsSecretField`),\n * so this builds the same field chrome from the primitives that ARE exported —\n * the shipped `Switch`, the overridden `Tag`, and a `ghost` `Button` for the\n * reset — in the vertical rhythm the shipped fields above and below it use.\n * Styling reads the host's own `--dsw-alias-*` tokens instead of shipping a\n * stylesheet, so the row tracks the active theme like everything around it.\n */\ninterface SettingsSwitchFieldProps\n extends Omit<SettingsFieldProps, 'text' | 'invalid' | 'invalidLabel' | 'onEdit'> {\n /** Whether the switch reads as on. */\n checked: boolean\n /** Stage the requested state. */\n onEdit: (next: boolean) => void\n}\n\n/**\n * Render one labelled boolean field.\n * @param props - the field's copy, its staged state, and the edit actions.\n * @returns the labelled switch.\n */\nfunction SettingsSwitchField(props: SettingsSwitchFieldProps): JSX.Element {\n const { id, label, hint, checked, overridden, overriddenLabel, resetLabel, disabled, onEdit, onReset } = props\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>\n {/* The Switch carries the accessible name itself (aria-label), so this\n stays presentational: a <label> around the whole row would also\n toggle the switch when the reset button beside it is clicked. */}\n <span style={{ fontSize: 13, fontWeight: 500, color: 'var(--dsw-alias-label-primary)' }}>{label}</span>\n <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n {overridden ? (\n <>\n <Tag tone=\"neutral\">{overriddenLabel}</Tag>\n <Button variant=\"ghost\" size=\"sm\" type=\"button\" disabled={disabled} onClick={onReset}>\n {resetLabel}\n </Button>\n </>\n ) : null}\n <Switch checked={checked} onChange={onEdit} label={label} disabled={disabled} />\n </span>\n </div>\n <p id={`${id}-hint`} style={{ margin: 0, fontSize: 12, color: 'var(--dsw-alias-label-tertiary)' }}>\n {hint}\n </p>\n </div>\n )\n}\n\n/** Props the renderer binds for the gitmemo page. */\nexport type GitMemoSettingsSectionProps = PropsRuntime<'settings.section'> &\n PropsLocale<typeof LOCALE_NS> &\n InjectFace<GitMemoSettingsFace>\n\n/**\n * The form frame's copy, read from this page's dictionary.\n * @param t - the page's locale reader.\n * @returns the labels the shared settings form renders.\n */\nfunction formLabels(t: GitMemoSettingsSectionProps['t']): SettingsFormLabels {\n return {\n unavailable: t('unavailable'),\n readOnly: t('readOnly'),\n saveFailed: t('saveFailed'),\n save: t('save'),\n saving: t('saving')\n }\n}\n\n/**\n * Render the gitmemo settings page.\n * @param props - locale copy, the staged form state, and its actions.\n * @returns the settings form.\n */\nexport function GitMemoSettingsSection(props: GitMemoSettingsSectionProps): JSX.Element {\n const { t, useGitMemoSettings, edit, resetField, save, discard } = props\n const state = useGitMemoSettings((snapshot) => snapshot)\n const sectionDisabled = !state.writable\n return (\n <SettingsForm labels={formLabels(t)} state={state} onSave={save} onDiscard={discard}>\n <SettingsSwitchField\n id=\"dsh-gitmemo-systemone-enabled\"\n label={t('enabled')}\n hint={t('enabledHint')}\n overriddenLabel={t('overridden')}\n resetLabel={t('reset')}\n disabled={sectionDisabled}\n /* An absent value means the declared default (enabled), so the field's\n draft is seeded with 'true' rather than an empty string. */\n checked={state.enabled.text === 'true'}\n overridden={state.enabled.overridden}\n onEdit={(next) => {\n edit('enabled', String(next))\n }}\n onReset={() => {\n resetField('enabled')\n }}\n />\n <SettingsValueField\n id=\"dsh-gitmemo-systemone-endpoint\"\n label={t('endpoint')}\n hint={t('endpointHint')}\n overriddenLabel={t('overridden')}\n resetLabel={t('reset')}\n invalidLabel={t('invalidText')}\n disabled={sectionDisabled}\n {...state.endpoint}\n onEdit={(text) => {\n edit('endpoint', text)\n }}\n onReset={() => {\n resetField('endpoint')\n }}\n />\n <SettingsValueField\n id=\"dsh-gitmemo-systemone-model\"\n label={t('model')}\n hint={t('modelHint')}\n overriddenLabel={t('overridden')}\n resetLabel={t('reset')}\n invalidLabel={t('invalidText')}\n disabled={sectionDisabled}\n {...state.model}\n onEdit={(text) => {\n edit('model', text)\n }}\n onReset={() => {\n resetField('model')\n }}\n />\n <SettingsSecretField\n id=\"dsh-gitmemo-systemone-apikey\"\n label={t('apiKey')}\n hint={t('apiKeyHint')}\n disabled={!state.apiKeyWritable}\n text={state.apiKey.text}\n configured={state.apiKeyConfigured}\n stateLabel={state.apiKeyConfigured ? t('apiKeySet') : t('apiKeyUnset')}\n onEdit={(text) => {\n edit('apiKey', text)\n }}\n />\n </SettingsForm>\n )\n}\n","/**\n * A staged, path-aware settings form model.\n *\n * Why this exists instead of `SettingsFormModel` from\n * `@deepseek-ai/dsh-client-ui-primitives`: that model addresses every field as\n * a SINGLE top-level key of the namespace section (`path: [field]` in its\n * `plan()`), while this plugin's editable fields live one level down under the\n * nested `systemOne` object its `Config` declares. Feeding it\n * `settingsTextField('systemOne.endpoint')` would read `section['systemOne.endpoint']`\n * and write a literal dotted key — silently configuring nothing.\n *\n * So this model keeps the shipped model's staging semantics (one save writes\n * every staged edit; an empty draft clears the field; a draft the field does\n * not accept BLOCKS the save rather than being dropped; a save that did not\n * land keeps its drafts) and its state shapes (`SettingsFormShell`,\n * `SettingsFieldState`), but carries an explicit `path` per field and emits\n * nested `SettingsFormPathOp`s — the vocabulary the Host's settings plane\n * actually accepts (`isVolatilePath` walks multi-segment paths, and\n * `settings/mutate` applies them positionally).\n */\n\nimport type {\n SettingsFieldState,\n SettingsFieldWrite,\n SettingsFormPathOp,\n SettingsFormScope,\n SettingsFormScopeSnapshot,\n SettingsFormShell,\n SettingsSecretSpec\n} from '@deepseek-ai/dsh-client-ui-primitives'\n\n/** The editable projection of this plugin's settings namespace. */\nexport interface GitMemoSettings {\n /** The System-one recall gate, as `src/index.ts` declares it. */\n systemOne?: {\n enabled?: boolean\n endpoint?: string\n model?: string\n apiKey?: string\n apiKeyEnv?: string\n mode?: 'noul' | 'score'\n threshold?: number\n scoreMin?: number\n minKeep?: number\n maxCandidates?: number\n maxTaskChars?: number\n timeoutMs?: number\n }\n}\n\n/** How one section field converts between its stored value and its draft text. */\nexport interface PathFieldSpec {\n /** Key addressing this control inside the card's form. */\n field: string\n /** Path inside the namespace section this control edits. */\n path: readonly string[]\n /** Render a stored value as draft text; the empty string when the section carries none. */\n format: (value: unknown) => string\n /** The write this draft text stages, or undefined when the text is not a value this field accepts. */\n parse: (text: string) => SettingsFieldWrite | undefined\n}\n\n/**\n * A free-text field. An empty draft clears the field, so emptying the control\n * and saving is the same gesture as resetting it.\n * @param field - key addressing this control inside the card's form.\n * @param path - path of the field inside the namespace section.\n * @returns the field's conversion spec.\n */\nexport function pathTextField(field: string, path: readonly string[]): PathFieldSpec {\n return {\n field,\n path,\n format: (value) => (typeof value === 'string' ? value : ''),\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n }\n }\n}\n\n/**\n * A whole-number field. An empty draft clears the field; any other draft that\n * is not a finite number blocks the save.\n * @param field - key addressing this control inside the card's form.\n * @param path - path of the field inside the namespace section.\n * @returns the field's conversion spec.\n */\nexport function pathNumberField(field: string, path: readonly string[]): PathFieldSpec {\n return {\n field,\n path,\n format: (value) => (typeof value === 'number' ? String(value) : ''),\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n return Number.isFinite(parsed) ? { kind: 'set', value: parsed } : undefined\n }\n }\n}\n\n/**\n * Draft text a boolean field renders while the section carries no value.\n *\n * A missing boolean is not \"unknown\": `src/index.ts` declares\n * `systemOne.enabled` with `default(true)` and reads it back through\n * `liveValue(section.enabled, true)`, so an absent value means ENABLED. Rendering\n * an absent boolean as the empty string would show a disabled switch for a gate\n * that is actually running, so the draft is seeded with the declared default.\n */\nconst ABSENT_BOOLEAN_TEXT = 'true'\n\n/**\n * A boolean field, staged as the `'true'`/`'false'` draft the card's switch\n * renders. An empty draft clears the field (re-inheriting the declared\n * default); any other draft that is not one of those two words blocks the save.\n * @param field - key addressing this control inside the card's form.\n * @param path - path of the field inside the namespace section.\n * @returns the field's conversion spec.\n */\nexport function pathBooleanField(field: string, path: readonly string[]): PathFieldSpec {\n return {\n field,\n path,\n format: (value) => (typeof value === 'boolean' ? String(value) : ABSENT_BOOLEAN_TEXT),\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n if (trimmed === 'true') return { kind: 'set', value: true }\n if (trimmed === 'false') return { kind: 'set', value: false }\n return undefined\n }\n }\n}\n\n/** One staged draft: what the user typed, and whether it stages a clear. */\ninterface Staged {\n text: string\n clear: boolean\n}\n\n/** One planned write: a section op, a credential write, or a blocking invalid draft. */\ninterface PlannedWrite {\n field: string\n op?: SettingsFormPathOp\n run?: () => Promise<boolean>\n invalid?: boolean\n}\n\n/** Read one path inside a JSON-shaped layer. */\nfunction member(value: unknown, path: readonly string[]): unknown {\n let node: unknown = value\n for (const key of path) {\n if (node === null || typeof node !== 'object') return undefined\n node = (node as Record<string, unknown>)[key]\n }\n return node\n}\n\n/** Whether the user layer actually carries this path (presence, not value, marks an override). */\nfunction carries(value: unknown, path: readonly string[]): boolean {\n const last = path[path.length - 1]\n if (last === undefined) return false\n const parent = member(value, path.slice(0, -1))\n return parent !== null && typeof parent === 'object' && Object.hasOwn(parent, last)\n}\n\n/**\n * Stages one card's edits over one settings namespace and writes them on save.\n */\nexport class GitMemoFormModel<T> {\n private readonly scope: SettingsFormScope<T>\n private readonly specs: Map<string, PathFieldSpec>\n private readonly secretSpecs: Map<string, SettingsSecretSpec>\n private readonly staged = new Map<string, Staged>()\n private readonly listeners = new Set<() => void>()\n private readonly unsubscribe: () => void\n private baseline: SettingsFormScopeSnapshot<T> | undefined\n private saving = false\n private failed = false\n\n /**\n * @param scope - the shared configuration form for this card's namespace.\n * @param specs - the section fields this card edits.\n * @param secrets - the card's write-only controls, written outside the section.\n */\n constructor(scope: SettingsFormScope<T>, specs: PathFieldSpec[], secrets: SettingsSecretSpec[] = []) {\n this.scope = scope\n this.specs = new Map(specs.map((spec) => [spec.field, spec]))\n this.secretSpecs = new Map(secrets.map((spec) => [spec.field, spec]))\n this.unsubscribe = scope.subscribe(() => {\n this.publish()\n })\n }\n\n /** Observe draft or host-state changes. */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n /** Read the card-level state: what the Host serves, and what a save would do. */\n shell(): SettingsFormShell {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n return {\n available: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: plan.length > 0,\n invalid: plan.some((item) => item.invalid === true),\n saving: this.saving,\n failed: this.failed\n }\n }\n\n /**\n * Read one control's state.\n * @param field - key of a section field or of a write-only control.\n * @returns the draft text, whether a save would leave an override, and whether it is invalid.\n */\n field(field: string): SettingsFieldState {\n const staged = this.staged.get(field)\n if (this.secretSpecs.has(field)) return { text: staged?.text ?? '', overridden: false, invalid: false }\n const spec = this.spec(field)\n if (staged === undefined) {\n return { text: spec.format(this.sectionValue(spec.path)), overridden: this.stored(spec.path), invalid: false }\n }\n const write = staged.clear ? { kind: 'clear' } : spec.parse(staged.text)\n return { text: staged.text, overridden: write?.kind === 'set', invalid: write === undefined }\n }\n\n /** Build the edit, reset, save, and discard actions bound to this form. */\n actions(): {\n edit: (field: string, text: string) => void\n resetField: (field: string) => void\n save: () => void\n discard: () => void\n } {\n return {\n edit: (field, text) => {\n this.stage(field, { text, clear: false })\n },\n resetField: (field) => {\n const spec = this.spec(field)\n this.stage(field, { text: spec.format(this.baseValue(spec.path)), clear: true })\n },\n save: () => {\n void this.save()\n },\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return\n this.staged.clear()\n this.baseline = undefined\n this.failed = false\n this.publish()\n }\n }\n }\n\n /**\n * Write every staged edit, then re-seed from what the Host accepted.\n *\n * The Host is the only authority on whether a value was accepted, so the\n * outcome is read back from the section rather than predicted here. A save\n * that did not land keeps its drafts, so the user can correct them instead of\n * retyping.\n */\n async save(): Promise<void> {\n const plan = this.plan()\n if (\n plan.length === 0 ||\n this.saving ||\n !this.scope.getSnapshot().writable ||\n plan.some((item) => item.invalid === true)\n ) {\n return\n }\n this.saving = true\n this.failed = false\n this.publish()\n try {\n const ops = plan.flatMap((item) => (item.op === undefined ? [] : [item.op]))\n let landed = ops.length === 0 || (await this.scope.mutate(ops, this.baseline?.revision))\n if (!landed) {\n this.failed = true\n return\n }\n for (const item of plan) if (item.run !== undefined) landed = (await item.run()) && landed\n if (landed) {\n this.staged.clear()\n this.baseline = undefined\n }\n this.failed = !landed\n } catch {\n this.failed = true\n } finally {\n this.saving = false\n this.publish()\n }\n }\n\n /** Release the form's accepted-value subscription. */\n dispose(): void {\n this.unsubscribe()\n this.listeners.clear()\n }\n\n /**\n * Every staged edit a save would write, in staging order. An entry whose\n * draft is not a value its field accepts carries no write: the form is still\n * dirty, and the save refuses rather than dropping the edit.\n */\n private plan(): PlannedWrite[] {\n const plan: PlannedWrite[] = []\n for (const [field, staged] of this.staged) {\n const secret = this.secretSpecs.get(field)\n if (secret !== undefined) {\n const value = staged.text.trim()\n if (value !== '') plan.push({ field, run: () => secret.write(value) })\n continue\n }\n const spec = this.spec(field)\n if (staged.clear) {\n if (this.stored(spec.path)) plan.push({ field, op: { op: 'unset', path: [...spec.path] } })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(spec.path))) continue\n const write = spec.parse(staged.text)\n if (write === undefined) plan.push({ field, invalid: true })\n else if (write.kind === 'clear') plan.push({ field, op: { op: 'unset', path: [...spec.path] } })\n else plan.push({ field, op: { op: 'set', path: [...spec.path], value: write.value } })\n }\n return plan\n }\n\n private stage(field: string, edit: Staged): void {\n this.baseline ??= this.scope.getSnapshot()\n this.staged.set(field, edit)\n this.failed = false\n this.publish()\n }\n\n private spec(field: string): PathFieldSpec {\n const spec = this.specs.get(field)\n if (spec === undefined) throw new Error(`dsh-gitmemo settings card has no field ${field}`)\n return spec\n }\n\n private sectionValue(path: readonly string[]): unknown {\n return member(this.scope.getSnapshot().value, path)\n }\n\n private baseValue(path: readonly string[]): unknown {\n return member(this.scope.getSnapshot().base, path)\n }\n\n private stored(path: readonly string[]): boolean {\n return carries(this.scope.getSnapshot().user, path)\n }\n\n private publish(): void {\n for (const listener of [...this.listeners]) listener()\n }\n}\n","/**\n * The gitmemo settings page's staged form over the `dsh-gitmemo` settings\n * namespace — the profile entry id of this package's host half.\n *\n * The API key is the one control that does not live in the section: its literal\n * never rides a response, so the page learns only whether one is configured for\n * the reference the section names, and writes it through the credentials domain.\n * It is still staged with the rest of the form, so one save covers everything\n * the page shows.\n */\n\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { HostObservable } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsFieldState, SettingsFormActions, SettingsFormScope, SettingsFormShell } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { GitMemoFormModel, pathBooleanField, pathTextField, type GitMemoSettings } from './form-model'\n\n/**\n * Settings namespace of this plugin. Spelled here rather than imported: a\n * client half must not depend on a host half, and the id is the profile entry\n * id the settings plane keys forms by.\n */\nexport const GITMEMO_NS = 'dsh-gitmemo'\n\n/** Credential reference the host resolves when the section names none. */\nexport const DEFAULT_API_KEY_REF = 'TYPESAFE_API_KEY'\n\n/** Form field the credential control stages under. */\nconst API_KEY_FIELD = 'apiKey'\n\n/** What the gitmemo page renders. */\nexport interface GitMemoCardState extends SettingsFormShell {\n /** Whether the recall gate runs at all. */\n enabled: SettingsFieldState\n /** System-one endpoint. */\n endpoint: SettingsFieldState\n /** Model identifier sent in the request body. */\n model: SettingsFieldState\n /** The staged credential, which starts blank on every load. */\n apiKey: SettingsFieldState\n /** Whether the Host reports a credential configured for the referenced key. */\n apiKeyConfigured: boolean\n /** Whether the credentials domain accepts a write for it; false disables the control. */\n apiKeyWritable: boolean\n}\n\n/** The registration-side face the gitmemo page's slot entry injects. */\nexport interface GitMemoSettingsFace extends SettingsFormActions {\n hooks: {\n /** Page snapshot bound by the renderer as useGitMemoSettings. */\n gitMemoSettings: HostObservable<GitMemoCardState>\n }\n}\n\n/** One credential reference's presence and writability, as the wire reports it. */\ninterface CredentialView {\n ref: string\n configured: boolean\n writable: boolean\n}\n\n/** Bridges the `dsh-gitmemo` scope and the credentials domain onto the page. */\nexport class GitMemoSettingsController {\n private readonly scope: SettingsFormScope<GitMemoSettings>\n private readonly ctx: ClientContext\n private readonly form: GitMemoFormModel<GitMemoSettings>\n private readonly listeners = new Set<() => void>()\n private readonly unsubscribe: () => void\n private readonly unsubscribeForm: () => void\n private snapshot: GitMemoCardState\n private credential: CredentialView = { ref: '', configured: false, writable: true }\n\n /**\n * @param scope - the bound settings scope for the `dsh-gitmemo` namespace.\n * @param ctx - the page plugin's context, whose `remote.credentials` namespace\n * answers for the credential the section references.\n */\n constructor(scope: SettingsFormScope<GitMemoSettings>, ctx: ClientContext) {\n this.scope = scope\n this.ctx = ctx\n this.form = new GitMemoFormModel<GitMemoSettings>(\n scope,\n [\n pathBooleanField('enabled', ['systemOne', 'enabled']),\n pathTextField('endpoint', ['systemOne', 'endpoint']),\n pathTextField('model', ['systemOne', 'model'])\n ],\n [{ field: API_KEY_FIELD, write: (text) => this.writeKey(text) }]\n )\n this.snapshot = this.projection()\n // Host-state changes and staged drafts both move the page snapshot: the\n // scope subscription covers accepted values, the form subscription covers\n // drafts (text, the overridden badge, dirty, invalid, saving, failed).\n this.unsubscribe = scope.subscribe(() => {\n void this.readCredential()\n this.publish()\n })\n this.unsubscribeForm = this.form.subscribe(() => {\n this.publish()\n })\n void this.readCredential()\n }\n\n /** Read the current page snapshot (stable reference until the next change). */\n getSnapshot = (): GitMemoCardState => this.snapshot\n\n /** Observe page-snapshot replacements. */\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n /**\n * Re-read after the Host reports a change to the reference this page watches.\n * A key can be written from somewhere else, and the settings section does not\n * change when it is.\n * @param ref - the reference the Host reports as changed.\n */\n refreshCredential(ref: string): void {\n if (ref !== this.credential.ref) return\n void this.readCredential()\n }\n\n /**\n * Build the face the page's slot registration injects.\n * @returns the page's snapshot and its form actions.\n */\n inject(): GitMemoSettingsFace {\n return {\n hooks: { gitMemoSettings: { getSnapshot: this.getSnapshot, subscribe: this.subscribe } },\n ...this.form.actions()\n }\n }\n\n /** Release configuration subscriptions. */\n dispose(): void {\n this.unsubscribe()\n this.unsubscribeForm()\n this.form.dispose()\n this.listeners.clear()\n }\n\n private projection(): GitMemoCardState {\n return {\n ...this.form.shell(),\n enabled: this.form.field('enabled'),\n endpoint: this.form.field('endpoint'),\n model: this.form.field('model'),\n apiKey: this.form.field(API_KEY_FIELD),\n apiKeyConfigured: this.credential.configured,\n apiKeyWritable: this.credential.writable\n }\n }\n\n private publish(): void {\n this.snapshot = this.projection()\n for (const listener of [...this.listeners]) listener()\n }\n\n /**\n * Ask the credentials domain about the reference the section currently names.\n *\n * The answer is stored with the reference it describes: `apiKeyEnv` can change\n * between the request and its response, so a response is published only while\n * it still answers for the reference in force.\n */\n private async readCredential(): Promise<void> {\n const ref = refOf(this.scope.getSnapshot())\n if (ref !== this.credential.ref) {\n this.credential = { ref, configured: false, writable: true }\n this.publish()\n }\n const response = await this.ctx.remote.credentials.describe([ref])\n if (!response.ok || ref !== refOf(this.scope.getSnapshot())) return\n const view = response.value[ref]\n const next: CredentialView = { ref, configured: view?.configured ?? false, writable: view?.writable ?? true }\n if (next.configured === this.credential.configured && next.writable === this.credential.writable) return\n this.credential = next\n this.publish()\n }\n\n /**\n * Write the staged key, then re-read whether the Host now holds one.\n * @param value - the staged credential literal.\n * @returns whether the Host reports a configured credential afterwards.\n */\n private async writeKey(value: string): Promise<boolean> {\n const response = await this.ctx.remote.credentials.set(refOf(this.scope.getSnapshot()), value)\n await this.readCredential()\n return response.ok && this.credential.configured\n }\n}\n\n/**\n * The credential reference the section names, or the host's default.\n * @param snapshot - the current scope snapshot.\n * @returns the reference to address.\n */\nfunction refOf(snapshot: { value: GitMemoSettings | undefined }): string {\n const declared = snapshot.value?.systemOne?.apiKeyEnv\n return declared !== undefined && declared.length > 0 ? declared : DEFAULT_API_KEY_REF\n}\n","/**\n * Locale dictionaries for the gitmemo settings page.\n *\n * The namespace is the plugin's own cordis id (kebab), which is also the\n * settings namespace and the profile entry id; the scoped npm package name is\n * reserved for package-bound identifiers (the module-loader id, the bundle\n * route base). zh is the key source of truth — en is typed against it, and the\n * locale registry re-checks the key sets at registration time.\n */\n\n/** Dictionary namespace owned by this page. */\nexport const LOCALE_NS = 'dsh-gitmemo'\n\n/** Simplified Chinese copy. */\nexport const zh = {\n settingsTitle: 'GitMemo',\n settingsSub: 'Git 长期记忆(.mem)中「系统一召回闸门」的配置。',\n enabled: '启用 System-one 召回闸门',\n enabledHint:\n '关闭后 mem_search 不再调用 System-one 模型,召回行为与门控存在前逐字节一致;此外仍需已配置密钥。',\n endpoint: 'System-one 接口地址',\n endpointHint: '接受 System-one 请求契约的 HTTP 端点;留空表示恢复默认地址。',\n model: '模型',\n modelHint: '请求体中携带的模型标识;留空表示恢复默认模型。',\n apiKey: 'API Key',\n apiKeyHint: '凭据不写入设置文件。留空表示保持当前密钥。',\n apiKeySet: '已配置密钥。',\n apiKeyUnset: '未配置密钥;配置之前召回闸门不生效。',\n overridden: '已覆盖',\n reset: '恢复默认',\n invalidText: '该字段不接受这个值。',\n readOnly: '本部署的设置为只读。',\n unavailable: '该插件当前未加载,暂时无法配置。',\n save: '保存',\n saving: '保存中…',\n saveFailed: '本部署没有接受这些值,已保留供你修改。'\n}\n\n/** English copy; the key set must match {@link zh} exactly. */\nexport const en: Record<keyof typeof zh, string> = {\n settingsTitle: 'GitMemo',\n settingsSub: 'Configuration of the System-one recall gate over the Git-backed .mem memory.',\n enabled: 'Enable the System-one recall gate',\n enabledHint:\n 'When off, mem_search never calls the System-one model and recall behaves byte-for-byte as it did before the gate existed; a credential is still required for it to run.',\n endpoint: 'System-one endpoint',\n endpointHint: 'HTTP endpoint accepting the System-one request contract; blank restores the default.',\n model: 'Model',\n modelHint: 'Model identifier sent in the request body; blank restores the default.',\n apiKey: 'API key',\n apiKeyHint: 'Stored outside the settings file. Leave blank to keep the current key.',\n apiKeySet: 'A key is configured.',\n apiKeyUnset: 'No key is configured; the recall gate stays a no-op until one is.',\n overridden: 'Overridden',\n reset: 'Reset to default',\n invalidText: 'This field does not accept that value.',\n readOnly: 'This deployment stores settings read-only.',\n unavailable: 'This plugin is not loaded, so it cannot be configured right now.',\n save: 'Save',\n saving: 'Saving…',\n saveFailed: 'The deployment did not accept these values; they were left for you to correct.'\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** GitMemo settings page copy. */\n 'dsh-gitmemo': keyof typeof zh\n }\n}\n","/**\n * dsh-gitmemo settings page, browser half.\n *\n * DSH 0.1.7-alpha.1 ships no client that auto-generates a settings page from a\n * plugin's schema (`@deepseek-ai/dsh-settings/README.md`: \"no shipped client\n * does so yet\"), so this plugin ships its own page. It rides the settings\n * namespace named by the profile entry id — `dsh-gitmemo` — which is the\n * namespace the host half's `.volatile()` `systemOne` fields are exposed under,\n * and registers into the `settings.section` list slot: one entry in the settings\n * sidebar, its content rendered into the panel's content column.\n *\n * Registration is gated on the Host actually serving that namespace\n * (`configForms.whileServed`), so a deployment that never loaded this plugin\n * shows no trace of the page.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\n// Type-only: each import installs a declaration this page compiles against —\n// the client services (`slots`, `locale`, `remote`, `configForms`), the\n// `settings.section` slot contract, and the generated `remote.credentials`\n// namespace. They are erased before the bundle purity gate ever sees them.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-api-settings-controller/remote'\nimport { GitMemoSettingsSection } from './card'\nimport { GitMemoSettingsController, GITMEMO_NS } from './controller'\nimport { LOCALE_NS, zh, en } from './locales'\n\n/** The settings sidebar entry this plugin's page owns (must stay stable). */\nconst SETTINGS_SECTION_ID = 'dsh-gitmemo'\n\n/** Services required before mounting (provided by the client runtime). */\nexport const inject = ['slots', 'locale', 'remote', 'remote.credentials', 'configForms']\n\n/**\n * Mount the gitmemo settings page while the Host serves its namespace.\n * @param ctx - the browser plugin context.\n */\nexport function apply(ctx: ClientContext): void {\n // Live translate bound to the active locale (labels re-read it per call).\n const t = ctx.locale.bind(LOCALE_NS)\n ctx.effect(() => ctx.locale.register(LOCALE_NS, { zh, en }), 'dsh-gitmemo: dictionaries')\n\n // One staged form over the `dsh-gitmemo` namespace, plus the credentials\n // domain read the API-key control's Set / Not-set badge reports.\n const controller = new GitMemoSettingsController(ctx.configForms.get(GITMEMO_NS), ctx)\n ctx.effect(\n () => () => {\n controller.dispose()\n },\n 'dsh-gitmemo: settings form'\n )\n ctx.effect(\n () =>\n ctx.remote.$on('credentials/reference-updated', (ref) => {\n controller.refreshCredential(ref)\n }),\n 'dsh-gitmemo: credential invalidations'\n )\n\n ctx.effect(\n () =>\n ctx.configForms.whileServed([GITMEMO_NS], () =>\n ctx.slots.inject('settings.section', () =>\n ctx.slots.register(\n {\n name: 'settings.section',\n id: SETTINGS_SECTION_ID,\n order: 200,\n label: () => t('settingsTitle'),\n locale: LOCALE_NS,\n inject: () => controller.inject()\n } as never,\n GitMemoSettingsSection as never\n )\n )\n ),\n 'dsh-gitmemo: settings page'\n )\n}\n"],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
|
@@ -21,38 +21,283 @@
|
|
|
21
21
|
* @module dsh-gitmemo
|
|
22
22
|
*/
|
|
23
23
|
import z from "@deepseek-ai/schemastery";
|
|
24
|
+
import { type SearchScoring } from "./mem.js";
|
|
24
25
|
/** Cordis plugin name. */
|
|
25
26
|
declare const name = "dsh-gitmemo";
|
|
26
27
|
/** Host services this plugin needs. */
|
|
27
28
|
declare const inject: string[];
|
|
28
29
|
/** Plugin configuration. */
|
|
29
|
-
declare const Config: z<Schemastery.ObjectS<{
|
|
30
|
+
declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
30
31
|
/** @deprecated — the memory dir is fixed at `<projectRoot>/.mem`; kept for one version. */
|
|
31
|
-
memDirName: z<string, string>;
|
|
32
|
+
memDirName: z<string, string, "defined">;
|
|
32
33
|
/** Max search hits per mem_search call (page size). Default 20. */
|
|
33
|
-
searchLimit: z<number, number>;
|
|
34
|
+
searchLimit: z<number, number, "defined">;
|
|
35
|
+
/**
|
|
36
|
+
* How a matched entry is scored (search order only — matching itself is
|
|
37
|
+
* identical in both modes).
|
|
38
|
+
*
|
|
39
|
+
* - `weighted` (default): sum of per-keyword rarity weights within the
|
|
40
|
+
* recall page, so a distinctive match outranks several common ones.
|
|
41
|
+
* - `count`: the previous default behaviour (one point per matched keyword plus the
|
|
42
|
+
* recency bonus), kept for exact backwards compatibility.
|
|
43
|
+
*
|
|
44
|
+
* Measured motivation: on LongMemEval `_S` the engine reached
|
|
45
|
+
* recall_all@50 = 0.998 while ndcg@5 was only 0.686 — evidence was reachable
|
|
46
|
+
* but ranked poorly, because a saturated-free match count cannot tell a rare
|
|
47
|
+
* keyword from a ubiquitous one.
|
|
48
|
+
*/
|
|
49
|
+
searchScoring: z<"count" | "weighted", "count" | "weighted", "defined">;
|
|
34
50
|
/** @deprecated — `.mem` always stays on main; kept for one version, no effect. */
|
|
35
|
-
branchAlign: z<boolean, boolean>;
|
|
51
|
+
branchAlign: z<boolean, boolean, "defined">;
|
|
36
52
|
/** @deprecated — session-start recent seeding was removed; kept for one version, no effect. */
|
|
37
|
-
recentContextLimit: z<number, number>;
|
|
53
|
+
recentContextLimit: z<number, number, "defined">;
|
|
38
54
|
/** Cross-process lock wait timeout in milliseconds. Default 30000. */
|
|
39
|
-
lockTimeoutMs: z<number, number>;
|
|
55
|
+
lockTimeoutMs: z<number, number, "defined">;
|
|
40
56
|
/** Optional explicit project root; defaults to the calling session's cwd. */
|
|
41
|
-
projectRoot: z<string, string>;
|
|
42
|
-
|
|
57
|
+
projectRoot: z<string, string, "plain">;
|
|
58
|
+
/**
|
|
59
|
+
* Optional System-one recall gate. When an endpoint and a credential are
|
|
60
|
+
* configured, each `mem_search` page is narrowed by a System-one model
|
|
61
|
+
* (TypeSafe Jev by default) before it reaches the model; when nothing is
|
|
62
|
+
* configured the gate is a no-op and recall behaves exactly as before.
|
|
63
|
+
*
|
|
64
|
+
* `.volatile()` is REQUIRED here, not cosmetic: the settings plane only
|
|
65
|
+
* exposes a field that sits on or under a volatile node (`volatileForm()`
|
|
66
|
+
* returns undefined otherwise, and `describe()` then skips this entry
|
|
67
|
+
* entirely while `write()` throws). Verified against
|
|
68
|
+
* `@deepseek-ai/dsh-settings`. Note that DSH 0.1.7-alpha.1 ships no client
|
|
69
|
+
* that auto-generates a page from the schema, so this plugin also ships its
|
|
70
|
+
* own settings card (see `src/client/`).
|
|
71
|
+
*/
|
|
72
|
+
systemOne: z<Schemastery.ObjectS<NoInfer<{
|
|
73
|
+
/** Master switch. Defaults to true; with no credential the gate stays a no-op. */
|
|
74
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
75
|
+
/** Endpoint accepting the System-one request contract. */
|
|
76
|
+
endpoint: z<string, string, "volatile-defined">;
|
|
77
|
+
/** Model identifier sent in the request body. */
|
|
78
|
+
model: z<string, string, "volatile-defined">;
|
|
79
|
+
/** Literal API key. Declared secret: redacted on every read, write-only in the form. */
|
|
80
|
+
apiKey: z<string, string, "volatile">;
|
|
81
|
+
/** Credential reference resolved through the credentials service, then the environment. */
|
|
82
|
+
apiKeyEnv: z<string, string, "volatile-defined">;
|
|
83
|
+
/** Question type used to judge each candidate. */
|
|
84
|
+
mode: z<"noul" | "score", "noul" | "score", "volatile-defined">;
|
|
85
|
+
/** noul mode: keep a candidate when its probability is at least this value. */
|
|
86
|
+
threshold: z<number, number, "volatile-defined">;
|
|
87
|
+
/** score mode: keep a candidate when its score is at least this value.
|
|
88
|
+
* Jev's `score` is Σ(level_index × probability) over 0…levels−1, NOT 0–1;
|
|
89
|
+
* with the default 5 levels the range is 0…4, where 2 = "partially relevant". */
|
|
90
|
+
scoreMin: z<number, number, "volatile-defined">;
|
|
91
|
+
/** Retain at least this many candidates when the model rejects an entire page. */
|
|
92
|
+
minKeep: z<number, number, "volatile-defined">;
|
|
93
|
+
/**
|
|
94
|
+
* What happens to a judged candidate.
|
|
95
|
+
*
|
|
96
|
+
* `rerank` (default) keeps every candidate and lets the judge's value order
|
|
97
|
+
* the page; `filter` drops those below the threshold, bounded by
|
|
98
|
+
* `maxDropFraction`. Measured end-to-end on LongMemEval `_S` with the same
|
|
99
|
+
* judge and the same per-candidate values: filtering at the default
|
|
100
|
+
* threshold scored 0.3800, ordering scored 0.8020. The judge's AUC is
|
|
101
|
+
* ~0.71-0.75, so no threshold is safe, but the ordering is useful. See
|
|
102
|
+
* evals/longmemeval/README.md.
|
|
103
|
+
*/
|
|
104
|
+
policy: z<"filter" | "rerank", "filter" | "rerank", "volatile-defined">;
|
|
105
|
+
/**
|
|
106
|
+
* `filter` policy only: never drop more than this share of the judged page,
|
|
107
|
+
* lowest-scoring first. Caps the damage a mis-calibrated threshold can do —
|
|
108
|
+
* a memory dropped is gone, a memory kept only costs context. The offline
|
|
109
|
+
* sweep held recall_all@5 at 0.8875 with a 20 % cap against 0.6875 uncapped.
|
|
110
|
+
*/
|
|
111
|
+
maxDropFraction: z<number, number, "volatile-defined">;
|
|
112
|
+
/** Never judge more than this many candidates per request. */
|
|
113
|
+
maxCandidates: z<number, number, "volatile-defined">;
|
|
114
|
+
/** Truncate the task text to this many characters before sending it. */
|
|
115
|
+
maxTaskChars: z<number, number, "volatile-defined">;
|
|
116
|
+
/** End-to-end request deadline in milliseconds. */
|
|
117
|
+
timeoutMs: z<number, number, "volatile-defined">;
|
|
118
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
119
|
+
/** Master switch. Defaults to true; with no credential the gate stays a no-op. */
|
|
120
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
121
|
+
/** Endpoint accepting the System-one request contract. */
|
|
122
|
+
endpoint: z<string, string, "volatile-defined">;
|
|
123
|
+
/** Model identifier sent in the request body. */
|
|
124
|
+
model: z<string, string, "volatile-defined">;
|
|
125
|
+
/** Literal API key. Declared secret: redacted on every read, write-only in the form. */
|
|
126
|
+
apiKey: z<string, string, "volatile">;
|
|
127
|
+
/** Credential reference resolved through the credentials service, then the environment. */
|
|
128
|
+
apiKeyEnv: z<string, string, "volatile-defined">;
|
|
129
|
+
/** Question type used to judge each candidate. */
|
|
130
|
+
mode: z<"noul" | "score", "noul" | "score", "volatile-defined">;
|
|
131
|
+
/** noul mode: keep a candidate when its probability is at least this value. */
|
|
132
|
+
threshold: z<number, number, "volatile-defined">;
|
|
133
|
+
/** score mode: keep a candidate when its score is at least this value.
|
|
134
|
+
* Jev's `score` is Σ(level_index × probability) over 0…levels−1, NOT 0–1;
|
|
135
|
+
* with the default 5 levels the range is 0…4, where 2 = "partially relevant". */
|
|
136
|
+
scoreMin: z<number, number, "volatile-defined">;
|
|
137
|
+
/** Retain at least this many candidates when the model rejects an entire page. */
|
|
138
|
+
minKeep: z<number, number, "volatile-defined">;
|
|
139
|
+
/**
|
|
140
|
+
* What happens to a judged candidate.
|
|
141
|
+
*
|
|
142
|
+
* `rerank` (default) keeps every candidate and lets the judge's value order
|
|
143
|
+
* the page; `filter` drops those below the threshold, bounded by
|
|
144
|
+
* `maxDropFraction`. Measured end-to-end on LongMemEval `_S` with the same
|
|
145
|
+
* judge and the same per-candidate values: filtering at the default
|
|
146
|
+
* threshold scored 0.3800, ordering scored 0.8020. The judge's AUC is
|
|
147
|
+
* ~0.71-0.75, so no threshold is safe, but the ordering is useful. See
|
|
148
|
+
* evals/longmemeval/README.md.
|
|
149
|
+
*/
|
|
150
|
+
policy: z<"filter" | "rerank", "filter" | "rerank", "volatile-defined">;
|
|
151
|
+
/**
|
|
152
|
+
* `filter` policy only: never drop more than this share of the judged page,
|
|
153
|
+
* lowest-scoring first. Caps the damage a mis-calibrated threshold can do —
|
|
154
|
+
* a memory dropped is gone, a memory kept only costs context. The offline
|
|
155
|
+
* sweep held recall_all@5 at 0.8875 with a 20 % cap against 0.6875 uncapped.
|
|
156
|
+
*/
|
|
157
|
+
maxDropFraction: z<number, number, "volatile-defined">;
|
|
158
|
+
/** Never judge more than this many candidates per request. */
|
|
159
|
+
maxCandidates: z<number, number, "volatile-defined">;
|
|
160
|
+
/** Truncate the task text to this many characters before sending it. */
|
|
161
|
+
maxTaskChars: z<number, number, "volatile-defined">;
|
|
162
|
+
/** End-to-end request deadline in milliseconds. */
|
|
163
|
+
timeoutMs: z<number, number, "volatile-defined">;
|
|
164
|
+
}>>, "plain">;
|
|
165
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
43
166
|
/** @deprecated — the memory dir is fixed at `<projectRoot>/.mem`; kept for one version. */
|
|
44
|
-
memDirName: z<string, string>;
|
|
167
|
+
memDirName: z<string, string, "defined">;
|
|
45
168
|
/** Max search hits per mem_search call (page size). Default 20. */
|
|
46
|
-
searchLimit: z<number, number>;
|
|
169
|
+
searchLimit: z<number, number, "defined">;
|
|
170
|
+
/**
|
|
171
|
+
* How a matched entry is scored (search order only — matching itself is
|
|
172
|
+
* identical in both modes).
|
|
173
|
+
*
|
|
174
|
+
* - `weighted` (default): sum of per-keyword rarity weights within the
|
|
175
|
+
* recall page, so a distinctive match outranks several common ones.
|
|
176
|
+
* - `count`: the previous default behaviour (one point per matched keyword plus the
|
|
177
|
+
* recency bonus), kept for exact backwards compatibility.
|
|
178
|
+
*
|
|
179
|
+
* Measured motivation: on LongMemEval `_S` the engine reached
|
|
180
|
+
* recall_all@50 = 0.998 while ndcg@5 was only 0.686 — evidence was reachable
|
|
181
|
+
* but ranked poorly, because a saturated-free match count cannot tell a rare
|
|
182
|
+
* keyword from a ubiquitous one.
|
|
183
|
+
*/
|
|
184
|
+
searchScoring: z<"count" | "weighted", "count" | "weighted", "defined">;
|
|
47
185
|
/** @deprecated — `.mem` always stays on main; kept for one version, no effect. */
|
|
48
|
-
branchAlign: z<boolean, boolean>;
|
|
186
|
+
branchAlign: z<boolean, boolean, "defined">;
|
|
49
187
|
/** @deprecated — session-start recent seeding was removed; kept for one version, no effect. */
|
|
50
|
-
recentContextLimit: z<number, number>;
|
|
188
|
+
recentContextLimit: z<number, number, "defined">;
|
|
51
189
|
/** Cross-process lock wait timeout in milliseconds. Default 30000. */
|
|
52
|
-
lockTimeoutMs: z<number, number>;
|
|
190
|
+
lockTimeoutMs: z<number, number, "defined">;
|
|
53
191
|
/** Optional explicit project root; defaults to the calling session's cwd. */
|
|
54
|
-
projectRoot: z<string, string>;
|
|
55
|
-
|
|
192
|
+
projectRoot: z<string, string, "plain">;
|
|
193
|
+
/**
|
|
194
|
+
* Optional System-one recall gate. When an endpoint and a credential are
|
|
195
|
+
* configured, each `mem_search` page is narrowed by a System-one model
|
|
196
|
+
* (TypeSafe Jev by default) before it reaches the model; when nothing is
|
|
197
|
+
* configured the gate is a no-op and recall behaves exactly as before.
|
|
198
|
+
*
|
|
199
|
+
* `.volatile()` is REQUIRED here, not cosmetic: the settings plane only
|
|
200
|
+
* exposes a field that sits on or under a volatile node (`volatileForm()`
|
|
201
|
+
* returns undefined otherwise, and `describe()` then skips this entry
|
|
202
|
+
* entirely while `write()` throws). Verified against
|
|
203
|
+
* `@deepseek-ai/dsh-settings`. Note that DSH 0.1.7-alpha.1 ships no client
|
|
204
|
+
* that auto-generates a page from the schema, so this plugin also ships its
|
|
205
|
+
* own settings card (see `src/client/`).
|
|
206
|
+
*/
|
|
207
|
+
systemOne: z<Schemastery.ObjectS<NoInfer<{
|
|
208
|
+
/** Master switch. Defaults to true; with no credential the gate stays a no-op. */
|
|
209
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
210
|
+
/** Endpoint accepting the System-one request contract. */
|
|
211
|
+
endpoint: z<string, string, "volatile-defined">;
|
|
212
|
+
/** Model identifier sent in the request body. */
|
|
213
|
+
model: z<string, string, "volatile-defined">;
|
|
214
|
+
/** Literal API key. Declared secret: redacted on every read, write-only in the form. */
|
|
215
|
+
apiKey: z<string, string, "volatile">;
|
|
216
|
+
/** Credential reference resolved through the credentials service, then the environment. */
|
|
217
|
+
apiKeyEnv: z<string, string, "volatile-defined">;
|
|
218
|
+
/** Question type used to judge each candidate. */
|
|
219
|
+
mode: z<"noul" | "score", "noul" | "score", "volatile-defined">;
|
|
220
|
+
/** noul mode: keep a candidate when its probability is at least this value. */
|
|
221
|
+
threshold: z<number, number, "volatile-defined">;
|
|
222
|
+
/** score mode: keep a candidate when its score is at least this value.
|
|
223
|
+
* Jev's `score` is Σ(level_index × probability) over 0…levels−1, NOT 0–1;
|
|
224
|
+
* with the default 5 levels the range is 0…4, where 2 = "partially relevant". */
|
|
225
|
+
scoreMin: z<number, number, "volatile-defined">;
|
|
226
|
+
/** Retain at least this many candidates when the model rejects an entire page. */
|
|
227
|
+
minKeep: z<number, number, "volatile-defined">;
|
|
228
|
+
/**
|
|
229
|
+
* What happens to a judged candidate.
|
|
230
|
+
*
|
|
231
|
+
* `rerank` (default) keeps every candidate and lets the judge's value order
|
|
232
|
+
* the page; `filter` drops those below the threshold, bounded by
|
|
233
|
+
* `maxDropFraction`. Measured end-to-end on LongMemEval `_S` with the same
|
|
234
|
+
* judge and the same per-candidate values: filtering at the default
|
|
235
|
+
* threshold scored 0.3800, ordering scored 0.8020. The judge's AUC is
|
|
236
|
+
* ~0.71-0.75, so no threshold is safe, but the ordering is useful. See
|
|
237
|
+
* evals/longmemeval/README.md.
|
|
238
|
+
*/
|
|
239
|
+
policy: z<"filter" | "rerank", "filter" | "rerank", "volatile-defined">;
|
|
240
|
+
/**
|
|
241
|
+
* `filter` policy only: never drop more than this share of the judged page,
|
|
242
|
+
* lowest-scoring first. Caps the damage a mis-calibrated threshold can do —
|
|
243
|
+
* a memory dropped is gone, a memory kept only costs context. The offline
|
|
244
|
+
* sweep held recall_all@5 at 0.8875 with a 20 % cap against 0.6875 uncapped.
|
|
245
|
+
*/
|
|
246
|
+
maxDropFraction: z<number, number, "volatile-defined">;
|
|
247
|
+
/** Never judge more than this many candidates per request. */
|
|
248
|
+
maxCandidates: z<number, number, "volatile-defined">;
|
|
249
|
+
/** Truncate the task text to this many characters before sending it. */
|
|
250
|
+
maxTaskChars: z<number, number, "volatile-defined">;
|
|
251
|
+
/** End-to-end request deadline in milliseconds. */
|
|
252
|
+
timeoutMs: z<number, number, "volatile-defined">;
|
|
253
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
254
|
+
/** Master switch. Defaults to true; with no credential the gate stays a no-op. */
|
|
255
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
256
|
+
/** Endpoint accepting the System-one request contract. */
|
|
257
|
+
endpoint: z<string, string, "volatile-defined">;
|
|
258
|
+
/** Model identifier sent in the request body. */
|
|
259
|
+
model: z<string, string, "volatile-defined">;
|
|
260
|
+
/** Literal API key. Declared secret: redacted on every read, write-only in the form. */
|
|
261
|
+
apiKey: z<string, string, "volatile">;
|
|
262
|
+
/** Credential reference resolved through the credentials service, then the environment. */
|
|
263
|
+
apiKeyEnv: z<string, string, "volatile-defined">;
|
|
264
|
+
/** Question type used to judge each candidate. */
|
|
265
|
+
mode: z<"noul" | "score", "noul" | "score", "volatile-defined">;
|
|
266
|
+
/** noul mode: keep a candidate when its probability is at least this value. */
|
|
267
|
+
threshold: z<number, number, "volatile-defined">;
|
|
268
|
+
/** score mode: keep a candidate when its score is at least this value.
|
|
269
|
+
* Jev's `score` is Σ(level_index × probability) over 0…levels−1, NOT 0–1;
|
|
270
|
+
* with the default 5 levels the range is 0…4, where 2 = "partially relevant". */
|
|
271
|
+
scoreMin: z<number, number, "volatile-defined">;
|
|
272
|
+
/** Retain at least this many candidates when the model rejects an entire page. */
|
|
273
|
+
minKeep: z<number, number, "volatile-defined">;
|
|
274
|
+
/**
|
|
275
|
+
* What happens to a judged candidate.
|
|
276
|
+
*
|
|
277
|
+
* `rerank` (default) keeps every candidate and lets the judge's value order
|
|
278
|
+
* the page; `filter` drops those below the threshold, bounded by
|
|
279
|
+
* `maxDropFraction`. Measured end-to-end on LongMemEval `_S` with the same
|
|
280
|
+
* judge and the same per-candidate values: filtering at the default
|
|
281
|
+
* threshold scored 0.3800, ordering scored 0.8020. The judge's AUC is
|
|
282
|
+
* ~0.71-0.75, so no threshold is safe, but the ordering is useful. See
|
|
283
|
+
* evals/longmemeval/README.md.
|
|
284
|
+
*/
|
|
285
|
+
policy: z<"filter" | "rerank", "filter" | "rerank", "volatile-defined">;
|
|
286
|
+
/**
|
|
287
|
+
* `filter` policy only: never drop more than this share of the judged page,
|
|
288
|
+
* lowest-scoring first. Caps the damage a mis-calibrated threshold can do —
|
|
289
|
+
* a memory dropped is gone, a memory kept only costs context. The offline
|
|
290
|
+
* sweep held recall_all@5 at 0.8875 with a 20 % cap against 0.6875 uncapped.
|
|
291
|
+
*/
|
|
292
|
+
maxDropFraction: z<number, number, "volatile-defined">;
|
|
293
|
+
/** Never judge more than this many candidates per request. */
|
|
294
|
+
maxCandidates: z<number, number, "volatile-defined">;
|
|
295
|
+
/** Truncate the task text to this many characters before sending it. */
|
|
296
|
+
maxTaskChars: z<number, number, "volatile-defined">;
|
|
297
|
+
/** End-to-end request deadline in milliseconds. */
|
|
298
|
+
timeoutMs: z<number, number, "volatile-defined">;
|
|
299
|
+
}>>, "plain">;
|
|
300
|
+
}>>, "plain">;
|
|
56
301
|
/** Shape of the agent payload received by an `agent/created` listener. */
|
|
57
302
|
interface CreatedAgent {
|
|
58
303
|
id: string;
|
|
@@ -86,13 +331,19 @@ declare function apply(ctx: {
|
|
|
86
331
|
}) => void): unknown;
|
|
87
332
|
logger: {
|
|
88
333
|
warn(message: string): void;
|
|
334
|
+
info?(message: string): void;
|
|
89
335
|
};
|
|
336
|
+
/** Optional service accessor (credentials); absent in hand-built test contexts. */
|
|
337
|
+
get?(name: string): unknown;
|
|
90
338
|
}, config?: Partial<{
|
|
91
339
|
memDirName?: string;
|
|
92
340
|
searchLimit?: number;
|
|
341
|
+
searchScoring?: SearchScoring;
|
|
93
342
|
branchAlign?: boolean;
|
|
94
343
|
recentContextLimit?: number;
|
|
95
344
|
lockTimeoutMs?: number;
|
|
96
345
|
projectRoot?: string;
|
|
346
|
+
/** System-one gate section; a live (`.volatile()`) node in the real loader. */
|
|
347
|
+
systemOne?: unknown;
|
|
97
348
|
}>): Promise<void>;
|
|
98
349
|
export { Config, apply, inject, name };
|