New sessions/session_export tools plus a sessions_block vault map in the system prompt (tai.py, ported to detz); recall/search carry a session footer instead of letting the model grep sealed bytes. write_file refuses new markdown at working/repo roots, and the blanket *.md gitignore is gone so docs stay visible. One LineInput owns fd 0 for every prompt (ask, approvals, shell_ask, secrets), ending phantom-empty answers; Ctrl-C re-prompts (double exits), Ctrl-D exits, Ctrl-Z suspends; mid-turn Ctrl-C announces itself and kills foreground shell children via RunInterrupted. Covered by SessionsTests, repl_keys.py pty checks, agent_diff sessions_block cases.
88 lines
6.6 KiB
Markdown
88 lines
6.6 KiB
Markdown
# misc modules: skills, sched, telegram, rag, install (parity spec)
|
|
|
|
Source of truth: `../tai.py`. Every class here is a literal port; method names keep the Python names so the
|
|
parity ledger matches them. Behavior is proven by `tests/misc_diff.py` (18 scenarios, byte-identical
|
|
transcripts plus file trees against the real tai.py). Build: `make -f tests/misc.mk all`, run:
|
|
`python3 tests/misc_diff.py`.
|
|
|
|
## Shared helpers (src/skills, namespace detz::misc)
|
|
|
|
| tai.py construct | C++ | notes |
|
|
|---|---|---|
|
|
| json.dumps / json.loads | `Json` | ensure_ascii, ", " / ": " separators, insertion-ordered objects, big ints keep digits, JSONDecodeError text |
|
|
| datetime.fromisoformat, astimezone, isoformat | `DateTime` | CPython port: week dates, 24:00, stray char before offset, gap/fold local times |
|
|
| str.splitlines / strip / len / slice, short_error | `PyStr` | code point semantics, Unicode whitespace and Nd digits (`PyUnicode`, generated table) |
|
|
| os / shutil / subprocess | `PyFs`, `PyProc` | universal newlines on text reads, OSError text `[Errno N] ...: 'path'` |
|
|
| hashlib.sha256 | `Sha256` | |
|
|
| LOG.event / LOG.context | `LogSink` | port, default drops |
|
|
| normalize_tag(s) | `TagNames` | |
|
|
|
|
## skills (src/skills) vs skills.md
|
|
|
|
| tai.py | C++ |
|
|
|---|---|
|
|
| parse_skill_front, parse_skill_file, skill_scope_dir, default_skill_scope, skill_extra_files, skill_install_meta_path, load/save_skill_install_meta, is_external_skill_root, skill_provenance_note, discover_skills, skill_catalog, create_skill_prompt | `SkillFiles` |
|
|
| BUNDLED_SKILLS, BUNDLED_SKILL_UPSTREAM, SKILL_BLUEPRINTS | `BundledData` (generated `bundled_data.cpp`, byte-identical; regenerate with `python3 -I src/skills/gen_bundled.py`) |
|
|
| bundled_skill_digest, bundled_skill_pristine, write_bundled_skill, remove_bundled_skill, op_skills, skills line of status_lines | `BundledSkills` |
|
|
| Tools.run_load_skill, run_create_skill, find_skill_root, resolve_skill_source, run_install_skill | `SkillTool` (+ `SkillHost` port, zlib `ZipArchive`) |
|
|
|
|
## sched (src/sched) vs scheduler section of tai.py
|
|
|
|
| tai.py | C++ |
|
|
|---|---|
|
|
| parse_schedule_at, parse_duration, format_delay, local_display, now_iso | `ScheduleTime` |
|
|
| Store.add_schedule / remove_schedule / list_schedules | `ScheduleVault` (+ `SealPort`, `TagPort`) |
|
|
| format_schedule_lines, note_schedule_result, watch_schedule, schedule_running, scheduler_tick, run_scheduler_loop, start_scheduler | `Scheduler` (+ `AgentPort`, `StopFlag`) |
|
|
| Tools.run_schedule / run_unschedule / run_schedules, normalize_tags | `ScheduleTool` (+ `ScheduleHost`) |
|
|
|
|
## telegram (src/telegram)
|
|
|
|
| tai.py | C++ |
|
|
|---|---|
|
|
| class Telegram | `Telegram` (+ `TelegramTransport`, libcurl `CurlTransport`) |
|
|
| telegram_env_path, load_telegram_token, telegram_send, telegram_transcribe, handle_telegram_update, _handle_telegram_update_inner, run_telegram_bot | `TelegramBot` (+ `TelegramAgent`, `BoxPort`) |
|
|
|
|
Wire format (request bodies, paths, headers) is compared against a scripted local Bot API.
|
|
|
|
## rag (src/rag)
|
|
|
|
| tai.py | C++ |
|
|
|---|---|
|
|
| chunk_lines, collapse_repeated_lines, Store.add_chunks / get_chunks_by_ids | `Chunker`, `ChunkStore` |
|
|
| fts_escape, fts_match, fts_match_or, fts_match_prefix, fts_match_variants, fts_rank, Store.fts_search | `FtsQuery`, `FtsSearch` |
|
|
| class RetrievalEval, the `--eval-retrieval` body | `RetrievalEval` (`run_eval`) |
|
|
| Tools.run_search | `RagTool` (+ `RagHost`) | session footer included via `RagHost::profiles_dir`, byte-compared by the rag diff |
|
|
|
|
`--stats-rag` does not exist in tai.py (no such argument); nothing is ported for it.
|
|
|
|
## install (src/install)
|
|
|
|
| tai.py | C++ |
|
|
|---|---|
|
|
| rc block helpers, hook_present and friends | `RcBlocks`, `Installer::hook_present` etc. |
|
|
| unit_dir, service_state, activate_service, remove_service_unit | `Systemd` |
|
|
| Install, venv_dir, venv_python, ensure_venv, script_version, shell_rc_path, shell_present | `Install` |
|
|
| op_binary ... op_skills, status_lines, vault_line, install_report, install_self, install_telegram, uninstall_telegram, Tools.run_install | `Installer` (+ `ContainerPort`, `InstallIo`) |
|
|
| next_version, release_bump, atomic_write, sealed_write, quarantine, backups_dir, prune_backups, snapshot_self, backup_has_digest, ensure_self_backup, do_release, capped_text, trunc_marker, read_capped, Tools.run_release | `SelfRelease`, `ReleaseTool` |
|
|
| Store.audit_event / audit_history / audit_get / audit_search / tag_counts, Tools.run_audit / run_restore / run_tags | `AuditVault`, `AuditTool` |
|
|
|
|
### `--install` of the native binary (what it does today)
|
|
|
|
- `--install` runs `Installer::install_self`: `op_binary("upgrade")`, bash hook (plus zsh/fish hook per `$SHELL`), venv, bundled skills. It always copies, so a second run refreshes.
|
|
- Target: `$HOME/.local/bin/tai.py` (same path as tai.py, the shell hooks in `installconsts.cpp` alias `tai` to it). The native binary replaces the Python product at that path; it is not installed as `detz`. A copy that is running (`ETXTBSY`) is written beside the target and renamed.
|
|
- `OpsAdapter` sets `InstallContext::version_reader`. It returns the running version only if the file at the given path exists, otherwise nothing, so a fresh install reports `binary: installed <v>` and an existing one `binary: refreshed <old> -> <new>`. Before this fix the reader ignored the path and a fresh install printed `refreshed X -> X`. Limit: the reader cannot read the version of the installed binary, so `<old>` is the running version.
|
|
- Verified by running `build/detz --install` against a throwaway `HOME`: binary byte-identical to `build/detz`, hook, venv and six skills created. The message fix itself is not yet verified by a run (build was still in progress when this was written).
|
|
|
|
## Known gaps
|
|
|
|
- Sealed vaults: the Seal crypto and the sealed events memdb belong to the store module; sealed paths are
|
|
reachable through `SealPort`/`MemEventsPort` but only the passphrase-less seal is verified against tai.py.
|
|
- `Store.upsert_file_record`, `delete_file_record`, canonical tag folding (`singular_noun`) are store-module work
|
|
(`FileRecordPort`, `TagPort`); the tests use a plain implementation.
|
|
- Box restore (`box_restore`), container probes and `ensure_box` are reached through ports; fakes are verified,
|
|
the real podman path is not.
|
|
- urllib error text for network failures other than HTTP status, timeout, DNS and refused is approximated.
|
|
- JSON numbers beyond int64 keep exact digits; floats beyond that use double.
|
|
- Copying a native binary in `op_binary` cannot read a version from it; set `InstallContext::version_reader`.
|
|
- `--install` installs under the name `tai.py`, not `detz`; renaming needs `installconsts.cpp` hooks changed too.
|