File size: 5,355 Bytes
b0fbec3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"""FastAPI server for ForgeEnv (OpenEnv-compliant).



Exposes /reset, /step, /state HTTP endpoints via OpenEnv's `create_app`.

HF Spaces sets PORT=7860 automatically.

"""
from __future__ import annotations

import os

from fastapi.responses import HTMLResponse
from openenv.core import create_app

from forgeenv.env.actions import ForgeAction
from forgeenv.env.forge_environment import ForgeEnvironment
from forgeenv.env.observations import ForgeObservation

app = create_app(
    env=ForgeEnvironment,
    action_cls=ForgeAction,
    observation_cls=ForgeObservation,
    env_name="forgeenv",
)


_LANDING_HTML = """<!doctype html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>ForgeEnv — OpenEnv server</title>

<meta name="viewport" content="width=device-width,initial-scale=1">

<style>

  :root { color-scheme: light dark; }

  body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

         max-width: 760px; margin: 2.5rem auto; padding: 0 1.25rem;

         line-height: 1.55; color: #1f2937; background: #fafafa; }

  @media (prefers-color-scheme: dark) { body { color: #e5e7eb; background: #0f172a; } }

  h1 { font-size: 1.65rem; margin-bottom: 0.25rem; }

  .sub { color: #6b7280; margin-top: 0; }

  code, pre { font-family: ui-monospace, "SF Mono", Menlo, monospace; }

  pre { background: rgba(127,127,127,0.12); padding: 0.9rem; border-radius: 8px;

        overflow-x: auto; }

  table { border-collapse: collapse; width: 100%; margin: 0.75rem 0 1.25rem; }

  td, th { text-align: left; padding: 0.5rem 0.75rem;

           border-bottom: 1px solid rgba(127,127,127,0.25); }

  th { font-weight: 600; }

  a { color: #2563eb; text-decoration: none; } a:hover { text-decoration: underline; }

  .ok { color: #16a34a; font-weight: 600; }

  .muted { color: #6b7280; font-size: 0.9rem; }

  .pill { display: inline-block; padding: 0.1rem 0.5rem; border-radius: 999px;

          background: rgba(34,197,94,0.15); color: #16a34a; font-size: 0.85rem; }

</style>

</head>

<body>

<h1>ForgeEnv 🔧 <span class="pill">running</span></h1>

<p class="sub">OpenEnv-compliant RL environment for HuggingFace

ecosystem repair under library version drift.</p>



<p>This URL serves the environment over HTTP. It is not a UI — it's the

runtime that <strong>training notebooks connect to</strong>. Open one of

the endpoints below, or use the demo Space to try the trained Repair

Agent in a browser.</p>



<h2>Endpoints</h2>

<table>

  <tr><th>Method</th><th>Path</th><th>Purpose</th></tr>

  <tr><td>GET </td><td><a href="/health">/health</a></td><td>Health probe</td></tr>

  <tr><td>POST</td><td><code>/reset</code></td><td>Sample task, return drift-gen observation</td></tr>

  <tr><td>POST</td><td><code>/step</code></td><td>Apply <code>ForgeAction</code> (breakage or repair)</td></tr>

  <tr><td>GET </td><td><a href="/state">/state</a></td><td>Current internal state</td></tr>

  <tr><td>GET </td><td><a href="/metadata">/metadata</a></td><td>Env name + version + schema URLs</td></tr>

  <tr><td>GET </td><td><a href="/schema">/schema</a></td><td>Action / observation JSON schemas</td></tr>

  <tr><td>GET </td><td><a href="/docs">/docs</a></td><td>Interactive Swagger UI</td></tr>

</table>



<h2>Quick start (Python)</h2>

<pre><code>import asyncio

from openenv.core import GenericEnvClient



async def go():

    client = GenericEnvClient(base_url="https://akhiilll-forgeenv.hf.space")

    obs = await client.reset()

    print(obs.observation["current_phase"], obs.observation["task_id"])



asyncio.run(go())</code></pre>



<h2>Project links</h2>

<ul>

  <li>Space card &amp; README:

      <a href="https://huggingface.co/spaces/akhiilll/forgeenv" target="_blank" rel="noopener noreferrer">huggingface.co/spaces/akhiilll/forgeenv</a></li>

  <li>Gradio demo:

      <a href="https://huggingface.co/spaces/akhiilll/forgeenv-demo" target="_blank" rel="noopener noreferrer">huggingface.co/spaces/akhiilll/forgeenv-demo</a></li>

  <li>Trained model (LoRA) <span class="muted">— published after the Colab training run finishes</span>:

      <a href="https://huggingface.co/akhiilll/forgeenv-repair-agent" target="_blank" rel="noopener noreferrer">huggingface.co/akhiilll/forgeenv-repair-agent</a></li>

</ul>

<p class="muted">Tip: if links don't open from inside the embedded Space frame,

right-click and choose <em>Open in new tab</em>, or open this URL directly

at <a href="https://akhiilll-forgeenv.hf.space/" target="_blank" rel="noopener noreferrer">akhiilll-forgeenv.hf.space</a>.</p>

</body>

</html>"""


def _attach_supplementary_routes(_app) -> None:
    """Add /health and a friendly GET / landing page if not present."""
    existing = {
        getattr(r, "path", None) for r in getattr(_app, "routes", [])
    }

    if "/health" not in existing:
        @_app.get("/health")
        def _health() -> dict:
            return {"status": "ok", "env": "forgeenv"}

    if "/" not in existing:
        @_app.get("/", response_class=HTMLResponse, include_in_schema=False)
        def _root() -> str:
            return _LANDING_HTML


_attach_supplementary_routes(app)


if __name__ == "__main__":
    import uvicorn

    port = int(os.environ.get("PORT", "7860"))
    uvicorn.run(app, host="0.0.0.0", port=port)