-
Notifications
You must be signed in to change notification settings - Fork 0
feat(AIC-3408): add Vercel AI SDK messages and agents adapters #103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0d0384d
e83fa11
a6bd910
c4ef4b8
46eb972
6a91a0f
89c52d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| """Framework-native graph runner using Vercel ``ai.Agent`` instances.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import json | ||
|
|
||
| from examples.tools import get_preferences, web_search | ||
| from examples.utils import new_context, write_output | ||
| from launchdarkly_ai_server import resolve_graph | ||
| from launchdarkly_ai_vercel_agents import to_vercel_agents | ||
|
|
||
|
|
||
| async def run(key: str, user_input: str) -> None: | ||
| context = new_context() | ||
| response = await to_vercel_agents( | ||
| resolve_graph(key, context=context), | ||
| { | ||
| "context": context, | ||
| "tool_handlers": { | ||
| "user-preferences-lookup": get_preferences, | ||
| "web-search-tool": web_search, | ||
| }, | ||
| }, | ||
| ).invoke(user_input, {"user_id": "user-123"}) | ||
|
|
||
| print(json.dumps(response, indent=2, default=str)) | ||
| write_output(response) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| """Run the wildcard native Vercel AI SDK agents adapter.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import json | ||
|
|
||
| from examples.tools import ( | ||
| fetch_launchdarkly_documentation, | ||
| get_preferences, | ||
| search_ld_documentation, | ||
| web_search, | ||
| ) | ||
| from examples.utils import new_context, write_output | ||
| from launchdarkly_ai_vercel_agents import vercel_agents | ||
|
|
||
|
|
||
| async def run(key: str, user_input: str) -> None: | ||
| response = await vercel_agents( | ||
| key, | ||
| user_input, | ||
| new_context(), | ||
| tool_handlers={ | ||
| "get-user-preferences": get_preferences, | ||
| "search-ld-documentation": search_ld_documentation, | ||
| "fetch-ld-documentation": fetch_launchdarkly_documentation, | ||
| "fetch-launchdarkly-documentation": fetch_launchdarkly_documentation, | ||
| "web-search": web_search, | ||
| }, | ||
| ) | ||
| print(json.dumps(response, indent=2, default=str)) | ||
| write_output(response) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| """Inject a constructed OpenAI model so the Vercel adapter skips AI Gateway. | ||
|
|
||
| Usage (via main.py): | ||
| python main.py vercel-direct launch-darkly-documentation-summarizer-messages-openai "What is the LaunchDarkly AI SDK?" | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import json | ||
|
|
||
| import ai | ||
|
|
||
| from examples.utils import new_context, write_output | ||
| from launchdarkly_ai_server import AiConfigRep | ||
| from launchdarkly_ai_vercel_messages import vercel_messages | ||
|
|
||
|
|
||
| def openai_model(config: AiConfigRep) -> ai.Model: | ||
| return ai.Model(id=str(config["model"]["name"]), provider=ai.get_provider("openai")) | ||
|
|
||
|
|
||
| async def run(key: str, user_input: str) -> None: | ||
| response = await vercel_messages( | ||
| key, | ||
| user_input, | ||
| new_context(), | ||
| model=openai_model, | ||
| variables={"user_input": user_input}, | ||
| ) | ||
| print(json.dumps(response, indent=2, default=str)) | ||
| write_output(response) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| """Run the wildcard Vercel AI SDK messages adapter.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import json | ||
|
|
||
| from examples.tools import ( | ||
| fetch_launchdarkly_documentation, | ||
| get_preferences, | ||
| search_ld_documentation, | ||
| web_search, | ||
| ) | ||
| from examples.utils import new_context, write_output | ||
| from launchdarkly_ai_vercel_messages import vercel_messages | ||
|
|
||
|
|
||
| async def run(key: str, user_input: str) -> None: | ||
| response = await vercel_messages( | ||
| key, | ||
| user_input, | ||
| new_context(), | ||
| tool_handlers={ | ||
| "get-user-preferences": get_preferences, | ||
| "search-ld-documentation": search_ld_documentation, | ||
| "fetch-ld-documentation": fetch_launchdarkly_documentation, | ||
| "fetch-launchdarkly-documentation": fetch_launchdarkly_documentation, | ||
| "web-search": web_search, | ||
| }, | ||
| variables={"user_input": user_input}, | ||
| ) | ||
| print(json.dumps(response, indent=2, default=str)) | ||
| write_output(response) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # `launchdarkly-ai-vercel-agents` | ||
|
|
||
| Wildcard LaunchDarkly AI agent handler built on the official Vercel `ai.Agent` | ||
| runtime for Python. | ||
|
|
||
| ## Install | ||
|
|
||
| ```bash | ||
| pip install launchdarkly-ai-server launchdarkly-server-sdk launchdarkly-ai-vercel-agents | ||
| ``` | ||
|
|
||
| Default routing is AI Gateway via a mapped `creator/model` id (for example, | ||
| `xAI` + `grok-4.5` becomes `spacexai/grok-4.5`). Already-qualified ids remain | ||
| unchanged. Set `AI_GATEWAY_API_KEY` or Vercel OIDC. This package does not load a provider SDK from | ||
| `config.provider.name`. Inject a model or model factory to call a provider | ||
| directly. | ||
|
|
||
| All LaunchDarkly providers are handled explicitly. Anthropic, OpenAI, Azure, | ||
| Gemini, Cohere, DeepSeek, Meta, Mistral, Perplexity, and Vertex map directly. | ||
| Bedrock, Cortex, Cursor, Databricks, and Fireworks AI infer the creator from the | ||
| model and fail locally if ambiguous. AI21 Labs and IBM Watson fail locally | ||
| because Vercel's current catalog has no corresponding creator. | ||
|
|
||
| ## Use | ||
|
|
||
| ```python | ||
| from launchdarkly_ai_server import config | ||
| from launchdarkly_ai_vercel_agents import create_vercel_agents_handler | ||
|
|
||
| result = await config( | ||
| key="my-agent-config", | ||
| handler=create_vercel_agents_handler(), | ||
| ).invoke("Help me", {"kind": "user", "key": "user-123"}) | ||
| ``` | ||
|
|
||
| The package also exports `vercel_graph()` and `to_vercel_agents()` for | ||
| LaunchDarkly and framework-native graph execution. The native adapter builds one | ||
| `ai.Agent` per graph node and follows only a `transfer_to_<target>` tool that the | ||
| current node actually selects. | ||
|
|
||
| This package advertises `("*", "agent")`; register only one wildcard agent | ||
| adapter in a handler pool. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # Agent Guide — Vercel Agents | ||
|
|
||
| This Tier 1 package provides the wildcard `("*", "agent")` handler. | ||
|
|
||
| - Default models use a mapped Gateway `creator/model` id. Preserve | ||
| slash-qualified ids, map `xAI` to `spacexai`, and split recognized LD dotted | ||
| creator prefixes once. Injected models are the only Gateway opt-out. | ||
| - `handler.py` constructs the native `ai.Agent` and maps models, messages, | ||
| `AgentTool`/`Tool`/`ToolSpec`, request parameters, streams, usage, and spans. | ||
| - `graph.py` pre-wires exactly one Vercel handler into the core graph API. | ||
| - `native_graph.py` creates one native agent per node. Handoff tools only select | ||
| a target; execution follows the selected target after the current run ends. | ||
| - Root caller history is never replayed into child nodes. | ||
| - Native graph spans end in `finally`, including `CancelledError`. | ||
| - Runtime calls are always async context-managed and never enable duplicate | ||
| runtime telemetry. | ||
|
|
||
| `TESTING.md` §2.x and Appendix A.14 are authoritative. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| [project] | ||
| name = "launchdarkly-ai-vercel-agents" | ||
| version = "0.1.0" | ||
| requires-python = ">=3.12" | ||
| dependencies = [ | ||
| "launchdarkly-ai-server", | ||
| "opentelemetry-api>=1.25", | ||
| "ai>=0.7", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| ] | ||
| description = "Vercel AI SDK agent handler for LaunchDarkly AI SDK" | ||
| readme = "README.md" | ||
| license = "Apache-2.0" | ||
| authors = [{name = "LaunchDarkly", email = "team@launchdarkly.com"}] | ||
| keywords = ["launchdarkly", "ai", "vercel", "agents"] | ||
|
|
||
| [build-system] | ||
| requires = ["hatchling>=1.32,<2"] | ||
| build-backend = "hatchling.build" | ||
|
|
||
| [tool.hatch.build.targets.wheel] | ||
| packages = ["src/launchdarkly_ai_vercel_agents"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| """LaunchDarkly AI SDK integration for native Vercel AI SDK agents.""" | ||
|
|
||
| __version__ = "0.1.0" # x-release-please-version | ||
|
|
||
| from launchdarkly_ai_server import register_ai_sdk_package | ||
|
|
||
| from .graph import vercel_graph | ||
| from .handler import create_vercel_agents_handler, vercel_agents | ||
| from .native_graph import to_vercel_agents | ||
|
|
||
| __all__ = [ | ||
| "create_vercel_agents_handler", | ||
| "to_vercel_agents", | ||
| "vercel_agents", | ||
| "vercel_graph", | ||
| ] | ||
|
|
||
| register_ai_sdk_package("launchdarkly-ai-vercel-agents", __version__) |
Uh oh!
There was an error while loading. Please reload this page.