Commit Graph
65 Commits
Author SHA1 Message Date
Devika Verma 5aa27e2c76 Step 3b: web_search -> EGRESS + the 1.9 egress cards
web_search reclassified EGRESS (spec 2.2, decided 2026-08-12): the destination is
fixed (the configured provider) but the query is model-chosen free text - the same
outbound channel web_fetch's URL is. It ran completely ungated in every mode until
now; it gates like any egress from here on, which also puts it in front of the
Auto-Approve reviewer.

The egress approval cards (spec 1.9):
- web_fetch offers "Always allow <host> this session" -> ALWAYS_DOMAIN. Tool-wide
  "always" is gone from the card AND server-refused (_grant_offered): it would
  cover every future destination, and the live A/B showed exactly that (one click
  on a bbc.com card ran promptless fetches to hosts no card ever named).
- www. stripped at grant minting (allow_domain_for_session) - pure spelling only,
  never eTLD+1. The card button shows the exact spelling the grant mints.
- web_search offers "Always allow searches this session" -> ALWAYS_TOOL (tool-wide
  IS provider-wide for a fixed destination), with the card naming the LIVE
  destination: "Queries go to your configured search provider (currently: <name>)".
  Provider resolved when the card is raised (engine.approval_extras hook), not at
  session start.
- Provider-change invalidation: set_web_search clears the web_search session grant
  in every live engine when the provider actually changes - the grant was consent
  to a named destination.
- Auto-Approve fall-through cards hide every session "always" button: grants don't
  skip the reviewer there (1.5), and a button that lies is worse than none.
- scopeNote tells the truth for egress: "leaves this computer -> <host>" replaces
  "stays on this computer" on fetch/search cards.

Corpora gain web_search cases (benign 22 / dangerous 17 / injection 14), including
query-borne secret exfiltration and a planted search-the-credentials injection.

Tests: test_egress_and_overrides (EGRESS class, gating, www-strip, 1.5 in
Auto-Approve), test_approval_integrity (tool-wide refused for URL-carrying egress,
kept for web_search; provider-change invalidation), ApprovalCard.test.tsx (domain
button + www-strip, provider line, Auto-Approve hides always). Full suites pass;
the 22 pre-existing failures (Slack fake-gateway timeouts, a Windows file-lock
rename) fail identically on the pre-change tree.
2026-08-13 08:41:44 -07:00
Devika Verma c59c5deae1 Feature 4: reviewer metering - badge, mode-menu summary, durable stats
Spec 1.7: the cost of Auto-Approve is visible while it accrues, not
discovered later. This is also where "uses your session model" gets
communicated (picker copy decision A): as a real accruing number.

Audit store:
- New columns call_id / tokens_in / tokens_out, with an idempotent ALTER
  migration for existing databases. This also fixes a feature-1 gap found
  in the process: the engine passed call_id and token counts on reviewer
  rows but the fixed column set silently dropped them, which would have
  broken the shadow-eval join and made token metering impossible.
- reviewer_stats(session_id): SQL aggregation of reviewer_verdict (live)
  and reviewer_shadow rows into checks/allow/deny/unsure + token sums.
  Durable - survives restarts and engine rebuilds.

Server: GET /v1/sessions/{id}/reviewer-stats (same shape as /unattended).

GUI:
- Polled with the existing 4s per-session poller.
- Mode button gains the badge when the session is in auto-approve and has
  checks: "Auto-Approve . 12 checks".
- Mode menu gains the session summary line: "This session: 12 checks . 10
  cleared . 0 blocked . 2 asked you . ~1k tokens". Only the LIVE bucket
  surfaces in the composer; shadow counts are a Settings/analysis concern.

Verified live against the running sidecar: the store already held 9 real
verdicts from manual testing of the mode, the endpoint aggregates them,
and both badge and summary render with real data.

Tests: stats aggregation (per-stage, per-session isolation, token sums),
legacy-DB migration (old schema opens, migrates, and round-trips call_id),
and the endpoint's empty shape. 113 backend + 114 GUI green.
2026-08-12 17:40:51 -07:00
Devika Verma 29c9f2b4a8 Feature 3: reviewer deny card + one-shot "Allow anyway" (8.4)
A reviewer deny now renders as a proper card in the transcript - the FULL
reason (the agent only ever got the terse refusal) plus an "Allow anyway"
button - and clicking it mints a ONE-SHOT exact-action approval.

Engine:
- approve_action_once(tool, arguments): human-minted grant keyed on the
  exact tool + canonical (sort_keys) JSON arguments, consumed on first
  match. Checked in _authorize's needs_user branch AHEAD of the reviewer,
  so the approved re-proposal runs without a reviewer call or a card.
  Audited as allow_anyway_granted + auto_allowed.
- Deliberately narrow: a re-proposal with even slightly different
  arguments does not match and goes back through the normal flow, and the
  grant only applies where needs_user is true - it CANNOT unlock a hard
  deny (1.2), which is now a test.

Server: WS kind "allow_anyway" {name, arguments} -> engine.approve_action_
once, with input validation. The GUI follows up through the normal
user_message path with a visible "go ahead with it exactly as proposed"
message, so the retry is in the transcript, not magic.

GUI:
- tool items carry reviewerReason/allowAnyway (the event fields were
  already broadcast verbatim; updateLastTool now keeps them).
- StepRow renders the deny card: full reason, a note that the agent was
  told only THAT it was blocked (not why), and the button - which
  collapses into a confirmation after one click (no double-fire).
- SessionSocket.allowAnyway; App.allowAnyway = WS grant + canned retry
  message; onAllowAnyway threaded Transcript -> TurnGroup -> StepRow.

Tests: 4 engine (runs once without card/reviewer; consumed not standing;
different action never matches; hard deny stays denied) + 3 component
(card + reason + exact-args callback + one-shot button; no card on
ordinary denies; no button without the callback). 110 backend + 114 GUI
tests green.
2026-08-12 17:30:58 -07:00
Devika Verma 71c786ab45 Feature 2: settings pass - flag exposure, gated picker entry, toggles
The auto_approve flag (and its shadow sibling) become first-class settings
instead of hand-edited TOML, and the Auto-Approve mode entry appears in the
picker only when the flag is on.

Server:
- manager: auto_approve()/auto_approve_shadow() read prefs.json first,
  falling back to the config.toml value a power user may have set; both
  writers persist to prefs. Both stores are user-global, so a cloned repo
  still can't enable either (the 1.5 invariant, unchanged).
- get_settings() exposes both; POST /v1/settings/auto-approve and
  /auto-approve-shadow write them (same shape as context-bar).
- Session builds pass the prefs-backed values into build_engine via new
  optional auto_approve/auto_approve_shadow overrides (None = config value),
  so a Settings flip takes effect on the next session build with no restart.
  Scheduled runs keep reading config only - they are unattended, so the
  live reviewer can never fire there regardless.

GUI:
- Mode picker: the Auto-Approve entry is `gated` - shown when
  getSettings().auto_approve is true, fetched on menu open. A session
  already IN auto-approve always shows its own entry so the current mode
  stays legible even if the flag was later turned off. This replaces the
  TEST-ONLY unconditional entry.
- Settings: AutoApproveCard with the feature toggle and the nested shadow-
  evaluation toggle ("records what it would have decided next to your own
  choice - without changing anything").
- api.ts: ModelSettings.auto_approve/auto_approve_shadow + setters.

Verified live against the running sidecar: flag off hides the entry on an
interactive session, flag on shows it, the Settings toggles round-trip and
persist. tests/test_auto_approve_settings.py (6): defaults, REST round-
trip, restart persistence, config fallback, prefs-beats-config, and the
build_engine override. tsc clean; 111 GUI unit tests pass.
2026-08-12 17:25:12 -07:00
Devika Verma dd2090be5c Mode picker: drop the note machinery - Auto-Approve copy is two lines (A)
Owner call after seeing it rendered: the three-line entry read as a
paragraph in a list of two-liners. Decision A: fold the who-judges fact
into the description itself -

  Auto-Approve
  Your session model clears routine actions; doubtful ones still ask

- and let per-check cost surface in the 1.7 metering badge where it
actually accrues, instead of as picker text. This supersedes the copy
recorded in the previous commit.

The `note` field and its render block are removed as dead code; `caution`
(the Bypass warning triangle) stays. tsc clean.
2026-08-12 14:03:29 -07:00
Devika Verma 17cd6b281f Mode picker: caution icon on Bypass approvals; note line machinery
- Icon.tsx: "warning" caution triangle (24px grid, 1.7 stroke, Lucide-style
  rounded triangle + exclamation) matching the existing icon set.
- Composer.tsx: ModeOption extends Dropdown's Option with `caution` (warning
  triangle before the label, themed via text-warnInk so it follows
  light/dark) and `note` (a second, dimmer italic line under the
  description). Bypass approvals carries the caution icon.

The Auto-Approve picker entry itself remains unshipped until the settings
pass gates it on the server-exposed auto_approve flag; its copy is decided
(owner, 2026-08-12): description "A reviewer clears routine actions;
doubtful ones still ask", note "Uses your session model for judgement - one
extra model call per check".

tsc clean; 111 GUI unit tests pass; rendered live and verified (note line
under Auto-Approve, warnInk triangle on Bypass).
2026-08-12 13:51:32 -07:00
Devika Verma c958d6f262 Step 2: Auto-Approve mode - the reviewer, the hook, and the renames
The mode from ocw-context/docs/reviewed-auto-mode.md (rev. 4), v1 scope.

coworker/reviewer.py (new)
- The 8.3 prompt verbatim, cache-shaped: instructions + known world (folders
  and remotes only) + user-message history in the stable prefix; this turn's
  request and ONE action in the suffix.
- parse_verdict: any defect (empty, non-JSON, unknown verdict) -> unsure.
  There is no parse path that results in execution (8.5).
- Reviewer.review never raises: provider errors and timeouts -> unsure.
  Metering counters (checks / verdicts / tokens) for 1.7.
- AGENT_DENY_MESSAGE: the terse, non-diagnostic refusal the agent gets on a
  deny; the full reason goes to the user only (8.4 asymmetry).

coworker/engine.py
- Reviewer consulted ONLY when: attached, mode is AUTO_APPROVE, session
  explicitly attended (unset is_attended counts as NOT attended, so
  automations can never be reviewed), fewer than two denials this turn.
- Consulted ONLY on decisions the gate marked needs_user - hard denies
  never reach it, so it can only turn "ask" into "allow" (1.2).
- One action per request, fired concurrently for all of a turn's escalating
  calls before the sequential authorize loop (8.6): a verdict cannot land
  on the wrong action, and approval cards still reach the human one at a
  time in call order.
- allow -> runs, audited with the reason. deny -> blocked; user event
  carries the full reviewer reason + allow_anyway; agent message carries
  only AGENT_DENY_MESSAGE. unsure -> today's card.
- Reviewer sees the user's words only, extracted mechanically from
  role=user messages - never agent output, never tool results (4.4).

coworker/permissions.py
- Mode.AUTO renamed Mode.BYPASS_APPROVALS ("bypass-approvals"); legacy
  "auto" still parses via _missing_ so configs, saved sessions, and the
  golden decision table are untouched.
- Mode.AUTO_APPROVE ("auto-approve"): gate-identical to INTERACTIVE except
  session grants ("always allow this ...") no longer auto-allow - they
  route to the reviewer instead (1.5: out-of-band standing policy may skip
  the judge; an in-flow click may not). Config allowlists still skip.
- _domain_allowed(include_session=False) checks the user-settings list only.

coworker/config.py: auto_approve flag, off by default, _GLOBAL_ONLY (a
cloned repo cannot hand itself a looser reviewer). agent.py attaches the
Reviewer only when the flag is on; without it AUTO_APPROVE behaves exactly
like INTERACTIVE.

server/manager.py: autonomy audit ranks auto-approve above interactive
(turning the reviewer on IS raising autonomy) and below bypass.

GUI: mode picker label "Full access" -> "Bypass approvals" (wire value
"auto" kept). Verified live against the real sidecar; e2e spec updated;
tsc and all 111 GUI unit tests pass.

Tests: tests/test_auto_approve.py (33) - gate behaviour per mode, fail-
closed parsing, prompt shape, deny asymmetry, retry guard, attended
gating, hard-deny isolation, per-action verdict landing, and that the
reviewer never sees agent prose. Permission suites + golden table: 146
passing unchanged.
2026-08-12 12:42:17 -07:00
Rohit Prasad 7bcff0f88b Merge pull request #417 from coderdailyone/fix/stale-platform-paths
docs: fix stale platform/ paths in the GUI README
2026-08-07 20:36:44 -07:00
Rohit P f21c53dd29 Merge branch 'main' into feature/memory 2026-08-07 19:33:58 -07:00
Rohit P 53d5fc498f Merge branch 'main' into issue/ope-51-ask_user-upgrades 2026-08-01 09:45:03 -07:00
Devika Verma 70e4610a3e Add support for Skills (#391)
Global & per-workspace skill.
Per-persona skills will be improved later as we re-design that abstraction, as per roadmap.
2026-08-01 08:50:53 -07:00
coderdailyoneandClaude Fable 5 6356aa6cd0 docs: fix stale platform/ paths in the GUI README
The GUI README still described the pre-split monorepo layout: every command
cd'd into a platform/ directory that does not exist in this repository, so a
fresh contributor following it verbatim fails at the first step. The venv,
packaging scripts, and surfaces/gui all live at the repo root now — align the
commands and the server_bin() dev-fallback comment with the layout the root
README already documents.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 10:17:19 +01:00
Rohit C Prasad ae7256f6b9 Prepare app release 0.1.7: version bump 2026-07-30 13:29:07 -07:00
Rohit C Prasad 25dc283d9b fix: stop artifact walk entering OS app-data dirs; context bar off by default
The artifacts scan used rglob and filtered after descending, so a home directory
workspace walked into ~/Library and triggered the macOS App Data consent prompt on
every turn. Walk with pruning instead, and skip Library / AppData in search too.

The composer chip now shows the session total by default, with the context window
bar behind a Settings toggle.
2026-07-30 13:10:30 -07:00
Rohit C Prasad fe034c8b70 models: Kimi K3 via Together (1M window, vision); right-align the more/less toggle
Toggle also loses its underline.
2026-07-30 10:32:47 -07:00
Rohit C Prasad 1e819e0159 transcript: clamp long user messages with a more…/less… toggle
Pastes over 1200 chars collapse in the bubble; copy still gets the full text.
2026-07-30 10:25:32 -07:00
Rohit C Prasad f9f51c97c6 compaction: live progress signal + user-message cap
COMPACTING event drives a 'Compacting context…' transient in the GUI.
Cap the compacted block's user-message list at 40 with an honest omitted count.
2026-07-30 06:24:39 -07:00
Devika Verma 4fa8acffed compaction: Settings overrides + GUI divider (OPE-27 3/4)
Settings -> Models grows a Context compaction card next to Token savings:
the trigger % of the context window (10-95), the absolute token cap
(clamped 10k-2M), and the summarizer-model pin (default: the session's
own model). POST /v1/settings/compaction persists them; engines read the
knobs live per check, so changes apply to running sessions immediately.

The "context compacted" divider rides the existing notice machinery: the
persisted `compacted` notice replays on reload (itemsFromMessages) and
the live COMPACTED event appends the same info notice mid-turn. The
transcript itself stays intact - outbound-only by construction.

Covered by vitest (marker replay), a settings-card e2e (defaults +
clamped POSTs + model pin), and a mid-session divider e2e driven by the
fixtures' scripted `compacted` event.
2026-07-29 16:20:24 +05:30
Devika Verma 70cd1fa3d4 ask_user upgrades: rich options, grouped questions, option previews (OPE-51)
Options accept {label, description, recommended, preview} objects (plain
strings unchanged — old sessions render as today's pills), and `questions`
groups up to 4 questions into one call, rendered as a stepper via the
header chips. Any option preview switches the card to a two-pane layout:
options left, monospace pane right, following hover/focus.

Grouped calls resolve with a JSON map keyed by header-or-question and
return {answers: {...}} to the agent (single stays {answer: ...});
a grouped item's first question doubles as its title/options so channel
mirrors and legacy surfaces degrade sensibly. Channel buttons use option
labels; grouped items mirror as text with the open-the-app hint.
2026-07-29 15:52:05 +05:30
Devika Verma 964da79ad6 Merge branch 'main' of https://github.com/andrewyng/openworker into feature/memory 2026-07-29 12:04:52 +05:30
Rohit C Prasad 27311cd97f Usage popover: 'Uncached input' when a cache split exists
Input rows then read as components: uncached + cache reads + cache
writes = Total input; plain 'Input' stays for cacheless backends.
2026-07-28 11:48:21 -07:00
Rohit C Prasad d1524b3376 Usage popover: label rows as session totals
Section header 'Session totals' + pluralized cache rows make the
cumulative semantics explicit.
2026-07-28 11:42:44 -07:00
Rohit C Prasad a35b505659 Usage popover: add cumulative Total input row
Fresh + cache read + cache write — the session's billed input volume;
shown only when a cache split exists.
2026-07-28 11:39:15 -07:00
Rohit C Prasad 92c1833223 Usage popover: one field per line
Stacked label/value rows instead of the wrapped inline stats; values are
session sums per model (fresh input split from the cache rows).
2026-07-28 11:30:57 -07:00
Devika Verma ef59b0f39a Memory V1: remembered facts, your instructions, one screen
Coworkers remember durable things you tell them and use them in future sessions.
One Settings screen lists everything remembered - edit, delete, or stop new saves; standing instructions ride along.
Knowledge is session-stable, the save switch is per-message; sqlite gains a summary column via in-place migration.
2026-07-28 20:32:14 +05:30
Rohit C Prasad 7a108b25f9 Show per-session token usage in the composer
Quiet chip (context-fill meter + session total) opening a per-model
input/output/cache breakdown popover; accumulation from live events,
rebuilt from persisted sidecars on load; unit + e2e coverage.
2026-07-27 21:15:30 -07:00
Rohit C Prasad f281b29ff1 Provider auth redesign: joined segments, method panels, Vertex methods
Segmented track + inset per-method panel with its own Test & save footer.
Vertex gains the same treatment: Google Cloud login (default), service account,
and API key (express mode, Gemini-only with a clear error elsewhere).
2026-07-26 21:10:59 -07:00
Rohit C Prasad b3a2b130d2 Vendor Bedrock, Vertex, and OpenRouter brand marks
Same MIT lobe-icons set as the existing gallery logos.
2026-07-26 21:04:49 -07:00
Rohit C Prasad b719227a9a Bedrock settings: one auth method at a time
'Connect with' segmented choice (API key / profile / IAM keys) shows only that
method's fields; non-selected fields are dropped at build so stale values can't leak.
2026-07-25 22:55:28 -07:00
Rohit C Prasad 333f589c80 Support Bedrock API keys (bearer auth)
New optional field: paste the console-generated key, no CLI/IAM setup needed.
Takes precedence over SigV4 credentials, matching boto3; live-tested on Converse.
2026-07-25 21:58:24 -07:00
Rohit C Prasad 241af5e15f GUI: multi-field provider credentials and add-model family dropdown
Test button and saved pill follow the required-secret field (or the first field for
cloud providers); Bedrock/Vertex add-model rows get a family selector.
2026-07-25 16:22:27 -07:00
Rohit C Prasad ee495b9006 Add OpenRouter as an OpenAI-compatible reseller provider
Descriptor + curated matrix rows + sk-or- key auto-detect (server and GUI).
2026-07-25 16:07:33 -07:00
Rohit C Prasad fc6ce501dd Add Meta Model API provider with Muse Spark 1.1 2026-07-25 01:21:07 -07:00
Rohit P 7656952692 security: harden Slack approval handling 2026-07-24 22:33:13 -07:00
Rohit P ac83bc0490 security: complete local access protections 2026-07-24 18:44:39 -07:00
Rohit P 3f5ac872ca security: refine workspace trust controls 2026-07-24 18:44:39 -07:00
Rohit P 8ee0a0d082 security: strengthen session handling 2026-07-24 18:44:39 -07:00
Rohit C Prasad da1d25373c Prepare app release 0.1.6: version bump 2026-07-23 08:49:30 -07:00
Rohit C Prasad ba99978e03 Enable Claude extended thinking by default, drop the settings field
Fixed 8192 budget; the provider profile key stays a hidden override (0 = off).
Per-turn composer control is future work.
2026-07-23 07:57:04 -07:00
Rohit C Prasad 2968254713 Keep the BETA chip on the wordmark line
Smaller raised chip, nowrap on the wordmark — no second line under the traffic lights.
2026-07-23 07:50:27 -07:00
Rohit C Prasad a9458524e8 Blur-save non-secret provider fields on configured providers
The Test button was the form's only save path — extras like the thinking budget
silently never persisted. Blur saves with a Saved flash; empty clears.
2026-07-23 07:43:24 -07:00
Rohit C Prasad 3d00187310 Add BETA tag: sidebar wordmark, boot splash, onboarding, README
Quiet gray chip, presentation-only — never in bundle or artifact names (updater safety).
2026-07-23 07:43:24 -07:00
Rohit C Prasad f2b8fde428 Keep Retry offered across model switches
Switch notices no longer consume the retry guard or hide the button.
Error, switch model, Retry is the intended recovery path; retry runs on the new model.
2026-07-23 07:43:24 -07:00
Rohit C Prasad 52038c2136 Fix boot splash mark and stuck model picker on cold start
Splash shows the real 6-point OpenWorker star, not the 4-point sparkle glyph.
Settings reload after the health check lands, so the picker can't stay on Loading models.
2026-07-23 07:43:24 -07:00
Rohit C Prasad 2a2fffd280 Pause Google one-click connect pending CASA verification
Gmail/Calendar/Drive show a disabled Coming-soon button; the server refuses the flow too.
Manual token connect and already-connected accounts are untouched.
2026-07-23 07:43:24 -07:00
Rohit C Prasad 71b0df8ea2 Rename bot references from ocw to OpenWorker
Correlation token now emits [ow:id]; legacy [ocw:id] replies still parse.
Invite hints and docstrings say @OpenWorker.
2026-07-23 07:43:24 -07:00
Rohit C Prasad 5a61873ae0 Trim release UI: simpler Settings, mode menu, session subtitle
Mode menu offers Discuss/Ask for approval/Full access only.
Topbar subtitle is model-only and inert (persona page hidden this release).
2026-07-23 07:43:24 -07:00
Rohit C Prasad 0e8b85e6f3 Show reasoning traces: live Thinking block + persisted disclosure
New reasoning_delta event; traces persist as a display sidecar stripped from provider feeds.
Sources: compat vendors' reasoning_content and Gemini thought summaries (include_thoughts).
Live-verified on GLM via Together and Gemini 3; Gemini tool loops stay healthy.
2026-07-22 16:15:11 -07:00
Rohit C Prasad f1eb652d61 Allow mid-session model switching with a persisted transcript marker
Picker stays live for the session; switches persist a model_switch notice (§17 revised).
Rebinds refused mid-turn; images become placeholders for non-vision targets at send time.
2026-07-22 15:43:54 -07:00
Rohit C Prasad 878b858ece Persist error/interrupt markers in history; add Retry on failed turns
Engine appends a display-only notice message on error/interrupted; providers never see it.
New retry frame re-runs a failed turn with no new user message, guarded on the error tail.
GUI renders persisted notices on reload and a Retry button on the trailing error.
2026-07-22 13:45:43 -07:00