llama-agents-agentcore 0.4.15__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.3
2
+ Name: llama-agents-agentcore
3
+ Version: 0.4.15
4
+ Summary: LlamaAgents x Bedrock AgentCore deployment utilities
5
+ Requires-Dist: bedrock-agentcore>=1.2.0
6
+ Requires-Dist: llama-deploy-core>=0.4.15,<0.5.0
7
+ Requires-Dist: llama-deploy-appserver>=0.4.15,<0.5.0
8
+ Requires-Dist: click>=8.3.1
9
+ Requires-Python: >=3.10, <4
10
+ Description-Content-Type: text/markdown
11
+
12
+ # LlamaAgents AgentCore
13
+
14
+ LlamaAgents x Bedrock AgentCore deployment utilities.
15
+
16
+ ## Usage
17
+
18
+ ```bash
19
+ llamactl agentcore run # runs the server locally
20
+ llamactl agentcore export # exports code to a .agentcore/ directory
21
+ ```
@@ -0,0 +1,10 @@
1
+ # LlamaAgents AgentCore
2
+
3
+ LlamaAgents x Bedrock AgentCore deployment utilities.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ llamactl agentcore run # runs the server locally
9
+ llamactl agentcore export # exports code to a .agentcore/ directory
10
+ ```
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.10.8,<0.11"]
3
+ build-backend = "uv_build"
4
+
5
+ [dependency-groups]
6
+ dev = [
7
+ "pytest>=8.4.2",
8
+ "pytest-asyncio>=0.25.3",
9
+ "ruff>=0.15.0",
10
+ "ty>=0.0.15"
11
+ ]
12
+
13
+ [project]
14
+ name = "llama-agents-agentcore"
15
+ version = "0.4.15"
16
+ description = "LlamaAgents x Bedrock AgentCore deployment utilities"
17
+ readme = "README.md"
18
+ requires-python = ">=3.10,<4"
19
+ dependencies = [
20
+ "bedrock-agentcore>=1.2.0",
21
+ "llama-deploy-core>=0.4.15,<0.5.0",
22
+ "llama-deploy-appserver>=0.4.15,<0.5.0",
23
+ "click>=8.3.1"
24
+ ]
25
+
26
+ [tool.uv.build-backend]
27
+ module-name = "llama_agents.agentcore"
28
+
29
+ [tool.uv.sources]
30
+ llama-deploy-core = {workspace = true}
31
+ llama-deploy-appserver = {workspace = true}
@@ -0,0 +1,134 @@
1
+ # SPDX-License-Identifier: MIT
2
+ """
3
+ AgentCore entrypoint for LlamaIndex Workflows.
4
+ Auto-generated by LlamaCloud — wraps workflows for AWS Bedrock AgentCore Runtime.
5
+
6
+ Uses BedrockAgentCoreApp with @app.entrypoint decorator for native AgentCore integration.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import functools
12
+ import logging
13
+ from pathlib import Path
14
+ from typing import Any, Literal, cast
15
+
16
+ from bedrock_agentcore import BedrockAgentCoreApp
17
+ from llama_deploy.appserver.workflow_loader import load_workflows
18
+ from llama_deploy.core.deployment_config import (
19
+ read_deployment_config_from_git_root_or_cwd,
20
+ )
21
+ from pydantic import BaseModel, ValidationError
22
+ from workflows import Workflow
23
+ from workflows.context.serializers import JsonSerializer
24
+ from workflows.events import StartEvent
25
+
26
+ logger = logging.getLogger(__name__)
27
+ app = BedrockAgentCoreApp()
28
+
29
+
30
+ class WorkflowResult(BaseModel):
31
+ workflow: str
32
+ status: Literal["completed", "failed"]
33
+ result: str | None = None
34
+ error: str | None = None
35
+ session_id: str | None = None
36
+
37
+
38
+ @functools.lru_cache(maxsize=1)
39
+ def _load_workflows() -> tuple[dict[str, Workflow], str, str | None]:
40
+ config_dir = Path.cwd()
41
+ if not (config_dir / "pyproject.toml").exists():
42
+ raise FileNotFoundError(
43
+ "No pyproject.toml found at "
44
+ f"{config_dir}.\n"
45
+ "Add a pyproject.toml to your project and re-run."
46
+ )
47
+ config = read_deployment_config_from_git_root_or_cwd(
48
+ Path.cwd(), config_dir
49
+ ) # let errors bubble up if misconfigured
50
+ workflows = load_workflows(config)
51
+ has_default = any(key == "default" for key in list(workflows.keys()))
52
+ default_workflow = "default" if has_default else next(iter(workflows))
53
+ file_workflow = None
54
+ for name, wf in workflows.items():
55
+ if wf.start_event_class.__name__ == "FileEvent":
56
+ file_workflow = name
57
+ break
58
+ return workflows, default_workflow, file_workflow
59
+
60
+
61
+ async def _run_workflow(
62
+ workflow_name: str, wf: Workflow, start_event: StartEvent
63
+ ) -> WorkflowResult:
64
+ """Run a workflow by name with the given event data."""
65
+ try:
66
+ handler = wf.run(start_event=start_event)
67
+ result = await handler
68
+ except Exception as e:
69
+ logger.error("Workflow '%s' failed: %s", workflow_name, e, exc_info=True)
70
+ return WorkflowResult(
71
+ workflow=workflow_name, error=f"Workflow failed: {e}", status="failed"
72
+ )
73
+
74
+ return WorkflowResult(
75
+ workflow=workflow_name,
76
+ status="completed",
77
+ result=JsonSerializer().serialize(result),
78
+ )
79
+
80
+
81
+ def _parse_and_validate_payload(
82
+ workflows: dict[str, Any],
83
+ default_workflow: str,
84
+ file_workflow: str | None,
85
+ payload: dict,
86
+ ) -> tuple[str, Workflow, StartEvent] | tuple[str, str]:
87
+ """Parse incoming payload to determine workflow and event data.
88
+
89
+ Supports:
90
+ - Explicit: {"workflow": "process-file", "start_event": {"file_id": "123"}}
91
+ - Shorthand: {"file_id": "123"} -> routes to process-file workflow
92
+ - Default: {} -> routes to default workflow
93
+ """
94
+ workflow_name = payload.get("workflow")
95
+ event_data = payload.get("start_event", {})
96
+
97
+ if not workflow_name:
98
+ if "file_id" in payload and file_workflow is not None:
99
+ workflow_name = file_workflow
100
+ event_data = {"file_id": payload["file_id"]}
101
+ else:
102
+ workflow_name = default_workflow
103
+ if workflow_name not in workflows:
104
+ return workflow_name, f"Workflow not found: {workflow_name}"
105
+ wf = workflows[workflow_name]
106
+ start_cls = wf.start_event_class
107
+ try:
108
+ data = start_cls.model_validate(event_data)
109
+ except ValidationError as e:
110
+ return workflow_name, f"Invalid input data: {e}"
111
+ return workflow_name, wf, data
112
+
113
+
114
+ @app.entrypoint
115
+ async def invoke(payload: dict, context: Any) -> dict[str, Any]:
116
+ """Main AgentCore entrypoint — routes to appropriate workflow."""
117
+ workflows, default_workflow, file_workflow = _load_workflows()
118
+ parsed = _parse_and_validate_payload(
119
+ workflows, default_workflow, file_workflow, payload
120
+ )
121
+ if len(parsed) == 2 and all(isinstance(p, str) for p in parsed):
122
+ workflow_name, error = cast(tuple[str, str], parsed)
123
+ return WorkflowResult(
124
+ workflow=workflow_name,
125
+ error=error,
126
+ status="failed",
127
+ session_id=getattr(
128
+ context, "session_id"
129
+ ), # stay on the safe side with the session_id attribute on an unknown type
130
+ ).model_dump()
131
+ workflow_name, wf, event = cast(tuple[str, Workflow, StartEvent], parsed)
132
+ result = await _run_workflow(workflow_name, wf, event)
133
+ result.session_id = getattr(context, "session_id")
134
+ return result.model_dump()
@@ -0,0 +1,12 @@
1
+ from pathlib import Path
2
+
3
+ agentcore_dir = Path(".agentcore")
4
+
5
+
6
+ def export_generated_entrypoint_code() -> None:
7
+ entrypoint = Path(__file__).parent / "entrypoint.py"
8
+ content = entrypoint.read_text()
9
+ agentcore_dir.mkdir(exist_ok=True)
10
+ with open(agentcore_dir / "entrypoint.py", "w") as f:
11
+ f.write(content)
12
+ return None
@@ -0,0 +1,19 @@
1
+ from argparse import ArgumentParser
2
+
3
+ from .entrypoint import app
4
+
5
+ if __name__ == "__main__":
6
+ parser = ArgumentParser()
7
+
8
+ parser.add_argument(
9
+ "--run",
10
+ help="Run the application in the target environment",
11
+ action="store_true",
12
+ default=False,
13
+ )
14
+
15
+ args = parser.parse_args()
16
+
17
+ if args.run:
18
+ print("Starting app on 0.0.0.0:8080") # noqa
19
+ app.run(port=8080, host="0.0.0.0")