bend-kit-llm Releases (14): 0.13.0.1 0x4241bd59e0fba0c2cb4ad0636e5bce89 indexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.13.0.1 0.13.0.0 0xe1545b121103b27fc5cd5c22308db81e unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.13.0.0 0.12.0.0 0x550a924a5c983d7b4f09d71f7b06bb28 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.12.0.0 0.11.0.0 0xe3138d414c0f4f841a69039462da7a29 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.11.0.0 0.10.0.0 0x483e94e805b7e59e7499a48ba4f76018 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.10.0.0 0.9.0.0 0x83b5e3a2eb0c92672b3a397ae5ab4ee5 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.9.0.0 0.8.0.0 0x3aebfb456e42b4f0345f6c4eb0451e8a unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.8.0.0 0.7.0.0 0x2f89a910226c013be3a35bc6a4f29802 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.7.0.0 0.6.0.0 0xf1cea2d3078aa99bd029354b32412984 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.6.0.0 0.5.0.0 0xf5d0acdf5f312aa37c144e3e55a3cb53 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.5.0.0 0.4.0.0 0xd656dc843639933cea41399fb8ed6e01 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.4.0.0 0.3.0.0 0xce2a0a9d4864ec82024ab27469071032 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.3.0.0 0.2.0.0 0x10ade7fad6475d1f90ad2d2a4120337e unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.2.0.0 0.1.0.0 0x19246c2d3d82e756322a18d7212c64a2 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-llm@0.1.0.0 Definitions (134, 1 to 100 shown): Llm.Api (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Api) # Anthropic: POST {base}/v1/messages. OpenAI: POST {base}/chat/completions, which many other providers serve too. type Api is Data: Anthropic{} OpenAI{} Llm.Role (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Role) type Role is Data: User{} Assistant{} Llm.Msg (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Msg) type Msg is Data: Msg{role: Role, text: String} Llm.Req (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Req) # system: "" for none. max: the most tokens to write. type Req is Data: Req{model: String, system: String, msgs: List<&2, Msg>, max: U32} Llm.Reply (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Reply) # stop: the API's reason, as "end_turn" or "stop". input and output count tokens. type Reply is Data: Reply{id: String, model: String, text: String, stop: String, input: U32, output: U32} Llm.Err (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Err) # ErrNet: the request did not complete, or Hairpin's breaker admitted no attempt. ErrApi: the API refused, with # its status and error text; an error event in a stream has status 200. ErrReply: a reply that is not the API's JSON, with its text. type Err is Data: ErrNet{e: Hairpin.Err} ErrApi{status: U32, body: String} ErrReply{body: String} Llm.Client (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Client) # headers go on every request. ms: the step timeout. retries: extra tries after a retryable failure. type Client is Type: Client{api: Api, base: String, headers: Map<&2, List<&2, String>>, ms: U32, retries: U32, http: Hairpin.Client} Llm.str (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=str) def str(s: String) -> Json.Val: Llm.kv (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=kv) def kv(k: String, v: Json.Val) -> Bytes.Bytes & Json.Val: Llm.num (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=num) def num(+n: U32) -> Json.Val: Llm.obj (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=obj) def obj(kvs: List<&1, Bytes.Bytes & Json.Val>) -> Json.Val: Llm.when (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=when) def when(on: Bool, x: Bytes.Bytes & Json.Val, xs: List<&1, Bytes.Bytes & Json.Val>) -> List<&1, Bytes.Bytes & Json.Val>: Llm.role (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=role) def role(r: Role) -> String: Llm.msg (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=msg) def msg(+r: String, t: String) -> Json.Val: Llm.msgs (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=msgs) def msgs(xs: List<&2, Msg>) -> List<&1, Json.Val>: Llm.sys (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=sys) def sys(on: Bool, s: String, xs: List<&1, Json.Val>) -> List<&1, Json.Val>: Llm.body (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=body) # The request body for api. stream asks for SSE. def body(api: Api, req: Req, stream: Bool) -> Json.Val: Llm.Leaf (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Leaf) # A JSON leaf: its path, as "content.0.text", and its text. type Leaf is Data: Leaf{p: String, v: String} Llm.path (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=path) def path(+p: String, +k: String) -> String: Llm.push.arr (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=push.arr) def push.arr(xs: List<&1, Json.Val>, +p: String, +i: U32, t: List<&1, String & Json.Val>) -> List<&1, String & Json.Val>: Llm.push.obj (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=push.obj) def push.obj(kvs: List<&1, Bytes.Bytes & Json.Val>, +p: String, t: List<&1, String & Json.Val>) -> List<&1, String & Json.Val>: Llm.flat (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=flat) # The leaves under the stack's values, last first. f: at least the values left. def flat(f: Nat, stack: List<&1, String & Json.Val>, acc: List<&2, Leaf>) -> List<&2, Leaf>: Llm.doc.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=doc.of) def doc.of(+n: U32, m: Maybe<&1, Json.Val>) -> Maybe<&2, List<&2, Leaf>>: Llm.doc (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=doc) # Every non-null leaf of a JSON text in document order, keyed by its path, as ("content.0.text", "Hi"). # Strings are decoded; numbers keep their text. None when b is not JSON. Each value takes a byte, so n + 1 steps suffice. def doc(b: Bytes.Bytes) -> Maybe<&2, List<&2, Leaf>>: Llm.look (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=look) # The first value at path k, or "". def look(d: List<&2, Leaf>, +k: String) -> String: Llm.count (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=count) def count(s: String) -> U32: Llm.dots (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=dots) def dots(s: String, +n: U32) -> U32: Llm.block (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=block) # Is p the text of a content block, "content..text"? def block(+p: String) -> Bool: Llm.blocks (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=blocks) # The text blocks of an Anthropic message, joined. def blocks(d: List<&2, Leaf>) -> String: Llm.reply.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=reply.of) def reply.of(api: Api, +d: List<&2, Leaf>) -> Reply: Llm.reply.got (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=reply.got) def reply.got(api: Api, b: Bytes.Bytes, m: Maybe<&2, List<&2, Leaf>>) -> Result<&1, &1, Err, Reply>: Llm.reply.copy (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=reply.copy) def reply.copy(api: Api, r: Bytes.Bytes & Bytes.Bytes) -> Result<&1, &1, Err, Reply>: Llm.reply (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=reply) # A 2xx response body as a Reply. def reply(api: Api, b: Bytes.Bytes) -> Result<&1, &1, Err, Reply>: Llm.Ev (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Ev) # A text piece, the end, an error, or an event with no text. type Ev is Data: EText{s: String} EEnd{} EFail{e: Err} ESkip{} Llm.ev.text (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=ev.text) def ev.text(+s: String) -> Ev: Llm.ev.doc (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=ev.doc) def ev.doc(m: Maybe<&2, List<&2, Leaf>>) -> List<&2, Leaf>: Llm.ev.anthropic (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=ev.anthropic) def ev.anthropic(+name: String, data: Bytes.Bytes) -> Ev: Llm.ev.openai (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=ev.openai) def ev.openai(+s: String) -> Ev: Llm.ev (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=ev) # What one SSE event of api means. def ev(api: Api, e: Sse.Message) -> Ev: Llm.ok (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=ok) def ok(+s: U32) -> Bool: Llm.again.status (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=again.status) # Statuses a later try may clear: 408, 409, 429, and 5xx, which holds Anthropic's 529. def again.status(+s: U32) -> Bool: Llm.again.err (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=again.err) # A refused connect or a timeout may clear. def again.err(+e: Http.Err) -> Maybe<&2, String>: Llm.again.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=again.of) def again.of(+status: U32, +h: Map<&2, List<&2, String>>) -> Maybe<&2, String>: Llm.verdict (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=verdict) # Again when another try may help; otherwise settled, as Hairpin.judge would settle it. def verdict(m: Maybe<&2, String>, settled: Hairpin.Verdict) -> Hairpin.Verdict: Llm.again (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=again) # Hairpin's judge for every call. def again(r: Result<&1, &1, Http.Err, Http.Res>) -> Result<&1, &1, Http.Err, Http.Res> & Hairpin.Verdict: Llm.body.ok (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=body.ok) def body.ok(good: Bool, +status: U32, b: Bytes.Bytes) -> Result<&1, &1, Err, Bytes.Bytes>: Llm.body.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=body.of) # The 2xx body, or why there is none. def body.of(r: Result<&1, &1, Hairpin.Err, Http.Res>) -> Result<&1, &1, Err, Bytes.Bytes>: Llm.url (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=url) def url(api: Api, +base: String) -> String: Llm.new (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=new) def new(+api: Api, base: String, headers: Map<&2, List<&2, String>>) -> Client: Llm.json (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=json) def json(h: Map<&2, List<&2, String>>) -> Map<&2, List<&2, String>>: Llm.anthropic (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=anthropic) # base https://api.anthropic.com, 10 min steps, 2 retries. def anthropic(key: String) -> Client: Llm.openai (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=openai) # base https://api.openai.com/v1, 10 min steps, 2 retries. def openai(key: String) -> Client: Llm.base (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=base) # Another base URL, as for a provider that serves the same API. def base(c: Client, url: String) -> Client: Llm.header (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=header) # A header on every request, as anthropic-beta. It replaces one of the same name. def header(c: Client, k: String, v: String) -> Client: Llm.timeout (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=timeout) def timeout(c: Client, +ms: U32) -> Client: Llm.retry (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=retry) def retry(c: Client, n: U32) -> Client: Llm.close (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=close) def close(c: Client) -> IO(Unit): Llm.call.done (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=call.done) def call.done(+api: Api, base: String, headers: Map<&2, List<&2, String>>, +ms: U32, +n: U32, x: Hairpin.Client & Retry.Budget & Result<&1, &1, Hairpin.Err, Http.Res>) -> Client & Result<&1, &1, Err, Bytes.Bytes>: Llm.call.budget (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=call.budget) def call.budget(+api: Api, +base: String, +headers: Map<&2, List<&2, String>>, body: Bytes.Bytes, y: Hairpin.Client & Retry.Budget) -> IO(Hairpin.Client & Retry.Budget & Result<&1, &1, Hairpin.Err, Http.Res>): Llm.call (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=call) # POST body to the API with n retries on a budget of n + 1; the 2xx body comes back. # These POSTs are safe to repeat, so Hairpin retries them as again judges. def call(c: Client, body: Bytes.Bytes) -> IO(Client & Result<&1, &1, Err, Bytes.Bytes>): Llm.raw.got (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=raw.got) def raw.got(b: Bytes.Bytes, m: Maybe<&1, Json.Val>) -> Result<&1, &1, Err, Json.Val>: Llm.raw.copy (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=raw.copy) def raw.copy(r: Bytes.Bytes & Bytes.Bytes) -> Result<&1, &1, Err, Json.Val>: Llm.raw.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=raw.of) def raw.of(r: Result<&1, &1, Err, Bytes.Bytes>) -> Result<&1, &1, Err, Json.Val>: Llm.raw.done (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=raw.done) def raw.done(x: Client & Result<&1, &1, Err, Bytes.Bytes>) -> Client & Result<&1, &1, Err, Json.Val>: Llm.send.raw (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=send.raw) # Any request body, as for tools or images, and the reply as JSON. def send.raw(c: Client, v: Json.Val) -> IO(Client & Result<&1, &1, Err, Json.Val>): Llm.send.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=send.of) def send.of(r: Result<&1, &1, Err, Bytes.Bytes>, +api: Api) -> Result<&1, &1, Err, Reply>: Llm.send.done (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=send.done) def send.done(+api: Api, x: Client & Result<&1, &1, Err, Bytes.Bytes>) -> Client & Result<&1, &1, Err, Reply>: Llm.send (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=send) # One whole reply. def send(c: Client, req: Req) -> IO(Client & Result<&1, &1, Err, Reply>): Llm.Stream (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Stream) type Stream is Type: Stream{api: Api, h: Http.Stream, rd: Sse.Reader} Llm.open.res (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=open.res) def open.res(x: Http.Stream & Http.Res) -> Result<&1, &1, Http.Err, Http.Stream> & Hairpin.Verdict: Llm.open.judge (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=open.judge) def open.judge(r: Result<&1, &1, Http.Err, Http.Stream>) -> Result<&1, &1, Http.Err, Http.Stream> & Hairpin.Verdict: Llm.drain (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=drain) # A refused stream's error body, at most f more pieces, then the stream closed. def drain(f: Nat, x: Http.Stream & Result<&1, &1, Http.Err, Maybe<&1, Bytes.Bytes>>, acc: Bytes.Bytes) -> IO(Bytes.Bytes): Llm.start.refused (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=start.refused) def start.refused(+status: U32, h: Http.Stream) -> IO(Result<&1, &1, Err, Http.Stream>): Llm.start.ok (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=start.ok) def start.ok(good: Bool, +status: U32, h: Http.Stream) -> IO(Result<&1, &1, Err, Http.Stream>): Llm.start.res (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=start.res) def start.res(x: Http.Stream & Http.Res) -> IO(Result<&1, &1, Err, Http.Stream>): Llm.start (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=start) def start(r: Result<&1, &1, Hairpin.Err, Http.Stream>) -> IO(Result<&1, &1, Err, Http.Stream>): Llm.stream.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=stream.of) def stream.of(r: Result<&1, &1, Err, Http.Stream>, +api: Api) -> Result<&1, &1, Err, Stream>: Llm.stream.done (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=stream.done) def stream.done(+api: Api, base: String, headers: Map<&2, List<&2, String>>, +ms: U32, +n: U32, x: Hairpin.Client & Retry.Budget & Result<&1, &1, Hairpin.Err, Http.Stream>) -> IO(Client & Result<&1, &1, Err, Stream>): Llm.open.budget (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=open.budget) def open.budget(+api: Api, +base: String, +headers: Map<&2, List<&2, String>>, body: Bytes.Bytes, y: Hairpin.Client & Retry.Budget) -> IO(Hairpin.Client & Retry.Budget & Result<&1, &1, Hairpin.Err, Http.Stream>): Llm.stream.raw (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=stream.raw) # Any request body that asks for SSE, as for tools. The open retries as call does, on a budget of n + 1. # A stream opens on the client's pool. Close it with stream.close to give its connection back. def stream.raw(c: Client, v: Json.Val) -> IO(Client & Result<&1, &1, Err, Stream>): Llm.stream (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=stream) # The reply as it is written: read it with next. def stream(c: Client, req: Req) -> IO(Client & Result<&1, &1, Err, Stream>): Llm.stream.close (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=stream.close) # Close a stream. A stream read to its end gives its connection to the client's pool. def stream.close(c: Client, s: Stream) -> IO(Client): Llm.Rn (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=Rn) # The reader after the next event, or the stream's result. type Rn is Type: RnNext{h: Http.Stream, r: Sse.Reader & Sse.Next} RnOut{h: Http.Stream, rd: Sse.Reader, r: Result<&1, &1, Err, Maybe<&1, Sse.Message>>} Llm.event.read (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=event.read) def event.read(rd: Sse.Reader, x: Http.Stream & Result<&1, &1, Http.Err, Maybe<&1, Bytes.Bytes>>) -> Rn: Llm.event.loop (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=event.loop) # f: pieces left to read before the stream counts as stalled. def event.loop(f: Nat, st: Rn) -> IO(Http.Stream & Sse.Reader & Result<&1, &1, Err, Maybe<&1, Sse.Message>>): Llm.event.done (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=event.done) def event.done(+api: Api, x: Http.Stream & Sse.Reader & Result<&1, &1, Err, Maybe<&1, Sse.Message>>) -> Stream & Result<&1, &1, Err, Maybe<&1, Sse.Message>>: Llm.event (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=event) # The next SSE event, or None when the stream ends. An event the end cuts off is dropped. def event(s: Stream) -> IO(Stream & Result<&1, &1, Err, Maybe<&1, Sse.Message>>): Llm.next.ev (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=next.ev) def next.ev(r: Result<&1, &1, Err, Maybe<&1, Sse.Message>>, +api: Api) -> Ev: Llm.next.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=next.of) def next.of(x: Stream & Result<&1, &1, Err, Maybe<&1, Sse.Message>>) -> Stream & Ev: Llm.next.loop (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=next.loop) # f: events left to skip. def next.loop(f: Nat, x: Stream & Ev) -> IO(Stream & Result<&1, &1, Err, Maybe<&2, String>>): Llm.next (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/llm.bend&name=next) # The next piece of reply text, or None at the end. def next(s: Stream) -> IO(Stream & Result<&1, &1, Err, Maybe<&2, String>>): Sse.Message (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/sse.bend&name=Message) # name: the event type, "message" when the stream sets none. data: the data lines joined by LF. # id: the last event ID the stream set. name and id hold one Char per octet. type Message is Type: Message{name: String, data: Bytes.Bytes, id: String} Sse.St (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/sse.bend&name=St) # The event so far: its type, its data lines each ended by LF, the last event ID, and the last retry in ms. type St is Type: St{name: String, data: Bytes.Bytes, id: String, retry: Maybe<&2, U32>} Sse.Reader (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/sse.bend&name=Reader) # buf from pos: bytes not yet read as lines. No CR or LF is between pos and seen. # cr: the last line ended with a CR at the end of buf, so an LF first belongs to it. type Reader is Type: Reader{buf: Bytes.Bytes, pos: U32, seen: U32, cr: Bool, st: St} Sse.Next (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/sse.bend&name=Next) type Next is Type: Got{e: Message} Want{} Sse.reader (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/sse.bend&name=reader) # ponytail: a leading U+FEFF is not dropped; the LLM APIs never send one. def reader() -> Reader: Sse.feed.at (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/sse.bend&name=feed.at) def feed.at(zero: Bool, buf: Bytes.Bytes, +pos: U32, +seen: U32, cr: Bool, st: St, chunk: Bytes.Bytes) -> Reader: Sse.feed (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/sse.bend&name=feed) # Drops the lines already read, then adds chunk. def feed(r: Reader, chunk: Bytes.Bytes) -> Reader: Sse.retry (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/sse.bend&name=retry) # The last retry field, in ms. def retry(r: Reader) -> Reader & Maybe<&2, U32>: Sse.eol (https://jend.leeeet.dev/definition.txt?path=bend-kit-llm@0.13.0.1/sse.bend&name=eol) # The first CR or LF at or after i, or the end. f counts the bytes from i to the end; r holds byte i. def eol(f: Nat, r: Array & U32, +i: U32) -> Array & U32: More: https://jend.leeeet.dev/packages/bend-kit-llm.txt?definitions_offset=100