Repository navigation
test(harness): a CrewAI reference agent for the hosted path (TH-8811) - #311
khushalsonawat wants to merge 5 commits into
Conversation
A small support agent on CrewAI 1.15.33, the same desk as the other T43 references, written with CrewAI's chat surface: a standalone Agent whose kickoff_async takes the conversation, served through the kit's callback bridge. The Agent and its LLM are built per call, the LLM as CrewAI's native OpenAI-compatible client (custom_openai) pointed at the model gateway and held on chat completions; a model string such as openai/vertex_ai/... cannot carry the gateway URL and falls back to LiteLLM. CrewAI's telemetry and first-run tracing are turned off before CrewAI is imported, without disabling OpenTelemetry as a whole. Offline tests pin what the hosted path does with it, with a stand-in for CrewAI: it is detected as crewai; the build runs it through the callback bridge with the generic tool tracer (not the CrewAI observer, which the kit enables only for one-shot command agents); the real tracer bootstrap records each tool as CrewAI calls it; and the glue. Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
| # ones the kit's tool tracer is bound to. | ||
| # `custom_openai` keeps the model on the OpenAI-compatible chat-completions client with | ||
| # the name unchanged. A model string would be routed by its prefix, and | ||
| # `openai/vertex_ai/...` falls back to LiteLLM, which cannot take a gateway base URL. |
There was a problem hiding this comment.
P3. On CrewAI 1.15.33 this isn't what happens. LLM(model="openai/vertex_ai/gemini-3.7-flash", base_url=..., api_key=...) goes to the native OpenAICompletion with model vertex_ai/gemini-3.7-flash, the gateway URL and api="completions" (llm.py:512-523). LiteLLM is picked only when the URL comes from the environment alone.
custom_openai=True is still right, for a different reason: it stops CrewAI switching to the Responses API after a "responses-only" error (openai/completion.py:751). Reword this comment, the README line and the description to give that reason.
| ) | ||
|
|
||
|
|
||
| def _copy_example(destination: Path) -> Path: |
There was a problem hiding this comment.
P3. Same copied setup as the other reference-agent PRs (_copy_example, the stand-in writer, the fresh-import fixture, the detection tests, the build test skeleton, the tracer driver, the pin tests). See the shared-helper comment on #301: this file would import from that one module instead.
…eference Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
…s, and give the real reason for custom_openai (TH-8811) The test file uses tests/harness/reference_agents.py from #301 instead of its own copies. The agent's comment and the README say custom_openai stops CrewAI switching to the Responses API after a responses-only error, which the gateway can't serve; a plain openai/ model string with a base URL reaches the native client too. The README says agent-simulate is pinned for the kit's callback bridge. Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
…s API (TH-8811) Only a known OpenAI model name given with a base URL can switch; an unknown name with an explicit base URL already takes CrewAI's custom_openai route, and one whose URL comes only from the environment goes to LiteLLM. Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
| # bound to the loop they were first used in, so the model and the agent live for one | ||
| # call. `tool()` wraps here, not at import, so the module's functions stay the plain | ||
| # ones the kit's tool tracer is bound to. | ||
| # `custom_openai` keeps the name unchanged and stops CrewAI switching to the Responses |
There was a problem hiding this comment.
P3. The comment now gives only the Responses API reason and dropped the main one for this example's default model. vertex_ai/gemini-3.7-flash has no openai/ prefix and vertex_ai is not in CrewAI 1.15.33's PROVIDER_ALIASES (crewai/llm.py:211-229), so without custom_openai=True the name goes to LiteLLM whatever base_url says (llm.py:500-525), and LiteLLM isn't installed here, so LLM() fails.
Fix: add a clause, e.g. "and sends a non-openai/ name such as vertex_ai/... to the OpenAI-compatible client at all, where it would otherwise go to LiteLLM, which isn't installed". In the README narrow "an openai/ string whose URL comes only from the environment goes to LiteLLM" to "an openai/ name CrewAI doesn't know".
|
|
||
| # T1: detection ------------------------------------------------------------------------------ | ||
|
|
||
|
|
There was a problem hiding this comment.
P3. Moving to the shared helper weakened the shadow check: it now passes when CrewAI is still detected with a blocker (reference_agents.py:197, assert not (found == expected and blockers == frozenset())), where the old test asserted detect_framework(run) != CREWAI. The PR body says the tests are otherwise unchanged. Fix in the helper (see the comment on #301).
Summary
TH-8811 is part of T43: qualify the hosted harness across frameworks. This is CrewAI's offline half, on the same desk as #301, #304, #305 and #306. The real run comes later; the local end-to-end run of 12 Nov didn't include CrewAI.
examples/harness/crewai_support/uses CrewAI 1.15's own chat surface: a standaloneAgentwhosekickoff_async(messages)takes the conversation (the last user message is the request; earlier turns are history), served through the kit's callback bridge.Agentand itsLLMare built on each call, because CrewAI's agent keeps per-run state and the bridge serves requests on parallel threads.LLM(model=MODEL, custom_openai=True, base_url=OPENAI_BASE_URL, api_key=OPENAI_API_KEY), CrewAI's native OpenAI-compatible client on chat completions, with the model name unchanged.custom_openai=Truestops CrewAI switching to the Responses API after a "responses-only" error, which the gateway can't serve.CREWAI_DISABLE_TELEMETRY,CREWAI_TRACING_ENABLED=false).OTEL_SDK_DISABLEDis not used, because it would turn off all OpenTelemetry in the process.tool()per call.tests/harness/test_crewai_reference.pyuses a stand-in for CrewAI, since CrewAI isn't a kit dependency.crewai, with acrewai.pyshadow flipping it.ALK_CREWAI_TOOL_TRACE(see the known limits).No kit code changes.
Stacked on #301 (
feat/th-8800-openai-agents-reference): it uses #301's shared test helpers, so #301 merges first, with a merge commit.Review round 1 (Dileep)
tests/harness/reference_agents.py(from test(harness): an OpenAI Agents SDK reference agent for the hosted path (TH-8800) #301); the four detection tests are one parametrised test, and the 21 tests are otherwise unchanged.custom_openai=True.agent-simulateis pinned for the kit's callback bridge (fi.simulate.AgentInput).openai/strings was broader than CrewAI 1.15.33's routing). That sentence now says which names can switch to the Responses API, and a second fix-only check of that change was CLEAR, with no findings. Tests on Python 3.12.3: the CrewAI reference file and five neighbouring files, 322 passed; two planted bugs caught.Overlap
examples/harness/multi_agent_compatibility/crewai/(the CrewAI 1.6.1 multi-agent reference) is stale for CrewAI 1.15. Its string model"openai/vertex_ai/..."can't reach the gateway on 1.15, and itslitellm==1.101.0pin conflicts with 1.15's extra (<1.100.5). It's named here and not changed.Verification
ruff checkon the new filesuv run pytest -q: not run, because no shared runtime is touched.sdk-smokeruns a fixed list of test files, which didn't include this one. It now does (tests/harness/test_crewai_reference.py).str()differs from.raw) had a fix-only check: CLEAR, with one Low (a two-line comment), accepted. The audit fixes (this CI-list line, and this description) had a fix-only check as well: CLEAR, nothing above Low.custom_openaidropped;OTEL_SDK_DISABLED;agent-simulatedropped;crewai.pyshadow;kickoff.Known limits
"strict": true, and whether the model gateway's Gemini route accepts it is unverified until the real run.Checklist
agent_learning.*,agent-learn, or@future-agi/agent-learning-kit