- Introduce `@oh-my-pi/omptype` as a new ArkType-compatible schema validation package featuring a lazy JIT runtime, JSON Schema emission, and compatibility adapters.
- Replace `arktype` across workspace packages and test utilities with `@oh-my-pi/omptype`.
- Add benchmark suites, tests, and documentation for the new validation engine and adapters.
- Update workspace build, test runner, and release configurations to include the new package.
- Prevented compaction from reopening a settled terminal answer unless queued work or an active goal remains.
- Ran auto-learn capture in an abortable detached agent with constrained tools and isolated provider state.
- Replaced primary-turn capture coverage with private-capture regression tests.
Fixes#5715
Op: remove the unrelated sendUserMessage changelog entry and replace the aborted-turn test cast with a typed assistant fixture.
Restores: PR #4924 carries only the autolearn changelog bullet and its regression test no longer relies on as-never type hacks.
Stopped passive autolearn from adding hidden conversation messages and froze local memory developer instructions per session so learn writes land in future sessions instead of mutating the active Anthropic prompt prefix.
Fixes#3743
With `autolearn.autoContinue` on, the controller fires a synthetic
turn whose only user-role payload is `autolearn-nudge.md`. The old
prompt opened with "Before you finish:" and gave no terminal
contract, so after the `learn`/`manage_skill` call the agent read
its own unanswered prior question (e.g. "Want me to commit and
push?") as accepted and continued — pushing commits, running tools,
etc. — without the user ever answering.
Split the nudge into two prompts and pick at fire time:
- passive (rides the user's real next message) keeps additive
framing — "answer the user normally; the capture is in addition
to, not a replacement for, the work the user just asked for".
- auto-continue (`autolearn-nudge-autocontinue.md`) is explicitly
terminal — "not a user reply; do not treat this as approval or
acceptance of any pending action; capture, then stop; do not run
other tools, resume prior work, or answer your own pending
questions; wait for the user's next prompt".
Attribution stays `user` so llama.cpp keeps reusing the warm
prefix (#3456). Regression tests pin the load-bearing terminal
language in both branches.
Fixes#3504
- agent-loop: raise repetition-detection floor to 180 chars and clear thinking
replay anchors when collapsing a detected loop.
- providers/google: ignore empty text parts, retain terminal thoughtSignatures,
and stop function-call signatures clobbering the prior block.
- autolearn: capture goal-mode at the turn boundary; harden managed-skill writes
against hard-links/symlinks (O_NOFOLLOW + nlink); refuse minting managed skills
whose name an authored skill already claims.
- eager tasks: thread agentKind through the session so a custom top-level agentId
still gets always-mode delegation; split Eager Tasks prompt into hard vs soft.
- title-generator: race the online title model against a local tiny-model fallback.
- eager-todo: keep the soft reminder aligned with the todo init schema.
- mcp/stdio: keep close() detaching the read loop instead of awaiting it.
- stream loop: fix collapsing and tool-call thought-signature handling.
Grill findings on the auto-learn change-set — the controller nudge, the standing
guidance, and the actual tool availability could disagree:
- Guidance was rebuilt from live `autolearn.enabled`, so a mid-session enable (or
a subagent that filtered the tools out) injected guidance for tools the session
never built. `buildAutoLearnInstructions` now takes `{ manageSkill, learn }` and
is driven by the auto-learn BUILTINS that `createTools` actually built
(`builtInToolNames`) — provenance, so a same-named custom/extension tool can't
trigger it while auto-learn is off.
- The controller install reverted to gate on `autolearn.enabled && taskDepth === 0`:
the tool registry is built once at session start, so installing it while disabled
would nudge toward absent tools. The fire-time re-check still handles a
mid-session disable.
- Force-included auto-learn tools are now ACTIVATED for restricted top-level
sessions (mirroring the `yield` invariant), so a session with an explicit tool
whitelist actually exposes manage_skill/learn instead of building them inactive.
Tests: guidance gating by tool presence (none/manage-only/learn), restricted-session
activation via createAgentSession, and removal of the obsolete mid-session-enable
controller case.
The controller was only constructed when `autolearn.enabled` was true at
`createAgentSession` time. Because `newSession` reuses the session without
rerunning startup, enabling the setting via the UI mid-session never installed
the listener, so the feature stayed inert until the app was recreated. The
controller already re-checks the live flag at fire time, so install it for every
top-level session and let that check gate activation; when disabled it only
counts tool calls and returns.
Addresses review thread on PR #2542 (thread 18).
Two controller bugs from review:
- The post-stop nudge still queued a passive `nextTurn` message during goal
mode (goal mode only disabled `autoContinue`). That message rides the goal
continuation and can divert the goal loop into capture. Return early when
goal mode is active.
- `#suppressNext` was latched before the fire-and-forget `sendCustomMessage`.
It must arm synchronously (the synthetic turn's `agent_end` fires inside
`sendCustomMessage` before it resolves), but a rejected or *deferred* dispatch
(ACP clients downgrade `triggerTurn` to a queue) then produces no `agent_end`,
so the latch swallowed the next real stop. `sendCustomMessage` now returns
whether it actually started a turn; the controller disarms the latch when no
turn ran (rejection or deferral).
`task/executor.ts` widens its pending-message array to `Promise<unknown>[]` to
absorb the new return type (the resolved values are discarded).
Addresses review threads on PR #2542 (threads 5, 9, 12).
The `learn` tool previously required a `hindsight`/`mnemopi` backend. It now
also works when `memory.backend` is `local` (the file-based rollout backend):
lessons append to a `learned.md` under the project's memory root, kept separate
from the consolidation artifacts so a consolidation pass never clobbers them,
and are injected into future sessions alongside the memory summary.
- memories: `saveLearnedLesson` (newest-first, deduped, count- and per-field
size-capped, secret-redacted, injection-neutralized) with per-path write
serialization; `buildMemoryToolDeveloperInstructions` reads `learned.md` and
shares one injection budget with the summary; `redactSecrets` extended with
GitHub/npm/Slack/Google token prefixes.
- local backend: implements `save()`; status reports `writable: true`.
- learn tool: `local` execute branch; `createIf`/`isToolAllowed`/auto-include
and the standing guidance extended to `local`; local saves tier as a `write`
approval.
- read-path prompt: renders the learned-lessons block when present.
- Lessons are injection-neutralized and secret-redacted on BOTH write and read
(they render unescaped into the system prompt).
Also moves the auto-learn CHANGELOG entry out of the released [15.12.6] section
(a cherry-pick artifact) back under [Unreleased] and notes the local backend.
Tests: local storage (format, dedup, cap, redaction incl. provider/delimiter-
split tokens, concurrency), read-back (with/without summary, off-gating, raw
hand-edited file), tool gating + write-approval tiering.
Add a default-off "auto-learn" loop. When `autolearn.enabled` is set, after the
agent stops a session controller nudges it to capture reusable lessons: durable
facts go to long-term memory and repeatable procedures become "managed skills" —
SKILL.md files written to an isolated ~/.omp/agent/managed-skills directory that is
discovered and surfaced like authored skills but never overwrites them.
Two tools back this:
- `manage_skill` — create/update/delete managed skills.
- `learn` — record a lesson, optionally minting/enhancing a managed skill in the
same call (requires a hindsight/mnemopi memory backend).
The nudge is passive by default (a hidden reminder rides the next turn);
`autolearn.autoContinue` instead auto-runs one capture turn at stop, and
`autolearn.minToolCalls` (default 5) gates trivial turns. Plan/goal-mode turns and
subagents are never nudged, and the controller re-checks the live setting at fire
time so a mid-session opt-out takes effect.
Isolation & precedence: managed skills are a separate lowest-priority discovery
provider, so an authored skill of the same name wins across every provider and
custom directory regardless of third-party toggles; a disabled higher-priority
authored skill can never hide a managed one, and managed never masks an enabled
authored skill. Managed names and descriptions are sanitized on both write and
read (control/format chars, angle brackets, and Markdown fences) before they render
into the system prompt, and the SKILL.md byte cap is enforced on the final
serialized file.
Default off → zero footprint when disabled.