enhance(agent): sandbox runtime integration

This commit is contained in:
Tienson Qin
2026-02-02 00:15:09 +08:00
parent 4ddce67288
commit bba3014243
3 changed files with 112 additions and 3 deletions

View File

@@ -2,6 +2,7 @@
(:require [lambdaisland.glogi :as log]
[logseq.db-sync.common :as common]
[logseq.db-sync.platform.core :as platform]
[logseq.db-sync.worker.agent.sandbox :as sandbox]
[logseq.db-sync.worker.agent.session :as session]
[logseq.db-sync.worker.http :as http]
[promesa.core :as p]))
@@ -60,6 +61,38 @@
(broadcast-event! self event)
{:session session :event event})))))
(defn- sandbox-base [^js env]
(aget env "SANDBOX_AGENT_URL"))
(defn- sandbox-token [^js env]
(aget env "SANDBOX_AGENT_TOKEN"))
(defn- <provision-sandbox! [^js self task session-id]
(let [base (sandbox-base (.-env self))]
(if-not (string? base)
(p/resolved nil)
(p/let [payload {:agent (:agent task)
:repo (get-in task [:execution :repo])
:workdir (get-in task [:execution :workdir])
:env (get-in task [:execution :env])
:task-id session-id}
response (sandbox/<create-session base (sandbox-token (.-env self)) payload)
sandbox-session-id (:session-id response)
runtime {:sandbox {:base (sandbox/normalize-base-url base)
:session-id sandbox-session-id
:stream-url (sandbox/stream-url base sandbox-session-id)}}]
(p/let [session (<get-session self)
events (<get-events self)]
(if (nil? session)
nil
(let [session (assoc session :runtime runtime)
[session events _event] (session/append-event session events {:type "session.provisioned"
:data {:sandbox-session-id sandbox-session-id}
:ts (common/now-ms)})]
(p/let [_ (<put-session! self session)
_ (<put-events! self events)]
runtime))))))))
(defn- handle-init [^js self request]
(p/let [existing (<get-session self)]
(if existing
@@ -94,11 +127,12 @@
(let [session (session/initial-session task audit now)
[session events _event] (session/append-event session [] {:type "session.created" :data {:requested-by user-id} :ts now})]
(p/let [_ (<put-session! self session)
_ (<put-events! self events)]
_ (<put-events! self events)
_ (<provision-sandbox! self task task-id)]
(http/json-response :sessions/create
{:session-id task-id
:status (:status session)
:stream-url (stream-url request task-id)}))))))))))
:stream-url (stream-url request task-id)})))))))))))
(defn- handle-status [^js self _request]
(p/let [session (<get-session self)]
@@ -131,7 +165,15 @@
(p/let [res (<append-event! self {:type "audit.log"
:data {:message message
:kind (:kind body)
:by user-id}})]
:by user-id}})
session (<get-session self)
runtime (get-in session [:runtime :sandbox])
_ (when (and runtime (string? (:session-id runtime)))
(sandbox/<send-message (sandbox/normalize-base-url (:base runtime))
(sandbox-token (.-env self))
(:session-id runtime)
{:message message
:kind (:kind body)}))]
(if (= (:error res) :missing-session)
(http/not-found)
(http/json-response :sessions/message {:ok true})))))))))

View File

@@ -0,0 +1,47 @@
(ns logseq.db-sync.worker.agent.sandbox
(:require [clojure.string :as string]
[logseq.db-sync.platform.core :as platform]
[promesa.core :as p]))
(defn normalize-base-url [base]
(string/replace (or base "") #"/+$" ""))
(defn sessions-url [base]
(str (normalize-base-url base) "/sandbox/sessions"))
(defn messages-url [base session-id]
(str (normalize-base-url base) "/sandbox/sessions/" session-id "/messages"))
(defn stream-url [base session-id]
(str (normalize-base-url base) "/sandbox/sessions/" session-id "/stream"))
(defn- json-request [url method headers body]
(let [init (cond-> {:method method :headers headers}
(some? body)
(assoc :body (js/JSON.stringify (clj->js body))))]
(platform/request url (clj->js init))))
(defn <create-session
[base token {:keys [agent repo workdir env] :as payload}]
(let [headers (js/Headers.)
_ (.set headers "content-type" "application/json")
_ (when (string? token) (.set headers "authorization" (str "Bearer " token)))
req (json-request (sessions-url base) "POST" headers
{:agent agent
:repo repo
:workdir workdir
:env env
:payload payload})]
(p/let [resp (js/fetch req)
json (.json resp)]
(js->clj json :keywordize-keys true))))
(defn <send-message
[base token session-id message]
(let [headers (js/Headers.)
_ (.set headers "content-type" "application/json")
_ (when (string? token) (.set headers "authorization" (str "Bearer " token)))
req (json-request (messages-url base session-id) "POST" headers message)]
(p/let [resp (js/fetch req)
json (.json resp)]
(js->clj json :keywordize-keys true))))

View File

@@ -0,0 +1,20 @@
(ns logseq.db-sync.agent-sandbox-test
(:require [cljs.test :refer [deftest is testing]]
[logseq.db-sync.worker.agent.sandbox :as sandbox]))
(deftest normalize-base-url-test
(testing "normalizes sandbox base urls"
(is (= "https://sandbox.example" (sandbox/normalize-base-url "https://sandbox.example")))
(is (= "https://sandbox.example" (sandbox/normalize-base-url "https://sandbox.example/")))
(is (= "http://localhost:8787" (sandbox/normalize-base-url "http://localhost:8787//")))))
(deftest session-endpoint-test
(testing "builds sandbox session endpoints"
(let [base "https://sandbox.example"
session-id "sess-1"]
(is (= "https://sandbox.example/sandbox/sessions"
(sandbox/sessions-url base)))
(is (= "https://sandbox.example/sandbox/sessions/sess-1/messages"
(sandbox/messages-url base session-id)))
(is (= "https://sandbox.example/sandbox/sessions/sess-1/stream"
(sandbox/stream-url base session-id))))))