generated from exteraGramPlugins/pluginBase
Implement Chat Summaries plugin
Replace the sample plugin with an AI chat summarizer that renders its
output as a native RichMessage injected into the chat.
Summarization pipeline:
- Fetch chat/topic history via paginated TL requests.
- Send a system prompt, the user's instructions and an anonymized JSON
transcript as three separate roles. Only message text and attachment
names leave the device; senders and message ids are replaced by
indices, and out-of-range reply parents are included with negative ids
so replies keep their context.
- Stream the response over SSE, reading reasoning from reasoning_content,
reasoning or inline <think> tags.
- Substitute the model's {userN}/{msgN} placeholders back into real names
and deep links. Placeholders are used instead of Markdown links because
a half-streamed link renders as broken literal text.
Rendering:
- Compile Markdown into TL_iv page blocks (headings, lists, quotes, code,
dividers, inline styles) since the app's own converter works off
Android Spanned spans rather than Markdown source.
- Show progress stages immediately on click, animate reasoning while it
streams, then collapse it into a tappable details block.
- Attribute the card to a client-side mock sender and insert it directly
after the newest analyzed message, scrolling it into view.
Persistence:
- Store summaries in SQLite keyed by (dialog, topic, anchor) and
re-inject them when the chat is reopened.
Also add tools/release.py and a Gitea workflow that builds, verifies and
publishes dist/<id>.plugin to the Releases tab, and extend
tools/verify_bundle.py to 104 offline checks covering the transcript,
streaming, rendering, injection and storage behaviour.
This commit is contained in:
1 parent
a3b0b264c1
commit
196da742de
27 files changed
+5261
-121
No files matched your search
@@ -34,12 +34,18 @@ This repo does not use the official Elyx/ElyxBuilder archive format — see
|
||||
plugin.json single source of truth for plugin metadata
|
||||
src/ the plugin, written as an ordinary Python package
|
||||
main.py entry module — exactly one BasePlugin subclass, absolute imports only
|
||||
greeting/ sample package (proves relative + cross-module imports survive bundling)
|
||||
textutil.py sample top-level sibling module
|
||||
config.py setting keys, defaults and tunables
|
||||
diagnostics.py bounded in-memory log, mirrored to a file (logcat is restricted here)
|
||||
providers/ endpoint settings, prompt assembly and SSE streaming
|
||||
services/ history fetch, anonymized transcript, markdown→RichMessage, injection, SQLite store
|
||||
hooks/ Xposed hooks (unread-button entry points, summary restore on chat open)
|
||||
ui/ summarize dialog, bulletin and theme helpers
|
||||
tools/
|
||||
bundle.py compiles plugin.json + src/ into dist/<id>.plugin
|
||||
devclient.py speaks the on-device dev-server protocol (127.0.0.1:42690)
|
||||
verify_bundle.py offline harness that proves a built bundle behaves correctly, no phone needed
|
||||
release.py publishes a built bundle to a Gitea release (used by CI)
|
||||
.gitea/workflows/ CI that builds, verifies and publishes the .plugin to Releases
|
||||
scripts/ bash automation for the ADB debug loop (see below)
|
||||
docs/sdk-notes.md condensed SDK API surface gathered from the official docs
|
||||
```
|
||||
@@ -91,6 +97,36 @@ standard `ANDROID_SERIAL` env var for device selection.
|
||||
- `scripts/fetch-sdk-stubs.sh [--beta]` — downloads the latest SDK type stubs into `stubs/`
|
||||
for editor autocomplete.
|
||||
|
||||
## Publishing a release
|
||||
|
||||
`.gitea/workflows/release.yml` builds, verifies and publishes the `.plugin` to the repo's
|
||||
Releases tab. `dist/` is gitignored, so the artifact is always built by CI rather than
|
||||
committed.
|
||||
|
||||
```bash
|
||||
# tag a version and push it -> release named after the tag
|
||||
git tag v1.0.1 && git push origin v1.0.1
|
||||
```
|
||||
|
||||
The workflow also accepts a manual run (Actions → Publish plugin → Run workflow), which
|
||||
derives the tag from `version` in `plugin.json`. Either way it runs `--check`, builds with
|
||||
`--release`, and gates the upload on `verify_bundle.py`, so a bundle that fails verification
|
||||
is never published.
|
||||
|
||||
Re-running against an existing tag reuses that release and replaces the attachment instead of
|
||||
piling up duplicates.
|
||||
|
||||
Authentication uses `secrets.API_TOKEN`, an organisation-level Actions secret holding a user
|
||||
token with the `write:repository` scope (which covers releases). Set it once under
|
||||
**Org → Settings → Actions → Secrets** and every repo in the organisation inherits it; a
|
||||
repo-level secret of the same name takes precedence if one repo ever needs different
|
||||
credentials.
|
||||
|
||||
If you would rather not manage a token, Gitea also injects a per-job `secrets.GITEA_TOKEN`
|
||||
that can create releases in its own repo — swap the `env:` line in the workflow and drop the
|
||||
org secret. It is scoped to the single job and expires with it, so it is the safer default;
|
||||
`API_TOKEN` is what you want when publishing needs to reach beyond this repo.
|
||||
|
||||
## Writing your own plugin
|
||||
|
||||
1. Edit `plugin.json` (id, name, description, etc.).
|
||||
|
||||
Reference in new issue
Block a user