ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s

This commit is contained in:
2026-08-20 13:12:50 +00:00
commit b119135836
10275 changed files with 3284984 additions and 0 deletions
@@ -0,0 +1,52 @@
import logging
import json
from typing import Dict
from fastapi import APIRouter, Depends, Request
from fastapi.responses import StreamingResponse
from aworld.cmd.data_model import AgentModel, ChatCompletionRequest
from aworld.cmd.utils import agent_executor
from aworld.cmd.utils.trace_summarize import summarize_trace
from aworld.cmd.web.utils.users import get_user_id_from_jwt
import aworld.trace as trace
logger = logging.getLogger(__name__)
router = APIRouter()
prefix = "/api/agent"
@router.get("/list")
@router.get("/models")
async def list_agents(request: Request) -> Dict[str, AgentModel]:
return request.app.state.agent_server.list_agents()
@router.post("/chat/completions")
async def chat_completion(
form_data: ChatCompletionRequest,
request: Request,
user_id: str = Depends(get_user_id_from_jwt),
) -> StreamingResponse:
# Set user_id from JWT to form_data
form_data.user_id = user_id
async def generate_stream():
async with trace.span(
"/chat/chat_completion", attributes={"model": form_data.model}
) as span:
form_data.trace_id = span.get_trace_id()
async for chunk in agent_executor.stream_run(
form_data, request.app.state.agent_server
):
yield f"data: {json.dumps(chunk.model_dump(), ensure_ascii=False)}\n\n"
summarize_trace(form_data.trace_id)
return StreamingResponse(
generate_stream(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
},
)
@@ -0,0 +1,52 @@
import logging
from typing import List
from fastapi import APIRouter, Depends, Request
from pydantic import BaseModel, Field
from aworld.cmd.data_model import SessionModel
from aworld.cmd.web.utils.users import get_user_id_from_jwt
logger = logging.getLogger(__name__)
router = APIRouter()
prefix = "/api/session"
@router.get("/list")
async def list_sessions(
request: Request,
user_id: str = Depends(get_user_id_from_jwt),
) -> List[SessionModel]:
return await request.app.state.agent_server.get_session_service().list_sessions(
user_id
)
class CommonResponse(BaseModel):
code: int = Field(..., description="The code")
message: str = Field(..., description="The message")
@staticmethod
def success(message: str = "success"):
return CommonResponse(code=0, message=message)
@staticmethod
def error(message: str):
return CommonResponse(code=1, message=message)
class DeleteSessionRequest(BaseModel):
session_id: str = Field(..., description="The session id")
@router.post("/delete")
async def delete_session(
request: DeleteSessionRequest, user_id: str = Depends(get_user_id_from_jwt)
) -> CommonResponse:
try:
await request.app.state.agent_server.get_session_service().delete_session(
user_id, request.session_id
)
return CommonResponse.success()
except Exception as e:
return CommonResponse.error(str(e))
@@ -0,0 +1,50 @@
import json
import logging
from fastapi import APIRouter
from aworld.trace.server import get_trace_server
from aworld.trace.server.util import build_trace_tree, get_agent_flow
from aworld.cmd.utils.trace_summarize import get_summarize_trace
logger = logging.getLogger(__name__)
router = APIRouter()
prefix = "/api/trace"
@router.get("/list")
async def list_traces():
storage = get_trace_server().get_storage()
trace_data = []
for trace_id in storage.get_all_traces():
spans = storage.get_all_spans(trace_id)
spans_sorted = sorted(spans, key=lambda x: x.start_time)
trace_tree = build_trace_tree(spans_sorted)
trace_data.append({
'trace_id': trace_id,
'root_span': trace_tree,
})
return {
"data": trace_data
}
@router.get("/agent")
async def get_agent_trace(trace_id: str):
data = get_agent_flow(trace_id)
await _add_trace_summary(trace_id, data.get('nodes'))
return data
async def _add_trace_summary(trace_id, spans):
summary = await get_summarize_trace(trace_id)
json_summary_dict = {}
if summary:
json_summary = json.loads(summary)
json_summary_dict = {item['agent']: json.dumps(
item) for item in json_summary}
for span in spans:
if summary and "event_id" in span:
span['summary'] = json_summary_dict.get(span['event_id'])
span['attributes'] = None
@@ -0,0 +1,74 @@
import logging
import os
from typing import List, Optional
from pydantic import BaseModel
from fastapi import APIRouter, HTTPException, status, Query, Body
from aworld.output import WorkSpace, ArtifactType
from aworld.output.utils import load_workspace
router = APIRouter()
prefix = "/api/workspaces"
@router.get("/{workspace_id}/tree")
async def get_workspace_tree(workspace_id: str):
logging.info(f"get_workspace_tree: {workspace_id}")
workspace = await get_workspace(workspace_id)
return workspace.generate_tree_data()
class ArtifactRequest(BaseModel):
artifact_ids: Optional[List[str]] = None
artifact_types: Optional[List[str]] = None
@router.post("/{workspace_id}/artifacts")
async def get_workspace_artifacts(workspace_id: str, request: ArtifactRequest):
"""
Get artifacts by workspace id and filter by a list of artifact types.
Args:
workspace_id: Workspace ID
request: Request body containing optional artifact_types list
Returns:
Dict with filtered artifacts
"""
artifact_types = request.artifact_types
if artifact_types:
# Validate all types
invalid_types = [t for t in artifact_types if t not in ArtifactType.__members__]
if invalid_types:
logging.error(f"Invalid artifact_types: {invalid_types}")
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Invalid artifact types: {invalid_types}")
logging.info(f"Fetching artifacts of types: {artifact_types}")
else:
logging.info(f"Fetching all artifacts (no type filter)")
workspace = await get_workspace(workspace_id)
all_artifacts = workspace.list_artifacts()
filtered_artifacts = all_artifacts
if request.artifact_ids:
filtered_artifacts = [a for a in filtered_artifacts if a.artifact_id in request.artifact_ids]
if artifact_types:
filtered_artifacts = [a for a in filtered_artifacts if a.artifact_type.name in artifact_types]
return {
"data": filtered_artifacts
}
@router.get("/{workspace_id}/file/{artifact_id}/content")
async def get_workspace_file_content(workspace_id: str, artifact_id: str):
logging.info(f"get_workspace_file_content: {workspace_id}, {artifact_id}")
workspace = await get_workspace(workspace_id)
return {
"data": workspace.get_file_content_by_artifact_id(artifact_id)
}
async def get_workspace(workspace_id: str) -> WorkSpace:
workspace_type = os.environ.get("WORKSPACE_TYPE", "local")
workspace_path = os.environ.get("WORKSPACE_PATH", "./data/workspaces")
return await load_workspace(workspace_id, workspace_type, workspace_path)