Download docs/modules/capi.md from PYTHAI/bankml: direct link, hf CLI and curl.
- Browser
- Download file 7 kB
-
https://huggingface.co/spaces/PYTHAI/bankml/resolve/main/docs/modules/capi.md
- Command line
-
hf download hf://spaces/PYTHAI/bankml/docs/modules/capi.md
-
curl -L -o capi.md https://huggingface.co/spaces/PYTHAI/bankml/resolve/main/docs/modules/capi.md
capi/src/ — the C API: libbankml.so / libbankml.a
Summary
capi/ (package bankml-capi) is bankML as a library for C, C++, Python, Go or Swift programs, declared in
capi/include/bankml.h (since 0.3.2). It is the llama.h-shaped seam for embedding bankML in another program, with
bankML's verification gate in front. lib.rs holds the entry points; printf.rs is the formatter behind
bankml_log. The full reference (build and link, every function, ownership, threads, error codes, oracles) is CAPI.md;
this page only maps it to the two source files.
Technical usage
lib.rs:bankml_version,bankml_open(the sameverifyasbankml serve, then the native forward pass),bankml_chat(theserve --nativechat request, streamed to a callback, with the same receipt throughserve::NativeChat,serve::completion_jsonandserve::Tally),bankml_close,bankml_free,bankml_set_logandbankml_log. Every entry point returns an error code or NULL with a message and runs insidecatch_unwind. One handle has one slot, so calls on it serialize.pub unsafe extern "C" fn bankml_open(model_path: *const c_char, fork_json_path: *const c_char, n_ctx: u32, err: *mut *mut c_char) -> *mut Bankml // n_ctx 0: 4096 pub unsafe extern "C" fn bankml_chat(h: *mut Bankml, request_json: *const c_char, cb: Option<PieceCb>, user: *mut c_void, result_json: *mut *mut c_char) -> c_intbankml_openreads the FORK.json, records the file's identity, runsverify(the guard, then the sha256 pin), and refuses the file if its identity changed while it was being hashed, asbankml servedoes. A model that bankML's native forward pass does not play is refused with serve's reason. The refusal goes to*errand is also logged at error level. Messages use the file name as given; themodelfield of each answer uses the canonical file's name, as serve does.bankml_chatchecks before every answer, asserve --nativedoes, that the file is still the one that was verified (otherwiseBANKML_E_CHANGED: reopen to verify again). The request takesmessages,temperature,top_k,top_p,min_p,seed,max_tokens/n_predictandstop; since 0.3.3response_format,json_schemaandgrammarasserve --nativetakes them. The answer streams to the callback as whole, non-empty UTF-8 pieces, each NUL-terminated. The handle's lock is held while the callback runs, so the callback must not close the handle or callbankml_chaton it.bankml_chatreturnsBANKML_OK(0) orBANKML_E_ARG(−1),_REQUEST(−2),_CHANGED(−3, the file changed since it was verified),_ENGINE(−4) or_PANIC(−5). Because it parses the request withserve --native'sNativeChat::parse, it takes what/v1takes: the whole sampler chain (0.3.7) andlogprobs/top_logprobs(0.3.8), whose entries come back in*result_jsonaschoices[0].logprobs.content. The callback receives text only.bankml_logis a C-variadic function defined in Rust (stabilized in Rust 1.99, pinned inrust-toolchain.toml):pub unsafe extern "C" fn bankml_log(level: c_int, fmt: *const c_char, mut args: ...)It passes
&mut args(aVaList) toprintf::formatand delivers the result to the sinkbankml_set_loginstalled (standard error by default). The library's own messages reach the same sink throughbankml::log. The sink is process-wide; the callback is called outside the sink's lock, so it may run concurrently on any thread that calls into bankML. A NUL inside a message is replaced by U+2400 so that C does not truncate it.printf.rs:pub unsafe fn format(fmt: &[u8], a: &mut impl Args) -> Vec<u8>. TheArgstrait is the typed reads the formatter needs;VaListimplements it withnext_arg::<T>()at the C type each conversion names, and the unit tests implement it with a typed queue.- Supported, byte-identical to glibc's
snprintf:%d %i %u %x %X(withhh h l ll z),%f %F %lf,%c,%s,%p,%%; the flags- + space # 0; a width and a precision, each a number or*(anintargument, as C reads it). - Anything else is written
%<unsupported:SPEC>and never guessed.%nnever writes through its argument. - An unknown conversion or length (
%e,%g,%o,%n,%Lf,%ls,%jd, …) reads no argument. Since the formatter cannot know that argument's type, it reads no argument after it either: every later conversion is written%<skipped:SPEC>(%%still prints%). - A known conversion with a flag combination it does not vouch for (
%+s,%05c,%#p,%#d), or with a width or precision above 65,536 (LIMIT), is written%<unsupported:SPEC>. Its argument has a known type, so it is read and dropped and the rest of the format goes on. The limit exists because this is a log line, not a way to make the library allocate gigabytes. - A
%with anything between it and the next%(%5%) is marked but reads no argument; a format that ends inside a conversion is written%<incomplete:SPEC>. %frelies on Rust printing the exact decimal expansion of the double, rounded to nearest with ties to even, as glibc does in the default rounding mode. A NULL%sprints(null)when the precision allows six bytes, otherwise nothing; a%swith a precision never reads past it, so an unterminated buffer is legal, as in C.
- Supported, byte-identical to glibc's
How it is verified
The printf oracle (testing/capi/printf_oracle.c: bankml_log against libc snprintf, byte for byte, 47 of 47
formats identical, 17 of 17 unsupported cases marked), the capi chat oracle (bankml_chat against serve --native
and llama-server b11192's records), and cargo test -p bankml-capi. Details in CAPI.md.
Advantages and efficiency
A program that links llama.cpp's llama.h can link bankML instead and get the same answers with verification and a
receipt built in. The crate's only dependency is the bankml crate itself, so the workspace still has no external
crate. printf.rs states a # Safety contract for each typed argument read and for format.
Limitations
No tokenizer or raw logits access (only the request's logprobs), one slot per handle (calls on a handle
serialize), and no stable ABI promise before 1.0.0 (TODO.md). The capi chat oracle does not yet cover
the 0.3.7 samplers or logprobs through bankml_chat; they share serve --native's code and its oracles. The release
profile aborts on a panic rather than unwinding, as a C library's failed assertion does; catch_unwind (and
BANKML_E_PANIC) only takes effect in an unwinding build.
See also
CAPI.md · usage.md (6b, the C API) · oracles.md · TODO.md