;; lib/flow/host.sx — the host integration ABI (Phase 8).
;;
;; `suspend` is flow's seam to the outside world, but a bare (suspend tag) is just a
;; signal — every author would invent their own tag shape. This layer defines a
;; stable request/response contract so a host (e.g. an art-dag driver, or a human
;; review UI) can hook in WITHOUT reverse-engineering ad-hoc tags.
;;
;; A flow asks the host to do something and waits for the answer:
;;   (request kind payload)  — suspend with a typed envelope (flow-request kind
;;     payload); evaluates to the host's resume value.
;;   (await-human prompt)    — request kind=human (a decision point)
;;   (await-render recipe)   — request kind=render (e.g. an art-dag job)
;;   (await-effect kind p)   — request of an arbitrary kind
;;
;; The host drives flows by polling its work queue and resuming:
;;   (flow-host-requests)    — ((id kind payload) ...) for every SUSPENDED flow whose
;;     waiting tag is a host request. The host dispatches by kind (render -> submit a
;;     Celery job; human -> show UI), then calls (flow/resume id answer).
;;   (request? tag) / (request-kind tag) / (request-payload tag) — parse one tag.
;;
;; Reference driver — the host only supplies `dispatch`, a (kind payload) -> answer:
;;   (flow-drive-host dispatch)        — one tick: service every CURRENTLY pending
;;     request (snapshot), resuming each with (dispatch kind payload); returns the
;;     count serviced. Resumes may create new requests — serviced on the next tick.
;;   (flow-run-host dispatch maxticks) — tick until quiescent (no pending requests)
;;     or maxticks reached; returns total requests serviced. Bounded for determinism.
;;
;; Contract: the host owns IO and persistence. flow stays deterministic — a flow
;; never performs IO itself, it only `request`s; the host performs the effect and
;; feeds the result back via resume (which the replay log records, so the effect is
;; not re-run on recovery). Persist with flow-store-export after each transition and
;; flow-store-import! on boot.

(define
  flow-host-src
  "(define (request kind payload) (suspend (list (quote flow-request) kind payload)))\n   (define (request? tag) (and (pair? tag) (eq? (car tag) (quote flow-request))))\n   (define (request-kind tag) (car (cdr tag)))\n   (define (request-payload tag) (car (cdr (cdr tag))))\n   (define (await-human prompt) (request (quote human) prompt))\n   (define (await-render recipe) (request (quote render) recipe))\n   (define (await-effect kind payload) (request kind payload))\n   (define (flow-host-req-step pend)\n     (if (null? pend)\n         (list)\n         (let ((id (car (car pend))) (tag (car (cdr (car pend)))))\n           (if (request? tag)\n               (cons (list id (request-kind tag) (request-payload tag))\n                     (flow-host-req-step (cdr pend)))\n               (flow-host-req-step (cdr pend))))))\n   (define (flow-host-requests) (flow-host-req-step (flow/pending)))\n   (define (flow-drive-host-step reqs dispatch)\n     (if (null? reqs)\n         0\n         (begin\n           (flow/resume (car (car reqs)) (dispatch (car (cdr (car reqs))) (car (cdr (cdr (car reqs))))))\n           (+ 1 (flow-drive-host-step (cdr reqs) dispatch)))))\n   (define (flow-drive-host dispatch) (flow-drive-host-step (flow-host-requests) dispatch))\n   (define (flow-run-host dispatch maxticks)\n     (if (<= maxticks 0)\n         0\n         (let ((n (flow-drive-host dispatch)))\n           (if (= n 0) 0 (+ n (flow-run-host dispatch (- maxticks 1)))))))")

(define
  flow-load-host!
  (fn
    (env)
    (begin (scheme-eval-program (scheme-parse-all flow-host-src) env) env)))
