Commit graph

39241 commits

Author SHA1 Message Date
Ishaan Jaffer
78c69ce273
feat(proxy): drive runs via litellm.managed_agents async task 2026-05-06 18:10:18 -07:00
Ishaan Jaffer
58840a1389
feat(proxy): add managed_agents_runner to drive queued runs in-process 2026-05-06 18:10:11 -07:00
Ishaan Jaffer
47415550ee
feat(managed_agents): expose AgentRuntime + ClaudeSDK + LiteLLM runtimes from agent_runtime package
The package __init__ now re-exports AgentRuntime/AgentConfig/SessionState
plus both runtime implementations (ClaudeSDKAgentRuntime and the new
LiteLLMAgentRuntime) so callers can do
'from litellm.managed_agents.agent_runtime import LiteLLMAgentRuntime'
without poking into submodules.

Required for the package-level __init__.py re-exports to resolve.
2026-05-06 18:04:35 -07:00
Ishaan Jaffer
5133953121
test(managed_agents): unwrap Prisma relation syntax in fake DB so create payloads land on FK columns
Real Prisma translates {agent: {connect: {id: X}}} into the underlying
agent_id FK column at write time. The in-memory FakePrismaClient we
share with the proxy tests stores the dict verbatim, so the agent_id
column was None on every row our managed_agents code wrote. Tests
asserting session.agent_id == 'agent_1' (and the same for session_id /
run_id) all failed at the same boundary.

Fix: wrap each table's create() in a small adapter that unwraps the
relation-syntax keys into bare FK columns before delegating. Local to
this test conftest so the change does not leak into the proxy tests
that re-use the same fake.
2026-05-06 18:04:07 -07:00
Ishaan Jaffer
6cb0475972
test(managed_agents): test_subclass_override.py from swarm 2026-05-06 18:02:42 -07:00
Ishaan Jaffer
2ecd15ac05
test(managed_agents): test_sandbox_local.py from swarm 2026-05-06 18:02:41 -07:00
Ishaan Jaffer
b4f3c5d2c9
test(managed_agents): test_session.py from swarm 2026-05-06 18:02:41 -07:00
Ishaan Jaffer
430d17e67d
test(managed_agents): test_agent.py from swarm 2026-05-06 18:02:41 -07:00
Ishaan Jaffer
5f85c4e83d
test(managed_agents): conftest.py from swarm 2026-05-06 18:02:41 -07:00
Ishaan Jaffer
229dbb19f0
test(managed_agents): mocked LiteLLMAgentRuntime tool loop 2026-05-06 18:02:07 -07:00
Ishaan Jaffer
d5cc949f47
test(managed_agents): real-Anthropic e2e for ClaudeSDKAgentRuntime + LocalSandbox 2026-05-06 18:01:47 -07:00
Ishaan Jaffer
6a0214a97b
feat(managed_agents): expose Agent/Session/Run/runtimes/sandboxes from package root
The package __init__ now re-exports the public surface so SDK callers
can do a single 'from litellm.managed_agents import Agent, Session, ...'
instead of digging into submodules.

Also pins what's public — anything not in __all__ is implementation
detail and may move.
2026-05-06 17:59:03 -07:00
Ishaan Jaffer
af0f76368e
feat(managed_agents): add Session class with send() that drives runs end-to-end
Session is the unit of work in the managed-agents API. send(prompt)
mirrors what the HTTP create_run + event_stream pair does on the proxy:

  1. INSERT LiteLLM_AgentRun (status=queued, prompt={text}).
  2. Flip session status ready -> busy and run status queued -> running.
  3. async for event in self.runtime.run(...) — persist each event to
     LiteLLM_AgentRunEvent and yield it back to the consumer.
  4. On exit (clean or error), set the run terminal status and restore
     session to ready in a finally block so a single failed send never
     locks the session forever.

Also adds get_run/list_runs/conversation read helpers — same wire shape
the corresponding HTTP endpoints serve.
2026-05-06 17:58:30 -07:00
Ishaan Jaffer
b700e2243e
feat(managed_agents): add Agent class for in-process session orchestration
Agent is the SDK-side handle for one LiteLLM_Agent row. It wraps:
  * the static agent definition (name, model, system_prompt, tools_config)
  * the AgentRuntime + Sandbox that spawned sessions will use
  * session lifecycle helpers (create_session, get_session, list_sessions,
    delete)

create_session inserts the LiteLLM_AgentSession row directly in 'ready'
status, mints a daemon JWT (same shape the proxy mints in /v2/sessions),
and returns a Session ready to send() prompts.

The HTTP /v2/sessions path uses 'provisioning' because it kicks off a
remote VM provider call; the managed_agents Python layer owns the sandbox
in-process and is ready immediately.
2026-05-06 17:58:23 -07:00
Ishaan Jaffer
330056eb9b
feat(managed_agents): add Run accessor for AgentRun rows and event streaming
Run is the read-only Python accessor for one LiteLLM_AgentRun row. It is
the SDK-side counterpart to GET /v2/sessions/{sid}/runs/{rid} and to the
SSE event stream.

Two entry points:
  * Run.from_db_row(row, db) — build from a Prisma row.
  * await run.stream(starting_seq=N) — async iterator over persisted
    events ordered by seq, paginated through the DB to bound memory on
    chatty runs.

Stream is snapshot-based; live tailing remains the SSE endpoint's job.
2026-05-06 17:55:31 -07:00
Ishaan Jaffer
0811302088
feat(managed_agents): add LiteLLMAgentRuntime for multi-provider tool loops
LiteLLMAgentRuntime drives a manual tool loop on top of litellm.acompletion
so the same managed agent can run against any provider that supports tool
calling (Anthropic, OpenAI, Gemini, Bedrock, etc.).

Unlike ClaudeSDKAgentRuntime, this runtime routes every tool call through
sandbox.execute_tool(), which means EC2SandboxViaSSM and any future
remote-execution sandbox actually get used.

Tools come from AgentConfig.tools_config (accepts both {tools: [...]} and
bare list shapes), with a sensible default that mirrors the LocalSandbox
surface (Bash/Read/Write/Edit/ls).
2026-05-06 17:55:27 -07:00
Ishaan Jaffer
86c73a1d2d
feat(managed_agents): add ClaudeSDKAgentRuntime wrapping claude-agent-sdk 2026-05-06 17:35:06 -07:00
Ishaan Jaffer
3590a1f5fc
feat(managed_agents): add AgentRuntime ABC plus AgentConfig and SessionState 2026-05-06 17:34:14 -07:00
Ishaan Jaffer
03ba743706
feat(managed_agents): expose Sandbox classes from sandbox/__init__ 2026-05-06 17:33:40 -07:00
Ishaan Jaffer
0a13083355
feat(managed_agents): add EC2SandboxViaSSM placeholder for follow-up wiring 2026-05-06 17:33:40 -07:00
Ishaan Jaffer
29e7afa1ca
feat(managed_agents): add LocalSandbox for in-process tool execution 2026-05-06 17:33:17 -07:00
Ishaan Jaffer
71bc4442ed
feat(managed_agents): add Sandbox ABC and ToolResult dataclass 2026-05-06 17:32:41 -07:00
Ishaan Jaffer
fbb7dbc6b2
feat(managed_agents): add Event dataclass and event type constants 2026-05-06 17:32:12 -07:00
Ishaan Jaffer
a31ab78bac
fix(agent-sdk): translate snake_case SSE wire shape and recognise run_finished/cancelled/error as terminal
Backend SSE frames are {seq, event_type, payload} but the SDK was
reading obj.type / obj.data without any snake-to-camel transform —
all events were being dropped. Apply the same snakeToCamel walk used
for JSON responses, then map event_type/payload to type/data so the
public RunEvent shape stays stable. Also extend the terminal-event
check so the stream returns on the actual backend terminal types
(run_finished | run_cancelled | run_error) instead of hanging until
the keep-alive timeout.
2026-05-06 17:15:30 -07:00
Ishaan Jaffer
2bf50108fe
fix(agent-sdk): wrap session.send body in {prompt: ...} to match RunCreate schema
Backend RunCreate expects {prompt: {...}} but the SDK was posting
{text, images} directly. Wrap the normalized payload accordingly so
session.send returns a real Run instead of 422.
2026-05-06 17:15:21 -07:00
Ishaan Jaffer
b0f21dd137
fix(agent-sdk): point createSession at /v2/sessions and pass agent_id in body
Backend exposes POST /v2/sessions (with agent_id in body) and
GET /v2/sessions; there is no /v2/agents/{id}/sessions route. Also
align getSession/listSessions to the same routes so SDK -> proxy
calls actually resolve. listSessions filters by agent_id via the
existing query param.
2026-05-06 17:15:15 -07:00
Ishaan Jaffer
18164dfb90
fix(internal_endpoints): use connect for run relation and wrap event payload in prisma.Json()
Daemon events:append was failing with MissingRequiredValueError because
the bare run_id FK and dict payload don't pass Prisma's input validation
on the LiteLLM_AgentRunEvent.create call.
2026-05-06 17:15:07 -07:00
Ishaan Jaffer
85bb7fec07
fix(run_endpoints): use connect for session relation and wrap prompt/payload in prisma.Json()
The Prisma generated client wants {"connect": {"id": ...}} for the
session relation and prisma.Json(...) wrapping for the prompt + event
payload Json columns.
2026-05-06 17:15:01 -07:00
Ishaan Jaffer
8b015ee223
fix(session_endpoints): use connect for agent relation and wrap repos/env_vars in prisma.Json()
The generated Prisma client requires {"connect": {"id": ...}} for
relation fields and prisma.Json(...) for Json columns. Bare agent_id
strings and bare dict/list values both raise MissingRequiredValueError
on session create.
2026-05-06 17:14:56 -07:00
Ishaan Jaffer
576f90d07e
fix(agent_endpoints): wrap optional Json columns in prisma.Json() and omit None values
Prisma rejects bare None / dict / list for optional Json columns with
MissingRequiredValueError. Wrap dict/list values in prisma.Json(...) and
drop the key entirely when the source is None so the column resolves to
SQL NULL.
2026-05-06 17:14:50 -07:00
Ishaan Jaffer
119db234e0
fix(warm_pool): import build_vm_provider directly (factory has no get_vm_provider alias) 2026-05-06 17:14:43 -07:00
Ishaan Jaffer
2e9421e9d9
fix(schema): restore LiteLLM_AgentVM table from B2 (lost during conflict resolution) 2026-05-06 17:11:55 -07:00
Ishaan Jaffer
c6ec1a8ec6
merge: integrate B0 (LIT-2888) — EC2 spike 2026-05-06 16:48:00 -07:00
Ishaan Jaffer
06d6073586
merge: integrate E (LIT-2881) — Admin UI three-pane dashboard 2026-05-06 16:47:59 -07:00
Ishaan Jaffer
84cfae0220
merge: integrate D (LIT-2880) — TS SDK with snake↔camel transform 2026-05-06 16:47:58 -07:00
Ishaan Jaffer
0e371e2fbb
merge: integrate B2 (LIT-2890) — warm pool + LiteLLM_AgentVM tracking
reconcile: schema dedup B2's LiteLLM_AgentVMConfig/Secret/Worker (already in HEAD from G) — keep G's versions and add B2's new LiteLLM_AgentVM table.
2026-05-06 16:47:41 -07:00
Ishaan Jaffer
6dccf40e0e
merge: integrate Epic B (LIT-2878) — vm_providers, sweepers, AMI
Reconciliation:
- adopt B's richer base.py types (ProvisionContext, VMHandle, AwsCreds,
  Ec2Config, ProvisionError) as canonical; keep A's NoopVMProvider alias
  and the registry helpers (register_vm_provider, reset_vm_provider_registry)
  for tests.
- rename B's factory entry point from get_vm_provider to build_vm_provider so
  it doesn't collide with the runtime registry's get_vm_provider(name).
- update A's session_endpoints._provision_in_background to construct a
  ProvisionContext and call provider.provision(ctx); pass team_id from
  the caller's API key.
- update _terminate_session_internal to construct a VMHandle when a vm_id
  is recorded on the session row.
- extend B's NoopProvider with provision_calls/terminate_calls recording for
  backward compat with A's tests; accept either VMHandle-style or legacy
  keyword-style terminate args.
- de-duplicate LiteLLM_AgentVMConfig from all 3 schema.prisma files —
  G's (LIT-2891) version wins; B's stub at the top is collapsed to a
  comment pointing to G's section.
- delete B's 20260506220000_add_agent_vm_config migration (collides with
  G's 20260506220000_add_cloud_agent_settings_tables which already creates
  the table).
- rewrite team_config.py to read G's per-field encrypted columns
  (aws_access_key_id_enc, aws_secret_access_key_enc, aws_region) instead
  of B's single-blob aws_creds_enc; rewrite test_team_config.py to match.
2026-05-06 16:31:37 -07:00
Ishaan Jaffer
8a0f4203e7
merge: integrate litellm_lit-2891-settings-ui-cloud-agents into cursor-sdk-integration
Resolved schema conflicts in schema.prisma, litellm/proxy/schema.prisma,
and litellm-proxy-extras/litellm_proxy_extras/schema.prisma by unioning
A's agent/session/run/event tables with G's VM config / secrets /
worker / pairing-token tables. Both sets of tables now coexist.
2026-05-06 16:16:03 -07:00
Ishaan Jaffer
92bc874efc
merge: integrate litellm_lit-2877-proxy-api-surface into cursor-sdk-integration 2026-05-06 16:12:56 -07:00
Ishaan Jaffer
1b0ca087d4
test(agent-sdk): cover snake_case <-> camelCase transform helpers
Round-trip + edge-case coverage: digits in keys (agent_v2_id), nested
objects, arrays of objects, top-level arrays, single-word key passthrough,
and primitive passthrough.
2026-05-06 16:10:50 -07:00
Ishaan Jaffer
fb05cf0200
test(agent-sdk): switch removed Run.conversation() test to session.conversation()
Also update the wait() test to expect the new 'finished' terminal status.
2026-05-06 16:10:44 -07:00
Ishaan Jaffer
290808fa64
test(agent-sdk): expect 'finished' instead of 'completed' for terminal RunStatus 2026-05-06 16:10:39 -07:00
Ishaan Jaffer
f68bd10230
test(agent-sdk): mirror backend snake_case wire format and new status enums in mock proxy
Mock proxy now serializes responses using snake_case keys (agent_id,
created_at, system_prompt, run_id, etc.) and reads request bodies as
snake_case so it matches the real backend that the SDK now talks to via
the new transform layer. Also update the status string literals to the
new SessionStatus and RunStatus values, and read the followup body as
{prompt: {text}}.
2026-05-06 16:10:35 -07:00
Ishaan Jaffer
b65d494c39
refactor(agent-sdk): drop Run.conversation() and update terminal states
There is no per-run conversation endpoint on the backend; conversation
history is session-scoped. Callers should use SessionHandle.conversation()
instead. Also update TERMINAL_STATES to the new RunStatus values
(finished/cancelled/error).
2026-05-06 16:10:28 -07:00
Ishaan Jaffer
3ffaad8b1a
fix(agent-sdk): send {prompt: {text}} as followup body to match backend FollowupCreate
The backend's followup endpoint expects a FollowupCreate payload with a
nested prompt object ({prompt: {text: ...}}), not a flat {message: ...}.
Public method signature followup(message: string) is unchanged - only
the wire body changes.
2026-05-06 16:10:22 -07:00
Ishaan Jaffer
68e58bf69b
feat(agent-sdk): add snake_case <-> camelCase transform layer to HTTP client
Backend speaks snake_case (Python idiom) while the SDK's public TS API
is camelCase. Add recursive snakeToCamel and camelToSnake helpers and
wire them into the HTTP layer so request bodies are camel->snake before
JSON.stringify and response JSON is snake->camel before being returned
to callers. Single-word keys like id/type/data/seq/status pass through
unchanged in both directions, and non-object values are not touched.
2026-05-06 16:10:16 -07:00
Ishaan Jaffer
595f660899
fix(agent-sdk): align SessionStatus and RunStatus enums with backend wire values
Backend (LIT-2890) emits provisioning/ready/busy/error/terminated for
session status and queued/running/finished/cancelled/error for run status.
Update the SDK type aliases so callers compare against the actual values
the proxy returns over the wire.
2026-05-06 16:10:10 -07:00
Ishaan Jaffer
ecf62c5fa8
test(cascade_delete): regression test for status-based cascade filter
Greptile P3 (regression coverage): the cascade filter in
delete_agent was changed from terminated_at is None to
status not in SESSION_TERMINAL_STATUSES in commit a0015e8564.
Add an explicit test that exercises the bug surface — a session
flipped to error (terminal) but with terminated_at deliberately
left None. The legacy filter would have re-terminated it; the
status-based filter must skip it.
2026-05-06 16:10:00 -07:00
Ishaan Jaffer
7561b4b9b8
test(warm-pool): real-cloud P95 latency gate (slow-marked, validation #2) 2026-05-06 16:05:04 -07:00
Ishaan Jaffer
371893df6d
test(warm-pool): unit tests for race-safe attach (concurrent CAS) 2026-05-06 16:05:04 -07:00