X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/d008b46cbfc6348255e9b9a1fc009f0e4bd6aa2a..790279faf0fda789d93a75f6f5996e65d5de4a18:/README.rst?ds=inline diff --git a/README.rst b/README.rst index 7930b0e..16aabce 100644 --- a/README.rst +++ b/README.rst @@ -73,7 +73,10 @@ Start the daemon, and then the client in another terminal: .. code:: console onechat daemon - onechat chat + onechat + +``onechat`` with no command is the same as ``onechat chat``. ``onechat +help`` lists the commands. The daemon owns the root agent in ``agent/`` in the data directory and listens on the Unix socket ``onechat.sock`` there. In the client, each @@ -127,7 +130,94 @@ prompt cache key comes from it. ``workdir`` is an absolute path, and its default is the home directory. ``agent/instructions.md`` holds the user's instructions: who they are, how their files are organized, and how they want work done. The prompt -ends with them, and a change applies at the next call. +ends with them, and a change applies at the next call. The agent can +propose a change to the file, and it makes the change only after the +user agrees. + +************** + User service +************** + +The Nix package includes ``share/systemd/user/onechat.service``. It runs +``onechat daemon`` from that package, starts at login when enabled, and +restarts 5 seconds after a failure. A stop sends SIGTERM to the daemon +and allows up to 120 seconds for cleanup. Its output goes to the user +journal. The service has the rights of the user, as the terminal daemon +does. + +Build a package with a separate result link. Keep this link so that Nix +does not collect the package while the service uses it: + +.. code:: console + + nix build --out-link result-service + systemctl --user link --force "$PWD/result-service/share/systemd/user/onechat.service" + systemctl --user edit onechat.service + +In the editor, set the data directory with this drop-in. Replace +``DATA_DIR`` with an absolute path to the data directory. Set the same +``ONECHAT_DIR`` for each terminal client. Without a drop-in, the data +directory rules above apply to the environment of the user manager, not +to the development shell. + +.. code:: ini + + [Service] + Environment="ONECHAT_DIR=DATA_DIR" + +The service does not read the environment of an open terminal. If the +agent needs tools from a shell, set ``Environment="PATH=TOOLS_PATH"`` in +the same drop-in, with ``TOOLS_PATH`` replaced by the complete search +path, including bash. For the API endpoint, use +``EnvironmentFile=ENV_FILE``, with ``ENV_FILE`` replaced by an absolute +path to a mode 0600 file that sets ``OPENAI_API_KEY``. Keep secrets out +of the unit and Nix sources. + +Use the existing data directory, or copy the development data before the +first service start. For a copy, first stop the terminal daemon with +Ctrl-C and wait for it to exit. Replace ``DATA_DIR`` below with a new, +empty destination. If the development shell uses a custom +``ONECHAT_DIR``, replace ``.devenv/onechat`` with that source. Copy the +whole directory so that ``auth.json``, ``telegram.json``, +``config.json``, ``agent/``, and ``whatsapp/`` stay together, including +the WhatsApp session and its database files. The copy preserves the file +modes and the source as a backup. Do not copy or use the same data from +two running daemons. + +.. code:: console + + install -d -m 0700 DATA_DIR + cp -a .devenv/onechat/. DATA_DIR/ + +After the terminal daemon exits and the data is ready, enable and start +the service: + +.. code:: console + + systemctl --user daemon-reload + systemctl --user enable --now onechat.service + systemctl --user status onechat.service + ONECHAT_DIR=DATA_DIR ./result-service/bin/onechat + journalctl --user -u onechat.service -f + +After a pull, update the package and unit with: + +.. code:: console + + git pull + bin/service-update + +The script builds with the same ``result-service`` link, reloads the +user manager, and restarts the service only if it is active. The unit +link follows ``result-service``, so no new link is needed. + +The service starts with the user manager at login, not at boot without a +login. To stop it, or also remove its start at login: + +.. code:: console + + systemctl --user stop onechat.service + systemctl --user disable onechat.service ********** Telegram @@ -269,12 +359,56 @@ Each batch of a group goes to the chat, also with no turn, and the memory tree summarizes it with model calls, which use the quota. When the session holds a linked device, the daemon connects at its -start, and after a network failure it connects again by itself. When a -disconnection lasts 10 minutes, all clients get one notice, and one more -when the connection comes back. When WhatsApp ends the connection for -good, for example because another program uses the same session, all -clients get a notice at once. When the user removes the device in the -phone, the daemon deletes the session and tells all clients one time. +start. If the first connection fails, it tries again after 2 seconds, +then doubles the wait up to 5 minutes. The inbox and commands stay +active during each wait. An unlink or a logout stops these retries. +After a network failure of an open connection, the library connects +again by itself. When a disconnection lasts 10 minutes, all clients get +one notice, and one more when the connection comes back. When WhatsApp +ends the connection for good, for example because another program uses +the same session, all clients get a notice at once. When the user +removes the device in the phone, the daemon deletes the session and +tells all clients one time. + +************************* + Import WhatsApp history +************************* + +Stop the daemon and finish all subagents before an import. Export each +chat from WhatsApp as a ZIP with ``_chat.txt``. Keep the chat name in +the ZIP name, such as ``WhatsApp Chat - Example.zip``. Read the plan +first: + +.. code:: console + + onechat import -n CHAT.zip OTHER.zip + onechat import CHAT.zip OTHER.zip + +``-n`` makes no model call and prints the chats, chat-day batches, local +dates, cutoff, text bytes, merged message count, and estimated calls. +The import keeps multiline text, system lines, and omitted-media +markers. It maps the session's profile name to ``You``. Without that +name, it keeps the senders as written and says so in the plan. An exact, +unambiguous local contact or batch name supplies the chat ID when known. +No network lookup is made. + +Each chat and local day becomes one work message marked ``(imported)``. +Only messages before the first message of the earliest live WhatsApp +batch enter the import. Live times have minute precision, so the cutoff +excludes that whole minute. A chat-day already imported is skipped. +Overlapping chat-days in the supplied ZIPs are refused. Review the +exports before import: their text goes to the model as chat history. + +The import merges the full log in date order and builds its tree with +real compactor calls, the agent prompt, and the agent cache key. It uses +a limit of 1,500 calls and the probe's 15-quota-point limit, and prints +the same usage report. Its estimate is about 1.3 calls per merged +message, not a cost guarantee. A stopped or failed run leaves the agent +unchanged. A new run starts over. Success keeps the other agent files +and renames the old directory to ``agent-backup-TIMESTAMP`` before it +installs the new one. Keep the backup until the new memory is checked, +then start the daemon. Message IDs change to their positions in the +merged log. *********** Schedules @@ -365,6 +499,9 @@ Build and run: nix build ./result/bin/onechat +``onechat version`` prints ``yyyy-mm-dd-gitshort`` for a Nix build, adds +``-dirty`` for a dirty tree, and prints ``dev`` for a direct Go build. + Format and check all files: .. code:: console