8.6 KiB
AGENTS Guidelines for Sortana
This file provides guidelines for codex agents contributing to the Sortana project. It describes the repository structure, the expected coding conventions, and testing commands. If you make changes to Sortana, make sure to update this document and the README.md if applicable.
Repository Overview
background.js: Handles startup tasks and coordinates message passing within the extension.modules/: Contains reusable JavaScript modules such asAiClassifier.js,defaultParams.jsandthemeUtils.js.options/: The options page HTML, JavaScript and bundled Bulma CSS (v1.0.3).details.htmlanddetails.js: View classification evidence and clear cache for a message.resources/: Images and other static files.build-xpi.ps1: PowerShell script to package the extension.build-xpi.sh: Bash script to package the extension.resources/svg2img.ps1: PowerShell script to regenerate themed PNG icons from SVGs.resources/svg2img.sh: Bash script to regenerate themed PNG icons from SVGs.
Coding Style
- Use modern JavaScript (ES6 or later). Prefer
constandletovervar. - Keep functions small and focused. Aim for clear naming and concise comments when necessary.
- Use template literals for string interpolation.
- Avoid trailing whitespace and ensure files end with a newline.
Commit Guidelines
- Group related changes together. Each commit should have a clear purpose.
- Use descriptive commit messages in the imperative mood (e.g., "Add filter editor patch").
- Run
git statusbefore committing to verify only intended files are staged.
Testing
Run the dependency-free suite with Node.js 22 or newer: node --test tests/*.test.mjs.
The tests mock extension storage, HTTP responses, and Thunderbird rule execution.
Manual verification in Thunderbird is still required for UI and real-server integration.
Do not run the ps1 build script or the SVG processing script.
Endpoint Notes
Sortana supports apiType: "chat-completions" (default) and "systemone".
Plain adapter modules under modules/backends/ own request construction and response
validation; AiClassifier owns shared transport, configuration snapshots, threshold
policy, and caching. The stored endpoint is a base URL. Normalization accepts /v1
and recognized full API paths, preserves proxy prefixes, and defaults to HTTPS
when no scheme is supplied. Model discovery uses /v1/models; None omits model.
Bearer authentication is optional for both APIs. Organization/project headers are
sent only for Chat Completions.
Chat Completions sends system/user messages and extracts the last JSON object from
choices[0].message.content, requiring a match or matched boolean. SystemOne
sends prepared email text as state with noul questions identified by stable
rule_<snapshot index> IDs. The single-question API still uses match for backward
compatibility and cache fingerprinting. Every requested answer must have type
noul and a finite numeric probability in [0, 1]; response order is irrelevant.
No chat generation parameters or system prompt are sent to SystemOne.
The global decisionThreshold defaults to 0.5; optional rule-level
decisionThreshold overrides it. UI percentages are stored as numbers in [0, 1].
Matching uses probability >= threshold before display rounding. Details displays
probabilities in a progress bar with the percentage inside; threshold and model
appear in its tooltip. Results use the current threshold, never fabricated reasoning or action
history. No secondary model calls are made.
classify() returns structured evidence; classifyText() remains a boolean wrapper.
Failures throw and are never cached. HTTP errors include the request URL and
JSON server error message when available; SystemOne 404 errors suggest checking
the running server build and decision-model support. The rule runner stops that email, reports the
error, and continues the next queued email. Snapshot settings and rules per email.
inputCharacterLimit replaces coupling input truncation to output max_tokens;
it applies with aggressive reduction and migrates from the old effective limit.
SystemOne batching
systemOneProcessAll defaults to true; systemOneBatchSize defaults to 8 and must
be a positive safe integer. Only SystemOne shows these controls. The numeric input
is disabled while Process all is enabled, retaining its value. Include both in
settings import/export, startup loading, live updates, and per-email snapshots.
classifyRules() is a lazy ordered async iterator over precomputed candidate keys.
Chat requests stay sequential. SystemOne batches the next N unique uncached keys
(or all), sends state once, validates the whole response, and persists one batch
of evidence before yielding ordered results. Per-rule thresholds remain independent.
Do not change existing cache keys or include batch settings in their fingerprint.
Prepare eligibility and keys before actions, using the existing initial mail metadata.
Stop-after-match ends action iteration and prevents further requests; already
computed later answers remain cached. A malformed answer fails its entire batch:
no partial cache writes or new actions. Keep cache-generation guards for imports
and clearing during inference. No automatic splitting or retries. Tests in
tests/batching.test.mjs cover batching, cache reuse, failure atomicity, and actual
rule-runner stop behavior with the real classifier.
Documentation
Additional documentation exists outside this repository.
- Development guide: Webextention-API for Thunderbird
- Thunderbird Add-on Store Policies
- Third Party Libraries
- Issue tracker: Thunderbird tracker on Bugzilla
Message Structure Notes
Messages retrieved with messenger.messages.getFull are returned as
nested objects. The root contains headers and a parts array. Each part may
itself contain parts for multipart messages or a body string. Attachments are
indicated via the content-disposition header.
When constructing the text sent to the AI service, parse the full message
recursively. Include key headers such as from, to, subject, and others, and
record attachment summaries rather than raw binary data. Inline or attached
base64 data should be replaced with placeholders showing the byte size. The
final string should have the headers, a brief attachment section, then the plain
text extracted from all text parts.
Cache Strategy
aiCache persists version 2 inference evidence. Keys are
v2:<SHA-256 Message-ID>:<SHA-256 stable configuration/criterion fingerprint>.
Include backend, endpoint, model, effective request parameters and preprocessing;
exclude secrets, actions and thresholds. Recompute SystemOne matches from cached
probability and current thresholds without automatically executing actions.
Entries retain a hashed message identifier for clearing across configurations.
Version 4.0.0 intentionally breaks legacy cache compatibility: legacy caches
(including aiReasonCache) are invalidated because their inference
configuration is unknown. Import/export validates versioned evidence; storage
changes refresh the running cache. Maintenance uses sortana:getCacheSize to
count validated entries in the background classifier, rather than raw storage keys.
Full restoration requires matching settings and rules as well as cache evidence;
tests/cacheRestore.test.mjs exercises export/reinstall/import through the actual
storage and Details handlers, including changed numeric Thunderbird message IDs. Clearing/importing during inference prevents
that in-flight result from repopulating the replaced cache.
Icon Set Usage
Toolbar and menu icons reside under resources/img and are provided in 16, 32
and 64 pixel variants. When changing these icons, pass a dictionary mapping the
sizes to the paths in browserAction.setIcon or messageDisplayAction.setIcon.
Use resources/svg2img.ps1 on Windows or resources/svg2img.sh on Linux to
regenerate PNGs from the SVG sources.