@siax/mobile-ai (0.1.1)
Installation
@siax:registry=https://git.cloud.siax.io/api/packages/sax3l/npm/npm install @siax/mobile-ai@0.1.1"@siax/mobile-ai": "0.1.1"About this package
@siax/mobile-ai
INF0-klient för SIAX-mobilappar. Ingen modellnyckel når enheten (MSEC-02).
Status: implementerad och testad (38 tester). Aldrig körd mot en riktig INF0-instans — se Vad som INTE är gjort nedan.
Kärnbussgränsen (MOB-02)
Detta paket är en yta, inte en AI-tjänst. Ingen modellroutning, ingen promptmall, ingen kostnadsberäkning och inget modellval bor här — det ägs av INF0/LiteLLM. Klienten gör bara det som måste ske på enheten: bär användarens ID0-token, startar traceen, bryter strömmen när användaren trycker stopp, och normaliserar fel.
Vad som faktiskt är byggt
| Fil | Innehåll |
|---|---|
src/client.ts |
Inf0Client — chat(), streamChat(), models() |
src/sse.ts |
SseParser — inkrementell SSE enligt WHATWG-semantik |
src/guard.ts |
MSEC-02-spärrar: förbjudna värdar, leverantörsnyckelmönster |
src/problem.ts |
RFC 9457 Problem Details + Inf0Error / Inf0AbortError |
src/trace.ts |
W3C traceparent, klientgenererat trace-id |
src/http.ts |
Timeout, inaktivitetsgräns, avbrytbar kroppsläsning |
src/types.ts |
Publika typer |
MSEC-02 är en runtime-spärr, inte en konvention
new Inf0Client({ baseUrl }) kastar om baseUrl pekar på api.openai.com,
api.anthropic.com, openrouter.ai, generativelanguage.googleapis.com m.fl., eller
om den använder klartext-http utanför loopback. Varje utgående request skannas
dessutom efter leverantörsnyckelmönster (sk-…, sk-ant-…, AIza…, gsk_…,
hf_…, xai-…, AKIA…) och efter huvudnamn som bara finns för att bära en
nyckel (x-api-key, openai-api-key, …). En ID0-JWT passerar; en
leverantörsnyckel gör det inte — oavsett var i kedjan den satts.
looksLikeProviderKey() är exporterad så att samma regel kan köras som en
byggkontroll mot en bundlad sträng i CI, i stället för att MSEC-02 bara hoppas på.
SSE-parsern
Byggd som en tillståndsmaskin över en buffert, utan antaganden om chunk-gränser.
Testad mot: en data:-rad delad i tre chunkar, hela strömmen matad tecken för
tecken, \r\n delat mitt itu över chunkgränsen, ett UTF-8-tecken delat mellan
två byte-chunkar, :-heartbeats, okända fält, BOM, och en ström som stängs utan
avslutande tomrad.
Ett medvetet avsteg från specen: flush() dispatchar ett event som har data men
aldrig fick sin avslutande tomrad. Specen säger "kasta bort"; i praktiken är det
skillnaden mellan att tappa sista meningen i ett svar och inte.
Avbrytbarhet (AI-12)
streamChat() är en async-generator. break i en for await stänger strömmen;
en AbortSignal bryter även under uppkopplingen. Avbrottet observeras i
klienten, inte bara via fetch — RN:s fetch-polyfill avbryter inte en pågående
kroppsläsning, och undici levererar redan buffrade chunkar. Utan den explicita
kapplöpningen fortsätter strömmen efter att användaren tryckt stopp.
Ett användaravbrott ger status 499, en timeout 408. Skillnaden är avsiktlig: den ena ska inte generera ett larm, den andra ska.
Vad som INTE är gjort
- Aldrig kört mot en riktig INF0-instans. Alla tester använder en injicerad
fetch. Kontraktet är OpenAI-kompatibelt (LiteLLM), men fältnamn och felformat är verifierade mot specifikationen — inte mot en levande gateway. - Verklig strömning i React Native kräver ett annat transportlager. RN:s
inbyggda
fetchexponerar interesponse.body. Klienten upptäcker det och faller tillbaka påresponse.text()— svaret kommer då som ett enda block, inte token för token. För riktig strömning på enhet: skicka inexpo/fetch(eller motsvarande) viaconfig.fetchImpl. Detta är inte åtgärdat i paketet. - Ingen tokenräkning, ingen retry-med-backoff, inga verktygsanrop
(tool calls).
usagevidarebefordras när INF0 skickar den; ingenting beräknas lokalt. - Ingen AUD0-emission. Klienten sätter
traceparentochx-request-id; det är INF0 som ska logga mot AUD0 (MOB-02). - Ingen typkontroll har körts. Repot har inga byggberoenden installerade, så
tschar aldrig körts mottsconfig.json. Koden är skriven i erasable TypeScript och körs av Node:s type stripping, vilket bevisar att den parsar — inte att den typkontrollerar.
Tester
cd packages/mobile-ai && node --test # eller: npm test
38 tester, alla gröna. Kräver Node ≥ 22.18 (native type stripping) — inga
beroenden, ingen npm install, ingen testrunner utöver node:test.