e2b template

This commit is contained in:
Tienson Qin
2026-03-08 18:23:46 +08:00
parent f5a8e44f68
commit 5e2b461f46
13 changed files with 429 additions and 30 deletions

View File

@@ -45,6 +45,7 @@
:logseq.class/Project
{:title "Project"
:schema {:properties [:logseq.property/git-repo
:logseq.property/project.docker-file
:logseq.property/project-sandbox-init-setup]
:required-properties [:logseq.property/git-repo]}}

View File

@@ -449,6 +449,12 @@
:public? true
:view-context :page}
:properties {:logseq.property/description "Runs after sandbox startup is ready. Store setup commands in a code block, e.g. `yarn install`."}}
:logseq.property/project.docker-file
{:title "Project Dockerfile"
:schema {:type :default
:public? true
:view-context :page}
:properties {:logseq.property/description "Store Dockerfile content in a code block. Used to build the sandbox image before startup."}}
:logseq.property/pr
{:title "PR"
:schema {:type :url

View File

@@ -30,7 +30,7 @@
(map (juxt :major :minor)
[(parse-schema-version x) (parse-schema-version y)])))
(def version (parse-schema-version "65.28"))
(def version (parse-schema-version "65.29"))
(defn major-version
"Return a number.

View File

@@ -63,3 +63,13 @@
(testing "logseq property namespace"
(is (db-property/logseq-property? :logseq.property.reaction/emoji-id))
(is (db-property/logseq-property? :logseq.property.reaction/target)))))
(deftest project-docker-file-built-in-property
(let [props db-property/built-in-properties]
(is (contains? props :logseq.property/project.docker-file))
(is (= "Project Dockerfile"
(get-in props [:logseq.property/project.docker-file :title])))
(is (= :default
(get-in props [:logseq.property/project.docker-file :schema :type])))
(is (= true
(get-in props [:logseq.property/project.docker-file :schema :public?])))))

View File

@@ -132,6 +132,30 @@
checkpoint
(merge checkpoint (checkpoint-bundle-fields bundle))))
(def ^:private checkpoint-bundle-ks
[:bundle-id
:bundle-seq
:bundle-object-key
:bundle-byte-size
:bundle-checksum
:bundle-head-sha
:bundle-base-sha
:bundle-head-branch])
(defn- strip-checkpoint-bundle
[checkpoint]
(if (map? checkpoint)
(apply dissoc checkpoint checkpoint-bundle-ks)
checkpoint))
(defn- runtime-provider-id
[runtime]
(some-> (:provider runtime) str string/lower-case))
(defn- workspace-bundle-required?
[runtime]
(not= "e2b" (runtime-provider-id runtime)))
(defn- runtime-checkpoint-payload
[runtime result reason]
(let [snapshot-id (runtime-snapshot-id result)
@@ -423,10 +447,12 @@
(string? reason) (assoc :reason reason))
:ts (common/now-ms)})]
(if (map? checkpoint)
(p/let [checkpoint (<checkpoint-workspace-bundle! self current-session checkpoint (cond-> {:by by
:reason reason}
(string? head-branch)
(assoc :head-branch head-branch)))
(p/let [checkpoint (if (workspace-bundle-required? (:runtime current-session))
(<checkpoint-workspace-bundle! self current-session checkpoint (cond-> {:by by
:reason reason}
(string? head-branch)
(assoc :head-branch head-branch)))
(p/resolved (strip-checkpoint-bundle checkpoint)))
_ (<persist-session-checkpoint! self (:id current-session) checkpoint)
_ (<append-event! self {:type "sandbox.checkpoint.succeeded"
:data (checkpoint-event-data checkpoint
@@ -1113,9 +1139,12 @@
nil
:else
(p/let [restored-bundle (<restore-workspace-bundle! self session-id task runtime)]
(p/let [restored-bundle (if (workspace-bundle-required? runtime)
(<restore-workspace-bundle! self session-id task runtime)
(p/resolved nil))]
(let [base-checkpoint (or (runtime-checkpoint-payload runtime runtime "provisioned")
(checkpoint-payload-with-reason d1-checkpoint "provisioned"))
(some-> (checkpoint-payload-with-reason d1-checkpoint "provisioned")
strip-checkpoint-bundle))
runtime-checkpoint (merge-checkpoint-bundle base-checkpoint restored-bundle)
session (-> session
(assoc :runtime runtime)

View File

@@ -949,6 +949,19 @@
(some-> (get-in task [:runtime :template]) str string/trim not-empty)
(env-str env "E2B_TEMPLATE")))
(defn- task-graph-id
[task]
(some-> (get-in task [:project :graph-id]) str string/trim not-empty))
(defn- project-docker-file
[task]
(some-> (get-in task [:project :docker-file]) str string/trim not-empty))
(defn- e2b-template-name
[task]
(when-let [graph-id (task-graph-id task)]
(sanitize-name (str "logseq-" graph-id "-" (task-repo-name task)))))
(defn- e2b-agent-token
[^js env runtime]
(or (:agent-token runtime)
@@ -1163,6 +1176,41 @@
(seq env-vars) (assoc :envs env-vars)
(string? session-id) (assoc :metadata metadata))))
(defn- e2b-template-fn
[]
(aget e2b "Template"))
(defn- e2b-template-missing-error?
[error]
(let [message (some-> error str)]
(boolean (and (string? message)
(string/starts-with? message "Error: 404:")))))
(defn- <e2b-existing-template!
[^js env template-name]
(let [template-fn (e2b-template-fn)
get-tags (js-method template-fn "getTags")]
(when-not (fn? template-fn)
(throw (ex-info "e2b sdk missing Template"
{:reason :missing-e2b-template-sdk})))
(when-not (fn? get-tags)
(throw (ex-info "e2b sdk missing Template.getTags"
{:reason :missing-e2b-template-get-tags})))
(-> (->promise (.call get-tags template-fn template-name (clj->js (e2b-api-opts env))))
(p/then (fn [_tags] template-name))
(p/catch (fn [error]
(if (e2b-template-missing-error? error)
nil
(throw error)))))))
(defn- <e2b-resolve-template!
[^js env task runtime]
(if (project-docker-file task)
(if-let [template-name (e2b-template-name task)]
(<e2b-existing-template! env template-name)
(p/resolved nil))
(p/resolved (e2b-template env task runtime))))
(defn- e2b-server-command
[^js env task session-id port agent-token env-vars]
(let [auth-json (get-in task [:agent :auth-json])
@@ -1239,14 +1287,11 @@
nil))))))
(defn- <e2b-create-sandbox-for-restore!
[^js env template checkpoint create-opts]
[^js env checkpoint create-opts create-fn]
(p/let [checkpoint-restore (<e2b-create-sandbox-from-checkpoint! env checkpoint create-opts)]
(if (map? checkpoint-restore)
checkpoint-restore
(p/let [sandbox (<e2b-create-sandbox! env template create-opts)]
{:sandbox sandbox
:snapshot-id nil
:restored? false}))))
(create-fn))))
(defn- <e2b-runtime-base-url!
[^js env runtime]
@@ -2631,14 +2676,19 @@
repo-dir (get-repo-dir session-id task "e2b")
checkpoint (task-sandbox-checkpoint task)
backup-key (or (:backup-key checkpoint)
(repo-backup-key task))
template (e2b-template env task nil)]
(repo-backup-key task))]
(p/let [env-vars (<e2b-agent-env-vars! env task)
create-opts (e2b-create-opts env session-id env-vars)
{:keys [sandbox snapshot-id restored?]} (<e2b-create-sandbox-for-restore! env
template
checkpoint
create-opts)
{:keys [sandbox snapshot-id restored? template]} (<e2b-create-sandbox-for-restore! env
checkpoint
create-opts
(fn []
(p/let [template (<e2b-resolve-template! env task nil)
sandbox (<e2b-create-sandbox! env template create-opts)]
{:sandbox sandbox
:snapshot-id nil
:restored? false
:template template})))
_ (<e2b-ensure-running! env sandbox session-id task port agent-token env-vars)
_ (when-not restored?
(p/catch
@@ -2649,14 +2699,6 @@
:error (str error)
:error-data (ex-data error)})
nil)))
_ (p/catch
(<e2b-run-project-init-setup! sandbox session-id task)
(fn [error]
(log/error :agent/e2b-project-init-setup-failed
{:session-id session-id
:error (str error)
:error-data (ex-data error)})
nil))
base-url (e2b-sandbox-host sandbox port)
response (sandbox/<create-session base-url agent-token session-id payload)
sandbox-id (e2b-sandbox-id sandbox)]

View File

@@ -234,6 +234,8 @@
[:title :string]
[:repo-url :string]
[:base-branch {:optional true} :string]
[:graph-id {:optional true} :string]
[:docker-file {:optional true} :string]
[:sandbox-init-setup {:optional true} :string]]]
[:agent [:or :string
[:map

View File

@@ -742,6 +742,67 @@
(is false (str "unexpected checkpoint bundle error: " error))
(done))))))))
(deftest checkpoint-existing-snapshot-skips-workspace-bundle-for-e2b-test
(testing "e2b checkpoint refresh keeps snapshot metadata without persisting workspace bundle"
(async done
(let [env #js {"AGENT_RUNTIME_PROVIDER" "e2b"}
self (make-self env)
export-calls (atom 0)
put-calls (atom 0)
upsert-calls (atom 0)
session {:id "sess-checkpoint-e2b"
:status "running"
:task {:id "sess-checkpoint-e2b"
:project {:repo-url "https://github.com/logseq/logseq"
:base-branch "main"}
:sandbox-checkpoint {:provider "e2b"
:snapshot-id "e2b-snapshot-1"
:bundle-id "old-bundle"
:bundle-object-key "workspace-bundles/old.bundle.b64"}}
:runtime {:provider "e2b"
:session-id "sess-checkpoint-e2b"
:sandbox-id "sbx-checkpoint-e2b"
:snapshot-id "e2b-snapshot-1"
:backup-key "github/logseq/logseq#main"
:backup-dir "/home/user/workspace/logseq"}
:audit {}
:created-at 0
:updated-at 0}]
(-> (.put (.-storage self) "session" (clj->js session))
(.then (fn [_]
(with-redefs [checkpoint-store/<upsert-checkpoint-for-task! (fn [_env _task checkpoint]
(js/Promise.resolve checkpoint))
runtime-provider/<export-workspace-bundle! (fn [_provider _runtime _opts]
(swap! export-calls inc)
(js/Promise.resolve nil))
workspace-bundle-r2/<put-bundle-base64! (fn [_env _object-key _bundle-base64 _metadata]
(swap! put-calls inc)
(js/Promise.resolve nil))
workspace-bundle-store/<upsert-bundle-for-task! (fn [_env _task _bundle]
(swap! upsert-calls inc)
(js/Promise.resolve nil))]
(#'agent-do/<checkpoint-existing-snapshot! self
session
{:by "system"
:reason "pr-ready"}))))
(.then (fn [ok?]
(is (true? ok?))
(is (zero? @export-calls))
(is (zero? @put-calls))
(is (zero? @upsert-calls))
(.then (.get (.-storage self) "session")
(fn [session-js]
(let [stored (js->clj session-js :keywordize-keys true)
checkpoint (get-in stored [:task :sandbox-checkpoint])]
(is (= "e2b-snapshot-1" (:snapshot-id checkpoint)))
(is (= "e2b" (:provider checkpoint)))
(is (nil? (:bundle-id checkpoint)))
(is (nil? (:bundle-object-key checkpoint)))
(done))))))
(.catch (fn [error]
(is false (str "unexpected e2b checkpoint error: " error))
(done))))))))
(deftest provision-runtime-restores-workspace-bundle-test
(testing "provision runtime applies latest workspace bundle and stores bundle metadata in checkpoint"
(async done
@@ -814,6 +875,86 @@
(is false (str "unexpected restore bundle error: " error))
(done))))))))
(deftest provision-runtime-skips-workspace-bundle-restore-for-e2b-test
(testing "e2b provision should not restore workspace bundle metadata from R2"
(async done
(let [env #js {"AGENT_RUNTIME_PROVIDER" "e2b"
"AGENTS_DB" #js {}}
self (make-self env)
task {:id "sess-restore-e2b"
:agent "codex"
:project {:repo-url "https://github.com/logseq/logseq"
:base-branch "main"}}
runtime {:provider "e2b"
:session-id "runtime-restore-e2b"
:sandbox-id "sbx-restore-e2b"
:snapshot-id "e2b-snapshot-restored"}
get-bundle-calls (atom 0)
apply-calls (atom 0)
provider (reify runtime-provider/RuntimeProvider
(<provision-runtime! [_ _session-id _task]
(js/Promise.resolve runtime))
(<open-events-stream! [_ _runtime]
(js/Promise.resolve nil))
(<send-message! [_ _runtime _message]
(js/Promise.resolve true))
(<open-terminal! [_ _runtime _request _opts]
(js/Promise.resolve nil))
(<snapshot-runtime! [_ _runtime _opts]
(js/Promise.resolve nil))
(<export-workspace-bundle! [_ _runtime _opts]
(js/Promise.resolve nil))
(<apply-workspace-bundle! [_ _runtime _opts]
(swap! apply-calls inc)
(js/Promise.resolve true))
(<push-branch! [_ _runtime _opts]
(js/Promise.resolve nil))
(<terminate-runtime! [_ _runtime]
(js/Promise.resolve nil)))]
(-> (.put (.-storage self)
"session"
(clj->js {:id "sess-restore-e2b"
:status "running"
:task task
:audit {}
:created-at 0
:updated-at 0}))
(.then (fn [_]
(with-redefs [runtime-provider/resolve-provider (fn [_env _runtime] provider)
runtime-provider/provider-id (fn [_provider] "e2b")
agent-do/start-runtime-events-stream-background! (fn [& _] nil)
common/<d1-all (fn [_db _sql & _args]
(js/Promise.resolve
#js {:results #js [#js {"provider" "e2b"
"snapshot_id" "snapshot-from-d1"
"bundle_id" "bundle-restore-1"
"bundle_seq" 3
"bundle_object_key" "workspace-bundles/github/logseq/logseq/main/bundle-restore-1.bundle.b64"
"checkpoint_at" 1000}]}))
common/get-sql-rows (fn [result]
(aget result "results"))
workspace-bundle-store/<load-latest-bundle-for-task! (fn [_env _task _session-id]
(js/Promise.resolve {:bundle-id "bundle-restore-1"}))
workspace-bundle-r2/<get-bundle-base64! (fn [_env _object-key]
(swap! get-bundle-calls inc)
(js/Promise.resolve {:bundle-base64 "ZmFrZS1idW5kbGUtZGF0YQ=="}))]
(#'agent-do/<provision-runtime! self task "sess-restore-e2b"))))
(.then (fn [_]
(is (zero? @get-bundle-calls))
(is (zero? @apply-calls))
(.then (.get (.-storage self) "session")
(fn [session-js]
(let [stored (js->clj session-js :keywordize-keys true)
checkpoint (get-in stored [:task :sandbox-checkpoint])]
(is (= "e2b-snapshot-restored" (:snapshot-id checkpoint)))
(is (= "e2b" (:provider checkpoint)))
(is (nil? (:bundle-id checkpoint)))
(is (nil? (:bundle-object-key checkpoint)))
(done))))))
(.catch (fn [error]
(is false (str "unexpected e2b restore provision error: " error))
(done))))))))
(deftest restore-workspace-bundle-skips-when-session-changed-test
(testing "bundle apply should be skipped when expected session is no longer current"
(async done

View File

@@ -141,6 +141,146 @@
(is false (str "unexpected error: " error))
(done)))))))
(deftest e2b-provider-provision-uses-existing-template-from-project-docker-file-test
(async done
(let [calls (atom [])
env #js {"E2B_API_KEY" "e2b-key"
"SANDBOX_AGENT_TOKEN" "agent-token"
"E2B_TEMPLATE" "fallback-template"}
provider (runtime-provider/create-provider env "e2b")
task {:agent {:provider "codex"}
:project {:repo-url "https://github.com/logseq/agent-test"
:graph-id "graph-123"
:docker-file "FROM node:20\nRUN corepack enable"}}
e2b-ns (js/require "e2b")
original-template (aget e2b-ns "Template")
sandbox-class (runtime-provider/e2b-sandbox-class)
original-create (aget sandbox-class "create")
original-fetch js/fetch
restore! (fn []
(aset e2b-ns "Template" original-template)
(aset sandbox-class "create" original-create)
(set! js/fetch original-fetch))
template-fn (fn [] #js {})]
(aset template-fn "getTags"
(fn [name opts]
(swap! calls conj {:type :get-tags
:name name
:opts (js->clj opts :keywordize-keys true)})
(js/Promise.resolve #js [])))
(aset e2b-ns "Template" template-fn)
(aset sandbox-class "create"
(fn [& args]
(let [template (first args)
opts (js->clj (last args) :keywordize-keys true)]
(swap! calls conj {:type :create
:template template
:opts opts})
(js/Promise.resolve
#js {:sandboxId "e2b-sbx-docker"
:getHost (fn [_port]
"https://e2b-agent.local")
:commands
#js {:run (fn [cmd _opts]
(if (string/includes? cmd "/v1/health")
(js/Promise.resolve #js {:stdout "__HEALTH_OK__"
:stderr ""
:exitCode 0})
(js/Promise.resolve #js {:stdout ""
:stderr ""
:exitCode 0})))}}))))
(set! js/fetch
(fn [_request]
(js/Promise.resolve
(js/Response.
(js/JSON.stringify #js {:ok true})
#js {:status 200
:headers #js {"content-type" "application/json"}}))))
(-> (runtime-provider/<provision-runtime! provider "sess-e2b-docker" task)
(.then (fn [runtime]
(restore!)
(is (= "e2b" (:provider runtime)))
(is (= "logseq-graph-123-agent-test" (:template runtime)))
(is (some #(and (= :get-tags (:type %))
(= "logseq-graph-123-agent-test" (:name %))
(= "e2b-key" (get-in % [:opts :apiKey])))
@calls))
(is (some #(and (= :create (:type %))
(= "logseq-graph-123-agent-test" (:template %)))
@calls))
(done)))
(.catch (fn [error]
(restore!)
(is false (str "unexpected error: " error))
(done)))))))
(deftest e2b-provider-provision-falls-back-to-default-sandbox-when-template-missing-test
(async done
(let [calls (atom [])
env #js {"E2B_API_KEY" "e2b-key"
"SANDBOX_AGENT_TOKEN" "agent-token"
"E2B_TEMPLATE" "fallback-template"}
provider (runtime-provider/create-provider env "e2b")
task {:agent {:provider "codex"}
:project {:repo-url "https://github.com/logseq/agent-test"
:graph-id "graph-123"
:docker-file "FROM node:20\nRUN corepack enable"}}
e2b-ns (js/require "e2b")
original-template (aget e2b-ns "Template")
sandbox-class (runtime-provider/e2b-sandbox-class)
original-create (aget sandbox-class "create")
original-fetch js/fetch
restore! (fn []
(aset e2b-ns "Template" original-template)
(aset sandbox-class "create" original-create)
(set! js/fetch original-fetch))
template-fn (fn [] #js {})]
(aset template-fn "getTags"
(fn [_name _opts]
(js/Promise.reject (js/Error. "404: Not Found"))))
(aset e2b-ns "Template" template-fn)
(aset sandbox-class "create"
(fn [& args]
(swap! calls conj {:type :create
:argc (count args)
:first-arg (first args)
:last-arg (js->clj (last args) :keywordize-keys true)})
(js/Promise.resolve
#js {:sandboxId "e2b-sbx-docker-default"
:getHost (fn [_port]
"https://e2b-agent.local")
:commands
#js {:run (fn [cmd _opts]
(if (string/includes? cmd "/v1/health")
(js/Promise.resolve #js {:stdout "__HEALTH_OK__"
:stderr ""
:exitCode 0})
(js/Promise.resolve #js {:stdout ""
:stderr ""
:exitCode 0})))}})))
(set! js/fetch
(fn [_request]
(js/Promise.resolve
(js/Response.
(js/JSON.stringify #js {:ok true})
#js {:status 200
:headers #js {"content-type" "application/json"}}))))
(-> (runtime-provider/<provision-runtime! provider "sess-e2b-docker-default" task)
(.then (fn [runtime]
(restore!)
(is (= "e2b" (:provider runtime)))
(is (nil? (:template runtime)))
(is (some #(and (= :create (:type %))
(= 1 (:argc %))
(map? (:first-arg %))
(= "e2b-key" (get-in % [:first-arg :apiKey])))
@calls))
(done)))
(.catch (fn [error]
(restore!)
(is false (str "unexpected error: " error))
(done)))))))
(deftest e2b-run-shell-wraps-commandexiterror-test
(async done
(let [env #js {"E2B_API_KEY" "e2b-key"}

View File

@@ -14,7 +14,9 @@
:runner-id "runner-1"
:project {:id "project-1"
:title "Demo Project"
:repo-url "https://github.com/example/repo"}
:repo-url "https://github.com/example/repo"
:graph-id "graph-1"
:docker-file "FROM node:20\nRUN corepack enable"}
:agent "codex"}
coerced (http/coerce-http-request :sessions/create body)]
(is (= body coerced))))
@@ -30,7 +32,9 @@
:attachments ["https://example.com/a.png" "https://example.com/b.png"]
:project {:id "project-1"
:title "Demo Project"
:repo-url "https://github.com/example/repo"}
:repo-url "https://github.com/example/repo"
:graph-id "graph-1"
:docker-file "FROM node:20\nRUN corepack enable"}
:agent {:provider "codex"
:api-token "token-123"
:auth-json "{\"tokens\":{\"access_token\":\"abc\"}}"}
@@ -47,7 +51,9 @@
"https://example.com/b.png"]}
:project {:id "project-1"
:title "Demo Project"
:repo-url "https://github.com/example/repo"}
:repo-url "https://github.com/example/repo"
:graph-id "graph-1"
:docker-file "FROM node:20\nRUN corepack enable"}
:agent {:provider "codex"
:api-token "token-123"
:auth-json "{\"tokens\":{\"access_token\":\"abc\"}}"}

View File

@@ -11,6 +11,7 @@
[frontend.state :as state]
[frontend.util :as util]
[lambdaisland.glogi :as log]
[logseq.db :as ldb]
[logseq.shui.ui :as shui]
[logseq.sync.malli-schema :as db-sync-schema]
[promesa.core :as p]))
@@ -105,9 +106,12 @@
([project-page {:keys [base-branch]}]
(let [repo-url (blank->nil (or (pu/get-block-property-value project-page :logseq.property/git-repo)
(:logseq.property/git-repo project-page)))
docker-file (blank->nil (or (pu/get-block-property-value project-page :logseq.property/project.docker-file)
(:logseq.property/project.docker-file project-page)))
sandbox-init-setup (blank->nil (or (pu/get-block-property-value project-page :logseq.property/project-sandbox-init-setup)
(:logseq.property/project-sandbox-init-setup project-page)))
project-id (some-> (:block/uuid project-page) str)
graph-id (some-> (ldb/get-graph-rtc-uuid (db/get-db)) str blank->nil)
title (blank->nil (:block/title project-page))
base-branch (blank->nil base-branch)]
(when (and project-id title repo-url)
@@ -115,6 +119,8 @@
:title title
:repo-url repo-url}
(string? base-branch) (assoc :base-branch base-branch)
(string? graph-id) (assoc :graph-id graph-id)
(string? docker-file) (assoc :docker-file docker-file)
(string? sandbox-init-setup) (assoc :sandbox-init-setup sandbox-init-setup))))))
(defn- block-line-content

View File

@@ -86,7 +86,8 @@
:logseq.property/agent-auth-json]}]
["65.25" {:properties [:logseq.property/pr]}]
["65.27" {:properties [:logseq.property/agent-session-id]}]
["65.28" {:properties [:logseq.property/sandbox-checkpoint]}]])
["65.28" {:properties [:logseq.property/sandbox-checkpoint]}]
["65.29" {:properties [:logseq.property/project.docker-file]}]])
(let [[major minor] (last (sort (map (comp (juxt :major :minor) db-schema/parse-schema-version first)
schema-version->updates)))]

View File

@@ -82,3 +82,18 @@
(:kv/value (d/entity @conn :logseq.kv/schema-version))))
(is (some? property))
(is (= :map (:logseq.property/type property)))))
(deftest migrate-adds-project-docker-file-property-builtin
(let [conn (db-test/create-conn)
property-ident :logseq.property/project.docker-file
_ (d/transact! conn [{:db/ident :logseq.kv/schema-version
:kv/value {:major 65 :minor 28}}])
existing-eid (d/entid @conn property-ident)
_ (when existing-eid
(d/transact! conn [[:db/retractEntity existing-eid]]))
_ (db-migrate/migrate conn :target-version "65.29")
property (d/entity @conn property-ident)]
(is (= {:major 65 :minor 29}
(:kv/value (d/entity @conn :logseq.kv/schema-version))))
(is (some? property))
(is (= :default (:logseq.property/type property)))))