Skip to content

Releases: Joe20252030/University_Academic_Course_Review_Agent

v0.4.0

v0.4.0 Pre-release
Pre-release

Choose a tag to compare

@Joe20252030 Joe20252030 released this 08 Jun 06:49

UACRAgent v0.4.0


⚠️ First launch — OS security warning (unsigned build)

The standalone builds are not code-signed or notarized. Your OS will block
the app on first launch — this is expected. You only need to do this once.

macOS: Right-click UACRAgent.appOpenOpen.
Or: System Settings → Privacy & Security → Open Anyway.

Windows: Click More infoRun anyway when SmartScreen appears.

Alternatively — run from source

If you are comfortable with Python, you can run UACRAgent directly from
source without a standalone build, which bypasses the OS security check
entirely:

See the README for full setup instructions.


What's new

Auto-updater

The app now checks for new GitHub releases silently 4 seconds after launch. When a newer version is found, a non-blocking dialog presents three choices:

  • Update Now — downloads the platform installer with a live progress bar, then:
    • macOS: opens the .dmg in Finder so you can drag the app to /Applications. Your current session stays open.
    • Windows: launches the .exe installer as a detached background process and exits the running app so the installer can replace files.
  • Remind Me Later — dismisses the dialog; prompts again on the next launch.
  • Skip This Version — persists the skipped tag to ~/.uacragent/config.json so that release never prompts again.

Any network error during the check is handled silently — the updater never blocks startup or crashes the app.


PPTX embedded-image vision extraction

When you attach a .pptx file in the desktop chat, embedded images (photos, diagrams, charts) are now extracted and sent to the LLM as vision inputs — the model can now actually see what's on the slides.

  • Up to 5 images per file; images over 5 MB are skipped individually.
  • Active for vision-capable providers (Gemini, OpenAI) only. Text-only providers (DeepSeek) receive a visible warning.

Extraction-failure warnings in chat

Attachment extraction failures — python-pptx not installed, legacy .ppt format, corrupt files, unsupported MIME types — now surface as visible ⚠️ system messages in the chat area instead of being forwarded to the LLM silently.

Image-count notes in indexed PPTX slides

When Tesseract OCR is not installed, slides containing embedded pictures now include a note such as [2 images on this slide — text inside images not extracted], so the LLM knows visual content exists even when it cannot read it.

App Settings save-reminder banner

The App Settings dialog now shows a fixed banner at the top — "Appearance changes preview instantly. Click Save to confirm all changes, or Cancel to revert." — matching the existing Session Settings style. Available in English and Simplified Chinese.


Bug fixes

# Area Summary
1 Auto-updater Pre-releases skipped/releases/latest returns 404 when all releases are pre-releases. Switched to /releases?per_page=20; highest-versioned candidate with a matching asset is selected.
2 Auto-updater CERTIFICATE_VERIFY_FAILED on macOS frozen build — PyInstaller apps can't reach the macOS cert store. Added _make_ssl_context() backed by certifi; applied to every urlopen call.
3 Auto-updater Dialog close during download — two independent winfo_exists() guards prevent the installer from launching silently when the dialog is dismissed mid-download.
4 Auto-updater _on_download_failed TclError — widget calls guarded with try/except to prevent stderr tracebacks if the dialog was already destroyed.
5 Auto-updater Stale _running_version() — now delegates to uacragent.__version__ (correct pyproject.toml-fallback chain) instead of reading stale pip metadata directly.
6 Auto-updater Non-list API responseisinstance(data, list) guard returns None instead of crashing when a proxy intercepts the request.
7 Session save_session() orphaned directory — failed marker writes left an empty .uacragent/ dir permanently blocking future saves. Freshly-created directory is now removed in both rollback paths.
8 PPTX Vision guard bypass — PPTX image blobs were added as vision parts unconditionally; non-vision providers now receive text + warning.
9 API Workspace cleanup symlink guard — two independent symlink checks added before shutil.rmtree in _cleanup_expired_api_workspaces.
10 UI Output panel stat() TOCTOUFileNotFoundError on externally deleted files now caught; size label falls back to "—".
11 Build __init__.py hardcoded version — version fallback now reads pyproject.toml dynamically; no manual edit needed per release.

Internal changes

  • check_for_update() rewritten to scan the full /releases list and pick the highest-versioned valid candidate
  • certifi added to requirements.txt; bundled in both PyInstaller specs via collect_data_files("certifi")
  • _make_ssl_context() helper added to updater.py (certifi CA bundle, falls back to system default)
  • _safe_rmtree consolidated from workspace_manager.py + vectorstore.py into workspace.py
  • _extract_file_text() return type changed to tuple[str, str | None]

Tests

510 tests, all passing (up from 426 in v0.3.1).
84 new updater-specific tests across 11 sections — version parsing, all check_for_update branches, download progress and cleanup, macOS/Windows apply_update behaviour, skip-version persistence, _pending_update_path lifecycle, two-layer dialog-close guards, and _on_download_failed robustness.


Downloads

Platform Asset
macOS (Apple Silicon) UACRAgent-v0.4.0-macOS-AppleSilicon.dmg
Windows x64 UACRAgent-v0.4.0-windows-x64-setup.exe

Note: The standalone builds are not code-signed or notarized.

  • macOS: right-click → Open, or System Settings → Privacy & Security → Open Anyway.
  • Windows: SmartScreen → More info → Run anyway.

Links

v0.3.2

v0.3.2 Pre-release
Pre-release

Choose a tag to compare

@Joe20252030 Joe20252030 released this 02 Jun 08:30

UACRAgent v0.3.2

v0.3.2 is a stability, correctness, and file-system safety release. The headline
change is a complete fix for drag-and-drop in standalone built apps (three
independent root causes resolved). Additional changes cover dialog close-button
behaviour, attachment lifecycle management, and file-system safety hardening.
No RAG pipeline logic, API surface, or session-file format has changed.


⚠️ First launch — OS security warning (unsigned build)

The standalone builds are not code-signed or notarized. Your OS will block
the app on first launch — this is expected. You only need to do this once.

macOS: Right-click UACRAgent.appOpenOpen.
Or: System Settings → Privacy & Security → Open Anyway.

Windows: Click More infoRun anyway when SmartScreen appears.

Alternatively — run from source

If you are comfortable with Python, you can run UACRAgent directly from
source without a standalone build, which bypasses the OS security check
entirely:

See the README for full setup instructions.


What's Fixed

1 — Drag-and-drop broken in standalone builds (macOS & Windows)

Three independent root causes were found and resolved:

Root cause A — Tcl version incompatibility (tkinterdnd2 version pin)

requirements.txt previously allowed tkinterdnd2>=0.3. Newer releases of
the package ship libtcl9tkdnd*.dylib — a native extension compiled against
Tcl 9. Python 3.13's bundled Tcl is version 8.6; a Tcl 9 extension
cannot be loaded under Tcl 8.6, and the failure is silently wrapped as
"Unable to load tkdnd library."

Fix: requirements.txt now pins tkinterdnd2==0.4.3, the last release
whose dylib (libtkdnd2.9.3.dylib) is Tcl-8.6-compatible. This pin must be
revisited when a future Python version upgrades its bundled Tcl to 9.

Root cause B — CS_LINKER_SIGNED flag on the macOS dylib

The tkdnd dylib from the tkinterdnd2 wheel carries CS_LINKER_SIGNED
(flags=0x20002) — a signature flag applied at compile time by Apple's linker.
On Apple Silicon macOS, dlopen() rejects a linker-signed dylib inside an app
bundle that was signed separately (even with an ad-hoc codesign signature),
because the two signing contexts are treated as incompatible.

Fix: Both macOS and Windows spec files bundle the platform-specific
extension directory (dylib and .tcl scripts) as datas — guaranteeing exact
file placement at the path pkgIndex.tcl expects. The macOS spec then runs a
post-bundle step:

  1. codesign --force --sign - libtkdnd*.dylib — re-signs the dylib with a
    plain ad-hoc signature, removing CS_LINKER_SIGNED.
  2. codesign --force --deep --sign - UACRAgent.app — re-signs the entire
    bundle so the outer signature covers the updated dylib.

No Apple Developer account is required — --sign - is free ad-hoc signing.

Root cause C — Tcl auto_path scan completed before tkinterdnd2 registered

In a frozen build the Tcl interpreter is fully initialised — including its
initial pkgIndex.tcl scan — before any Python module is imported.
tkinterdnd2._require()'s lappend auto_path call therefore arrived too late;
package require tkdnd failed because the tkdnd directory was never scanned.

Fix: Both runtime hooks (rthooks/rthook_tkdnd_mac.py on macOS,
rthooks/rthook_tkdnd.py on Windows) now set TCLLIBPATH before any Python
code runs. Tcl reads TCLLIBPATH at interpreter startup — before the first
package-index scan — and prepends each listed path to auto_path.

Additional robustness:

  • Paths in TCLLIBPATH are brace-quoted so directory names containing
    spaces (e.g. C:\Users\John Smith\…) are treated as a single list element.
  • Both hooks include a fallback directory scan that finds the correct
    platform subdirectory even if the naming convention changes in a future
    tkinterdnd2 release.
  • The Windows hook uses a three-layer strategy: TCLLIBPATH (primary), PATH
    prepend for LoadLibrary dependency resolution, and os.add_dll_directory()
    (belt-and-suspenders).

2 — App Settings × close button applied live-preview changes permanently

Closing App Settings via the OS × button called raw destroy(), bypassing
_cancel. Live-preview theme or font-size changes were silently committed even
when the user intended to cancel. Fix: WM_DELETE_WINDOW is now wired to
_cancel, which reverts all live-preview state before destroying the window.


3 — Session Settings × close button raised TclError

Same root cause — raw destroy() raced with widget-command teardown and raised
TclError: can't delete Tcl command. Fix: WM_DELETE_WINDOW is now wired to
_safe_destroy_toplevel.


4 — Paste attachments not cleaned up on session switch or app close

Clipboard-pasted images written to temp files were only deleted after a
successful send or an explicit chip removal. Fix: a new
_discard_pending_attachments() helper is called on switching to a different
session, creating a new session, and closing the app. Re-clicking the active
session to reload is explicitly excluded — the queue is preserved in that case.


5 — Paste temp images scattered across the OS temp directory

Clipboard-pasted images were written via bare tempfile.mkstemp() into
/tmp or %TEMP%. Fix: all paste temp files now land in
~/.uacragent/paste_tmp/, a fixed app-owned directory unaffected by the user's
custom app data folder setting. A startup sweep clears any files orphaned by a
previous crash.


6 — User files with uacr_paste_ in their name could be accidentally deleted

All cleanup paths used name.startswith("uacr_paste_") as the deletion
predicate. A user file named uacr_paste_notes.pdf would have been deleted.
Fix: only attachment entries explicitly stamped "is_temp_file": True (set
solely by the mkstemp code path) are ever deleted.


7 — File-system safety hardening (six issues)

Issue Fix
TOCTOU race in session deletion is_symlink() re-checked immediately before rmtree
Fixed .tmp suffix in atomic writes NamedTemporaryFile for unique sibling temp file
Output panel delete: no symlink check is_symlink() checked before unlink()
Empty temp file leaked on paste-save failure Except block deletes _tmp before falling through
Temp files leaked if worker thread failed to start Thread.start() wrapped; cleanup on failure
reset_manifest swallowed errors silently Exception now logged at WARNING level

Changed Files

File Change
requirements.txt tkinterdnd2>=0.3==0.4.3 (Tcl 8.6 compatibility pin)
UACRAgent_mac.spec Bundle tkdnd as datas (exact placement); post-bundle codesign step
UACRAgent_win.spec Bundle tkdnd as datas; arch-specific subdir selection
rthooks/rthook_tkdnd_mac.py TCLLIBPATH with brace-quoting; fallback subdir scan; DYLD_FALLBACK_LIBRARY_PATH
rthooks/rthook_tkdnd.py TCLLIBPATH with brace-quoting; fallback subdir scan; three-layer strategy
src/uacragent/infra/persistence.py get_paste_tmp_dir(); unique temp names in atomic writes; TOCTOU re-check
src/uacragent/infra/vectorstore.py reset_manifest exception now logged
src/uacragent/ui/desktop/_chat_mixin.py _discard_pending_attachments(); is_temp_file flag; paste temp to paste_tmp/; cleanup fixes
src/uacragent/ui/desktop/_session_mixin.py _on_session_select and _on_new_session discard attachments on session change
src/uacragent/ui/desktop/_settings_mixin.py Session Settings WM_DELETE_WINDOW; output panel symlink guard
src/uacragent/ui/desktop/_appearance_mixin.py App Settings Cancel button safe destroy; WM_DELETE_WINDOW_cancel
src/uacragent/ui/desktop/app.py _on_close cleanup; _sweep_stale_paste_tmp(); WARNING-level DnD diagnostics
pyproject.toml Version 0.3.10.3.2
src/uacragent/__init__.py Fallback version 0.3.10.3.2
UACRAgent_installer.iss AppVersion0.3.2

Upgrade Notes

  • Standalone build users (macOS / Windows): Download the new build from
    GitHub Releases.
    No session data migration is required. Any uacr_paste_*.png files left in
    the OS temp directory by older builds are not touched by this release — they
    will be cleaned up by the OS in the normal course of temp-directory
    maintenance.
  • Source / pip install users: Run pip install -r requirements.txt after
    pulling to pick up the tkinterdnd2==0.4.3 pin. The DnD and paste_tmp fixes
    are active in all run modes. All file-system hardening applies regardless of
    interface.
  • Building from source: Rebuild the PyInstaller bundle with the updated
    .spec file. The updated runtime hooks are picked up automatically from
    rthooks/. Ensure tkinterdnd2==0.4.3 is installed in your build
    environment before running pyinstaller.

Full Changelog

See CHANGELOG.md for the complete version history.

v0.3.1

v0.3.1 Pre-release
Pre-release

Choose a tag to compare

@Joe20252030 Joe20252030 released this 01 Jun 09:48

UACRAgent v0.3.1

This is a patch release focused entirely on stability, safety, and correctness.
No new features are added. All changes are fixes to bugs and gaps identified
during a comprehensive production audit of the v0.3.0 codebase.


⚠️ First launch — OS security warning (unsigned build)

The standalone builds are not code-signed or notarized. Your OS will block
the app on first launch — this is expected. You only need to do this once.

macOS: Right-click UACRAgent.appOpenOpen.
Or: System Settings → Privacy & Security → Open Anyway.

Windows: Click More infoRun anyway when SmartScreen appears.

Alternatively — run from source

If you are comfortable with Python, you can run UACRAgent directly from
source without a standalone build, which bypasses the OS security check
entirely:

See the README for full setup instructions.


Critical fixes

Fatal crash on window close

Closing the app while an LLM stream or indexing operation was in-flight caused
a fatal Python error:

Fatal Python error: PyEval_RestoreThread: the function must be called with the
GIL held, after Python initialization and before Python finalization, but the
GIL is released (the current Python thread state is NULL)

Root cause: destroy() was called immediately, the main thread exited, and
Python's shutdown sequence killed daemon worker threads mid-execution while
they still held or were waiting for the GIL.

Fix: _on_close now sets the cancel event first (workers stop at the next
streaming chunk boundary), then defers destroy() by 200 ms so all threads
exit cleanly before the window tears down.


TclError: can't delete Tcl command on close

Closing the app also sometimes raised:

_tkinter.TclError: can't delete Tcl command

Root cause: the elapsed-timer ticker was re-registering itself via after()
during destroy()'s widget teardown, hitting a Tcl command that had already
been unregistered.

Fix: the timer is cancelled explicitly in _on_close before the deferred
destroy. The _do_destroy() method also catches TclError as a last-resort
guard.


Plain-text paste freezes the app (macOS)

Pasting any plain text into the chat input caused a multi-second UI freeze.

Root cause: PIL.ImageGrab.grabclipboard() runs
osascript -e "get the clipboard as «class PNGf»" synchronously on the Tkinter
main thread. On macOS, this subprocess can block for several seconds when the
clipboard holds plain text, freezing the entire event loop.

Fix: a new _clipboard_has_image() helper checks for image UTIs using
AppKit.NSPasteboard.types() (< 1 ms, no subprocess). PIL is only invoked when
image data is actually present.


Other bug fixes

Document ingestion

  • Per-file error recovery — a single bad file (corrupted PDF, unsupported
    extension, encoding error) no longer aborts the entire indexing run. It is
    skipped with a logged warning; other files are processed normally. If every
    file fails, a consolidated error lists each failure.
  • Non-UTF-8 text files — files encoded in Latin-1, GBK, or other non-UTF-8
    charsets now load correctly with replacement characters instead of raising a
    UnicodeDecodeError.
  • Scanned / image-only PDFs — PDFs with no embedded text layer now produce a
    specific error message naming the file and directing the user to an OCR tool,
    instead of the generic "no document chunks created" message.
  • Large file guard — files over 300 MB are refused before any I/O to prevent
    out-of-memory crashes; files over 100 MB log a warning.

Security

  • [TASK:] injection via history summary — the LLM-generated conversation
    summary was injected into the system prompt without sanitisation. A
    [TASK:mock_exam] pattern surviving from an earlier user turn could in theory
    cause unintended pipeline triggering. The summary now has [TASK: neutralised
    (U+2060 word-joiner) before injection, consistent with all other user-controlled
    fields.
  • [TASK:] injection via attachment filenames — attachment names in the
    system prompt's attachments_note were injected verbatim. Each name is now
    passed through _sanitise().
  • CLI --workspace-id path-traversal — the CLI set workspace_folder
    directly without the safe-character validation applied by the desktop and API
    layers. --workspace-id ../../sensitive could place session files outside the
    intended cli_run/ directory. The CLI now validates against
    ^[A-Za-z0-9_-]{1,128}$ and exits with a clear error on failure.
  • Non-secret env vars in secret-clearance listEMBEDDING_PROVIDER and
    LOCAL_EMBEDDING_MODEL were included alongside API keys in
    _runtime_secret_env_vars(). This silently stripped the user's embedding
    setting from the child process env during an app-data-folder relaunch. Only
    actual API keys are now cleared.

Desktop UI

  • Temp paste images not deleted on removal — clipboard-pasted screenshots
    written to uacr_paste_*.png temp files were only cleaned up after a send.
    Removing the attachment before sending left the temp file permanently.
    _remove_attachment now deletes the file immediately.
  • Session file picker incomplete — the file dialog offered only
    .pdf .txt .md .docx .csv, omitting .py .js .ts .html .htm .xml .json that
    the loader already supports. All supported extensions are now listed.
  • gpt-4o-search-preview models allowed image attachments — the vision
    guard was provider-level only; search-preview model variants (which do not
    accept multimodal inputs) were not excluded. _provider_supports_vision() now
    also checks the model name.
  • History summarisation rate-limit race — the trim/summarisation LLM call
    fired immediately after the preceding chat reply with no inter-call delay,
    risking 429 errors on Free-tier plans. _smart_trim_history now respects the
    request_delay from the active rate tier.

API

  • Concurrent workspace collision — two simultaneous POST /review calls
    with workspace_id="default" shared the same chroma_db/ directory, causing
    SQLite lock collisions. Requests using "default" now receive an isolated
    per-request UUID workspace.

Export

  • OSErrors escaped unwrappedsave_markdown, save_docx, and save_pdf
    let disk-full or permission errors propagate as bare OSError. All three now
    wrap OS failures in ExportError with a human-readable message.

Minor

  • _ls() silently swallowed missing i18n keys — missing keys were returned
    as raw key strings with no diagnostic. A WARNING is now logged.
  • _on_close duplicated _clear_runtime_secrets logic_on_close had
    its own hardcoded env-var list instead of delegating to the shared method.
    Consolidated to a single call.

Tests

180 new tests added across 8 new test files. 4 pre-existing test bugs fixed.

Total: 426 tests, all passing.

New coverage added for: rate tiers, document-priority weights, reasoning config,
_HistoryStore thread-safety, full session serialisation round-trips,
vectorstore manifest and chroma_is_current, chunk ID deduplication
(within-batch _seen set + cross-run existing_ids check), CSV ingestion edge
cases, pipeline effort config and cancellation paths, settings env-var aliases,
and regression tests for every bug fixed in this release.

Chunk ID collision — file-removal detection tests fixed

Each chunk stored in Chroma is identified by a content-hash ID computed from
SHA-256(source_path + "\x00" + page_content). When a document is removed from
a session the old chunks must be purged from ChromaDB; otherwise their IDs
remain in the database and prevent the same content from being re-indexed under
a new document set — a silent deduplication collision.

The mechanism that triggers this purge is _files_were_removed(). Three tests
that verified this wipe path (TestFilesWereRemoved) were writing the manifest
file in the wrong JSON schema:

# wrong — what the tests wrote
{"files": {"lecture_note": ["/a/lec.pdf"]}}

# correct — what _files_were_removed() expects
{"files": [{"doc_type": "lecture_note", "path": "/a/lec.pdf"}]}

This caused a TypeError: string indices must be integers in all three tests
and left the collision-avoidance wipe path completely untested. The tests are
now fixed and all three pass, confirming that stale chunks are correctly purged
when files are removed.

test_api_keys_not_persisted fixed

This test imported the nonexistent function session_to_dict and called
AgentSession(workspace="ws1") using a field that does not exist. The test
now uses the correct save_session + raw JSON file assertion that exercises
the actual persistence layer and verifies that API keys are never written to
session.json.


Upgrade notes

This is a drop-in replacement for v0.3.0. No configuration changes, migration
steps, or API changes are required. Existing session files, workspaces, and
Chroma indexes are fully compatible.

v0.3.0

v0.3.0 Pre-release
Pre-release

Choose a tag to compare

@Joe20252030 Joe20252030 released this 31 May 15:20

UACRAgent v0.3.0


⚠️ First launch — OS security warning (unsigned build)

The standalone builds are not code-signed or notarized. Your OS will block
the app on first launch — this is expected. You only need to do this once.

macOS: Right-click UACRAgent.appOpenOpen.
Or: System Settings → Privacy & Security → Open Anyway.

Windows: Click More infoRun anyway when SmartScreen appears.

Alternatively — run from source

If you are comfortable with Python, you can run UACRAgent directly from
source without a standalone build, which bypasses the OS security check
entirely:

See the README for full setup instructions.


What's New

Paste-to-attach

You can now paste files and images directly into the chat input box with Cmd+V (macOS) or Ctrl+V (Windows/Linux) to attach them. This has the same result as using the + button or dragging a file onto the chat area.

Supported formats:

  • PDF
  • DOCX
  • plain text
  • Markdown
  • CSV
  • JSON
  • XML
  • HTML
  • common code file types
  • images (PNG, JPEG, GIF, WebP, BMP)

Examples:

  • Copy a PDF or Word document in Finder or Explorer, then paste into chat: it attaches as its original file type, with text extracted for the LLM.
  • Paste a screenshot or an image copied from a browser: it attaches as a PNG image and is sent inline to vision-capable providers such as Gemini and OpenAI.

Windows installer

An Inno Setup installer script, UACRAgent_installer.iss, is now included in the repository.

This allows building a proper Windows setup wizard for distribution, providing a smoother installation experience compared to shipping only the raw zip.

Bug Fixes

Paste was always attaching files as PNG (macOS and Windows)

This was the primary bug driving this release.

Copying a PDF in Finder and pasting it into chat could produce a PNG attachment instead of the PDF. In that case, the LLM received a rendered image of the file’s icon rather than the document text.

macOS root cause

PIL.ImageGrab.grabclipboard() runs AppleScript equivalent to:

get the clipboard as «class PNGf»

That asks macOS to coerce clipboard content to PNG. When a file is copied in Finder, macOS may respond by rendering the file’s icon. As a result, the clipboard returned a PNG of the PDF file icon rather than the file itself.

The fix reads NSFilenamesPboardType directly from the pasteboard via the AppleScript / Objective-C Foundation bridge before PIL is called, with no extra dependencies required.

Windows root cause

The code that reads the file list from the Windows clipboard with DragQueryFileW was passed the wrong argument: a raw locked memory pointer from GlobalLock instead of the HDROP handle returned by GetClipboardData.

That made DragQueryFileW always return zero files, so the code fell through to PIL, which could return a thumbnail image instead.

The fix removes the unnecessary GlobalLock call and passes the HDROP handle directly.

Pasted image temp files were never deleted

When a screenshot or browser image is pasted, it is written to a temporary file such as uacr_paste_*.png in the OS temp directory so the LLM can read it.

These files were never cleaned up before. They are now deleted immediately after each send in a finally block, so cleanup runs whether the request succeeds, fails, or is cancelled.

Settings and search icons rendered incorrectly on Windows

The gear symbol in the App Settings and Session Settings button labels could appear garbled or missing on Windows.

TkDefaultFont on Windows resolves to Segoe UI, which does not cover the Unicode Miscellaneous Symbols block containing (U+2699). The fix automatically selects Segoe UI Symbol on Windows for the icon glyph, which ships with Windows and covers that block correctly.

The 🔍 emoji in the sidebar search box has also been replaced with a canvas-drawn magnifying glass built from tkinter canvas primitives (circle + handle). This renders sharply at all sizes and DPI settings on every platform, with no font dependency.

Upgrade Notes

No configuration changes or data migration are required.

Existing sessions, workspaces, and settings are fully compatible with v0.3.0.

v0.2.0

v0.2.0 Pre-release
Pre-release

Choose a tag to compare

@Joe20252030 Joe20252030 released this 30 May 13:58

UACRAgent v0.2.0


⚠️ First launch — OS security warning (unsigned build)

The standalone builds are not code-signed or notarized. Your OS will block
the app on first launch — this is expected. You only need to do this once.

macOS: Right-click UACRAgent.appOpenOpen.
Or: System Settings → Privacy & Security → Open Anyway.

Windows: Click More infoRun anyway when SmartScreen appears.

Alternatively — run from source

If you are comfortable with Python, you can run UACRAgent directly from
source without a standalone build, which bypasses the OS security check
entirely:

See the README for full setup instructions.


What's New

Responsive cancellation

Cancel now exits within a fraction of a second at every stage of the pipeline. The initial conversational LLM call, plan generation, each section write, and the exam-paper step are all interruptible via streaming.

Previously, cancelling during a long generation could leave the UI locked for up to a minute.

The user's message is now also preserved in session history when a request is cancelled.

Attachment visibility in chat

Files and images attached to a message are now shown as icon + filename chips inside the chat bubble.

  • Chips persist when a session is reloaded.
  • Clicking a chip in either the input strip or a historical message opens the file in your OS default application.
  • Only the × token removes an attachment from the queue.

Hover tooltips on toolbar buttons

Hovering over the Web Search (🌐) or Attach (+) button for 600 ms now shows a small tooltip describing the button's action.

Tooltips now:

  • follow the active colour theme
  • scale with the font-size setting in App Settings
  • track the cursor correctly on multi-monitor setups

Bug Fixes

False-positive generation trigger

A test message or image-visibility check such as can you see this? no longer accidentally starts study-plan generation.

A tightened system-prompt instruction set and a narrow code-level blocklist for unambiguous non-generation patterns now prevent the pipeline from firing, while leaving natural-language generation requests intact.

DOCX attachment extraction

Word documents that previously failed to extract because of complex formatting, embedded tables, or newer format features now fall back automatically from Docx2txtLoader to python-docx.

Only if both libraries fail does an error surface.

Tooltip placement on secondary monitors

Tooltips now use live cursor coordinates (winfo_pointerx/y) so they follow the window correctly when the app is on a non-primary display.

Tooltip rendering on macOS

The native help window level is now applied before overrideredirect, ensuring tooltips float above all application content on macOS.

v0.1.2

v0.1.2 Pre-release
Pre-release

Choose a tag to compare

@Joe20252030 Joe20252030 released this 29 May 09:35

UACRAgent v0.1.2

This release adds Windows support and includes privacy improvements,
security hardening, bug fixes, and UI refinements.


⚠️ First launch — OS security warning (unsigned build)

The standalone builds are not code-signed or notarized. Your OS will block
the app on first launch — this is expected. You only need to do this once.

macOS: Right-click UACRAgent.appOpenOpen.
Or: System Settings → Privacy & Security → Open Anyway.

Windows: Click More infoRun anyway when SmartScreen appears.

Alternatively — run from source

If you are comfortable with Python, you can run UACRAgent directly from
source without a standalone build, which bypasses the OS security check
entirely:

See the README for full setup instructions.


What's new in v0.1.2

Windows standalone build

UACRAgent is now available as a standalone build on Windows 10 / 11.
Windows-specific compatibility fixes included in this release:

  • Resolved a path-separator mismatch in the exam info file handler —
    Tkinter's file dialog returns forward-slash paths on Windows while
    Path uses backslashes; the containment check now uses
    Path.is_relative_to() which is separator-agnostic
  • Fixed a file-locking issue on Windows: the ChromaDB SQLite connection
    is now explicitly released before session deletion, preventing
    PermissionError from leaving orphaned files on disk

Privacy — OpenAI conversation storage opt-out

OpenAI's Responses API (used by newer models such as GPT-4o and later)
stores every request on the OpenAI platform dashboard by default.
UACRAgent now sends store=false on every OpenAI request to opt out
automatically.

Users who want to allow OpenAI to retain their conversations (e.g. for
fine-tuning) can re-enable this in App Settings → Privacy → Provider
data storage
, or by setting OPENAI_STORE_RESPONSES=true in .env.

Gemini and DeepSeek do not expose a per-request storage opt-out; their
data-retention policies are managed at the account level on their
respective platforms.

Security hardening

  • User-entered text fields (course name, extra instructions, exam info,
    etc.) are now sanitised before injection into the LLM system prompt,
    preventing {/} brace errors and [TASK:] prompt-injection via
    crafted text
  • workspace_id values loaded from session files are now validated
    against a safe-character allowlist, preventing path-traversal via
    tampered session data
  • llm_provider loaded from session files is now validated against a
    known provider allowlist
  • File copy operations now refuse to follow symlinks
  • Collision-avoidance loops in file operations are capped at 1 000
    iterations

Bug fixes

  • Font size setting in App Settings now correctly scales all UI text,
    including session list items, the placeholder label, the
    drag-and-drop overlay, and the thinking indicator
  • App Settings Cancel button now correctly reverts the OpenAI storage
    checkbox when the user made a change and then cancelled
  • App Settings "Browse…" button and folder picker title are now
    localised for Simplified Chinese users

UI / i18n

  • All 224 UI strings are present and consistent in both English and
    Simplified Chinese

Platform Support

Platform Status
macOS ✅ Standalone build available
Windows ✅ Standalone build available
Linux Source install may work but is not officially supported in this release

Notes

  • In the standalone builds, local embeddings use all-MiniLM-L6-v2
    via the built-in ONNX backend (~80 MB download on first use). Source
    installs support additional HuggingFace models via
    sentence-transformers.
  • The FastAPI API is intended for local trusted use in the current
    version.
  • API keys entered in the desktop settings window are kept in process
    memory only and are never written to disk.
  • Released under the MIT License.
  • Independent open-source project — not affiliated with any LLM
    provider, university, or examination body.
  • Intended as an educational study-assistance tool. Generated
    content should always be verified against official course materials
    and instructor guidance.

⚠️ Pre-release — this is an early public release under active
development. Features and data formats may change before v1.0.0.


Privacy

Most working data is stored locally, including session state, vector
indexes, generated outputs, and cached local embedding models.
Depending on your configuration, prompts, retrieved document excerpts,
and generation context may be sent to the selected external LLM or
embedding provider.

Please review the full privacy, data usage, and disclaimer notes in
the README before use.


Thanks to everyone who helped test and improve the project.

v0.1.1

v0.1.1 Pre-release
Pre-release

Choose a tag to compare

@Joe20252030 Joe20252030 released this 29 May 07:05

UACRAgent v0.1.1

This release adds Windows support to the initial macOS release (v0.1.0).
No new features have been added — this is the same app, now available as a
standalone build on both macOS and Windows.


⚠️ First launch — OS security warning (unsigned build)

The standalone builds are not code-signed or notarized. Your OS will block
the app on first launch — this is expected. You only need to do this once.

macOS: Right-click UACRAgent.appOpenOpen.
Or: System Settings → Privacy & Security → Open Anyway.

Windows: Click More infoRun anyway when SmartScreen appears.

Alternatively — run from source

If you are comfortable with Python, you can run UACRAgent directly from
source without a standalone build, which bypasses the OS security check
entirely:

See the README for full setup instructions.


What's new in v0.1.1

  • Windows standalone buildUACRAgent.exe available for Windows 10 / 11
  • Windows compatibility fixes:
    • Resolved a path separator issue affecting exam info file handling on Windows
    • Fixed a file locking issue that could leave orphaned files when deleting a
      session while ChromaDB had the workspace open

Platform Support

Platform Status
macOS ✅ Standalone build available
Windows ✅ Standalone build available
Linux Source install may work but is not officially supported in this release

Windows

  1. Download UACRAgent-windows-x64.zip
  2. Extract the zip
  3. Open the extracted UACRAgent folder
  4. Run UACRAgent.exe

Important: keep all bundled files in the extracted folder together. Do not move only the .exe by itself.


Features

Study workflow

  • Persistent desktop chat assistant for working with course materials
  • Upload and classify documents by type (syllabus, lecture notes, textbook,
    past exams, assignments, other)
  • Ask grounded study questions with answers drawn from your uploaded materials
  • Request generated study documents in natural language or via quick-action buttons
  • Reopen saved sessions and reuse existing indexes when files have not changed

Generated output types

Type Description
Review Summary Comprehensive review with key concepts, definitions, tips, and sample questions
Practice Booklet Structured practice problems (easy / medium / hard) with a solution key
Mock Exam Realistic exam paper with point allocations and a separate answer key
Exam Prediction Part A: topic-by-topic prediction analysis with confidence and study guidance. Part B: a complete predicted exam paper with mark allocations and a full answer key

LLM providers

  • Gemini — chat, planning, writing, embeddings, web search, file attachments
  • OpenAI — chat, planning, writing, embeddings, web search, file attachments
  • DeepSeek — chat, planning, writing

Embedding options

  • Gemini embeddings (cloud, needs GOOGLE_API_KEY)
  • OpenAI embeddings (cloud, needs OPENAI_API_KEY)
  • Local on-device embeddings (free, no API key required)

Export formats

  • Markdown (canonical output, always generated)
  • DOCX (optional)
  • PDF (optional)

Interfaces

  • Desktop GUI — primary interface with session management, settings, and chat
  • Interactive CLI — terminal-based conversational assistant
  • Local FastAPI API — programmatic one-shot document generation

Session management

  • Persistent sessions with saved course settings, file sets, and chat history
  • Per-session workspace with isolated vector store, outputs, and uploaded file copies
  • Configurable app data directory for all agent-managed storage
  • Fast-attach path: reuses the saved index when the file set has not changed

Notes

  • In the standalone builds, local embeddings use all-MiniLM-L6-v2 via the
    built-in ONNX backend (~80 MB download on first use). Source installs support
    additional HuggingFace models via sentence-transformers.
  • The FastAPI API is intended for local trusted use in the current version.
  • API keys entered in the desktop settings window are kept in process memory only
    and are never written to disk.
  • Released under the MIT License.
  • Independent open-source project — not affiliated with any LLM provider,
    university, or examination body.
  • Intended as an educational study-assistance tool. Generated content should
    always be verified against official course materials and instructor guidance.

Privacy

Most working data is stored locally, including session state, vector indexes,
generated outputs, and cached local embedding models. Depending on your
configuration, prompts, retrieved document excerpts, and generation context may
be sent to the selected external LLM or embedding provider.

Please review the full privacy, data usage, and disclaimer notes in the
README before use.


Thanks to everyone who helped test and improve the project.

v0.1.0

v0.1.0 Pre-release
Pre-release

Choose a tag to compare

@Joe20252030 Joe20252030 released this 27 May 13:18

UACRAgent v0.1.0

This release marks the second public version of UACRAgent, a desktop-first academic course assistant for studying from course materials with grounded AI support.

UACRAgent helps students work with class documents through a persistent conversational workflow, while also supporting generation of structured study materials such as review summaries, practice booklets, mock exams, and exam predictions.


⚠️ First launch — OS security warning (unsigned build)

The standalone builds are not code-signed or notarized. Your OS will block
the app on first launch — this is expected. You only need to do this once.

macOS: Right-click UACRAgent.appOpenOpen.
Or: System Settings → Privacy & Security → Open Anyway.

Alternatively — run from source

If you are comfortable with Python, you can run UACRAgent directly from
source without a standalone build, which bypasses the OS security check
entirely:

See the README for full setup instructions.


Highlights

  • Persistent desktop chat assistant for studying from course materials
  • RAG-based retrieval pipeline with local Chroma vector storage
  • Document-type-aware splitting for better retrieval quality
  • Support for:
    • Review summaries
    • Practice booklets
    • Mock exams
    • Exam predictions
  • Multi-provider LLM support:
    • Gemini
    • OpenAI
    • DeepSeek
  • Multiple embedding options:
    • Gemini embeddings
    • OpenAI embeddings
    • Local on-device embeddings (no API key required)
  • Multiple interfaces:
    • Desktop GUI
    • Interactive CLI
    • Local FastAPI API
  • Local session persistence with reusable workspaces and saved chat history
  • App-managed local storage for sessions, outputs, vector indexes, and downloaded local embedding models
  • Optional export to Markdown, DOCX, and PDF

Platform Support

Platform Status
macOS ✅ Standalone build available
Windows 🔄 In progress — coming in a future release
Linux Source install may work but is not officially supported in this release

Current Workflow

Users can create a study session, upload and classify course materials, choose provider and embedding settings, index documents, and then:

  • ask grounded study questions in chat
  • request generated study materials
  • reopen saved sessions later
  • reuse existing indexes when files have not changed

Privacy and Data Usage

Most working data is stored locally in the workspace and app data directory, including session state, vector indexes, outputs, and cached local embedding models.

Depending on configuration, prompts, retrieved document excerpts, and other request content may be sent to the selected external LLM or embedding provider.

The FastAPI API is intended for local trusted use in the current version.

Please review the project README for the full privacy, data usage, and disclaimer notes before use.

Notes

  • In the standalone macOS build, local embeddings use all-MiniLM-L6-v2 via the built-in ONNX backend. Source installs support additional HuggingFace models via sentence-transformers.
  • Released under the MIT License
  • Independent open-source project
  • Intended as an educational study-assistance tool
  • Generated content should always be verified against official course materials and instructor guidance

Thanks to everyone who helped test and improve the project.

v0.0.0

v0.0.0 Pre-release
Pre-release

Choose a tag to compare

@Joe20252030 Joe20252030 released this 06 May 22:23

UACRAgent v0.0.0

Initial release of UACRAgent, a university course review generator that turns course materials into exam-prep content using a retrieval-augmented generation (RAG) pipeline.

Highlights

  • Generate exam review materials from course documents including PDF, TXT, Markdown, and DOCX
  • Support for four output modes:
    • Review Summary
    • Practice Booklet
    • Mock Exam
    • Exam Prediction
  • Accept structured course context such as course name, university, department, course code, professor, semester, exam duration, and exam info sheet
  • Use document-aware processing with specialized handling for:
    • Syllabus
    • Lecture notes
    • Textbooks
    • Assignments
    • Past exams
    • Other materials
  • Save canonical output as Markdown with optional DOCX and PDF export through the desktop GUI

What’s Included

Multi-stage RAG pipeline

  • Ingests course materials
  • Classifies or accepts user-specified document types
  • Applies document-type-specific chunking strategies
  • Stores embeddings in a local Chroma vector store
  • Uses an LLM to plan the output structure
  • Retrieves relevant material section by section
  • Generates final exam-prep content in a structured format

Multiple interfaces

  • Desktop GUI for guided end-to-end use
  • CLI for scripting and local workflows
  • FastAPI API with:
    • GET /health
    • POST /review
    • POST /review/simple

Exam-prep generation modes

  • Review Summary for concepts, definitions, tips, and sample questions
  • Practice Booklet for leveled practice problems with solutions
  • Mock Exam for realistic exam papers with marking support
  • Exam Prediction for topic-by-topic prediction analysis plus a full predicted exam paper

Platform & Runtime Notes

  • Requires Python 3.10+
  • Uses Google Gemini models for planning, writing, and embeddings
  • Works across macOS, Windows, and Linux
  • Includes configurable retry and request-delay settings to help manage API rate limits

Status

This release is marked as Alpha and is intended as an early foundation for the project. Feedback on workflow, output quality, document handling, and export behavior is especially valuable at this stage.

License

Released under the MIT License.