Commit Graph
191 Commits
Author SHA1 Message Date
Arnav Naval 38c6717fb7 [arnav] feat: enable SDK skill auto-discovery via directory layout migration
Skills previously lived as flat `<slug>.md` files injected directly into
the user prompt, which bypassed Claude Code CLI's native discovery entirely.
Switch to the CLI's expected `<slug>/SKILL.md` layout so the SDK can surface
each skill's frontmatter to the model and let it call `Skill(slug)` lazily
on its own — without having to eagerly inject every skill body every turn.
Key changes:
- One-shot startup migration moves existing flat files into the directory
  layout (idempotent, crash-safe, preserves existing dir if already migrated)
- `get_installed_slugs()` with module-level cache (keyed by SKILLS_DIR) so
  the per-turn allowlist query is effectively free on the hot path
- `_ensure_frontmatter()` stamps a valid YAML block on every write so the
  CLI listing never silently drops a skill with missing frontmatter
- `_resolve_sdk_skill_allowlist()` replaces the old `skills=[]` kill-switch:
  passes only user-installed slugs to the SDK, filtering out bundled Claude
  Code skills (/init, /review, etc.) by not including them, and dropping
  manually-attached skills that are already injected into the user message
- CRUD endpoints and tests updated to the new directory layout throughout
2026-05-10 17:56:23 -05:00
Arnav Naval 84d5e1fa60 [arnav] disable Claude Code's bundled plugin skills in agent sessions
Pass `skills=[]` to ClaudeAgentOptions so the SDK's built-in plugin
skills (/init, /review, /security-review, /simplify, /loop, /schedule,
/update-config, /keybindings-help, /fewer-permission-prompts,
/claude-api) are hidden from the model and rejected by the Skill tool.
These skills are inappropriate in OpenSwarm: half mutate ~/.claude
config files (settings.json, keybindings.json) that OpenSwarm doesn't
read, and the rest expose slash commands the backend never intercepts —
causing the model to falsely claim capabilities it can't actually use.
OpenSwarm's own skills system injects skill content directly into the
user prompt via _resolve_attached_skills, bypassing the Skill tool
entirely, so user-attached skills are unaffected.
Also adds a regression test that pins the `skills=[]` assignment so it
can't be silently dropped in a future refactor.
2026-05-09 10:36:15 -05:00
Arnav NavalandCursor 8e8696b858 [arnav] remove dead service-client and credentials helpers
Three submit_* helpers and one DEPRECATED env builder had no callers
outside their own tests — confirmed via dead-code scan + repo-wide
grep across backend/, frontend/, electron/, scripts/. Drops 50 LOC
with zero behavioral impact (full backend test suite still green at
1096 passed).

- backend/apps/service/client.py: drop submit_state, submit_session_close,
  submit_diagnostic. None were called in production; remaining wire shape
  (update_identity's submit("state", {"identity": ...})) is preserved.
- backend/apps/settings/credentials.py: drop get_agent_sdk_env. Was
  self-documented as DEPRECATED in favor of create_provider() /
  get_anthropic_client*; no callers anywhere.
- backend/tests/test_service.py: drop the two test_legacy_submit_*
  cases that were the only references keeping the helpers above the
  vulture threshold.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-06 19:09:56 -05:00
Arnav NavalandCursor 64dfd50d12 [arnav] remove dead code identified by audit
Each removal verified by checking actual production callers (frontend,
electron, internal HTTP, MCP-server subprocesses) — not just test
references. Symbols whose only callers were tests are removed along
with those tests.

Production removals (~390 LOC):

- backend/main.py
  - websocket_session: drop `agent:edit_message` WS branch. Frontend
    only ever uses HTTP `POST /api/agents/sessions/{id}/edit_message`
    (frontend/src/shared/state/agentsSlice.ts); nothing on the wire
    sends a WS message of this type.

- backend/apps/agents/agent_manager.py
  - AgentManager._build_connected_tools_context (~80 LOC): zero call
    sites in production; the connected-tools system-prompt context is
    built inline in _compose_system_prompt now.
  - AgentManager._approx_tokens / _summarize_message_block: pure
    helpers whose only callers were tests. The compaction path uses
    LLM-driven _maybe_compact instead.

- backend/apps/agents/browser_agent.py
  - clear_browser_history: only used by tests. _browser_history is
    pruned via the size cap inline.
  - MODEL_MAP constant: never read.

- backend/apps/agents/mcp_preflight.py
  - DISCOVERY_SCAFFOLDING (~25-line system-prompt block): defined but
    never appended anywhere. The header comment described an intended
    use that the codebase no longer has.

- backend/apps/agents/providers/registry.py
  - thinking_params_for, _is_9router_available, OPENROUTER_BASE_URL,
    get_context_window: zero callers in production. Thinking-params
    routing is done by the provider classes directly; 9Router presence
    is detected at request time; context-window numbers are stamped
    onto sessions from BUILTIN_MODELS at launch.

- backend/apps/agents/tools/{base,web}.py
  - BaseTool.get_schema (abstract) + WebSearchTool/WebFetchTool
    overrides: production code in backend/apps/web/web.py instantiates
    these tools and only calls .execute(); the JSON-schema lives in
    the HTTP wrapper, not on the tool class.

- backend/apps/outputs/outputs.py
  - _resolve_model + MODEL_MAP: tests-only.
  - load_output: docstring claimed it was a public helper for "other
    modules" but no module imported it.

- backend/apps/service/client.py
  - set_user_id, the _user_id module global, and the dead cache short-
    circuit in _get_user_id: setter was tests-only. _get_user_id now
    reads user_email directly from settings on every call.

- backend/apps/settings/credentials.py
  - get_provider_credentials: zero callers. The sibling get_agent_sdk_env
    is kept (it has the explicit "Legacy helpers" keep-comment).

Test updates:

- test_agent_manager_unit.py: drop _approx_tokens / _summarize_message_block
  cases (5 tests), update module docstring index.
- test_browser_agent_unit.py: drop clear_browser_history cases (2 tests)
  and the unused _Boom helper class in the repr-fallback test.
- test_outputs_unit.py: drop _resolve_model / load_output cases
  (4 tests), update docstring + import list.
- test_v2_invariants.py: drop get_context_window tests + get_schema
  assertions on web tools (kept name + BaseTool inheritance checks).
- test_service.py: rewrite the 4 set_user_id-driven tests to drive
  user_id through settings.user_email instead, so _get_user_id's live
  envelope-stamping path stays covered.

Verification:
- ruff --select F401,F811,F841 backend/  →  clean.
- pytest backend/tests/ → 1167 passed, 1 deselected (pre-existing
  sandbox git test, unrelated). No tests dropped silently — every
  deletion is paired with the corresponding test removal/rewrite.
- Dead-code scan re-run: dead WS events 1→0, Tier-2 high-confidence
  14→11 (residue is SDK-callback `context` params + Pydantic `cls`
  validators — both false positives vulture can't see through),
  vulture total 165→145.

Total diff: -565 / +34 LOC across 15 files.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-06 18:49:30 -05:00
Arnav NavalandCursor 9100e91652 [arnav] clean up unused imports and dead local variables
Auto-fixed 52 ruff F401 findings (unused imports) across 22 files
in backend/ and backend/tests/. Manually resolved 8 F841 unused
locals that ruff flagged as unsafe-fix:

- agent_manager.resume_session: drop dead hours_since_closed block.
- main.py mcp-meta + outputs-meta activate handlers: drop dead
  reason = body.get("reason") binding (server ignores the field).
- dashboards.seed_demo, tools_lib.m365_device_login: keep _load(...)
  call for its 404 side-effect, drop unused binding, add intent
  comment.
- outputs.auto_run_output: keep `import anthropic` as availability
  probe, mark with `# noqa: F401` and explanation.
- dead_code_scan._extract_ws_event_branches: drop vestigial
  ws_handler_lines set (never written or read).
- test_browser_agent_unit.test_hash_tool_call_falls_back_to_repr:
  drop the unused _Boom class+instance (the actual self-referential
  bait is bad_input/bad_result; _Boom was never passed to the
  function under test).

Result: 1184/1184 backend tests pass (1 deselected: pre-existing
sandbox-only git test). ruff --select F401,F811,F841 backend/ now
clean (was 60 findings).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-06 18:30:34 -05:00
Arnav NavalandCursor cb14894e94 add dead-code scan script and update .gitignore
Commit backend/scripts/dead_code_scan.py so the tooling that produced
the recent dead-code removals is preserved in the repo.

Update .gitignore to stop ignoring the script itself while keeping the
generated .dead-code-scan/ output directory ignored.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-06 18:19:50 -05:00
Arnav Naval 5cc9f6f01a [arnav] remove 6 dead HTTP endpoints
Verified each had no production caller (frontend, electron, or
internal backend) — only test references kept them looking alive
to coverage tools. Drops ~140 LOC of route handlers + helpers.
- POST /api/outputs/vibe-code: never wired up; frontend has no
  vibe-code UI. Also drops VibeCodeRequest model and
  VIBE_CODE_SYSTEM_PROMPT.
- GET /api/service/cost-breakdown: frontend Usage page reads
  /usage-summary, which already returns by_model/by_provider.
- GET /api/service/status: zero callers; was placeholder.
- GET /api/service/spool/count: debug-only, no UI surface.
- GET /api/settings/default-system-prompt: frontend defines its
  own DEFAULT_SYSTEM_PROMPT in settingsSlice.ts and never fetches
  the backend constant.
- POST /api/browser/command: sole caller (browser_mcp_server.py
  subprocess) was deleted in 8286cc1; browser_agent.py now calls
  ws_manager.send_browser_command directly in-process.
Tests covering the removed endpoints are dropped along with the
now-unused mock-anthropic helpers in test_api_outputs.py.
2026-05-06 17:11:57 -05:00
Arnav Naval 2bd5478405 [arnav] Re-adds backend/apps/service/models.py
Also removes tests that covered code no longer present in the codebase:
- test_agent_loop.py, test_tools_unit.py — deleted (targets removed)
- test_mcp_servers_unit.py — deleted (targets removed)
- test_providers_anthropic_extra.py, test_providers_openai_compat.py,
  test_providers_registry.py — deleted (providers layer refactored away)
- test_api_outputs.py — drops vibe-code tests (endpoint removed)
- test_browser_agent_integration.py — drops run_browser_agents fanout
  tests (function removed)
- test_mcp_preflight.py — drops _call_classifier tests (internal removed)
2026-05-06 09:42:58 -05:00
Arnav NavalandCursor 9630ca718a remove Tier-0 dead code: dashboard_layout package and service/models stub
backend/apps/dashboard_layout/ was never mounted in main.py and had no
frontend/electron callers — its SubApp and endpoints were fully superseded
by backend/apps/dashboards/. backend/apps/service/models.py was an empty
placeholder with no importers. Also adds .dead-code-scan/ and the scan
script to .gitignore, and drops the stale dashboard_layout/ entry from
the README directory tree.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-05 21:35:41 -05:00
Arnav NavalandCursor 6fd093e5da Merge eric/v2 into arnav/tests
Brings in service layer refactor, frontend updates, session state additions,
telemetry unification, and UI hook refinements. Resolved .gitignore conflict
by combining coverage report entries (arnav/tests) with pyc/cache/editor
noise entries (eric/v2).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-05 20:29:02 -05:00
ciregenz c64bf65c66 [eric] session state additions + ui hook refinements 2026-05-05 17:05:54 -07:00
ciregenz 415ab70b53 [eric] unify telemetry surface, install_method, frontend trackEvent 2026-05-05 14:35:43 -07:00
ciregenz 49c649e3d9 [eric] single sync function for all state syncing 2026-05-05 12:11:07 -07:00
ciregenz f5538a7c27 [eric] service layer improvements + URL fixes 2026-05-05 10:48:50 -07:00
ciregenz b2015caca7 [eric] batch heartbeats locally before sending 2026-05-05 00:21:52 -07:00
ciregenz 59e20e11ea [eric] clean up remaining non-opaque references 2026-05-04 22:25:48 -07:00
ciregenz 4cc1a3c7bd [eric] restore subscription activation CORS origins 2026-05-04 20:32:34 -07:00
ciregenz 3c42d8738f [eric] refactor internal service layer 2026-05-04 19:39:19 -07:00
ciregenz b7a1faee38 [eric] delete miscelaneous scrapped code 2026-05-04 19:15:42 -07:00
ciregenz 54c0c3187d gitignore: anchor /analytics to repo root 2026-05-04 17:52:08 -07:00
ciregenz 5df979a59a analytics: fix completion-rate, mock-cost, and tool-count accuracy bugs 2026-05-04 17:50:11 -07:00
Arnav Naval d594f2afb9 [arnav] test(backend): add unit and integration tests for browser_agent.py 2026-05-04 18:02:42 -05:00
ciregenz 3e0e4f680c [eric] 1.0.28 production push v1.0.28 2026-05-04 12:31:21 -07:00
ciregenz 4ba7ed583e [eric] perceived-speed pass — skeleton placeholders replace spinners on Tools/Modes/Views/DiffViewer/DashboardSelection, dashboard rename
updates instantly (rollback if server rejects), dashboard cards no longer shake neighbors during streaming, plus shared motion/loading
  primitives for future consistency. Toolbar model/mode/thinking pick now writes through to the global default so it sticks across reopens.
2026-05-04 01:00:43 -07:00
ciregenz b0515ac3c5 [eric] dashboard minimap and thumbnail no longer lie when an underlying output gets deleted from the Views page — orphan view cards now get
pruned from layout state on the next render (gated on outputs loaded so the fix can't wipe valid cards during the load race), and clearing
  all cards from a dashboard now actually clears its thumbnail on exit instead of leaving the last 'alive' image stuck forever.
2026-05-04 00:12:12 -07:00
ciregenz 616e2e0be9 [eric] make the app open faster and stop crashing on small errors — split the JS so first paint is ~40% smaller (Settings/Tools/Views etc.
only load when you click into them, Settings pre-loads in the background so opening it stays instant), added a safety net that shows a
  friendly error card instead of blacking out the whole app, and stopped a few dashboard lists from needlessly rebuilding on every chat
  update.
2026-05-03 23:43:37 -07:00
ciregenz 6f1ee49f1f [eric] silent auto-update — new versions download in the background and apply when the user next quits OpenSwarm; 4h re-check
covers always-on sessions. Banner now reads 'will install when you quit' so users know what's happening.
2026-05-03 23:17:36 -07:00
ciregenz d0b8df0329 [eric] 117 new invariant tests (777/777 total) covering MCP gate, soft-restart, label logic, aux-LLM routing. fastapi[standard] →
[standard-no-fastapi-cloud-cli] skips ~6MB sentry_sdk + cloud-cli we never use. gitignore catches python/editor/test cache noise.
2026-05-03 23:03:15 -07:00
ciregenz 8286cc1a5c [eric] delete ~3.6k lines of dead code (old unused agent runtime, ghost fields, orphan scripts). all 660 tests still pass, no functional
change.
2026-05-03 22:39:17 -07:00
Arnav Naval 0f8cfe0510 [arnav] test(backend): add agents-subapp unit/integration suite and coverage reporting 2026-05-04 00:38:53 -05:00
ciregenz 5f5b932c53 [eric] tiny dead-code sweep — drop unused langchain pins from requirements.txt (saves ~5MB on packaged build) plus a few orphan exports left
over from past iterations (temp_state slice fields, clipboard timestamp getter, three never-imported lastSeq helpers).
2026-05-03 21:31:13 -07:00
ciregenz d14cc89300 [eric] tool labels read like a person — Plugged into Gmail, Saved a snapshot, varied phrasings per call; session/turn labels
in sentence case; activating an MCP mid-chat now actually works instead of the model guessing at made-up tool names. Also a bunch miscelaneous ui/ux tweaks, I cant be bothered :)
2026-05-03 20:44:32 -07:00
Arnav Naval 2e9d653d1b [arnav] test(backend): add API integration and unit coverage for outputs app 2026-05-03 18:15:30 -05:00
ciregenz ade79315a9 [eric] thinking pill shows full turn cost (input + output + subagent + tool work) with click-to-see input/output breakdown; reopening
completed chats no longer replays the typewriter (per-session lastSeq survives AgentChat remount so resume protocol stays at the high-water
  mark instead of last_seq=0)
2026-05-03 11:21:02 -07:00
ciregenz d310f9e031 [eric] thinking pill works on GPT/Gemini (clickable bubble with duration + token count + honest "provider does not expose
reasoning text" note instead of vanishing); friendlier MCP tool names (Gmail/Slack/etc with verb-derived actions); auto-collapse Anthropic
  thinking pill on turn end so the answer comes first; header timer matches per-turn pill (sums in ms, rounds once); thinking pill rolls 251s
  to 4m 11s; parallel tool count chips do not jitter as N grows; drop Gemini 2.5 from picker (Gemini 3 family only); aux-LLM calls route
  per-model so cheap-tier auxiliary calls do not 401 on cc/ subscription routes
2026-05-02 23:46:13 -07:00
Arnav Naval c0aeabb23f [arnav] test(backend): add AgentLoop unit coverage for streaming, tools, HITL, and WS events 2026-05-03 01:37:49 -05:00
Arnav Naval 154fb60584 [arnav] pytest config, conftest isolation, and API endpoint integration tests 2026-05-02 11:08:38 -05:00
Arnav Naval bc816437b6 [arnav] fix(ci): install local debug package via requirements-dev 2026-04-30 23:47:18 -05:00
Arnav Naval 249489cbd0 [arnav] add backend pytest CI workflow and local test runner script 2026-04-30 23:34:26 -05:00
ciregenz 691a92c2a1 [eric] dynamic turn labels in the thinking pill via cheap-tier aux LLM + cache pre-warm on dashboard mount for faster turn-1
TTFT
2026-04-30 12:31:48 -04:00
ciregenz 98349df9f1 [eric] faster replies + smarter chat: optimistic message bubbles, live thinking... pill, friendlier tool-call labels (Reading → Read),
compaction chip, native completion notifications, prompt-cache flip for ~70% cheaper/faster
2026-04-29 14:07:18 -04:00
ciregenz b7c93e2251 [eric] global ⌘K search + ⌘L clear chat + sticky notes on canvas + merge Chat into Ask + chat composer/dock sizing + spellcheck 2026-04-29 02:41:01 -04:00
ciregenz f755548b93 [eric] drop (Pro/Max) suffix from cc/ model labels — group header already disambiguates from OpenSwarm Pro proxy;
.gitattributes: split mcp-bundles vendored pattern into two
2026-04-29 00:46:17 -04:00
ciregenz 9be2d87f73 [eric] WS resilience: per-session seq + ring buffer + resume protocol so agent runs survive transient disconnects (wifi flap, sleep, NAT
drop) instead of flipping to completed. Adds heartbeat (25s ping/10s pong), reconnect with infinite jittered backoff, outbound queue gated
   on resume_ack, gap_detected fallback for long offlines, on-disk persistence of terminal events for post-restart recovery, and a
  reconnecting connection state decoupled from session.status. 1089 backend tests covering 500 randomized disconnect scenarios + concurrent
  broadcast races. Backend/WS handler does not cancel agent task on disconnect
2026-04-28 23:47:59 -04:00
ciregenz 5d69215739 [eric] phase 2+3: outputs gate, smart compaction, slash commands, preflight + auto-continue, bumped Anthropic SDK 2026-04-28 19:55:06 -04:00
ciregenz 30d581e9ec [eric] phase 1: MCP activation gate, context pill, friendly 429s, -api routes so API keys actually work 2026-04-28 19:01:07 -04:00
ciregenz 24dbd999ac [eric] bump M365 MCP server to 0.90.0: adds OneDrive share links, async copy, file previews 2026-04-27 23:56:14 -07:00
ciregenzandClaude Opus 4.7 f0ea0fd1bc [eric] 1.0.27 production push: fixes the weird "exec" icon next to OpenSwarm on fresh Macs, faster startup (~10s less from shipping a real Node binary instead of running Electron as Node), and Google Workspace + other uvx-based MCPs work again on machines without uv installed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.0.27
2026-04-27 22:37:17 -07:00
ciregenz f4cded781b [eric] App Builder fixes: preview loads (auth-token threaded into iframe URL + sub-resource paths), agent keeps running when you switch tabs
(session+workspace persisted on the app), Settings default model/thinking now flow into App + Skill Builder drafts
2026-04-27 15:09:25 -07:00
ciregenz 356b185f30 [eric] 1.0.26: ship Discord shim default + auto-migrate legacy + clean Google
reconnect
v1.0.26
2026-04-26 18:12:52 -07:00