-
Notifications
You must be signed in to change notification settings - Fork 0
feat: harden Agent Ready discovery surface #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
39b77d7
97c9460
979ec6e
1dd6de3
1eb378e
7bd2ea9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,14 @@ | ||
| from fastapi import FastAPI | ||
| from fastapi import FastAPI, Request | ||
| from fastapi.responses import HTMLResponse, PlainTextResponse, Response | ||
|
|
||
| from app.discovery import ( | ||
| AGENTS_MD, | ||
| DISCOVERY_BODY_HTML, | ||
| HEAD_DISCOVERY_HTML, | ||
| LLMS_FULL_TXT, | ||
| LLMS_TXT, | ||
| PLAYGROUND_MD, | ||
| RELEASE_VERSION, | ||
| ROBOTS_TXT, | ||
| SITEMAP_MD, | ||
| SITEMAP_XML, | ||
|
|
@@ -23,32 +25,49 @@ | |
|
|
||
| app = FastAPI( | ||
| title="Safe Agent API", | ||
| version="0.5.0", | ||
| version=RELEASE_VERSION, | ||
| description="Deterministic policy, approval and audit layer for agent tool execution demos.", | ||
| ) | ||
|
|
||
|
|
||
| @app.get("/", response_class=HTMLResponse, include_in_schema=False) | ||
| def playground() -> HTMLResponse: | ||
| MARKDOWN_HEADERS = { | ||
| "Link": '</>; rel="canonical", </sitemap.md>; rel="sitemap"', | ||
| "X-Robots-Tag": "index, follow, max-snippet:-1, max-image-preview:large", | ||
| } | ||
|
|
||
|
|
||
| @app.api_route("/", methods=["GET", "HEAD"], response_class=HTMLResponse, include_in_schema=False) | ||
| def playground(request: Request) -> Response: | ||
| accept = request.headers.get("accept", "").lower() | ||
| if request.method == "GET" and "text/markdown" in accept: | ||
|
Comment on lines
+41
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a client sends an Accept header such as Useful? React with 👍 / 👎. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For Useful? React with 👍 / 👎. |
||
| return PlainTextResponse( | ||
| PLAYGROUND_MD, | ||
| media_type="text/markdown", | ||
| headers=MARKDOWN_HEADERS, | ||
|
Comment on lines
+43
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The Markdown representation returned from Useful? React with 👍 / 👎. |
||
| ) | ||
|
|
||
| html = PLAYGROUND_HTML.replace("</head>", f"{HEAD_DISCOVERY_HTML}</head>") | ||
| html = html.replace('<p class="footer">', f'{DISCOVERY_BODY_HTML}<p class="footer">') | ||
| return HTMLResponse( | ||
| html, | ||
| headers={ | ||
| "Cache-Control": "no-store", | ||
| "Content-Security-Policy": ( | ||
| "default-src 'self'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; " | ||
| "connect-src 'self'; img-src 'self' data:; frame-ancestors 'none'" | ||
| "connect-src 'self'; img-src 'self' data: https://raw.githubusercontent.com; " | ||
| "frame-ancestors 'none'" | ||
| ), | ||
| "Link": '</llms.txt>; rel="describedby", </playground.md>; rel="alternate"; type="text/markdown"', | ||
| "Link": '</llms.txt>; rel="describedby", </index.md>; rel="alternate"; type="text/markdown"', | ||
| "Referrer-Policy": "no-referrer", | ||
| "X-Content-Type-Options": "nosniff", | ||
| "X-Robots-Tag": "index, follow, max-snippet:-1, max-image-preview:large", | ||
| }, | ||
| ) | ||
|
|
||
|
|
||
| @app.get("/health") | ||
| def health() -> dict[str, str]: | ||
| return {"status": "ok", "service": "safe-agent-api", "version": "0.5.0"} | ||
| return {"status": "ok", "service": "safe-agent-api", "version": RELEASE_VERSION} | ||
|
|
||
|
|
||
| @app.get("/llms.txt", response_class=PlainTextResponse, include_in_schema=False) | ||
|
|
@@ -81,12 +100,13 @@ def agents_md() -> PlainTextResponse: | |
| return PlainTextResponse(AGENTS_MD, media_type="text/markdown") | ||
|
|
||
|
|
||
| @app.get("/index.md", response_class=PlainTextResponse, include_in_schema=False) | ||
| @app.get("/playground.md", response_class=PlainTextResponse, include_in_schema=False) | ||
| def playground_md() -> PlainTextResponse: | ||
| return PlainTextResponse( | ||
| PLAYGROUND_MD, | ||
| media_type="text/markdown", | ||
| headers={"Link": '</sitemap.md>; rel="sitemap"'}, | ||
| headers=MARKDOWN_HEADERS, | ||
| ) | ||
|
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When these documented commands are run in a fresh shell, creating
.venvdoes not activate it, so the subsequent barepipresolves to the caller's existing environment and installs the package globally or into another environment despite the isolation claim. Activate.venvfirst or invoke.venv/bin/python -m pipdirectly.Useful? React with 👍 / 👎.