Spaces:
Running
Running
Make agent prompt work with private Spaces
#5
by thomwolf HF Staff - opened
- server/api.js +34 -10
server/api.js
CHANGED
|
@@ -410,24 +410,48 @@ function agentIdentity(req, asAgent) {
|
|
| 410 |
return { author: handle, authorType: 'agent' }
|
| 411 |
}
|
| 412 |
|
| 413 |
-
function agentPrompt(docId, handle) {
|
| 414 |
const tokenHint = OAUTH_ENABLED
|
| 415 |
? `the agent key that was shown when "@${handle}" was registered (an "ak_..." string; rotate it in the app if lost). It only works for this editor — it is not a Hugging Face credential.`
|
| 416 |
: `the dev token "dev:<your-username>" (no real key needed on this dev server)`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 417 |
return `You are the collaborative-editor agent "@${handle}" for the document ${docId} at ${HOST}.
|
| 418 |
|
| 419 |
You participate in a shared document, but you NEVER edit the text directly. You only:
|
| 420 |
1. reply to comment threads, and
|
| 421 |
2. propose suggestions (block replacements) that a human can accept or reject.
|
| 422 |
|
| 423 |
-
Authenticate every request with ${tokenHint}
|
| 424 |
export AGENT_KEY=<the key>
|
| 425 |
-
AUTH=
|
|
|
|
| 426 |
|
| 427 |
Work loop — repeat until the user tells you to stop:
|
| 428 |
|
| 429 |
1. Wait for work with ONE blocking call (up to ~50 minutes — do NOT use a short poll loop):
|
| 430 |
-
curl -sN --max-time 3300 $AUTH "${HOST}/api/mentions/stream?wait=3000" | grep -v '^:' | tail -n 1
|
| 431 |
The stream sends ":hb" heartbeat lines while idle; the final line is JSON:
|
| 432 |
{"mentions": [...]}. Empty output or an empty list just means the wait expired —
|
| 433 |
immediately make the same call again. This is the normal idle state; one call per
|
|
@@ -444,16 +468,16 @@ Work loop — repeat until the user tells you to stop:
|
|
| 444 |
thread you are involved in and is probably addressed to you. Judge it yourself —
|
| 445 |
if it asks you to act, act; if it needs no action from you (small talk, addressed
|
| 446 |
to someone else, a simple thanks), dismiss it silently:
|
| 447 |
-
curl -s $AUTH -X POST "${HOST}/api/mentions/<mention_id>/dismiss"
|
| 448 |
|
| 449 |
2. For each mention addressed to you, read the page for context:
|
| 450 |
-
curl -s $AUTH "${HOST}/api/docs/<doc_id>?page=<page>"
|
| 451 |
Returns the page markdown, "blocks": [{index, anchor_start, anchor_end, markdown}], and
|
| 452 |
"pages" (all pages in the project). GET ${HOST}/api/docs/<doc_id>/structure shows the
|
| 453 |
page tree. The tree is defined by a YAML code block on the special "_structure" page
|
| 454 |
(read it with ?page=_structure): one "- slug" line per page, two-space indent to nest.
|
| 455 |
To propose a NEW page, POST a single new-page suggestion with its title and full content:
|
| 456 |
-
curl -s $AUTH -X POST "${HOST}/api/docs/<doc_id>/page-suggestions" -H 'content-type: application/json' \\
|
| 457 |
-d '{"title": "Page Title", "content_markdown": "# Page Title\\n\\n...", "rationale": "why", "as_agent": "${handle}"}'
|
| 458 |
It appears in the sidebar as a pending page immediately; a human accepts it (which creates
|
| 459 |
the page with your content and adds it to the structure) or rejects it. To reorganize
|
|
@@ -483,7 +507,7 @@ Work loop — repeat until the user tells you to stop:
|
|
| 483 |
is answered in the thread — briefly.
|
| 484 |
|
| 485 |
Reply in the thread:
|
| 486 |
-
curl -s $AUTH -X POST "${HOST}/api/docs/<doc_id>/threads/<thread_id>/reply" \\
|
| 487 |
-H 'content-type: application/json' \\
|
| 488 |
-d '{"text": "...", "page": "<page>", "as_agent": "${handle}", "mention_id": "<mention_id>"}'
|
| 489 |
|
|
@@ -493,7 +517,7 @@ Work loop — repeat until the user tells you to stop:
|
|
| 493 |
with a | --- | --- | separator row), \`\`\`code\`\`\`, **bold**, *italic*, [links](url),
|
| 494 |
LaTeX math (inline \$x^2\$, or \$\$...\$\$ on its own line for a display formula),
|
| 495 |
and live HTML embeds — see below):
|
| 496 |
-
curl -s $AUTH -X POST "${HOST}/api/docs/<doc_id>/suggestions" \\
|
| 497 |
-H 'content-type: application/json' \\
|
| 498 |
-d '{"block_index": <n>, "replacement_markdown": "...", "rationale": "why", "page": "<page>",
|
| 499 |
"as_agent": "${handle}", "mention_id": "<mention_id>", "thread_id": "<thread_id>"}'
|
|
@@ -501,7 +525,7 @@ Work loop — repeat until the user tells you to stop:
|
|
| 501 |
or "supersedes": "<suggestion_id>" to mark it as a revision of an earlier suggestion of yours.)
|
| 502 |
|
| 503 |
Figures: you can include images in suggestions. Upload the bytes first:
|
| 504 |
-
curl -s $AUTH -X POST "${HOST}/api/docs/<doc_id>/upload" \\
|
| 505 |
-H 'content-type: image/png' --data-binary @figure.png
|
| 506 |
-> {"url": "/files/..."} — then reference it in replacement_markdown as .
|
| 507 |
External https image URLs work too.
|
|
|
|
| 410 |
return { author: handle, authorType: 'agent' }
|
| 411 |
}
|
| 412 |
|
| 413 |
+
export function agentPrompt(docId, handle) {
|
| 414 |
const tokenHint = OAUTH_ENABLED
|
| 415 |
? `the agent key that was shown when "@${handle}" was registered (an "ak_..." string; rotate it in the app if lost). It only works for this editor — it is not a Hugging Face credential.`
|
| 416 |
: `the dev token "dev:<your-username>" (no real key needed on this dev server)`
|
| 417 |
+
const privateSpaceAuth = OAUTH_ENABLED
|
| 418 |
+
? `
|
| 419 |
+
If this is a PRIVATE Hugging Face Space, the proxy needs Hugging Face access in
|
| 420 |
+
addition to the editor agent key. A proxy-level HTML 404 from ${HOST} (rather
|
| 421 |
+
than a JSON response from the editor) is the usual sign. Keep the two credentials
|
| 422 |
+
separate: the Space JWT goes in the \`spaces-jwt\` cookie, while AGENT_KEY stays in
|
| 423 |
+
the Authorization header that reaches the editor app. Never replace AGENT_KEY with
|
| 424 |
+
HF_TOKEN on an editor API request.
|
| 425 |
+
|
| 426 |
+
# Private Spaces only: HF_TOKEN must already be set, must have read access to
|
| 427 |
+
# ${process.env.SPACE_ID || '<owner/space>'}, and must never be printed.
|
| 428 |
+
: "\${HF_TOKEN:?Set HF_TOKEN to a Hugging Face token with access to the Space}"
|
| 429 |
+
SPACE_ID='${process.env.SPACE_ID || '<owner/space>'}'
|
| 430 |
+
SPACE_JWT=$(curl -fsS -H "Authorization: Bearer $HF_TOKEN" \\
|
| 431 |
+
"https://huggingface.co/api/spaces/$SPACE_ID/jwt" | jq -r '.token // .accessToken')
|
| 432 |
+
test -n "$SPACE_JWT" && test "$SPACE_JWT" != null
|
| 433 |
+
AUTH+=(--cookie "spaces-jwt=$SPACE_JWT")
|
| 434 |
+
|
| 435 |
+
The Hub URL (https://huggingface.co/spaces/$SPACE_ID) is the repository page;
|
| 436 |
+
continue sending editor API calls to ${HOST}. Refresh SPACE_JWT with the commands
|
| 437 |
+
above if the private-Space proxy later returns HTML 401/404 or the JWT expires.
|
| 438 |
+
`
|
| 439 |
+
: ''
|
| 440 |
return `You are the collaborative-editor agent "@${handle}" for the document ${docId} at ${HOST}.
|
| 441 |
|
| 442 |
You participate in a shared document, but you NEVER edit the text directly. You only:
|
| 443 |
1. reply to comment threads, and
|
| 444 |
2. propose suggestions (block replacements) that a human can accept or reject.
|
| 445 |
|
| 446 |
+
Authenticate every editor API request with ${tokenHint}
|
| 447 |
export AGENT_KEY=<the key>
|
| 448 |
+
AUTH=(-H "Authorization: Bearer $AGENT_KEY")
|
| 449 |
+
${privateSpaceAuth}
|
| 450 |
|
| 451 |
Work loop — repeat until the user tells you to stop:
|
| 452 |
|
| 453 |
1. Wait for work with ONE blocking call (up to ~50 minutes — do NOT use a short poll loop):
|
| 454 |
+
curl -sN --max-time 3300 "\${AUTH[@]}" "${HOST}/api/mentions/stream?wait=3000" | grep -v '^:' | tail -n 1
|
| 455 |
The stream sends ":hb" heartbeat lines while idle; the final line is JSON:
|
| 456 |
{"mentions": [...]}. Empty output or an empty list just means the wait expired —
|
| 457 |
immediately make the same call again. This is the normal idle state; one call per
|
|
|
|
| 468 |
thread you are involved in and is probably addressed to you. Judge it yourself —
|
| 469 |
if it asks you to act, act; if it needs no action from you (small talk, addressed
|
| 470 |
to someone else, a simple thanks), dismiss it silently:
|
| 471 |
+
curl -s "\${AUTH[@]}" -X POST "${HOST}/api/mentions/<mention_id>/dismiss"
|
| 472 |
|
| 473 |
2. For each mention addressed to you, read the page for context:
|
| 474 |
+
curl -s "\${AUTH[@]}" "${HOST}/api/docs/<doc_id>?page=<page>"
|
| 475 |
Returns the page markdown, "blocks": [{index, anchor_start, anchor_end, markdown}], and
|
| 476 |
"pages" (all pages in the project). GET ${HOST}/api/docs/<doc_id>/structure shows the
|
| 477 |
page tree. The tree is defined by a YAML code block on the special "_structure" page
|
| 478 |
(read it with ?page=_structure): one "- slug" line per page, two-space indent to nest.
|
| 479 |
To propose a NEW page, POST a single new-page suggestion with its title and full content:
|
| 480 |
+
curl -s "\${AUTH[@]}" -X POST "${HOST}/api/docs/<doc_id>/page-suggestions" -H 'content-type: application/json' \\
|
| 481 |
-d '{"title": "Page Title", "content_markdown": "# Page Title\\n\\n...", "rationale": "why", "as_agent": "${handle}"}'
|
| 482 |
It appears in the sidebar as a pending page immediately; a human accepts it (which creates
|
| 483 |
the page with your content and adds it to the structure) or rejects it. To reorganize
|
|
|
|
| 507 |
is answered in the thread — briefly.
|
| 508 |
|
| 509 |
Reply in the thread:
|
| 510 |
+
curl -s "\${AUTH[@]}" -X POST "${HOST}/api/docs/<doc_id>/threads/<thread_id>/reply" \\
|
| 511 |
-H 'content-type: application/json' \\
|
| 512 |
-d '{"text": "...", "page": "<page>", "as_agent": "${handle}", "mention_id": "<mention_id>"}'
|
| 513 |
|
|
|
|
| 517 |
with a | --- | --- | separator row), \`\`\`code\`\`\`, **bold**, *italic*, [links](url),
|
| 518 |
LaTeX math (inline \$x^2\$, or \$\$...\$\$ on its own line for a display formula),
|
| 519 |
and live HTML embeds — see below):
|
| 520 |
+
curl -s "\${AUTH[@]}" -X POST "${HOST}/api/docs/<doc_id>/suggestions" \\
|
| 521 |
-H 'content-type: application/json' \\
|
| 522 |
-d '{"block_index": <n>, "replacement_markdown": "...", "rationale": "why", "page": "<page>",
|
| 523 |
"as_agent": "${handle}", "mention_id": "<mention_id>", "thread_id": "<thread_id>"}'
|
|
|
|
| 525 |
or "supersedes": "<suggestion_id>" to mark it as a revision of an earlier suggestion of yours.)
|
| 526 |
|
| 527 |
Figures: you can include images in suggestions. Upload the bytes first:
|
| 528 |
+
curl -s "\${AUTH[@]}" -X POST "${HOST}/api/docs/<doc_id>/upload" \\
|
| 529 |
-H 'content-type: image/png' --data-binary @figure.png
|
| 530 |
-> {"url": "/files/..."} — then reference it in replacement_markdown as .
|
| 531 |
External https image URLs work too.
|