Skip to content

Commit bb6c4b2

Browse files
committed
manual fix
1 parent 87b5723 commit bb6c4b2

File tree

9 files changed

+185
-199
lines changed

9 files changed

+185
-199
lines changed

.env.template

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ AZURE_AI_SPEECH_API_KEY="<YOUR_AZURE_AI_SPEECH_API_KEY>"
1919
AZURE_AI_SPEECH_ENDPOINT="https://<speech-api-name>.cognitiveservices.azure.com/"
2020

2121
# Azure AI Foundry
22-
AZURE_AI_FOUNDRY_PROJECT_CONNECTION_STRING="https://<YOUR_PROJECT_NAME>.eastus.inference.ai.azure.com"
22+
AZURE_AI_FOUNDRY_PROJECT_ENDPOINT="https://xxx.services.ai.azure.com/api/projects/yyy"
2323
AZURE_AI_FOUNDRY_API_KEY="<YOUR_API_KEY>"
24-
AZURE_AI_FOUNDRY_PROJECT_ID="<YOUR_PROJECT_ID>"
2524

2625
# Chats WebSocket
2726
# Azure Container Apps: `wss://yourcontainerapps.japaneast.azurecontainerapps.io`

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,4 @@ possibly-unbound-attribute = "ignore" # Ignore possibly unbound attributes in cl
7171
unknown-argument = "ignore" # Ignore unknown arguments in function calls
7272
invalid-assignment = "ignore" # Ignore invalid assignments
7373
invalid-argument-type = "ignore" # Ignore invalid argument types
74+
invalid-return-type = "ignore" # Ignore invalid return types

scripts/agents.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,13 @@ def get_agent(
8383
@app.command()
8484
def list_agents(
8585
limit: int = typer.Option(10, "--limit", "-l", help="取得する件数"),
86-
offset: int = typer.Option(0, "--offset", "-o", help="オフセット"),
8786
):
8887
"""エージェントの一覧を取得する"""
8988
console.print("[bold green]エージェント一覧を取得します[/bold green]")
9089
console.print(f"取得件数: {limit}")
91-
console.print(f"オフセット: {offset}")
9290

9391
try:
94-
agents_response = agent_repo.list_agents(limit=limit, offset=offset)
92+
agents_response = agent_repo.list_agents(limit=limit)
9593

9694
if not agents_response.agents:
9795
console.print("[yellow]エージェントが見つかりません[/yellow]")

template_fastapi/models/agent.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@ class AgentStatus(str, Enum):
1515
class AgentRequest(BaseModel):
1616
"""Request model for creating an agent"""
1717

18-
name: str
19-
description: str | None = None
20-
instructions: str | None = None
18+
name: str = "Default Agent"
19+
description: str | None = "Hello Agent"
20+
instructions: str | None = "You are a helpful assistant."
2121
model: str = "gpt-4o"
22-
tools: list[dict[str, Any]] | None = None
2322

2423

2524
class AgentResponse(BaseModel):
@@ -36,6 +35,19 @@ class AgentResponse(BaseModel):
3635
updated_at: str
3736

3837

38+
class ThreadRequest(BaseModel):
39+
"""Request model for creating a chat thread"""
40+
41+
pass
42+
43+
44+
class ThreadResponse(BaseModel):
45+
"""Response model for chat thread"""
46+
47+
id: str
48+
created_at: str
49+
50+
3951
class ChatRequest(BaseModel):
4052
"""Request model for chat with agent"""
4153

@@ -59,3 +71,10 @@ class AgentListResponse(BaseModel):
5971

6072
agents: list[AgentResponse]
6173
total: int
74+
75+
76+
class ThreadListResponse(BaseModel):
77+
"""Response model for listing threads"""
78+
79+
threads: list[ThreadResponse]
80+
total: int

template_fastapi/repositories/agents.py

Lines changed: 81 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from datetime import datetime
22

3+
from azure.ai.agents.models import CodeInterpreterTool
34
from azure.ai.projects import AIProjectClient
45
from azure.identity import DefaultAzureCredential
56

@@ -10,17 +11,22 @@
1011
AgentStatus,
1112
ChatRequest,
1213
ChatResponse,
14+
ThreadListResponse,
15+
ThreadRequest,
16+
ThreadResponse,
1317
)
1418
from template_fastapi.settings.azure_ai_foundry import get_azure_ai_foundry_settings
1519

20+
code_interpreter = CodeInterpreterTool()
21+
1622

1723
class AgentRepository:
1824
"""Repository for handling agent-related operations with Azure AI Foundry."""
1925

2026
def __init__(self):
2127
self.settings = get_azure_ai_foundry_settings()
2228
self.client = AIProjectClient(
23-
self.settings.azure_ai_foundry_project_connection_string,
29+
endpoint=self.settings.azure_ai_foundry_project_endpoint,
2430
credential=DefaultAzureCredential(),
2531
)
2632

@@ -32,7 +38,7 @@ def create_agent(self, request: AgentRequest) -> AgentResponse:
3238
name=request.name,
3339
description=request.description,
3440
instructions=request.instructions,
35-
tools=request.tools or [],
41+
tools=code_interpreter.definitions,
3642
)
3743

3844
now = datetime.now().isoformat()
@@ -72,15 +78,17 @@ def get_agent(self, agent_id: str) -> AgentResponse:
7278
except Exception as e:
7379
raise Exception(f"Failed to get agent: {str(e)}")
7480

75-
def list_agents(self, limit: int = 10, offset: int = 0) -> AgentListResponse:
81+
def list_agents(self, limit: int = 10) -> AgentListResponse:
7682
"""List agents."""
7783
try:
78-
agents_response = self.client.agents.list_agents()
84+
agents_response = self.client.agents.list_agents(
85+
limit=limit,
86+
)
7987

8088
now = datetime.now().isoformat()
8189

8290
agents = []
83-
for agent in agents_response.data:
91+
for agent in agents_response:
8492
agents.append(
8593
AgentResponse(
8694
id=agent.id,
@@ -96,7 +104,7 @@ def list_agents(self, limit: int = 10, offset: int = 0) -> AgentListResponse:
96104
)
97105

98106
return AgentListResponse(
99-
agents=agents[offset : offset + limit],
107+
agents=agents,
100108
total=len(agents),
101109
)
102110
except Exception as e:
@@ -113,46 +121,82 @@ def delete_agent(self, agent_id: str) -> bool:
113121
def chat_with_agent(self, agent_id: str, request: ChatRequest) -> ChatResponse:
114122
"""Chat with an agent."""
115123
try:
116-
# Create a thread if not provided
117-
if request.thread_id:
118-
thread_id = request.thread_id
119-
else:
120-
thread_response = self.client.agents.create_thread()
121-
thread_id = thread_response.id
122-
123-
# Create a message
124-
message_response = self.client.agents.create_message(
125-
thread_id=thread_id,
124+
_ = self.client.agents.messages.create(
125+
thread_id=request.thread_id,
126126
role="user",
127127
content=request.message,
128128
)
129129

130-
# Create a run
131-
run_response = self.client.agents.create_run(
132-
thread_id=thread_id,
133-
assistant_id=agent_id,
130+
run = self.client.agents.runs.create_and_process(
131+
agent_id=agent_id,
132+
thread_id=request.thread_id,
134133
)
135134

136-
# Poll for completion
137-
while run_response.status in ["queued", "in_progress"]:
138-
run_response = self.client.agents.get_run(
139-
thread_id=thread_id,
140-
run_id=run_response.id,
135+
print(f"Run ID: {run.id}m status: {run.last_error}")
136+
137+
messages = self.client.agents.messages.list(
138+
thread_id=request.thread_id,
139+
)
140+
141+
# FIXME: Iterable object の最初のメッセージを取得
142+
for message in messages:
143+
return ChatResponse(
144+
id=run.id,
145+
agent_id=agent_id,
146+
thread_id=request.thread_id,
147+
message=request.message,
148+
response=message.content.__str__() if messages else "",
149+
created_at=message.created_at.isoformat() if messages else "",
141150
)
142151

143-
# Get the response
144-
messages = self.client.agents.list_messages(thread_id=thread_id)
145-
response_message = messages.data[0].content[0].text.value
152+
except Exception as e:
153+
raise Exception(f"Failed to chat with agent: {str(e)}")
146154

147-
now = datetime.now().isoformat()
155+
def create_thread(self, request: ThreadRequest) -> ThreadResponse:
156+
"""Create a new thread for chatting with an agent."""
157+
try:
158+
thread_response = self.client.agents.threads.create(**request.model_dump())
159+
return ThreadResponse(
160+
id=thread_response.id,
161+
created_at=thread_response.created_at.isoformat(),
162+
)
163+
except Exception as e:
164+
raise Exception(f"Failed to create thread: {str(e)}")
148165

149-
return ChatResponse(
150-
id=message_response.id,
151-
agent_id=agent_id,
152-
thread_id=thread_id,
153-
message=request.message,
154-
response=response_message,
155-
created_at=now,
166+
def get_thread(self, thread_id: str) -> ThreadResponse:
167+
"""Get a specific thread by ID."""
168+
try:
169+
thread_response = self.client.agents.threads.get(thread_id=thread_id)
170+
return ThreadResponse(
171+
id=thread_response.id,
172+
created_at=thread_response.created_at.isoformat(),
156173
)
157174
except Exception as e:
158-
raise Exception(f"Failed to chat with agent: {str(e)}")
175+
raise Exception(f"Failed to get thread: {str(e)}")
176+
177+
def delete_thread(self, thread_id: str) -> bool:
178+
"""Delete a specific thread by ID."""
179+
try:
180+
self.client.agents.threads.delete(thread_id=thread_id)
181+
return True
182+
except Exception as e:
183+
raise Exception(f"Failed to delete thread: {str(e)}")
184+
185+
def list_threads(self, limit: int) -> ThreadListResponse:
186+
"""List threads for a specific agent."""
187+
try:
188+
threads_response = self.client.agents.threads.list(limit=limit)
189+
threads = []
190+
for thread in threads_response:
191+
threads.append(
192+
ThreadResponse(
193+
id=thread.id,
194+
created_at=thread.created_at.isoformat(),
195+
)
196+
)
197+
return ThreadListResponse(
198+
threads=threads,
199+
total=len(threads),
200+
)
201+
except Exception as e:
202+
raise Exception(f"Failed to list threads: {str(e)}")

template_fastapi/routers/agents.py

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
from fastapi import APIRouter, HTTPException, Query
32

43
from template_fastapi.models.agent import (
@@ -7,6 +6,9 @@
76
AgentResponse,
87
ChatRequest,
98
ChatResponse,
9+
ThreadListResponse,
10+
ThreadRequest,
11+
ThreadResponse,
1012
)
1113
from template_fastapi.repositories.agents import AgentRepository
1214

@@ -54,13 +56,12 @@ async def get_agent(agent_id: str) -> AgentResponse:
5456
)
5557
async def list_agents(
5658
limit: int = Query(default=10, ge=1, le=100, description="取得する件数"),
57-
offset: int = Query(default=0, ge=0, description="オフセット"),
5859
) -> AgentListResponse:
5960
"""
6061
エージェントの一覧を取得する
6162
"""
6263
try:
63-
return agent_repo.list_agents(limit=limit, offset=offset)
64+
return agent_repo.list_agents(limit=limit)
6465
except Exception as e:
6566
raise HTTPException(status_code=500, detail=f"エージェント一覧の取得に失敗しました: {str(e)}")
6667

@@ -98,3 +99,72 @@ async def chat_with_agent(agent_id: str, request: ChatRequest) -> ChatResponse:
9899
return agent_repo.chat_with_agent(agent_id, request)
99100
except Exception as e:
100101
raise HTTPException(status_code=500, detail=f"エージェントとのチャットに失敗しました: {str(e)}")
102+
103+
104+
@router.post(
105+
"/agents/threads/",
106+
response_model=ThreadResponse,
107+
tags=["agents"],
108+
operation_id="create_thread",
109+
)
110+
async def create_thread(request: ThreadRequest) -> ThreadResponse:
111+
"""
112+
新しいスレッドを作成する
113+
"""
114+
try:
115+
return agent_repo.create_thread(request)
116+
except Exception as e:
117+
raise HTTPException(status_code=500, detail=f"スレッドの作成に失敗しました: {str(e)}")
118+
119+
120+
@router.get(
121+
"/agents/threads/{thread_id}",
122+
response_model=ThreadResponse,
123+
tags=["agents"],
124+
operation_id="get_thread",
125+
)
126+
async def get_thread(thread_id: str) -> ThreadResponse:
127+
"""
128+
スレッドの情報を取得する
129+
"""
130+
try:
131+
return agent_repo.get_thread(thread_id)
132+
except Exception as e:
133+
raise HTTPException(status_code=404, detail=f"スレッドが見つかりません: {str(e)}")
134+
135+
136+
@router.delete(
137+
"/agents/threads/{thread_id}",
138+
tags=["agents"],
139+
operation_id="delete_thread",
140+
)
141+
async def delete_thread(thread_id: str) -> dict:
142+
"""
143+
スレッドを削除する
144+
"""
145+
try:
146+
success = agent_repo.delete_thread(thread_id)
147+
if success:
148+
return {"message": "スレッドが正常に削除されました"}
149+
else:
150+
raise HTTPException(status_code=500, detail="スレッドの削除に失敗しました")
151+
except Exception as e:
152+
raise HTTPException(status_code=500, detail=f"スレッドの削除に失敗しました: {str(e)}")
153+
154+
155+
@router.get(
156+
"/agents/threads/",
157+
response_model=ThreadListResponse,
158+
tags=["agents"],
159+
operation_id="list_threads",
160+
)
161+
async def list_threads(
162+
limit: int = Query(default=10, ge=1, le=100, description="取得する件数"),
163+
) -> ThreadListResponse:
164+
"""
165+
エージェントのスレッド一覧を取得する
166+
"""
167+
try:
168+
return agent_repo.list_threads(limit=limit)
169+
except Exception as e:
170+
raise HTTPException(status_code=500, detail=f"スレッド一覧の取得に失敗しました: {str(e)}")

template_fastapi/settings/azure_ai_foundry.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44

55

66
class Settings(BaseSettings):
7-
azure_ai_foundry_project_connection_string: str = "https://<YOUR_PROJECT_NAME>.eastus.inference.ai.azure.com"
7+
azure_ai_foundry_project_endpoint: str = "https://xxx.services.ai.azure.com/api/projects/yyy"
88
azure_ai_foundry_api_key: str = "<YOUR_API_KEY>"
9-
azure_ai_foundry_project_id: str = "<YOUR_PROJECT_ID>"
109

1110
model_config = SettingsConfigDict(
1211
env_file=".env",

0 commit comments

Comments
 (0)