Skip to content

Commit 8bb5a86

Browse files
authored
Merge branch 'main' into feature-Eliza-with-authentication
2 parents 7cfd1d5 + fc46580 commit 8bb5a86

File tree

106 files changed

+8758
-3488
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+8758
-3488
lines changed

.github/workflows/linter.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,9 @@ jobs:
3737
VALIDATE_YAML_PRETTIER: false
3838
VALIDATE_GIT_COMMITLINT: false
3939
VALIDATE_JSCPD: false
40+
VALIDATE_JUPYTER_NBQA_BLACK: false
41+
VALIDATE_JUPYTER_NBQA_ISORT: false
42+
VALIDATE_JUPYTER_NBQA_FLAKE8: false
43+
VALIDATE_JUPYTER_NBQA_MYPY: false
44+
VALIDATE_JUPYTER_NBQA_PYLINT: false
45+
VALIDATE_JUPYTER_NBQA_RUFF: false
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
"""Check links in notebooks for accuracy."""
2+
3+
import os
4+
import sys
5+
import urllib.parse
6+
7+
import nbformat
8+
9+
10+
LINK_PREFIXES = {
11+
'colab_link': 'https://colab.research.google.com/github/a2aproject/a2a-samples/blob/main/',
12+
'colab_enterprise_link': 'https://console.cloud.google.com/vertex-ai/colab/import/',
13+
'github_link': 'https://github.com/a2aproject/a2a-samples/blob/main/',
14+
'workbench_link': 'https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=',
15+
'bigquery_studio_link': 'https://console.cloud.google.com/bigquery/import?url=',
16+
'linkedin_link': 'https://www.linkedin.com/sharing/share-offsite/?url=',
17+
'bluesky_link': 'https://bsky.app/intent/compose?text=',
18+
'twitter_link': 'https://twitter.com/intent/tweet?url=',
19+
'reddit_link': 'https://reddit.com/submit?url=',
20+
'facebook_link': 'https://www.facebook.com/sharer/sharer.php?u=',
21+
}
22+
23+
GITHUB_URL_PREFIX = LINK_PREFIXES['github_link']
24+
RAW_URL_PREFIX = (
25+
'https://raw.githubusercontent.com/a2aproject/a2a-samples/main/'
26+
)
27+
28+
29+
def fix_markdown_links(
30+
cell_source: str, relative_notebook_path: str
31+
) -> tuple[str, bool]:
32+
"""Fixes links in a markdown cell and returns the updated source."""
33+
new_lines = []
34+
changes_made = False
35+
36+
encoded_url = urllib.parse.quote(
37+
f'{GITHUB_URL_PREFIX}{relative_notebook_path}'
38+
)
39+
40+
for line in cell_source.splitlines():
41+
for key, prefix in LINK_PREFIXES.items():
42+
if prefix not in line or '**NOTE:**' in line:
43+
continue
44+
45+
start_index = line.find(prefix) + len(prefix)
46+
end_index = line.find('.ipynb', start_index) + len('.ipynb')
47+
correct_link = ''
48+
49+
if key in {'colab_link', 'github_link'}:
50+
correct_link = relative_notebook_path
51+
elif key == 'colab_enterprise_link':
52+
correct_link = urllib.parse.quote(
53+
f'{RAW_URL_PREFIX}{relative_notebook_path}',
54+
safe=':',
55+
)
56+
elif key == 'workbench_link':
57+
correct_link = f'{RAW_URL_PREFIX}{relative_notebook_path}'
58+
elif key == 'bigquery_studio_link':
59+
correct_link = f'{GITHUB_URL_PREFIX}{relative_notebook_path}'
60+
elif key in {
61+
'linkedin_link',
62+
'bluesky_link',
63+
'twitter_link',
64+
'reddit_link',
65+
'facebook_link',
66+
}:
67+
correct_link = encoded_url
68+
69+
if correct_link.lower() not in line.lower():
70+
print(f'Incorrect link in {relative_notebook_path}: {line}\n')
71+
print(f'Should be: {correct_link}\n')
72+
line = line.replace(line[start_index:end_index], correct_link)
73+
changes_made = True
74+
75+
new_lines.append(line)
76+
77+
return '\n'.join(new_lines), changes_made
78+
79+
80+
def fix_links_in_notebook(notebook_path: str) -> int:
81+
"""Fixes specific types of links in a Jupyter notebook."""
82+
with open(notebook_path, encoding='utf-8') as f:
83+
notebook = nbformat.read(f, as_version=4)
84+
85+
relative_notebook_path = os.path.relpath(
86+
notebook_path, start=os.getcwd()
87+
).lower()
88+
89+
for cell in notebook.cells:
90+
if (
91+
cell.cell_type == 'markdown'
92+
and '<table' in cell.source
93+
and 'colab' in cell.source
94+
):
95+
updated_source, changes_made = fix_markdown_links(
96+
cell.source, relative_notebook_path
97+
)
98+
if changes_made:
99+
cell.source = updated_source
100+
with open(notebook_path, 'w', encoding='utf-8') as f:
101+
nbformat.write(notebook, f)
102+
return 1
103+
return 0
104+
105+
106+
def process_directory(directory_path: str) -> None:
107+
"""Recursively processes all notebooks in a directory."""
108+
for root, _, files in os.walk(directory_path):
109+
for filename in files:
110+
if filename.endswith('.ipynb'):
111+
notebook_path = os.path.join(root, filename)
112+
fix_links_in_notebook(notebook_path)
113+
114+
115+
if __name__ == '__main__':
116+
if len(sys.argv) != 2:
117+
print('Usage: python update_notebook_links.py <directory_path>')
118+
sys.exit(1)
119+
process_directory(sys.argv[1])

.ruff.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ ignore = [
2525
"TD003", # Ignore Missing issue link in TODOs (often not required/available)
2626
"T201", # Ignore print presence
2727
"RUF012", # Ignore Mutable class attributes should be annotated with `typing.ClassVar`
28+
"UP007", # Do not upgrade `Optional[T]` to `T | None` (PEP 604 syntax)
2829
"E501", # Ignore line length (handled by Ruff's dynamic line length)
2930
"ANN002",
3031
"ANN003",
3132
"ANN401",
33+
"E402",
3234
]
3335

3436
select = [

demo/ui/components/agent_list.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ def agents_list(
2626
df_data['Organization'].append(
2727
agent_info.provider.organization if agent_info.provider else ''
2828
)
29-
df_data['Input Modes'].append(', '.join(agent_info.defaultInputModes))
30-
df_data['Output Modes'].append(', '.join(agent_info.defaultOutputModes))
29+
df_data['Input Modes'].append(', '.join(agent_info.default_input_modes))
30+
df_data['Output Modes'].append(
31+
', '.join(agent_info.default_output_modes)
32+
)
3133
df_data['Streaming'].append(agent_info.capabilities.streaming)
3234
df = pd.DataFrame(
3335
pd.DataFrame(df_data),

demo/ui/components/conversation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ async def send_message(message: str, message_id: str = ''):
4242
if not c:
4343
print('Conversation id ', state.conversation_id, ' not found')
4444
request = Message(
45-
messageId=message_id,
46-
contextId=state.conversation_id,
45+
message_id=message_id,
46+
context_id=state.conversation_id,
4747
role=Role.user,
4848
parts=[Part(root=TextPart(text=message))],
4949
)

demo/ui/components/form_render.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,9 @@ async def cancel_form(e: me.ClickEvent):
314314
app_state.background_tasks[message_id] = ''
315315
app_state.completed_forms[form_message_id] = None
316316
request = Message(
317-
messageId=message_id,
318-
taskId=task_id,
319-
contextId=app_state.current_conversation_id,
317+
message_id=message_id,
318+
task_id=task_id,
319+
context_id=app_state.current_conversation_id,
320320
role=Role.user,
321321
parts=[Part(root=TextPart(text='rejected form entry'))],
322322
)
@@ -332,9 +332,9 @@ async def send_response(
332332
form = FormState(**json.loads(state.forms[id]))
333333
print('Sending form response', form)
334334
request = Message(
335-
messageId=message_id,
336-
taskId=task_id,
337-
contextId=app_state.current_conversation_id,
335+
message_id=message_id,
336+
task_id=task_id,
337+
context_id=app_state.current_conversation_id,
338338
role=Role.user,
339339
parts=[Part(root=DataPart(data=form.data))],
340340
)

demo/ui/pages/agent_list.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
from utils.agent_card import get_agent_card
1313

1414

15-
def agent_list_page(app_state: AppState):
16-
"""Agents List Page"""
15+
def agent_list_page(app_state: AppState) -> None:
16+
"""Agents List Page."""
1717
state = me.state(AgentState)
1818
with page_scaffold(): # pylint: disable=not-context-manager
1919
with page_frame():
@@ -65,41 +65,41 @@ def agent_list_page(app_state: AppState):
6565
me.button('Cancel', on_click=cancel_agent_dialog)
6666

6767

68-
def set_agent_address(e: me.InputBlurEvent):
68+
def set_agent_address(e: me.InputBlurEvent) -> None:
6969
state = me.state(AgentState)
7070
state.agent_address = e.value
7171

7272

73-
def load_agent_info(e: me.ClickEvent):
73+
async def load_agent_info(e: me.ClickEvent) -> None:
7474
state = me.state(AgentState)
7575
try:
7676
state.error = None
77-
agent_card_response = get_agent_card(state.agent_address)
77+
agent_card_response = await get_agent_card(state.agent_address)
7878
state.agent_name = agent_card_response.name
7979
state.agent_description = agent_card_response.description
8080
state.agent_framework_type = (
8181
agent_card_response.provider.organization
8282
if agent_card_response.provider
8383
else ''
8484
)
85-
state.input_modes = agent_card_response.defaultInputModes
86-
state.output_modes = agent_card_response.defaultOutputModes
85+
state.input_modes = agent_card_response.default_input_modes
86+
state.output_modes = agent_card_response.default_output_modes
8787
state.stream_supported = agent_card_response.capabilities.streaming
8888
state.push_notifications_supported = (
89-
agent_card_response.capabilities.pushNotifications
89+
agent_card_response.capabilities.push_notifications
9090
)
9191
except Exception as e:
9292
print(e)
9393
state.agent_name = None
9494
state.error = f'Cannot connect to agent as {state.agent_address}'
9595

9696

97-
def cancel_agent_dialog(e: me.ClickEvent):
97+
def cancel_agent_dialog(e: me.ClickEvent) -> None:
9898
state = me.state(AgentState)
9999
state.agent_dialog_open = False
100100

101101

102-
async def save_agent(e: me.ClickEvent):
102+
async def save_agent(e: me.ClickEvent) -> None:
103103
state = me.state(AgentState)
104104
await AddRemoteAgent(state.agent_address)
105105
state.agent_address = ''

demo/ui/pyproject.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,23 @@ dependencies = [
88
"asyncio>=3.4.3",
99
"httpx>=0.28.1",
1010
"httpx-sse>=0.4.0",
11-
"pydantic>=2.10.6",
11+
"pydantic>=2.11.0",
1212
"fastapi>=0.115.0",
1313
"uvicorn>=0.34.0",
1414
"mesop>=1.0.0",
15-
"a2a-sdk>=0.2.16",
15+
"a2a-sdk>=0.3.0",
1616
"pandas>=2.2.0",
1717
"google-genai>=1.9.0",
1818
"google-adk[a2a]>=1.7.0",
19+
"litellm",
1920
]
2021

2122
[tool.hatch.build.targets.wheel]
2223
packages = ["a2a_ui"]
2324

25+
[tool.hatch.metadata]
26+
allow-direct-references = true
27+
2428
[tool.uv.sources]
2529
a2a_ui = { workspace = true }
2630

0 commit comments

Comments
 (0)