@sayknow-cli/ai 0.5.2 → 0.5.8
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 +23 -0
- package/dist/types/model-thinking.d.ts +7 -0
- package/dist/types/provider-models/openai-compat.d.ts +10 -0
- package/dist/types/providers/anthropic.d.ts +1 -1
- package/dist/types/types.d.ts +7 -1
- package/dist/types/utils/discovery/openai-compatible.d.ts +10 -0
- package/dist/types/utils/oauth/sglang.d.ts +12 -0
- package/dist/types/utils/oauth/types.d.ts +1 -1
- package/package.json +2 -2
- package/src/auth-storage.ts +32 -6
- package/src/model-thinking.ts +68 -8
- package/src/models.json +12150 -1310
- package/src/provider-models/descriptors.ts +13 -1
- package/src/provider-models/openai-compat.ts +152 -0
- package/src/providers/anthropic.ts +12 -1
- package/src/providers/openai-completions.ts +56 -14
- package/src/stream.ts +15 -21
- package/src/types.ts +9 -1
- package/src/utils/discovery/openai-compatible.ts +106 -2
- package/src/utils/oauth/index.ts +6 -0
- package/src/utils/oauth/sglang.ts +39 -0
- package/src/utils/oauth/types.ts +1 -0
- package/src/utils/overflow.ts +64 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SGLang login flow.
|
|
3
|
+
*
|
|
4
|
+
* SGLang commonly exposes an OpenAI-compatible API on a local server. It may
|
|
5
|
+
* require a bearer token, but local servers commonly allow unauthenticated
|
|
6
|
+
* access. This flow stores an API-key-style credential for auth storage.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { OAuthController, OAuthProvider } from "./types";
|
|
10
|
+
|
|
11
|
+
const PROVIDER_ID: OAuthProvider = "sglang";
|
|
12
|
+
const AUTH_URL = "https://docs.sglang.io/docs/advanced_features/server_arguments.html";
|
|
13
|
+
const DEFAULT_LOCAL_BASE_URL = "http://127.0.0.1:30000/v1";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Login to SGLang with an explicit bearer token.
|
|
17
|
+
*/
|
|
18
|
+
export async function loginSglang(options: OAuthController): Promise<string> {
|
|
19
|
+
if (!options.onPrompt) {
|
|
20
|
+
throw new Error(`${PROVIDER_ID} login requires onPrompt callback`);
|
|
21
|
+
}
|
|
22
|
+
options.onAuth?.({
|
|
23
|
+
url: AUTH_URL,
|
|
24
|
+
instructions: `Paste the API key configured with SGLang's --api-key option. Local no-auth servers at ${DEFAULT_LOCAL_BASE_URL} are discovered automatically and do not need /login.`,
|
|
25
|
+
});
|
|
26
|
+
const apiKey = await options.onPrompt({
|
|
27
|
+
message: "Paste your SGLang API key",
|
|
28
|
+
placeholder: "SGLang API key",
|
|
29
|
+
allowEmpty: false,
|
|
30
|
+
});
|
|
31
|
+
if (options.signal?.aborted) {
|
|
32
|
+
throw new Error("Login cancelled");
|
|
33
|
+
}
|
|
34
|
+
const trimmed = apiKey.trim();
|
|
35
|
+
if (!trimmed) {
|
|
36
|
+
throw new Error("SGLang API key is required; local no-auth servers are discovered automatically");
|
|
37
|
+
}
|
|
38
|
+
return trimmed;
|
|
39
|
+
}
|
package/src/utils/oauth/types.ts
CHANGED
package/src/utils/overflow.ts
CHANGED
|
@@ -127,8 +127,12 @@ const EMPTY_RESPONSE_USAGE_THRESHOLD = 5;
|
|
|
127
127
|
* misleading error text.
|
|
128
128
|
*/
|
|
129
129
|
const OVERFLOW_PROVIDER_CODES = new Set(["context_length_exceeded", "request_too_large"]);
|
|
130
|
+
/**
|
|
131
|
+
* Codes that name a specific non-overflow *cause*. These are authoritative and
|
|
132
|
+
* can never be upgraded by error prose. Generic HTTP envelope types belong in
|
|
133
|
+
* {@link GENERIC_ENVELOPE_PROVIDER_CODES} instead.
|
|
134
|
+
*/
|
|
130
135
|
const NON_OVERFLOW_PROVIDER_CODES = new Set([
|
|
131
|
-
"invalid_request_error",
|
|
132
136
|
"authentication_error",
|
|
133
137
|
"invalid_api_key",
|
|
134
138
|
"invalid_token",
|
|
@@ -145,6 +149,7 @@ const NON_OVERFLOW_PROVIDER_CODES = new Set([
|
|
|
145
149
|
"rate_limit_error",
|
|
146
150
|
"rate_limit_exceeded",
|
|
147
151
|
"too_many_requests",
|
|
152
|
+
"empty_response",
|
|
148
153
|
]);
|
|
149
154
|
|
|
150
155
|
function transportCodes(transportFailure: TransportFailureFacts | undefined): string[] {
|
|
@@ -157,6 +162,53 @@ function hasTypedNonOverflowCode(transportFailure: TransportFailureFacts | undef
|
|
|
157
162
|
return transportCodes(transportFailure).some(code => NON_OVERFLOW_PROVIDER_CODES.has(code));
|
|
158
163
|
}
|
|
159
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Generic envelope codes that name the HTTP error *category*, not its cause.
|
|
167
|
+
*
|
|
168
|
+
* Anthropic reports context overflow through this envelope:
|
|
169
|
+
*
|
|
170
|
+
* {"type":"error","error":{"type":"invalid_request_error",
|
|
171
|
+
* "message":"prompt is too long: 1158066 tokens > 1000000 maximum"}}
|
|
172
|
+
*
|
|
173
|
+
* Treating the envelope as an authoritative non-overflow cause vetoed the
|
|
174
|
+
* overflow classification, so auto-compaction never ran and the session died on
|
|
175
|
+
* the very overflow it was supposed to absorb.
|
|
176
|
+
*
|
|
177
|
+
* Unlike {@link NON_OVERFLOW_PROVIDER_CODES} (auth, quota, rate limit), this
|
|
178
|
+
* envelope names no cause, so it must not veto an overflow the provider stated
|
|
179
|
+
* quantitatively. It still vetoes free-form prose: only the self-verifying
|
|
180
|
+
* measured form below can override it.
|
|
181
|
+
*/
|
|
182
|
+
const GENERIC_ENVELOPE_PROVIDER_CODES = new Set(["invalid_request_error"]);
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Anthropic's measured overflow report: `<used> tokens > <limit> maximum`.
|
|
186
|
+
*
|
|
187
|
+
* Deliberately far narrower than {@link OVERFLOW_PATTERNS}. Those patterns
|
|
188
|
+
* include loose prose (`too many tokens`, `token limit exceeded`) that a tool
|
|
189
|
+
* result or a model-authored string can trivially contain, so they must never
|
|
190
|
+
* be able to flip a typed transport classification. This form carries its own
|
|
191
|
+
* arithmetic proof and is verified below, so injected text cannot satisfy it
|
|
192
|
+
* without also asserting a real overage.
|
|
193
|
+
*/
|
|
194
|
+
const ANTHROPIC_MEASURED_OVERFLOW_PATTERN = /prompt is too long:\s*(\d+)\s*tokens?\s*>\s*(\d+)\s*maximum/i;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* True only for a provider-measured overflow that verifies against itself:
|
|
198
|
+
* the reported usage must actually exceed the reported maximum.
|
|
199
|
+
*/
|
|
200
|
+
function hasSelfVerifyingOverflowMeasurement(message: AssistantMessage): boolean {
|
|
201
|
+
if (message.stopReason !== "error") return false;
|
|
202
|
+
const errorMessage = message.errorMessage;
|
|
203
|
+
if (!errorMessage) return false;
|
|
204
|
+
const match = ANTHROPIC_MEASURED_OVERFLOW_PATTERN.exec(errorMessage);
|
|
205
|
+
if (!match) return false;
|
|
206
|
+
const used = Number(match[1]);
|
|
207
|
+
const maximum = Number(match[2]);
|
|
208
|
+
if (!Number.isFinite(used) || !Number.isFinite(maximum) || maximum <= 0) return false;
|
|
209
|
+
return used > maximum;
|
|
210
|
+
}
|
|
211
|
+
|
|
160
212
|
function isTypedNoBodyOverflow(
|
|
161
213
|
message: AssistantMessage,
|
|
162
214
|
transportFailure: TransportFailureFacts | undefined,
|
|
@@ -173,7 +225,18 @@ export function classifyContextOverflow(
|
|
|
173
225
|
if (transportFailure?.status === 429) return false;
|
|
174
226
|
const typedCodes = transportCodes(transportFailure);
|
|
175
227
|
if (typedCodes.some(code => OVERFLOW_PROVIDER_CODES.has(code))) return true;
|
|
228
|
+
// A specific non-overflow cause (auth, quota, rate limit) is authoritative
|
|
229
|
+
// and can never be upgraded by error prose.
|
|
176
230
|
if (hasTypedNonOverflowCode(transportFailure)) return false;
|
|
231
|
+
// A generic envelope (`invalid_request_error`) names no cause. It still
|
|
232
|
+
// vetoes free-form overflow prose, but must not veto a provider-measured,
|
|
233
|
+
// self-verifying overflow report — that is how Anthropic reports overflow.
|
|
234
|
+
if (
|
|
235
|
+
typedCodes.some(code => GENERIC_ENVELOPE_PROVIDER_CODES.has(code)) &&
|
|
236
|
+
!hasSelfVerifyingOverflowMeasurement(message)
|
|
237
|
+
) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
177
240
|
if (isTypedNoBodyOverflow(message, transportFailure)) return true;
|
|
178
241
|
|
|
179
242
|
const errorMessage = message.errorMessage;
|