Commit Graph
47 Commits
Author SHA1 Message Date
0b140110d8 Make OpenAI-compat and Ollama engine streaming truly async (#626)
The OpenAI-compat and Ollama engines exposed stream()/stream_full() as async def but iterated a synchronous httpx.Client.iter_lines() internally, blocking the single event loop on every inter-token read (serializing concurrent chats; one wedged upstream read froze the whole API). Convert both to a shared AsyncHTTPEngineMixin using httpx.AsyncClient + aiter_lines() with a per-event-loop pooled client and the configured timeout applied; map mid-stream transport errors (RemoteProtocolError/ReadError) to EngineConnectionError via a deliberately narrow set that keeps CancelledError/GeneratorExit propagating; handle non-2xx explicitly (incl. 3xx and a typed EngineContextLengthError for context-window overflow 400s); switch litellm streaming to acompletion; and offload the blocking non-streaming handlers and websocket generate() to asyncio.to_thread. No public API change. Strong MockTransport-based tests, including a pin that the async path never touches the sync client. Complements #618.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 14:10:22 -07:00
928776a71c ci: enforce ruff format in CI, add Makefile matching the CI test lane (#625)
CI's lint job ran ruff check but never ruff format --check, letting format drift land silently (79 files had drifted from the pinned ruff 0.15.1). Add the ruff format --check step to ci.yml, reformat the 79 drifted files with the pinned ruff (mechanical only — verified AST-identical to before across all files, no logic changes), and add a Makefile whose test target mirrors the actual CI lane.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 14:49:18 -07:00
c686517cc7 Fix upcoming Google Calendar event retrieval (#617)
Closes #388. Parse Google Calendar all-day events from start.date instead of stamping them with the current time; treat generic next/upcoming calendar-event queries as gcalendar timeline requests that return nearest-future events first (UTC-normalized, instant-aware comparison that handles tz offsets and all-day events); and update the research planner guidance to route such queries with sources=[gcalendar] + a today-onward time_range. Real in-memory KnowledgeStore integration tests cover ordering, tz normalization, all-day inclusion, and source narrowing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 14:18:09 -07:00
Elliot SluskyandGitHub b70be55681 fix(openhands): handle none content in token estimates (#612)
Closes #607. Assistant tool-call turns can carry content=None, which crashed token estimation (len(m.content)) and think-tag stripping. Normalize with 'content or ""', route native OpenHands truncation through the shared estimate_prompt_tokens, and add tests for the estimator, the truncation helper, and an end-to-end tool-call run with None content.
2026-06-29 16:51:52 -07:00
945dabbce7 fix(channels): use conversation_id (not channel type) as Discord reply destination (#495)
Closes #459. Reported by @jasonftl with a precise smoking gun: incoming ChannelMessage has channel="discord" (TYPE label) and conversation_id=<numeric channel id>, but the reply code was using cm.channel as the destination — Discord saw /channels/discord/messages and 404'd silently, blackholing every reply.

The bug was two field-mappings in channel_agent.py:_process_message (the happy path + the exception path):

  self._channel.send(
      msg.channel,                          # WRONG — TYPE label
      reply,
      conversation_id=msg.conversation_id,  # WRONG — channel id used as msg-ref-id
  )

The existing DiscordChannel.send() contract — proved by the existing test_send_with_conversation_id test — is:
  - first positional `channel` = native destination ID (Discord channel id)
  - `conversation_id` kwarg = native message ID for reply threading

Fix: swap both fields to the correct ones from ChannelMessage:

  self._channel.send(
      msg.conversation_id,                  # Discord channel id
      reply,
      conversation_id=msg.message_id,       # message id for threading
  )

Plus a defensive guard in discord_channel.py: when channel is empty, refuse fast with a clear warning instead of POSTing to /channels//messages and silently 404'ing.

3 new tests, 38 affected pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-03 19:54:03 -07:00
53fb42104e feat(rlm): expose real tool calls inside the REPL (#481)
* rlm: expose real tool calls inside the repl

* rlm: wrap long TypeError message in repl

* style(rlm): collapse over-wrapped TypeError to satisfy ruff format

The cherry-picked RLM tool-call work left a `raise TypeError(\n message\n)`
that `ruff format --check` rejects (the PR's own lint-fix commit broke
format). Collapse to `raise TypeError(message)`. No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Eddie Richter <eddie.richter@amd.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 19:31:08 -07:00
Jon Saad-FalconandGitHub 3aa24b2709 Merge pull request #429 from open-jarvis/feat/opencode-agent
feat(agents): add OpenCodeAgent — run opencode on a local engine
2026-05-28 20:38:46 -07:00
krypticmouseandClaude Opus 4.7 00b85b71dd fix(agents): unwrap wrapped engines to derive opencode provider URL (+ clear guard)
The real `jarvis ask --agent opencode` path passes an InstrumentedEngine
(telemetry wrapper) whose underlying engine — and its `_host` — lives at
`_inner`. The base-URL derivation only checked the top object, so it returned
"", no provider was registered, and opencode 500'd on `openjarvis/<model>`.
Direct construction with a raw engine masked this; only the CLI path exposed
it.

- _derive_openai_base_url now unwraps up to 6 wrapper layers
  (`_inner`/`_engine`/`_wrapped`) to find `_host`/`base_url`.
- run() resolves the provider/model spec up front and, when it genuinely
  can't (no base URL + bare model name), returns a clear actionable error
  instead of letting opencode 500.

Tests: wrapper-unwrap derivation + unresolvable-provider guard. 20 passed,
ruff clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 01:10:25 +00:00
krypticmouseandClaude Opus 4.7 6a011b4abb fix(agents): deterministic opencode permissions + no workspace pollution
Two hardening fixes for headless use, found while verifying real runs:

- Permissions: opencode's interactive default *asks* before some actions (and
  `plan` asks before bash), which would block forever with no TTY. The agent
  now writes an explicit permission policy: `build` allows edit+bash, `plan`
  denies them (read-only), overridable via a `permission` kwarg. Verified: a
  bash task completes without hanging and plan mode refuses to create files.
- Config no longer written into the user's workspace. We now write provider +
  permission config to a private temp file referenced via `OPENCODE_CONFIG`
  (confirmed honored by opencode), keeping the workspace clean while opencode
  still operates there as cwd.

Tests updated to cover `_build_config` (provider presence, per-mode
permission, custom override, no-pollution). 18 passed, ruff clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 01:07:00 +00:00
krypticmouseandClaude Opus 4.7 20f90f3ca0 fix(agents): recover opencode tool-results from the full turn, not just the final message
A real-model E2E (Ollama qwen3:8b) exposed what unit tests with synthetic
parts missed: `POST /session/{id}/message` returns only the final assistant
message (text/reasoning), while ToolParts live in intermediate assistant
messages. The parser was reading the wrong message, so tool_results was always
empty even when opencode actually edited files.

- run(): after the prompt POST, GET /session/{id}/message and collect parts
  across the whole turn for tool extraction (content still comes from the
  final message). Verified against a live opencode session.
- _extract_tool_results: success now keys on opencode's state.status ==
  "completed" (states: completed | error | running | pending).
- Test now feeds the real full-turn message shape and asserts the write tool
  is recovered.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 00:56:36 +00:00
krypticmouseandClaude Opus 4.7 4fa9163ea9 feat(agents): add OpenCodeAgent — run the opencode coding agent on a local engine
Adds an `OpenCodeAgent` (registry key `opencode`) that delegates coding tasks
to opencode (https://opencode.ai, MIT) while keeping inference local-first:
OpenJarvis's engine backs opencode via an OpenAI-compatible provider.

How it works:
- Derives an OpenAI-compatible base URL from the engine (e.g. Ollama/vLLM at
  `<host>/v1`) and writes an `opencode.json` registering it as an
  `@ai-sdk/openai-compatible` provider (`openjarvis/<model>`).
- Spawns a headless `opencode serve` (loopback, random port), waits for
  `/global/health`, then drives a session: `POST /session` →
  `POST /session/{id}/message` with `model={providerID,modelID}` + agent
  (`build`/`plan`) → parses message `parts` (text → content, tool → tool_results)
  into an `AgentResult`. `close()` disposes the server.
- opencode is an external binary (not bundled); `run()` returns a clear,
  actionable error when it's missing, mirroring ClaudeCodeAgent's degradation.

Verified end-to-end against the real opencode binary wired to a stub
OpenAI-compatible engine: opencode called the local endpoint and the agent
parsed the response (content/finish/model) correctly. Unit tests cover part
parsing, base-URL derivation, provider-config writing (incl. merge), binary
detection, graceful degradation, and run() parsing with a mocked client — 15
passed, ruff clean. Registered via the standard try/except import in
agents/__init__.py; documented in docs/user-guide/agents.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 00:41:22 +00:00
Robby ManihaniandGitHub 26285e56fa fix(agents): wire continuous-agent Interact tab end-to-end + CLI workflow polish (#425) 2026-05-28 12:07:03 -07:00
krypticmouseandClaude Opus 4.7 4ece9a933e fix(agents): persistent agents honor SOUL.md / MEMORY.md / USER.md persona files (#376)
SystemPromptBuilder (which loads the SOUL/MEMORY/USER persona files) was wired
only into the one-shot `jarvis ask` path, so persistent agents run through
AgentExecutor ignored persona entirely. The naive "pass prompt_builder" fix is
insufficient: `prompt_builder` was dropped at every __init__ hop
(ToolUsingAgent never accepted/forwarded it), and monitor_operative/operative
assemble their own system prompt and never consult `_prompt_builder` — so they
would silently ignore it even if it arrived.

Fix:
- `SystemPromptBuilder.persona_sections()` returns just the SOUL/MEMORY/USER
  sections (no agent template), for agents that build their own prompt and want
  to *append* persona rather than have it replace their instructions.
- `BaseAgent._apply_persona()` appends persona to a self-assembled prompt
  (no-op without a builder or persona files).
- Thread `prompt_builder` through the __init__ chain: ToolUsingAgent now
  accepts and forwards it to BaseAgent; monitor_operative and operative forward
  it and call `_apply_persona()` on their assembled system prompt.
- AgentExecutor constructs a SystemPromptBuilder from config and passes it to
  any agent whose __init__ accepts it (same gating as session_store /
  memory_backend). Agents that override __init__ without forwarding (e.g.
  orchestrator) opt out automatically and keep their own machinery.

Specialized prompts are preserved — persona is appended, not substituted. The
one-shot path is unchanged.

Verified: persona_sections() excludes the template but build() still includes
both; monitor_operative/operative receive the builder through the chain and
their assembled prompt includes the SOUL content. New tests in
tests/agents/test_persona_persistent.py (11 passed; ruff clean).

Closes #376

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 17:21:43 +00:00
Robby ManihaniandGitHub 363bdbfa41 feat: Deep Research Granola integration + citation fixes (#366) 2026-05-20 15:56:42 -07:00
Robby ManihaniandGitHub 855ed51780 feat: Deep Research Slack integration (#365) 2026-05-20 12:02:05 -07:00
Robby ManihaniandGitHub 9af0dfe336 feat: Deep Research — personal deep research over Gmail with hybrid retrieval and agentic synthesis (#354) 2026-05-18 17:46:12 -07:00
Avanika NarayanandGitHub a3ba63d148 AI_stack_support: subprocess-based external framework harness (#311) 2026-05-05 13:37:33 -07:00
Andrew ParkandGitHub 28e913f706 fix(agents): bind built-in tools, live tool-call UI, Markdown streaming (#255) 2026-04-17 11:01:50 -07:00
Avanika NarayanandGitHub a3789212ec refactor: remove dead shims, stale files, and test duplication (#243) 2026-04-13 15:03:03 -07:00
Tanvir BhathalandGitHub 0e122cd776 DGX Spark Fix (#231) 2026-04-10 11:40:03 -07:00
Robby ManihaniandGitHub cef64450bd fix: inject default system prompt to ground locally-hosted models (#184)
Closes #164 — Qwen and other models with baked-in corporate identities
would claim to be cloud services when running locally. Adds a
configurable default_system_prompt to AgentConfig that is injected as a
fallback when no other system prompt is provided. The default tells the
model it is running locally through OpenJarvis. Users can override or
clear it via config.toml.
2026-04-03 21:59:33 -07:00
Jon Saad-FalconandClaude Opus 4.6 c5c420c1c7 fix: use UTC timestamps in digest tests for CI compatibility
Tests were storing digests with local time but get_today() filters
by UTC date, causing failures when local date != UTC date.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:57:51 -07:00
Jon Saad-FalconandGitHub a009646071 feat: Morning Digest with Voice Mode + unified OAuth + Apple connectors (#174) 2026-04-03 11:05:41 -07:00
krypticmouseandClaude Opus 4.6 caf0e59f16 fix: remove unused imports flagged by ruff across 5 files
Pre-existing lint errors that caused CI failures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 23:39:35 +00:00
Jon Saad-FalconandClaude Opus 4.6 1add224599 test: add 59 tests for system prompt, Slack messaging, and connector health
- test_deep_research_prompt.py (8 tests): date injection, time, day of week,
  dynamic generation, response types, tool descriptions, /no_think, Jarvis name
- test_slack_messaging.py (7 tests): connect with/without tokens, error state,
  disconnect, handler registration, send without token
- test_connector_health.py (44 tests): all 11 connectors instantiate, have
  required methods, report not-connected without creds, have metadata.
  Plus KnowledgeStore data presence checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 14:35:58 -07:00
Jon Saad-FalconandClaude Opus 4.6 869d9256fd fix: resolve all lint errors after merge with main
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:33:42 -07:00
Jon Saad-FalconandClaude Opus 4.6 bce8a2fe12 merge: resolve conflicts with main — keep both DeepResearch tools + MCP functions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:09:12 -07:00
Jon Saad-FalconandClaude Opus 4.6 7366681f62 feat: wire tools from agent config to executor via ToolRegistry
Resolve tool names from config["tools"] into actual tool instances
using ToolRegistry, inject runtime deps, and pass them to the agent
constructor instead of hardcoded tools=[].

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:32:57 -07:00
Jon Saad-FalconandClaude Sonnet 4.6 ccea853e5e feat: expand system_prompt_template with instruction on agent creation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 11:28:18 -07:00
Jon Saad-FalconandClaude Sonnet 4.6 a1626960c1 feat: rewrite DeepResearch system prompt, wire SQL + scan + think tools, increase max_turns to 8
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 18:32:25 -07:00
Jon Saad-FalconandClaude Opus 4.6 1358d946c1 merge: resolve conflicts with main (streaming + auto-recover)
Merge main into fix/ssrf-check, keeping both the auto-recover
logic for error-state agents and the async streaming support
for the send_message endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:29:33 -07:00
krypticmouseandClaude Sonnet 4.6 f0e51b524f feat: add integration test for ChannelAgent with DeepResearchAgent
Adds tests/agents/test_channel_agent_integration.py covering the full
stack from KnowledgeStore + IngestionPipeline through TwoStageRetriever,
KnowledgeSearchTool, and DeepResearchAgent into ChannelAgent/FakeChannel:
- test_quick_query_inline_response: asserts inline reply with meeting info
  and no openjarvis:// escalation link
- test_deep_query_escalation_link: asserts openjarvis:// link is present
  when engine issues a tool call and returns a long report

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 04:13:05 +00:00
krypticmouseandClaude Sonnet 4.6 7e127811c7 feat: add ChannelAgent with query classification and escalation
Adds classify_query() heuristic (quick vs deep) and ChannelAgent that
bridges BaseChannel messages to any agent, delivering inline replies for
quick/short responses and preview+openjarvis:// escalation links for deep
or long responses. 18 tests cover classifier cases and agent behaviour
including non-blocking handler and error recovery.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 04:10:12 +00:00
krypticmouseandClaude Sonnet 4.6 5cf2de5f74 feat: add end-to-end integration test for Deep Research pipeline
Tests the full path from multi-source Document ingestion through
IngestionPipeline -> KnowledgeStore -> TwoStageRetriever ->
KnowledgeSearchTool -> DeepResearchAgent to a cited report, and
verifies cross-platform retrieval returns results from >= 2 sources.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 03:11:53 +00:00
krypticmouseandClaude Opus 4.6 39a8117596 feat: add DeepResearchAgent with multi-hop retrieval and cited reports
Multi-hop research agent that uses native function calling (OpenAI
tool_calls format) to search personal data across sources via
KnowledgeSearchTool, cross-references results, and produces narrative
answers with inline source citations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 03:09:23 +00:00
Jon Saad-FalconandClaude Opus 4.6 9624f53c18 style: apply ruff format to changed files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:43:51 -07:00
Jon Saad-FalconandClaude Opus 4.6 7b5f078b4b test: add failing tests for agent config-based default resolution (issue #103)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:14:31 -07:00
Prathap PandGitHub c2756964a7 fix(channels): wire channel→agent handler and fix Telegram send pipeline (#94)
* fix(channels): wire channel→agent handler and fix Telegram send pipeline

* format code

* add supported tests
2026-03-20 18:35:18 -07:00
Jon Saad-Falcon 941016f255 feat: add 12 agent lifecycle scenario tests with real SQLite state 2026-03-16 20:46:18 -07:00
Jon Saad-Falcon a3f3f047da feat: add FakeEngine and scenario_harness fixture for agent lifecycle testing 2026-03-16 20:41:24 -07:00
Tarun SureshandClaude Opus 4.6 181d9ac0eb fix: resolve ruff I001 import sorting and E501 line length in tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 00:13:49 +00:00
Tarun SureshandClaude Opus 4.6 1359c223ec feat: wire SystemPromptBuilder into BaseAgent._build_messages()
Add optional prompt_builder parameter to BaseAgent. When provided,
_build_messages() uses builder.build() output instead of raw system_prompt.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 18:37:41 +00:00
Tarun SureshandClaude Opus 4.6 0d5be075f6 feat: add AgentExecutor.run_ephemeral() for one-shot agent turns
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 18:02:28 +00:00
Tarun SureshandClaude Opus 4.6 6371e7521d feat: add warn-before-block escalation to LoopGuard
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 18:01:13 +00:00
Jon Saad-FalconandGitHub 51a2b4cceb feat: operatives tab improvements — 9 UX/functionality fixes (#63) 2026-03-14 21:31:38 -07:00
34000aea01 fix(cli): support configured tool defaults and interactive confirmations (#56)
* feat: add interactive agent confirmation mode and fix tool loading

- Add `interactive` and `confirm_callback` params to ToolUsingAgent and
  NativeReActAgent so CLI sessions can prompt user before tool execution
- Fix tool resolution in `ask` and `chat` commands to fall back to
  config.tools.enabled when no --tools flag is provided
- Register shell_exec tool in tools/__init__.py auto-discovery
- Add dspy and gepa as optional learning extras (learning-dspy, learning-gepa)
- Fix openjarvis-rust lock version (1.0.0 → 0.1.0)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(cli): support configured tool defaults and confirmations

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 14:42:58 -07:00
Jon Saad-Falconandkrypticmouse 8798e2ee4f init commit 2026-03-12 17:29:39 +00:00