Skip to content

Main - #24

Open
Keninjavelas wants to merge 3156 commits into
arcahyadi:mainfrom
Keninjavelas:main
Open

Main#24
Keninjavelas wants to merge 3156 commits into
arcahyadi:mainfrom
Keninjavelas:main

Conversation

@Keninjavelas

Copy link
Copy Markdown

Summary

Target branch

  • This PR targets dev, not main. All PRs land in dev; main is curated by the maintainer at each release. If your PR is on main by accident, click "Edit" on this PR and change the base.

Linked Issue

Fixes #

Type of Change

  • Bug fix (non-breaking — fixes a confirmed issue)
  • New feature (non-breaking — adds new behaviour)
  • Breaking change (changes or removes existing behaviour)
  • Refactor / cleanup (behaviour unchanged)
  • Documentation only
  • CI / tooling / configuration

Checklist

  • I searched open issues and open PRs — this is not a duplicate.
  • This PR targets dev
  • My changes are limited to the scope described above — no unrelated refactors or whitespace changes mixed in.
  • I actually ran the app (docker compose up or uvicorn app:app) and verified the change works end-to-end. Type-checks and unit tests are not enough.

How to Test

Visual / UI changes — REQUIRED if you touched anything that renders

Anything that changes what the UI looks like — buttons, icons, padding, colors, fonts, spacing, layout, CSS, HTML, SVG, or any static/js/ module that draws to the DOM — needs all of the following. PRs that change rendering without these WILL be closed.

  • Screenshot or short clip of the change in the running app, attached below. Mobile screenshot too if the change affects mobile.
  • Style match: the change uses Odysseus's existing visual language. Specifically:
    • Reuse existing CSS variables (--red, --fg, --bg, --card, --border, etc.) — do not introduce new color values, font sizes, or spacing units.
    • Reuse existing button/input/card/border classes. Don't invent parallel styling.
    • No Unicode emoji in UI or code. Use inline SVG (matching the monochrome icon style already in static/index.html) or plain text.
    • Monospaced font (Fira Code) for primary UI text. Don't override.
    • Dark theme is the default; any light-mode work must be wired through the existing theme system, not hard-coded.
  • No new component patterns. If a similar widget already exists in the app, extend it instead of writing a parallel one.
  • I am not an LLM agent submitting a bulk PR. If you are, please open an issue describing the problem first — bulk auto-generated PRs that don't match the project's visual style are closed on sight, even when the underlying fix is correct.

Screenshots / clips

RaresKeY and others added 30 commits October 25, 2026 13:45
…tion

- Vendor KaTeX fonts and Mermaid library to static/lib for offline math rendering
- Add comprehensive troubleshooting guide and setup documentation updates
- Implement CDN asset vendoring script (scripts/vendor_cdn_assets.py)
- Expand test suite with 60+ new test cases covering tool tiering, diagnostics, and first-boot scenarios
- Add smoke tests framework and core tour extraction tests
- Enhance security documentation and update roadmap checkpoints
- Refactor middleware and agent loop for improved context budget handling
- Add tour core module for guided user onboarding experiences
- Update CI workflow configuration and security settings
- Add desktop configuration file and branded documentation assets
- Improve cookbook, email, STT, and TTS route implementations
- Update tool execution, indexing, and provider configurations for better reliability
…pace is set (#6722)

* fix(agent): give file tools the agent workspace as root when no workspace is set (#6679)

With no workspace bound, bash/python run in data/agent_workspace, but
RequestAuthority sealed no filesystem root, so every native file tool
failed with "requires a sealed resource root", and an approved
write_file failed with "no sealed resource identity". Seal the agent
workspace instead, and resolve relative paths in _resolve_tool_path
against it rather than the server's cwd.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: re-seal resource roots when a test swaps the authority owner (#6679)

A no-workspace authority now seals the agent workspace for its owner, so
replace(authority, owner="bob") copied alice's root and was rejected
before the approval-binding check the tests are about.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(agent): only seal a vetted agent workspace as the file-tool root (#6679)

Apply the agent_cwd() check before sealing data/agent_workspace: it must
be a real directory in the readable data subdirs, otherwise no root is
sealed. A symlinked workspace no longer redirects the file tools or the
bash/python launch scope. Tighten the dispatch test assertions to the
exact 'outside the sealed roots' message.

* refactor(agent): vet the no-workspace file root with default_agent_workspace (#6679)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…6353)

* fix(security): block read-only cookbook tools for non-admin owners

list_cached_models, list_served_models, tail_serve_output, list_downloads,
search_hf_models, list_serve_presets and list_cookbook_servers were in the
plan-mode read-only allowlist but in neither NON_ADMIN_BLOCKED_TOOLS nor the
dispatcher's _ADMIN_TOOLS. Each implementation calls a require_admin route
over the internal loopback with the process-wide INTERNAL_TOOL_TOKEN and
never checks the owner, so a non-admin user's agent inherited admin reach
through them. list_cached_models is the worst case: a caller-chosen `host`
is forwarded to /api/model/cached, which SSHes to that host with the app
user's keys and walks caller-chosen model_dirs. THREAT_MODEL.md lists model
serving as admin-only, so gate the read side the same way as serve/download.

Adding the names to NON_ADMIN_BLOCKED_TOOLS also hides them from non-admin
tool schemas and caps bearer-token agent runs; _ADMIN_TOOLS blocks them at
dispatch. Regression test covers both lists, schema hiding, and that the
loopback is never reached for a non-admin owner.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TwcwfY2uQMxNRsK3y6xBAp

* fix(cookbook): bind request authority in admin gate regressions

Keep all seven read-only Cookbook tools in the admin prompt inventory. Grant request authority in dispatch tests so the admin gate itself is exercised, and verify administrators still reach each handler. Validation: 359 focused authorization, tool-policy and schema tests passed. Against the running app with real auth accounts, all seven tools reject a non-admin and an admin reaches the authenticated Cookbook HTTP API.

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Afonso Junior <chatgpt@yack.com.br>
* fix(email): guard user-supplied IMAP/SMTP hosts against SSRF

POST /api/email/accounts/test opened raw imaplib/smtplib connections to
whatever host:port the request body named, and POST/PUT /api/email/accounts
and PUT /api/email/config persisted arbitrary hosts for the background
pollers to contact. All of these sit behind require_user/require_owner with
no admin gate, so any authenticated user could make the server connect to
loopback, LAN and cloud-metadata targets (169.254.169.254) and read the
first 200 characters of the remote banner back out of the friendly error.
THREAT_MODEL.md lists email as admin-only; the tool layer honours that but
the HTTP routes did not.

Add check_outbound_host() to src/url_safety.py, a bare-host companion to
check_outbound_url() with the same classification (link-local, multicast,
reserved and unspecified always rejected; private/loopback only with
block_private) plus localhost-name handling and an explicit policy for names
that do not resolve. Wire it into the four email routes via
_check_mail_host(): non-admin owners (and everyone when
EMAIL_BLOCK_PRIVATE_IPS=true) also lose private/loopback targets, admins
keep the local-first LAN/Dovecot setups. Unresolvable names pass through
because the connect that follows fails with the same DNS error.

Regression tests cover the helper's policy table and each route: the test
route rejects before any socket opens, save routes reject before touching
the DB, admins keep loopback unless locked down, and an update that fails
validation leaves the stored row untouched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TwcwfY2uQMxNRsK3y6xBAp

* fix(email): harden IMAP/SMTP SSRF protection against rebinding, TOCTOU, and unvetted hosts

- P0: Implement safe_create_connection() in src/url_safety.py to resolve hostnames once, validate every returned address against SSRF policy, and connect directly to the pinned IP. This eliminates DNS rebinding and TOCTOU while preserving TLS SNI and certificate hostname verification across IMAP, IMAPS, STARTTLS, SMTP, and SMTP_SSL.
- P1: Ensure unresolvable or deferred hostnames cannot become an unrestricted future connection capability by enforcing runtime SSRF validation fail-closed on every connection, while maintaining compatibility with offline configurations.
- P2: Extend SSRF enforcement to the core connection layer (_open_imap_connection, _send_smtp_message, _imap_connect) using ContextVar owner scoping, protecting pre-existing DB rows, restored configs, background pollers, and scheduled operations.
- P3: Allow admin and single-user access to IPv6 loopback (::1, [::1]) for local mail servers (e.g. Dovecot) by checking loopback before is_reserved, while keeping link-local, cloud metadata (169.254.169.254, 100.100.100.200), and non-admin restrictions strictly enforced.
- Add comprehensive regression and adversarial test coverage in tests/test_email_account_host_ssrf.py.

* fix(email): reject unresolved saved hosts without stdlib monkeypatches

Use the existing explicit policy IMAP/SMTP classes and canonical connect_outbound_tcp helper. Remove process-wide stdlib assignments, context-variable plumbing, redundant aliases and resolver-signature retries. Reject unsafe or unresolved hosts before account/config persistence, keep DNS work off the event loop, return fixed client errors, identify Alibaba metadata accurately and reject invalid TCP ports. Validation: 654 relevant email, URL-safety and CodeQL regression tests passed, 3 skipped. Three unrelated browser checks were excluded after environment failures (missing Playwright browser and Chromium timeout). Running-app checks verified rejected create/update/config requests leave stored data unchanged, administrator LAN configuration still works, and metadata/non-admin loopback are blocked.

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: PR #6029 Reviewer <reviewer@odysseus-review.local>
Co-authored-by: Afonso Junior <chatgpt@yack.com.br>
JGW3 and others added 20 commits November 3, 2026 00:27
* fix(ui): let confirm-dialog buttons grow to fit wrapped labels

The global `button { height:32px }` rule also applies to styledConfirm's
buttons. A label that wraps to two lines, such as "Delete chat and images",
"Launch anyway (CPU)" or a three-button dialog's alternate action, keeps
one line's height, so its second line renders below the button. On narrow
windows the dialog makes the buttons equal width, so this hits most
multi-word labels; it also happens on desktop, where the dialog box is
narrow too.

Give .styled-confirm-box .confirm-btn height:auto with min-height:32px.
Single-line buttons keep their current 32px.

Bumps the shared stylesheet/app cache token and the service worker cache
name, since a stylesheet changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(static): leave admin.js's cache tag unchanged

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cache): keep upstream's service worker cache name format

dev's editor tests require CACHE_NAME to match
odysseus-v<N>-pr40-editor-precache, so keep the version bump and use
that suffix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(skills): restore the source editor from test results

* fix(skills): align the chat link module version

* test: isolate photo routing from external MCP registry state
* fix(modals): keep restored settings and theme windows open

* fix(theme): cancel closing on a rapid toggle reopen

* test: isolate photo routing from external MCP registry state

* fix(cache): preserve the upstream editor worker key format
…(#6782)

* fix(ui): keep the confirm dialog's OK button in line with the others

#styled-confirm-ok was moved down 2px (position: relative; top: 2px), so
the OK button sat 2px below Cancel and the alternate button in every
styledConfirm dialog. Its label, and the alternate button's, now sit in a
span nudged the same way as the Cancel label, so the text keeps its place
and no button moves. Stylesheets and app.js get a new cache-bust token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ui): build confirm labels inline and share the Cancel nudge rule

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cache): keep upstream's service worker cache name format

dev's editor tests require CACHE_NAME to match
odysseus-v<N>-pr40-editor-precache, so keep the version bump and use
that suffix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…n (#6725) (#6726)

The recipe Run button sent repo_id "<backend> setup"; the space fails the
pip package-spec check, so every Run returned "Invalid pip package name".
It now sends "<backend>-setup".

The vLLM/SGLang recipes start with `uv pip install ... --torch-backend
auto`, but uv was not in the serve command allowlist. Allow uv only for
the `pip install` subcommand.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…columns

MultiModelThread/MultiModelMessage map the new multi-model conversation
feature (created via create_all). PlanStep gains doc_id/doc_action so the
document-aware step code can read them; an idempotent ALTER-on-startup
migration backfills those two columns for existing databases (create_all
only covers fresh ones).
Run one prompt across several models/endpoint URLs concurrently, with a
thread lifecycle manager (core/multi_model_manager.py), an async fan-out
executor (src/multi_model_executor.py), authenticated routes registered in
app.py, and a browser pane-sync UI under static/js/multiModel/. Sessions
list and stylesheet gain the multi-model thread affordances.
Plan steps can now target a document with a create/update/edit/suggest/read
verb. Adds the /steps/document endpoint and doc context in _step_dict
(plan_routes.py), a _execute_document_step branch in PlanExecutor, and the
docStepBuilder UI wired into the plans panel and progress tracker. Relies on
the PlanStep doc_id/doc_action columns from the schema commit.
Adds GET /morning (returns today's digest, generating it in the background
via morning_digest_service if absent) plus GET/PUT /config for the per-user
schedule, backed by new morning_digest_enabled/time/delivery settings
(delivery method opt-in, defaults to in-session).
Documents the Photoshop-class editor gaps, the documentary compiler reworked
as an episode Plan (shot = step) on Odysseus's existing substrate, and the
NLE as an editable timeline-of-data, under the zero-cost local-rendering
policy. Framed as subsections of Odysseus, not a standalone project.
Extends the existing keep-agent-memory-out policy (165ced3) to the
.agents/ design/task scratch so it can never be staged.
multiModel/* had zero inbound references, so its code never loaded. Import
it into app.js and expose it on window (mirroring compare/researchPanel) so
the module graph boots, and precache multiModel/index.js with a CACHE_NAME
bump (v348 -> v349). docStepBuilder needs no precache since its importer
plans-panel isn't precached. The tour-core cache test now asserts a minimum
version (>= 348) instead of pinning v348, so a legitimate future bump passes.

Note: this makes the modules loadable; a user-facing launch trigger
(compare-style mode + opening is_multi_model sessions) is still pending.
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

⚠️ PR description — action needed

The following required sections are missing or incomplete. Please update the PR description to address them:

  • Summary is empty or too short — describe what changed and why.
  • Linked Issue — add a reference like Fixes #NNN, a bare #NNN, or a link to the issue.
  • Type of Change — check at least one box.
  • Checklist — check the duplicate-search box to confirm you searched existing issues and PRs.
  • How to Test — explain how a reviewer can verify this change. Numbered steps, the commands you ran, or a short code block all work — give a sentence or two of real detail (not just "tested locally").

This comment is deleted automatically once all sections are complete.

onemorethan0 pushed a commit to onemorethan0/odysseus that referenced this pull request Nov 9, 2026
…ules

refactor(settings): move the shell out of settings.js into settings/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.