Sheyda Kiani Mehr commited on
Commit
43d5db4
Β·
1 Parent(s): 71bf3a5

original a2a

Browse files
Containerfile.txt ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM registry.access.redhat.com/ubi8/python-312
2
+
3
+ # Set work directory
4
+ WORKDIR /opt/app-root/
5
+
6
+ # Copy Python Project Files (Container context must be the `python` directory)
7
+ COPY . /opt/app-root
8
+
9
+ USER root
10
+
11
+ # Install system build dependencies and UV package manager
12
+ RUN dnf -y update && dnf install -y gcc gcc-c++ \
13
+ && pip install uv
14
+
15
+ # Set environment variables for uv:
16
+ # UV_COMPILE_BYTECODE=1: Compiles Python files to .pyc for faster startup
17
+ # UV_LINK_MODE=copy: Ensures files are copied, not symlinked, which can avoid issues
18
+ ENV UV_COMPILE_BYTECODE=1 \
19
+ UV_LINK_MODE=copy
20
+
21
+ # Install dependencies using uv sync.
22
+ # --frozen: Ensures uv respects the uv.lock file
23
+ # --no-install-project: Prevents installing the project itself in this stage
24
+ # --no-dev: Excludes development dependencies
25
+ # --mount=type=cache: Leverages Docker's build cache for uv, speeding up repeated builds
26
+ RUN --mount=type=cache,target=/.cache/uv \
27
+ uv sync --frozen --no-install-project --no-dev
28
+
29
+ # Install the project
30
+ RUN --mount=type=cache,target=/.cache/uv \
31
+ uv sync --frozen --no-dev
32
+
33
+ # Allow non-root user to access the everything in app-root
34
+ RUN chgrp -R root /opt/app-root/ && chmod -R g+rwx /opt/app-root/
35
+
36
+ # Expose default port (change if needed)
37
+ EXPOSE 9999
38
+
39
+ USER 1001
40
+
41
+ # Run the agent
42
+ CMD uv run . --host 0.0.0.0
README-2.md ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hello World Example
2
+
3
+ Hello World example agent that only returns Message events
4
+
5
+ ## Getting started
6
+
7
+ 1. Start the server
8
+
9
+ ```bash
10
+ uv run .
11
+ ```
12
+
13
+ 2. Run the test client
14
+
15
+ ```bash
16
+ uv run test_client.py
17
+ ```
18
+
19
+ ## Build Container Image
20
+
21
+ Agent can also be built using a container file.
22
+
23
+ 1. Navigate to the directory `samples/python/agents/helloworld` directory:
24
+
25
+ ```bash
26
+ cd samples/python/agents/helloworld
27
+ ```
28
+
29
+ 2. Build the container file
30
+
31
+ ```bash
32
+ podman build . -t helloworld-a2a-server
33
+ ```
34
+
35
+ > [!Tip]
36
+ > Podman is a drop-in replacement for `docker` which can also be used in these commands.
37
+
38
+ 3. Run you container
39
+
40
+ ```bash
41
+ podman run -p 9999:9999 helloworld-a2a-server
42
+ ```
43
+
44
+ ## Validate
45
+
46
+ To validate in a separate terminal, run the A2A client:
47
+
48
+ ```bash
49
+ cd samples/python/hosts/cli
50
+ uv run . --agent http://localhost:9999
51
+ ```
52
+
53
+
54
+ ## Disclaimer
55
+ Important: The sample code provided is for demonstration purposes and illustrates the mechanics of the Agent-to-Agent (A2A) protocol. When building production applications, it is critical to treat any agent operating outside of your direct control as a potentially untrusted entity.
56
+
57
+ All data received from an external agentβ€”including but not limited to its AgentCard, messages, artifacts, and task statusesβ€”should be handled as untrusted input. For example, a malicious agent could provide an AgentCard containing crafted data in its fields (e.g., description, name, skills.description). If this data is used without sanitization to construct prompts for a Large Language Model (LLM), it could expose your application to prompt injection attacks. Failure to properly validate and sanitize this data before use can introduce security vulnerabilities into your application.
58
+
59
+ Developers are responsible for implementing appropriate security measures, such as input validation and secure handling of credentials to protect their systems and users.
__init__.py ADDED
File without changes
__main__.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import uvicorn
2
+
3
+ from a2a.server.apps import A2AStarletteApplication
4
+ from a2a.server.request_handlers import DefaultRequestHandler
5
+ from a2a.server.tasks import InMemoryTaskStore
6
+ from a2a.types import (
7
+ AgentCapabilities,
8
+ AgentCard,
9
+ AgentSkill,
10
+ )
11
+ from agent_executor import (
12
+ HelloWorldAgentExecutor, # type: ignore[import-untyped]
13
+ )
14
+
15
+
16
+ if __name__ == '__main__':
17
+ # --8<-- [start:AgentSkill]
18
+ skill = AgentSkill(
19
+ id='hello_world',
20
+ name='Returns hello world',
21
+ description='just returns hello world',
22
+ tags=['hello world'],
23
+ examples=['hi', 'hello world'],
24
+ )
25
+ # --8<-- [end:AgentSkill]
26
+
27
+ extended_skill = AgentSkill(
28
+ id='super_hello_world',
29
+ name='Returns a SUPER Hello World',
30
+ description='A more enthusiastic greeting, only for authenticated users.',
31
+ tags=['hello world', 'super', 'extended'],
32
+ examples=['super hi', 'give me a super hello'],
33
+ )
34
+
35
+ # --8<-- [start:AgentCard]
36
+ # This will be the public-facing agent card
37
+ public_agent_card = AgentCard(
38
+ name='Hello World Agent',
39
+ description='Just a hello world agent',
40
+ url='http://localhost:9999/',
41
+ version='1.0.0',
42
+ default_input_modes=['text'],
43
+ default_output_modes=['text'],
44
+ capabilities=AgentCapabilities(streaming=True),
45
+ skills=[skill], # Only the basic skill for the public card
46
+ supports_authenticated_extended_card=True,
47
+ )
48
+ # --8<-- [end:AgentCard]
49
+
50
+ # This will be the authenticated extended agent card
51
+ # It includes the additional 'extended_skill'
52
+ specific_extended_agent_card = public_agent_card.model_copy(
53
+ update={
54
+ 'name': 'Hello World Agent - Extended Edition', # Different name for clarity
55
+ 'description': 'The full-featured hello world agent for authenticated users.',
56
+ 'version': '1.0.1', # Could even be a different version
57
+ # Capabilities and other fields like url, default_input_modes, default_output_modes,
58
+ # supports_authenticated_extended_card are inherited from public_agent_card unless specified here.
59
+ 'skills': [
60
+ skill,
61
+ extended_skill,
62
+ ], # Both skills for the extended card
63
+ }
64
+ )
65
+
66
+ request_handler = DefaultRequestHandler(
67
+ agent_executor=HelloWorldAgentExecutor(),
68
+ task_store=InMemoryTaskStore(),
69
+ )
70
+
71
+ server = A2AStarletteApplication(
72
+ agent_card=public_agent_card,
73
+ http_handler=request_handler,
74
+ extended_agent_card=specific_extended_agent_card,
75
+ )
76
+
77
+ uvicorn.run(server.build(), host='0.0.0.0', port=9999)
agent_executor.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from a2a.server.agent_execution import AgentExecutor, RequestContext
2
+ from a2a.server.events import EventQueue
3
+ from a2a.utils import new_agent_text_message
4
+
5
+
6
+ # --8<-- [start:HelloWorldAgent]
7
+ class HelloWorldAgent:
8
+ """Hello World Agent."""
9
+
10
+ async def invoke(self) -> str:
11
+ return 'Hello World'
12
+
13
+
14
+ # --8<-- [end:HelloWorldAgent]
15
+
16
+
17
+ # --8<-- [start:HelloWorldAgentExecutor_init]
18
+ class HelloWorldAgentExecutor(AgentExecutor):
19
+ """Test AgentProxy Implementation."""
20
+
21
+ def __init__(self):
22
+ self.agent = HelloWorldAgent()
23
+
24
+ # --8<-- [end:HelloWorldAgentExecutor_init]
25
+ # --8<-- [start:HelloWorldAgentExecutor_execute]
26
+ async def execute(
27
+ self,
28
+ context: RequestContext,
29
+ event_queue: EventQueue,
30
+ ) -> None:
31
+ result = await self.agent.invoke()
32
+ await event_queue.enqueue_event(new_agent_text_message(result))
33
+
34
+ # --8<-- [end:HelloWorldAgentExecutor_execute]
35
+
36
+ # --8<-- [start:HelloWorldAgentExecutor_cancel]
37
+ async def cancel(
38
+ self, context: RequestContext, event_queue: EventQueue
39
+ ) -> None:
40
+ raise Exception('cancel not supported')
41
+
42
+ # --8<-- [end:HelloWorldAgentExecutor_cancel]
pyproject.toml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "helloworld"
3
+ version = "0.1.0"
4
+ description = "HelloWorld agent example that only returns Messages"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "a2a-sdk>=0.3.0",
9
+ "click>=8.1.8",
10
+ "dotenv>=0.9.9",
11
+ "httpx>=0.28.1",
12
+ "langchain-google-genai>=2.1.4",
13
+ "langgraph>=0.4.1",
14
+ "pydantic>=2.11.4",
15
+ "python-dotenv>=1.1.0",
16
+ "sse-starlette>=2.3.5",
17
+ "starlette>=0.46.2",
18
+ "uvicorn>=0.34.2",
19
+ ]
20
+
21
+ [tool.hatch.build.targets.wheel]
22
+ packages = ["."]
23
+
24
+ [build-system]
25
+ requires = ["hatchling"]
26
+ build-backend = "hatchling.build"
Dockerfile β†’ test/Dockerfile RENAMED
File without changes
Dockfile β†’ test/Dockfile RENAMED
File without changes
README.md β†’ test/README.md RENAMED
File without changes
main.py β†’ test/main.py RENAMED
File without changes
requirements.txt β†’ test/requirements.txt RENAMED
File without changes
simple_main.py β†’ test/simple_main.py RENAMED
File without changes
test.py β†’ test/test.py RENAMED
File without changes
test_docker β†’ test/test_docker RENAMED
File without changes
uv.lock ADDED
The diff for this file is too large to render. See raw diff