agenteng 0.0.1__py3-none-any.whl

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.
agenteng/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """Agent Engineering HQ public events service."""
2
+
3
+ __version__ = "0.0.1"
agenteng/__main__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ main()
agenteng/a2a.py ADDED
@@ -0,0 +1,191 @@
1
+ """Official A2A 1.0 SDK adapter; immediate responses with no retained conversations."""
2
+
3
+ import json
4
+ from uuid import uuid4
5
+
6
+ from a2a.server.agent_execution import AgentExecutor
7
+ from a2a.server.request_handlers import DefaultRequestHandler
8
+ from a2a.server.routes import (
9
+ add_a2a_routes_to_fastapi,
10
+ create_agent_card_routes,
11
+ create_jsonrpc_routes,
12
+ )
13
+ from a2a.server.tasks import InMemoryTaskStore
14
+ from a2a.types import (
15
+ AgentCapabilities,
16
+ AgentCard,
17
+ AgentInterface,
18
+ AgentProvider,
19
+ AgentSkill,
20
+ Message,
21
+ Part,
22
+ HTTPAuthSecurityScheme,
23
+ SecurityRequirement,
24
+ SecurityScheme,
25
+ StringList,
26
+ )
27
+ from a2a.utils.errors import InvalidParamsError, UnsupportedOperationError
28
+ from google.protobuf.json_format import MessageToDict, ParseDict
29
+ from google.protobuf.struct_pb2 import Value
30
+ from pydantic import ValidationError
31
+
32
+ from .auth import bearer
33
+ from .models import Request
34
+
35
+
36
+ def agent_card(service):
37
+ private_skills = []
38
+ security_schemes = {}
39
+ if service.settings.enable_intake:
40
+ security_schemes["participant"] = SecurityScheme(
41
+ http_auth_security_scheme=HTTPAuthSecurityScheme(
42
+ scheme="bearer",
43
+ description="Organizer-issued, per-participant pilot credential. "
44
+ "Not the optional inference operator credential.",
45
+ )
46
+ )
47
+ private_skills.append(
48
+ AgentSkill(
49
+ id="agenteng-participation",
50
+ name="Private Agent Engineering HQ participation",
51
+ description="Prepare an exact private preview, explicitly confirm submission, read your receipt or withdraw. "
52
+ "Requires participant access. No review, response, acceptance or event is guaranteed. "
53
+ "Submission content is never published automatically.",
54
+ tags=["proposals", "London", "San Francisco", "private-intake"],
55
+ security_requirements=[
56
+ SecurityRequirement(schemes={"participant": StringList(list=[])})
57
+ ],
58
+ )
59
+ )
60
+ return AgentCard(
61
+ name="Agent Engineering HQ — AgentEng Conference",
62
+ description="AgentEng, the Agent Engineering Conference, and Agent Engineering HQ technical events in London and San Francisco. Discover published dates, speakers, agendas, registration links, proposal drafting and a tool directory across twelve agent-engineering disciplines. Anonymous requests use catalogue lookup with no model calls. London 2026 has an invited programme and no public CFP.",
63
+ version="1.0",
64
+ provider=AgentProvider(
65
+ organization="Agent Engineering HQ", url="https://agentengineering.world"
66
+ ),
67
+ documentation_url=service.settings.public_url + "/docs",
68
+ supported_interfaces=[
69
+ AgentInterface(
70
+ url=service.settings.public_url + "/",
71
+ protocol_binding="JSONRPC",
72
+ protocol_version="1.0",
73
+ )
74
+ ],
75
+ capabilities=AgentCapabilities(
76
+ streaming=False, push_notifications=False, extended_agent_card=False
77
+ ),
78
+ default_input_modes=["application/json", "text/plain"],
79
+ default_output_modes=["application/json", "text/plain"],
80
+ security_schemes=security_schemes,
81
+ skills=[
82
+ AgentSkill(
83
+ id="agenteng",
84
+ name="AgentEng London and San Francisco events",
85
+ description="Use a typed AgentEng request or a public-event search question. Returns evidence, date precision and snapshot freshness.",
86
+ tags=[
87
+ "events",
88
+ "conferences",
89
+ "agent-engineering",
90
+ "AgentEng",
91
+ "Agent Engineering HQ",
92
+ "Agent Engineering Conference",
93
+ "London",
94
+ "San Francisco",
95
+ "coding-agents",
96
+ "mcp",
97
+ "a2a",
98
+ ],
99
+ examples=[
100
+ '{"operation":"events","upcoming":true}',
101
+ '{"operation":"discover"}',
102
+ '{"operation":"tickets","event_id":"agenteng-london-2026"}',
103
+ '{"operation":"proposal_draft","draft":{"city":"San Francisco","kind":"event_idea","title":"Agent evaluation workshop"}}',
104
+ ],
105
+ ),
106
+ AgentSkill(
107
+ id="agenteng-tools",
108
+ name="Agent-engineering tool directory",
109
+ description="Browse public tool names and links across twelve disciplines using "
110
+ "disciplines, tools and tool. Filter by discipline, kind, category or query; paginate "
111
+ "with limit/offset and next_offset. Offline, model-free listings with source provenance; "
112
+ "no popularity rankings, installations or vendor integrations are implied.",
113
+ tags=[
114
+ "tools",
115
+ "agent-engineering",
116
+ "disciplines",
117
+ "memory",
118
+ "inference",
119
+ "protocol",
120
+ ],
121
+ examples=[
122
+ '{"operation":"disciplines"}',
123
+ '{"operation":"tools","discipline":"memory"}',
124
+ '{"operation":"tool","tool_id":"langgraph"}',
125
+ ],
126
+ ),
127
+ ]
128
+ + private_skills,
129
+ )
130
+
131
+
132
+ class Executor(AgentExecutor):
133
+ def __init__(self, service):
134
+ self.service = service
135
+
136
+ async def execute(self, context, event_queue):
137
+ message = context.message
138
+ if message is None:
139
+ raise InvalidParamsError("A user message is required.")
140
+ if any(p.HasField("raw") or p.HasField("url") for p in message.parts):
141
+ raise InvalidParamsError("Only JSON request data or text input is supported.")
142
+ data_parts = [p for p in message.parts if p.HasField("data")]
143
+ try:
144
+ if data_parts:
145
+ if len(data_parts) != 1 or any(p.HasField("text") for p in message.parts):
146
+ raise ValueError("Send one JSON request part.")
147
+ request = Request.model_validate(MessageToDict(data_parts[0].data))
148
+ else:
149
+ text = context.get_user_input().strip()
150
+ request = (
151
+ Request.model_validate_json(text)
152
+ if text.startswith("{")
153
+ else Request(operation="ask", query=text)
154
+ )
155
+ except (ValueError, ValidationError) as exc:
156
+ raise InvalidParamsError(
157
+ "Invalid AgentEng request; use the documented request schema."
158
+ ) from exc
159
+ call_context = context.call_context
160
+ headers = call_context.state.get("headers", {}) if call_context else {}
161
+ result = await self.service.execute(request, token=bearer(headers))
162
+ await event_queue.enqueue_event(
163
+ Message(
164
+ message_id=str(uuid4()),
165
+ context_id=context.context_id,
166
+ role=2,
167
+ parts=[
168
+ Part(text=result.answer),
169
+ Part(
170
+ data=ParseDict(json.loads(result.model_dump_json()), Value()),
171
+ media_type="application/json",
172
+ ),
173
+ ],
174
+ )
175
+ )
176
+
177
+ async def cancel(self, context, event_queue):
178
+ raise UnsupportedOperationError(
179
+ "This agent returns immediate messages; persistent tasks are not supported."
180
+ )
181
+
182
+
183
+ def add_a2a(app, service):
184
+ card = agent_card(service)
185
+ handler = DefaultRequestHandler(Executor(service), InMemoryTaskStore(), card)
186
+ add_a2a_routes_to_fastapi(
187
+ app,
188
+ agent_card_routes=create_agent_card_routes(card),
189
+ jsonrpc_routes=create_jsonrpc_routes(handler, rpc_url="/"),
190
+ )
191
+ return card
agenteng/auth.py ADDED
@@ -0,0 +1,7 @@
1
+ """Credential parsing shared by transports without importing either SDK."""
2
+
3
+
4
+ def bearer(headers) -> str | None:
5
+ value = headers.get("authorization", "")
6
+ scheme, _, token = value.partition(" ")
7
+ return token if scheme.lower() == "bearer" and token else None
agenteng/calendar.py ADDED
@@ -0,0 +1,55 @@
1
+ """Standards-compliant UTC calendar export; never invent missing session times."""
2
+
3
+ from datetime import UTC, datetime
4
+
5
+ from .models import Event, Session
6
+
7
+
8
+ def escape(value: str) -> str:
9
+ return value.replace("\\", "\\\\").replace("\n", "\\n").replace(";", "\\;").replace(",", "\\,")
10
+
11
+
12
+ def fold(line: str) -> str:
13
+ chunks, current = [], ""
14
+ for char in line:
15
+ if len((current + char).encode()) > 75:
16
+ chunks.append(current)
17
+ current = " "
18
+ current += char
19
+ return "\r\n".join([*chunks, current])
20
+
21
+
22
+ def calendar(event: Event, sessions: list[Session], now: datetime) -> str:
23
+ def stamp(value):
24
+ return value.astimezone(UTC).strftime("%Y%m%dT%H%M%SZ")
25
+
26
+ lines = [
27
+ "BEGIN:VCALENDAR",
28
+ "VERSION:2.0",
29
+ "PRODID:-//AgentEng HQ//Events//EN",
30
+ "CALSCALE:GREGORIAN",
31
+ "METHOD:PUBLISH",
32
+ ]
33
+ # An event without an exact day/time cannot be exported as a timed event.
34
+ rows = (
35
+ [(event.id, event.title, event.start, event.end)]
36
+ if not sessions
37
+ else [(s.id, s.title, s.start, s.end) for s in sessions]
38
+ )
39
+ for uid, title, start, end in rows:
40
+ if start is None or end is None:
41
+ continue
42
+ lines.extend(
43
+ [
44
+ "BEGIN:VEVENT",
45
+ f"UID:{uid}@agentengineering.world",
46
+ "DTSTAMP:" + stamp(now),
47
+ "DTSTART:" + stamp(start),
48
+ "DTEND:" + stamp(end),
49
+ "SUMMARY:" + escape(title),
50
+ "LOCATION:" + escape(event.venue),
51
+ "END:VEVENT",
52
+ ]
53
+ )
54
+ lines.append("END:VCALENDAR")
55
+ return "\r\n".join(map(fold, lines)) + "\r\n"
agenteng/catalogue.py ADDED
@@ -0,0 +1,15 @@
1
+ """Load and validate the local immutable public snapshot."""
2
+
3
+ from importlib.resources import files
4
+
5
+ from .models import Catalogue
6
+
7
+
8
+ def load_catalogue(path: str | None = None) -> Catalogue:
9
+ if path:
10
+ from pathlib import Path
11
+
12
+ payload = Path(path).read_text()
13
+ else:
14
+ payload = files("agenteng").joinpath("data/catalogue.json").read_text()
15
+ return Catalogue.model_validate_json(payload)