@hilbras/omnihilbras 1.71.1 → 1.75.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/claude-code.d.ts +165 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +517 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/cline.js +1 -1
- package/dist/adapters/tokenharbor-web.d.ts +201 -0
- package/dist/adapters/tokenharbor-web.d.ts.map +1 -0
- package/dist/adapters/tokenharbor-web.js +619 -0
- package/dist/adapters/tokenharbor-web.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import type { ChatMessage, ChatRequest, ChatResponse, CredentialValidation, Model, ProviderAdapter, ProviderCredential, ProviderHealth, ProviderId, ProviderRequestContext } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Token Harbor Web — the chat application at tokenharbor.ai, driven by the Supabase session
|
|
4
|
+
* cookie a signed-in browser already holds.
|
|
5
|
+
*
|
|
6
|
+
* ## Read this before building on it
|
|
7
|
+
*
|
|
8
|
+
* Token Harbor's terms **prohibit** what this adapter does. Their product is itself a gateway,
|
|
9
|
+
* and the metered API key is its architectural guardrail; driving the web chat with a harvested
|
|
10
|
+
* session cookie routes around that guardrail. The two clauses that name it:
|
|
11
|
+
*
|
|
12
|
+
* > **Proxy Reselling:** Utilize the Service to construct a direct, white-labeled proxy
|
|
13
|
+
* > alternative to Token Harbor without adding substantive unique value or without prior written
|
|
14
|
+
* > enterprise authorization.
|
|
15
|
+
* >
|
|
16
|
+
* > ...designed to compromise the security, stability, or **architectural guardrails of the
|
|
17
|
+
* > Token Harbor gateway**.
|
|
18
|
+
*
|
|
19
|
+
* There is a legitimate path — `https://tokenharbor.ai/v1` with a Bearer key, OpenAI-compatible,
|
|
20
|
+
* documented, and free on the `:free` models — and it is the card beside this one. This adapter
|
|
21
|
+
* exists because the operator asked for the session-cookie route with that trade stated, and it
|
|
22
|
+
* carries the same warning in the dashboard catalog (`riskSeverity: 'high'`) so a user meets it
|
|
23
|
+
* before pasting a credential. It is the same shape as the Kiro notice: the vendor's terms and
|
|
24
|
+
* the gateway's behaviour are both on the card, and using it is the user's decision to make.
|
|
25
|
+
*
|
|
26
|
+
* ## What the credential is
|
|
27
|
+
*
|
|
28
|
+
* Auth is Supabase (`auth.tokenharbor.ai`), so the browser cookie is `sb-<ref>-auth-token`,
|
|
29
|
+
* where `<ref>` is the first label of the Supabase host — `auth`, giving `sb-auth-auth-token`.
|
|
30
|
+
* Above Supabase's size limit the value is split into `sb-...-auth-token.0`, `.1`, ... and the
|
|
31
|
+
* chunks are reassembled in order. It is written with `document.cookie`, so unlike ChatGPT Web's
|
|
32
|
+
* `HttpOnly` session it can be read from the Application panel or the Network tab's Cookie
|
|
33
|
+
* header — which is why the guide offers both.
|
|
34
|
+
*
|
|
35
|
+
* ## The wire format is not OpenAI's, and that is the whole adapter
|
|
36
|
+
*
|
|
37
|
+
* A turn is two requests and a decode:
|
|
38
|
+
*
|
|
39
|
+
* 1. `POST /api/direct-chat/sessions` with `{ model, temporary: true }` → `{ session: { id } }`.
|
|
40
|
+
* `temporary` is sent so a stateless gateway does not litter the user's sidebar with a
|
|
41
|
+
* conversation per request.
|
|
42
|
+
* 2. `POST /api/direct-chat/stream` with `{ sessionId, content, model, webSearch, tz }` → an SSE
|
|
43
|
+
* body whose events are **named**, not OpenAI's `choices[].delta`:
|
|
44
|
+
* `chunk` (the answer text in `delta`), `thinking` (reasoning in `delta`), `tool_use`,
|
|
45
|
+
* `citation`, `image`, `file`, `miniapp`, and `done`. `error` carries `{ code, message }`.
|
|
46
|
+
*
|
|
47
|
+
* Only `chunk`, `thinking`, `done` and `error` are consumed. The others are attachments and
|
|
48
|
+
* citations for a UI, and inventing an OpenAI shape for them here would be guessing at a
|
|
49
|
+
* contract this adapter cannot test without the session.
|
|
50
|
+
*
|
|
51
|
+
* ## What is not claimed
|
|
52
|
+
*
|
|
53
|
+
* `capabilities.streaming` is false and no `streamChat` is implemented: the transport is SSE,
|
|
54
|
+
* but the gateway consumes the whole body and returns one completion. A streaming surface would
|
|
55
|
+
* need the chunk boundary semantics verified against a live session first.
|
|
56
|
+
*
|
|
57
|
+
* `healthCheck` reports `verified: 'credential'`. It reads `/api/me/profile`, which proves the
|
|
58
|
+
* session cookie is accepted and nothing more — the same distinction the type exists to force.
|
|
59
|
+
*/
|
|
60
|
+
export declare const tokenHarborWebProviderId: ProviderId;
|
|
61
|
+
export declare const TOKENHARBOR_WEB: {
|
|
62
|
+
readonly origin: "https://tokenharbor.ai";
|
|
63
|
+
readonly apiBase: "https://tokenharbor.ai/api";
|
|
64
|
+
readonly profileUrl: "https://tokenharbor.ai/api/me/profile";
|
|
65
|
+
readonly sessionsUrl: "https://tokenharbor.ai/api/direct-chat/sessions";
|
|
66
|
+
readonly streamUrl: "https://tokenharbor.ai/api/direct-chat/stream";
|
|
67
|
+
readonly cookiePrefix: "sb-auth-auth-token";
|
|
68
|
+
readonly defaultModel: "th-rudder:free";
|
|
69
|
+
/** The page a user signs in on and copies the cookie from. */
|
|
70
|
+
readonly signInUrl: "https://tokenharbor.ai/login";
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* The catalog, read from `https://tokenharbor.ai/models` on 2026-10-07.
|
|
74
|
+
*
|
|
75
|
+
* A dated snapshot rather than a promise: the page is the live list and this is what it showed.
|
|
76
|
+
* Prices are per 1M tokens, which is the unit the SDK normalises to and the unit the page itself
|
|
77
|
+
* prints. The two `:free` ids are the ones that bill nothing.
|
|
78
|
+
*
|
|
79
|
+
* No context window is claimed because the page publishes none.
|
|
80
|
+
*/
|
|
81
|
+
export declare const TOKENHARBOR_WEB_MODELS: ReadonlyArray<{
|
|
82
|
+
id: string;
|
|
83
|
+
label: string;
|
|
84
|
+
family: string;
|
|
85
|
+
inputPer1M: number;
|
|
86
|
+
outputPer1M: number;
|
|
87
|
+
}>;
|
|
88
|
+
export declare function allTokenHarborWebModels(): string[];
|
|
89
|
+
/**
|
|
90
|
+
* Reads the Supabase session cookie out of whatever the user pasted.
|
|
91
|
+
*
|
|
92
|
+
* Two pastes are accepted, because both are things the guide tells people to copy:
|
|
93
|
+
*
|
|
94
|
+
* - the whole `Cookie:` request header (space for the Cloudflare clearance and the other cookies
|
|
95
|
+
* the SSR layer reads), and
|
|
96
|
+
* - just the `sb-auth-auth-token` value or the `sb-auth-auth-token=...` pair, from the
|
|
97
|
+
* Application panel.
|
|
98
|
+
*
|
|
99
|
+
* The chunks are **joined in numeric order**, which is not the order they appear in a header:
|
|
100
|
+
* a large token is stored as `.0`, `.1`, ... and a header that happens to list `.1` before `.0`
|
|
101
|
+
* would otherwise reassemble to a garbage session that fails later as an unexplained refusal.
|
|
102
|
+
*/
|
|
103
|
+
export declare function parseTokenHarborCookieHeader(raw: string): string;
|
|
104
|
+
/**
|
|
105
|
+
* Decodes the session cookie and reports what is wrong with it, or `undefined` when it is intact.
|
|
106
|
+
*
|
|
107
|
+
* Returns a sentence rather than a boolean because the two failures need different instructions: a
|
|
108
|
+
* value that does not decode is a **truncated paste**, and a value that decodes but carries no
|
|
109
|
+
* access token is a **shape this adapter does not recognise**. "Sign in again" is wrong for the
|
|
110
|
+
* first — the session is fine, the paste was short.
|
|
111
|
+
*/
|
|
112
|
+
export declare function sessionValueProblem(session: string): string | undefined;
|
|
113
|
+
/** The `expires_at` epoch seconds inside the session, when it is one this adapter can read.
|
|
114
|
+
*
|
|
115
|
+
* Accepts either the bare value or a whole Cookie header, because the two callers have different
|
|
116
|
+
* shapes in hand: the parser has the value, the refusal path has the assembled header.
|
|
117
|
+
*/
|
|
118
|
+
export declare function sessionExpiresAt(sessionOrCookie: string): number | undefined;
|
|
119
|
+
export declare function tokenHarborWebCredential(raw: string): ProviderCredential;
|
|
120
|
+
export declare function tokenHarborWebCookieFromCredential(credential: ProviderCredential | undefined): string;
|
|
121
|
+
export declare class TokenHarborWebAdapter implements ProviderAdapter {
|
|
122
|
+
readonly id: string;
|
|
123
|
+
readonly name = "Token Harbor Web";
|
|
124
|
+
readonly capabilities: {
|
|
125
|
+
readonly chat: true;
|
|
126
|
+
readonly models: true;
|
|
127
|
+
};
|
|
128
|
+
private readonly now;
|
|
129
|
+
private readonly fetchImpl;
|
|
130
|
+
constructor(options?: {
|
|
131
|
+
now?: () => number;
|
|
132
|
+
fetch?: typeof fetch;
|
|
133
|
+
});
|
|
134
|
+
/**
|
|
135
|
+
* The dated catalog above, not a request.
|
|
136
|
+
*
|
|
137
|
+
* Token Harbor publishes no public models JSON — the live list is rendered into the `/models`
|
|
138
|
+
* page — so there is nothing to read without a session, and an authenticated read per call
|
|
139
|
+
* would be a cost for a list that changes weekly. The snapshot is what the page showed on the
|
|
140
|
+
* date beside it, and the free-only policy narrows it the way the dialog's checkbox promises.
|
|
141
|
+
*/
|
|
142
|
+
listModels(context?: ProviderRequestContext): Promise<Model[]>;
|
|
143
|
+
/**
|
|
144
|
+
* A real round trip to `/api/me/profile`, which answers `{ ok: false }` with a 401 to a session
|
|
145
|
+
* it does not recognise. That is the cheapest endpoint that proves the cookie is accepted, and
|
|
146
|
+
* it is the whole of what this establishes — see `healthCheck`.
|
|
147
|
+
*/
|
|
148
|
+
validateCredential(credential: ProviderCredential | undefined, context?: ProviderRequestContext): Promise<CredentialValidation>;
|
|
149
|
+
/**
|
|
150
|
+
* `verified: 'credential'` — deliberately.
|
|
151
|
+
*
|
|
152
|
+
* Reading the profile proves the cookie is live; it says nothing about whether a model can
|
|
153
|
+
* answer. Claiming `inference` would need a real turn on every 60-second poll, which is a real
|
|
154
|
+
* request against someone else's service on a timer, and the type exists precisely so this
|
|
155
|
+
* distinction is stated rather than implied.
|
|
156
|
+
*/
|
|
157
|
+
healthCheck(context?: ProviderRequestContext): Promise<ProviderHealth>;
|
|
158
|
+
chat(request: ChatRequest, context?: ProviderRequestContext): Promise<ChatResponse>;
|
|
159
|
+
private createSession;
|
|
160
|
+
private request;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Flattens the message list into the single `content` string the endpoint takes.
|
|
164
|
+
*
|
|
165
|
+
* Labelled rather than concatenated: a bare join of `["You are terse.", "2+2?"]` loses which was
|
|
166
|
+
* which, and the model then answers as if the instruction were part of the question.
|
|
167
|
+
*/
|
|
168
|
+
export declare function flattenMessages(messages: readonly ChatMessage[]): string;
|
|
169
|
+
/**
|
|
170
|
+
* Reads a completed answer out of Token Harbor's named-event SSE body.
|
|
171
|
+
*
|
|
172
|
+
* The client's own parser is the source of truth for the shapes, and it is not OpenAI's:
|
|
173
|
+
*
|
|
174
|
+
* ```text
|
|
175
|
+
* event: chunk
|
|
176
|
+
* data: {"delta":"working"}
|
|
177
|
+
*
|
|
178
|
+
* event: thinking
|
|
179
|
+
* data: {"delta":"..."}
|
|
180
|
+
*
|
|
181
|
+
* event: done
|
|
182
|
+
* data: {}
|
|
183
|
+
* ```
|
|
184
|
+
*
|
|
185
|
+
* `chunk` is the answer text and `thinking` is the reasoning, split into their own events — so a
|
|
186
|
+
* model that thinks before answering does not have its reasoning read as the reply. `error`
|
|
187
|
+
* carries `{ code, message }` and is returned rather than thrown so the caller can name the code.
|
|
188
|
+
*
|
|
189
|
+
* **`done` is what makes a truncated body detectable.** A stream that closes without it was cut
|
|
190
|
+
* off, and the caller reports that instead of handing back half an answer labelled complete.
|
|
191
|
+
*/
|
|
192
|
+
export declare function decodeTokenHarborStream(body: string): {
|
|
193
|
+
content: string;
|
|
194
|
+
reasoning: string;
|
|
195
|
+
finished: boolean;
|
|
196
|
+
error?: {
|
|
197
|
+
code: string;
|
|
198
|
+
message: string;
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
//# sourceMappingURL=tokenharbor-web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenharbor-web.d.ts","sourceRoot":"","sources":["../../src/adapters/tokenharbor-web.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,oBAAoB,EAAgB,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE9M;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AAEH,eAAO,MAAM,wBAAwB,EAAE,UAA8B,CAAC;AA6BtE,eAAO,MAAM,eAAe;;;;;;;;IAQ1B,8DAA8D;;CAEtD,CAAC;AAEX;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,EAAE,aAAa,CAAC;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB,CAuBA,CAAC;AAEF,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAElD;AAgBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA2EhE;AAwBD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAuBvE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAW5E;AAUD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,CAExE;AAED,wBAAgB,kCAAkC,CAAC,UAAU,EAAE,kBAAkB,GAAG,SAAS,GAAG,MAAM,CAOrG;AA2BD,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,QAAQ,CAAC,EAAE,SAA4B;IACvC,QAAQ,CAAC,IAAI,sBAAsB;IACnC,QAAQ,CAAC,YAAY;;;MAAyC;IAE9D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAE7B,OAAO,GAAE;QAAE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;KAAO;IAKtE;;;;;;;OAOG;IACH,UAAU,CAAC,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAalE;;;;OAIG;IACG,kBAAkB,CAAC,UAAU,EAAE,kBAAkB,GAAG,SAAS,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAQzI;;;;;;;OAOG;IACG,WAAW,CAAC,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,cAAc,CAAC;IAc1E,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,YAAY,CAAC;YAkE/E,aAAa;IAgB3B,OAAO,CAAC,OAAO;CAYhB;AAsBD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAYxE;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAyC1J"}
|