@byokit/accounts 0.9.0 → 0.11.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/CHANGELOG.md +14 -0
- package/README.md +14 -1
- package/dist/accounts.d.ts +10 -9
- package/dist/accounts.js +15 -2
- package/dist/limits.d.ts +6 -2
- package/dist/limits.js +5 -3
- package/dist/portable.d.ts +1 -1
- package/dist/portable.js +1 -1
- package/dist/responses.d.ts +2 -0
- package/dist/responses.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Expose fresh subscription access to host-side capabilities using the app’s own sign-in.
|
|
6
|
+
|
|
7
|
+
## 0.11.0 (2026-09-30)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
- Add optional `parallelToolCalls` to `respond` and `Accounts.respond`, passed through to ChatGPT as `parallel_tool_calls`; omitted keeps the provider default.
|
|
12
|
+
|
|
13
|
+
## 0.10.0 (2026-09-30)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
- Export portable `classifyFailure` and `Failure`, with an injectable clock and `REST_MS` fallbacks; retain `classify` as an alias.
|
|
18
|
+
|
|
5
19
|
## 0.9.0 (2026-09-30)
|
|
6
20
|
|
|
7
21
|
|
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ and [`examples/pwa`](../../examples/pwa) (browser sign-in).
|
|
|
122
122
|
| `offered`, `provider`, `PROVIDERS` | The catalogue: each provider's billing, terms status, reason and source |
|
|
123
123
|
| `billingWords`, `say`, `WORDS`, `signInError`, `failure`, `clock`, `callbackPage` | The plain sentences every app shows the same way (`words.json`), a time in words, and the page a browser sees after a sign-in |
|
|
124
124
|
| `respond`, `ResponseError`, `IncompleteError`, `sseReader`, `limitResponse`, `isFunctionCall` | Ask ChatGPT's answers endpoint with a sign-in, with tools, pictures, thinking effort and an answer shape; the error with the words to show and the kind acted on |
|
|
125
|
-
| `classify`, `REST_MS` | An error's kind (limit, overload, plan without this use, lapsed sign-in, network) and default rest times |
|
|
125
|
+
| `classifyFailure`, `classify`, `REST_MS` | An error's kind (limit, overload, plan without this use, lapsed sign-in, network) and default rest times |
|
|
126
126
|
| `planOf`, `claims` | The ChatGPT plan and email behind a sign-in, from its own token |
|
|
127
127
|
| `deviceStart`, `devicePoll`, `credentialOf`, `portableEngine`, `PORTABLE` | The device-code flow, the sign-in built from a token answer, and the engine under `portable` |
|
|
128
128
|
| `isolate`, `INHERITED`, `emptyAuthContext` (`/isolate`) | Scrub inherited Pi settings and provider keys; ambient discovery off |
|
|
@@ -260,6 +260,11 @@ already have shown partial words. This covers `response.incomplete` events and `
|
|
|
260
260
|
whether fetch streams SSE, buffers it, or returns JSON. The account stays signed in and is not put to rest.
|
|
261
261
|
Successful return values are unchanged.
|
|
262
262
|
|
|
263
|
+
Set `parallelToolCalls: false` to request one tool call at a time; `true` allows parallel calls. Both pass through as
|
|
264
|
+
`parallel_tool_calls`; omitting it sends nothing and keeps the provider default. `respond` supports only the ChatGPT
|
|
265
|
+
subscription route; OpenRouter, Grok and Copilot are credential routes without `respond` support, and there is no
|
|
266
|
+
Anthropic response route.
|
|
267
|
+
|
|
263
268
|
The whole question passes through: `input` takes the turns so far (messages, with `input_image` where the person
|
|
264
269
|
attached a picture), `tools` and `tool_choice` take the app's own function tools and built-ins (including
|
|
265
270
|
`image_generation`), `reasoning.effort` how hard the model thinks, and `text` how long the answer is with the shape it
|
|
@@ -355,3 +360,11 @@ For a plaintext store, stop all writers, revoke the old credentials using the ol
|
|
|
355
360
|
remove the old app-owned credential file, and sign in again with a sealing adapter. Old plaintext
|
|
356
361
|
backups may retain tokens: delete them under the host's retention policy and revoke the affected
|
|
357
362
|
credentials. Do not point this migration at another tool's sign-in directory.
|
|
363
|
+
`classifyFailure(error, nowMs?)` returns a typed `Failure` (`{ kind, until }`) or `null`
|
|
364
|
+
for an unrecognized error. `until` is epoch milliseconds when the error says "try again
|
|
365
|
+
in N min/hours", and zero otherwise. For resting kinds, use
|
|
366
|
+
`failure.until || nowMs + REST_MS[failure.kind]`; signed-out, not-included and network
|
|
367
|
+
failures have no fallback rest. `classify` remains an alias. Pass a clock for deterministic
|
|
368
|
+
classification; the default uses `Date.now()`. It stores and logs no error text.
|
|
369
|
+
|
|
370
|
+
For a capability running where the sign-in lives, `await accounts.access(member, signal)` returns fresh `{ access, accountId }` from the app’s own ChatGPT store. Keep these credentials in that process; proxy signaling or relay media for another device. This uses the same refresh and signed-out behavior as `respond`.
|
package/dist/accounts.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { CredentialStore, Models } from '@earendil-works/pi-ai';
|
|
2
2
|
import { type Provider } from './catalogue.ts';
|
|
3
|
-
import { type Kind } from './limits.ts';
|
|
4
3
|
import { ResponseError, type Ask, type ResponseResult, type ResponseTool } from './responses.ts';
|
|
5
4
|
import { type EndingStore, type RefreshStore } from './stores.ts';
|
|
6
5
|
import { type Why } from './words.ts';
|
|
@@ -126,10 +125,11 @@ export declare class Accounts<R extends AuthHost = AuthHost, M extends Member =
|
|
|
126
125
|
forget(member: M, key: string): void;
|
|
127
126
|
/** 0 when the account is available; otherwise when it stops resting. */
|
|
128
127
|
restingUntil(member: M, key: string): number;
|
|
129
|
-
/**
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
/** Fresh ChatGPT access for a host-side capability. Never send this to another device. */
|
|
129
|
+
access(member: M, signal?: AbortSignal): Promise<{
|
|
130
|
+
access: string;
|
|
131
|
+
accountId: string;
|
|
132
|
+
}>;
|
|
133
133
|
/** Ask ChatGPT with this member's own sign-in, the answer streaming into `onText`; refreshed first when due. A
|
|
134
134
|
* failure about the account (a limit, a lapsed sign-in) is acted on as `failed()` does, then thrown as a
|
|
135
135
|
* ResponseError with the words to show. Without `tools` the answer is the plain text, as before: pass `input` as
|
|
@@ -141,10 +141,11 @@ export declare class Accounts<R extends AuthHost = AuthHost, M extends Member =
|
|
|
141
141
|
respond(member: M, ask: Ask & {
|
|
142
142
|
tools: ResponseTool[];
|
|
143
143
|
}): Promise<ResponseResult>;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
/** An account's error, acted on. A limit or overload rests it (until when it said, or a default). A plan without this
|
|
145
|
+
* use is marked so. A refusal is checked: a sign-in that no longer refreshes is signed out for real, one that still
|
|
146
|
+
* does was a passing refusal and rests a few minutes (kind `overloaded`) rather than loop. Returns the kind acted on,
|
|
147
|
+
* or null for an error that is not about the account; `network` changes nothing. */
|
|
148
|
+
failed(member: M, key: string, error: string | ResponseError): Promise<import("./limits.ts").Failure | null>;
|
|
148
149
|
/** The first choice whose account is neither resting nor known to be unusable: the fallback ladder. */
|
|
149
150
|
ladder<T>(member: M, choices: readonly T[], key?: (c: T) => string): T | undefined;
|
|
150
151
|
/** Where one account stands, in one plain sentence every app shows the same way. */
|
package/dist/accounts.js
CHANGED
|
@@ -228,7 +228,9 @@ export class Accounts {
|
|
|
228
228
|
const r = this.rests.get(`${member}:${key}`);
|
|
229
229
|
return r && r.until > Date.now() ? r.until : 0;
|
|
230
230
|
}
|
|
231
|
-
|
|
231
|
+
/** Fresh ChatGPT access for a host-side capability. Never send this to another device. */
|
|
232
|
+
async access(member, signal) {
|
|
233
|
+
signal?.throwIfAborted();
|
|
232
234
|
const key = 'chatgpt';
|
|
233
235
|
const p = this.offer(key);
|
|
234
236
|
const rt = await this.runtime(member);
|
|
@@ -247,8 +249,15 @@ export class Accounts {
|
|
|
247
249
|
const c = await rt.readCredential(p.pi).catch(() => undefined);
|
|
248
250
|
if (!access || c?.type !== 'oauth')
|
|
249
251
|
throw new ResponseError(say('status.signedOut', { name: p.name }), 'signed_out');
|
|
252
|
+
signal?.throwIfAborted();
|
|
253
|
+
return { access, accountId: String(c.accountId ?? '') };
|
|
254
|
+
}
|
|
255
|
+
async respond(member, ask) {
|
|
256
|
+
const key = 'chatgpt';
|
|
257
|
+
const p = this.offer(key);
|
|
258
|
+
const { access, accountId } = await this.access(member);
|
|
250
259
|
try {
|
|
251
|
-
const base = { ...ask, access, accountId
|
|
260
|
+
const base = { ...ask, access, accountId, model: ask.model ?? p.models.strong, base: this.opts.apiBase, fetch: this.opts.fetch, originator: ask.originator ?? this.opts.originator };
|
|
252
261
|
return ask.tools ? await respond({ ...base, tools: ask.tools }) : await respond({ ...base, tools: undefined });
|
|
253
262
|
}
|
|
254
263
|
catch (e) {
|
|
@@ -260,6 +269,10 @@ export class Accounts {
|
|
|
260
269
|
throw e;
|
|
261
270
|
}
|
|
262
271
|
}
|
|
272
|
+
/** An account's error, acted on. A limit or overload rests it (until when it said, or a default). A plan without this
|
|
273
|
+
* use is marked so. A refusal is checked: a sign-in that no longer refreshes is signed out for real, one that still
|
|
274
|
+
* does was a passing refusal and rests a few minutes (kind `overloaded`) rather than loop. Returns the kind acted on,
|
|
275
|
+
* or null for an error that is not about the account; `network` changes nothing. */
|
|
263
276
|
async failed(member, key, error) {
|
|
264
277
|
const c = error instanceof ResponseError ? error.kind && { kind: error.kind, until: error.until } : classify(error);
|
|
265
278
|
if (!c || c.kind === 'network')
|
package/dist/limits.d.ts
CHANGED
|
@@ -2,7 +2,11 @@ export type Kind = 'rate_limit' | 'overloaded' | 'signed_out' | 'not_included' |
|
|
|
2
2
|
/** How long an account rests when its error didn't say. */
|
|
3
3
|
export declare const REST_MS: Record<Kind, number>;
|
|
4
4
|
/** `until` is 0 when the error didn't say. Anything unrecognised is null: the app fails that one request. */
|
|
5
|
-
export
|
|
5
|
+
export type Failure = {
|
|
6
6
|
kind: Kind;
|
|
7
7
|
until: number;
|
|
8
|
-
}
|
|
8
|
+
};
|
|
9
|
+
/** Pure when the host passes its clock. REST_MS supplies the fallback rest duration. */
|
|
10
|
+
export declare function classifyFailure(error: string, nowMs?: number): Failure | null;
|
|
11
|
+
/** Backwards-compatible name for classifyFailure. */
|
|
12
|
+
export declare const classify: typeof classifyFailure;
|
package/dist/limits.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/** How long an account rests when its error didn't say. */
|
|
2
2
|
export const REST_MS = { rate_limit: 60 * 60_000, overloaded: 5 * 60_000, signed_out: 0, not_included: 0, network: 0 };
|
|
3
|
-
/**
|
|
4
|
-
export function
|
|
3
|
+
/** Pure when the host passes its clock. REST_MS supplies the fallback rest duration. */
|
|
4
|
+
export function classifyFailure(error, nowMs = Date.now()) {
|
|
5
5
|
const m = /try again in ~?(\d+)\s*(min|h)/i.exec(error);
|
|
6
|
-
const until = m ?
|
|
6
|
+
const until = m ? nowMs + Number(m[1]) * (m[2].toLowerCase() === 'h' ? 3_600_000 : 60_000) : 0;
|
|
7
7
|
if (/your plan doesn't include/i.test(error))
|
|
8
8
|
return { kind: 'not_included', until };
|
|
9
9
|
if (/usage limit|rate.?limit|quota|too many requests|\b429\b/i.test(error))
|
|
@@ -16,3 +16,5 @@ export function classify(error) {
|
|
|
16
16
|
return { kind: 'network', until };
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
|
+
/** Backwards-compatible name for classifyFailure. */
|
|
20
|
+
export const classify = classifyFailure;
|
package/dist/portable.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Accounts, planOf, portable, type AccountsOptions, type AuthHost, type Loopback, type Member, type Platform, type SignIn, type Status } from './accounts.ts';
|
|
2
2
|
export { PROVIDERS, offered, provider, type Billing, type Provider, type Terms } from './catalogue.ts';
|
|
3
3
|
export { PORTABLE, claims, credentialOf, devicePoll, deviceStart, portableEngine, type EngineOptions, type Poll } from './engine.ts';
|
|
4
|
-
export { REST_MS, classify, type Kind } from './limits.ts';
|
|
4
|
+
export { REST_MS, classify, classifyFailure, type Failure, type Kind } from './limits.ts';
|
|
5
5
|
export { IncompleteError, ResponseError, isFunctionCall, limitResponse, respond, sseReader, type Ask, type ResponseFunctionCall, type ResponseInputItem, type ResponseOutputItem, type ResponseOutputMessage, type ResponseReasoning, type ResponseResult, type ResponseStreamEvent, type ResponseText, type ResponseTextFormat, type ResponseTool, type ResponseToolChoice } from './responses.ts';
|
|
6
6
|
export { browserStore, memoryStore, recordStore, secureStore, RefreshRequiredError, type RefreshStore, type SecureStoreLike } from './stores.ts';
|
|
7
7
|
export { WORDS, billingWords, callbackPage, clock, failure, say, signInError, type WordKey, type Why } from './words.ts';
|
package/dist/portable.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
export { Accounts, planOf, portable } from "./accounts.js";
|
|
4
4
|
export { PROVIDERS, offered, provider } from "./catalogue.js";
|
|
5
5
|
export { PORTABLE, claims, credentialOf, devicePoll, deviceStart, portableEngine } from "./engine.js";
|
|
6
|
-
export { REST_MS, classify } from "./limits.js";
|
|
6
|
+
export { REST_MS, classify, classifyFailure } from "./limits.js";
|
|
7
7
|
export { IncompleteError, ResponseError, isFunctionCall, limitResponse, respond, sseReader } from "./responses.js";
|
|
8
8
|
export { browserStore, memoryStore, recordStore, secureStore, RefreshRequiredError } from "./stores.js";
|
|
9
9
|
export { WORDS, billingWords, callbackPage, clock, failure, say, signInError } from "./words.js";
|
package/dist/responses.d.ts
CHANGED
|
@@ -175,6 +175,8 @@ export type Ask = {
|
|
|
175
175
|
model?: string;
|
|
176
176
|
/** The tools the model may call. Passed, the result carries the output items next to the text. */
|
|
177
177
|
tools?: ResponseTool[];
|
|
178
|
+
/** Whether ChatGPT may call tools in parallel. Omitted: the provider's default. */
|
|
179
|
+
parallelToolCalls?: boolean;
|
|
178
180
|
/** Which tool the model must use. Default: whatever it wants. */
|
|
179
181
|
tool_choice?: ResponseToolChoice;
|
|
180
182
|
/** How hard the model thinks. Default: none. */
|
package/dist/responses.js
CHANGED
|
@@ -182,6 +182,7 @@ export async function respond(o) {
|
|
|
182
182
|
body: JSON.stringify({
|
|
183
183
|
model: o.model, store: false, stream: true, instructions: o.instructions, input,
|
|
184
184
|
...(o.tools ? { tools: o.tools } : {}),
|
|
185
|
+
...(o.parallelToolCalls !== undefined ? { parallel_tool_calls: o.parallelToolCalls } : {}),
|
|
185
186
|
...(o.tool_choice !== undefined ? { tool_choice: o.tool_choice } : {}),
|
|
186
187
|
text: { verbosity, ...(format ? { format } : {}), ...textRest },
|
|
187
188
|
reasoning: { effort, ...reasoningRest },
|