@gajae-code/ai 0.2.4 → 0.2.5
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/types/utils/oauth/callback-server.d.ts +3 -0
- package/package.json +2 -2
- package/src/auth-broker/remote-store.ts +1 -1
- package/src/auth-storage.ts +2 -2
- package/src/providers/anthropic.ts +1 -1
- package/src/providers/openai-completions.ts +3 -8
- package/src/providers/openai-responses-server.ts +6 -6
- package/src/utils/oauth/callback-server.ts +6 -1
|
@@ -7,6 +7,8 @@ export interface OAuthCallbackFlowOptions {
|
|
|
7
7
|
preferredPort: number;
|
|
8
8
|
callbackPath?: string;
|
|
9
9
|
callbackHostname?: string;
|
|
10
|
+
/** Local listener hostname; defaults to callbackHostname when omitted. */
|
|
11
|
+
callbackBindHostname?: string;
|
|
10
12
|
/** Exact redirect URI advertised to the provider; disables port fallback. */
|
|
11
13
|
redirectUri?: string;
|
|
12
14
|
}
|
|
@@ -19,6 +21,7 @@ export declare abstract class OAuthCallbackFlow {
|
|
|
19
21
|
preferredPort: number;
|
|
20
22
|
callbackPath: string;
|
|
21
23
|
callbackHostname: string;
|
|
24
|
+
callbackBindHostname: string;
|
|
22
25
|
redirectUri?: string;
|
|
23
26
|
constructor(ctrl: OAuthController, preferredPortOrOptions: number | OAuthCallbackFlowOptions, callbackPath?: string);
|
|
24
27
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/ai",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.5",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://gaebal-gajae.dev",
|
|
7
7
|
"author": "Yeachan-Heo",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@anthropic-ai/sdk": "^0.94.0",
|
|
45
45
|
"@bufbuild/protobuf": "^2.12.0",
|
|
46
|
-
"@gajae-code/utils": "0.2.
|
|
46
|
+
"@gajae-code/utils": "0.2.5",
|
|
47
47
|
"openai": "^6.36.0",
|
|
48
48
|
"partial-json": "^0.1.7",
|
|
49
49
|
"zod": "4.4.3"
|
|
@@ -281,7 +281,7 @@ export class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
281
281
|
|
|
282
282
|
async prepareForRequest(credentialId: number, opts: { signal?: AbortSignal } = {}): Promise<boolean> {
|
|
283
283
|
const entry = this.#snapshot.credentials.find(candidate => candidate.id === credentialId);
|
|
284
|
-
if (
|
|
284
|
+
if (entry?.credential.type !== "oauth" || entry.rotatesInMs === null) return false;
|
|
285
285
|
const remainingMs = this.#snapshotReceivedAt + entry.rotatesInMs - Date.now();
|
|
286
286
|
if (remainingMs > WAIT_THRESHOLD_MS) return false;
|
|
287
287
|
return this.waitForFreshSnapshot(MAX_WAIT_MS, opts);
|
package/src/auth-storage.ts
CHANGED
|
@@ -2733,7 +2733,7 @@ export class AuthStorage {
|
|
|
2733
2733
|
if (!prepare) return true;
|
|
2734
2734
|
const stored = this.#getStoredCredentials(provider);
|
|
2735
2735
|
const selected = stored[selection.index];
|
|
2736
|
-
if (
|
|
2736
|
+
if (selected?.credential.type !== "oauth") return false;
|
|
2737
2737
|
|
|
2738
2738
|
const prepared = await prepare(selected.id, { signal: options?.signal });
|
|
2739
2739
|
if (!prepared) return true;
|
|
@@ -2745,7 +2745,7 @@ export class AuthStorage {
|
|
|
2745
2745
|
const latestIndex = latestRows.findIndex(row => row.id === selected.id);
|
|
2746
2746
|
if (latestIndex === -1) return false;
|
|
2747
2747
|
const latest = latestRows[latestIndex];
|
|
2748
|
-
if (
|
|
2748
|
+
if (latest?.credential.type !== "oauth") return false;
|
|
2749
2749
|
selection.index = latestIndex;
|
|
2750
2750
|
selection.credential = latest.credential;
|
|
2751
2751
|
return true;
|
|
@@ -1684,7 +1684,7 @@ function disableThinkingIfToolChoiceForced(params: MessageCreateParamsStreaming)
|
|
|
1684
1684
|
|
|
1685
1685
|
function ensureMaxTokensForThinking(params: MessageCreateParamsStreaming, model: Model<"anthropic-messages">): void {
|
|
1686
1686
|
const thinking = params.thinking;
|
|
1687
|
-
if (
|
|
1687
|
+
if (thinking?.type !== "enabled") return;
|
|
1688
1688
|
|
|
1689
1689
|
const budgetTokens = thinking.budget_tokens ?? 0;
|
|
1690
1690
|
if (budgetTokens <= 0) return;
|
|
@@ -554,7 +554,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = (
|
|
|
554
554
|
eventStream: AssistantMessageEventStream,
|
|
555
555
|
text: string,
|
|
556
556
|
): void => {
|
|
557
|
-
if (
|
|
557
|
+
if (currentBlock?.type !== "text") {
|
|
558
558
|
finishCurrentBlock(currentBlock);
|
|
559
559
|
currentBlock = { type: "text", text: "" };
|
|
560
560
|
message.content.push(currentBlock);
|
|
@@ -575,8 +575,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = (
|
|
|
575
575
|
signature?: string,
|
|
576
576
|
): void => {
|
|
577
577
|
if (
|
|
578
|
-
|
|
579
|
-
currentBlock.type !== "thinking" ||
|
|
578
|
+
currentBlock?.type !== "thinking" ||
|
|
580
579
|
(signature !== undefined && currentBlock.thinkingSignature !== signature)
|
|
581
580
|
) {
|
|
582
581
|
finishCurrentBlock(currentBlock);
|
|
@@ -786,11 +785,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = (
|
|
|
786
785
|
|
|
787
786
|
if (choice?.delta?.tool_calls && choice.delta.tool_calls.length > 0) {
|
|
788
787
|
for (const toolCall of choice.delta.tool_calls) {
|
|
789
|
-
if (
|
|
790
|
-
!currentBlock ||
|
|
791
|
-
currentBlock.type !== "toolCall" ||
|
|
792
|
-
(toolCall.id && currentBlock.id !== toolCall.id)
|
|
793
|
-
) {
|
|
788
|
+
if (currentBlock?.type !== "toolCall" || (toolCall.id && currentBlock.id !== toolCall.id)) {
|
|
794
789
|
finishCurrentBlock(currentBlock);
|
|
795
790
|
currentBlock = {
|
|
796
791
|
type: "toolCall",
|
|
@@ -954,7 +954,7 @@ export function encodeStream(
|
|
|
954
954
|
break;
|
|
955
955
|
}
|
|
956
956
|
case "text_delta": {
|
|
957
|
-
if (
|
|
957
|
+
if (state.open?.kind !== "message") break;
|
|
958
958
|
const cur: OpenMessage = state.open;
|
|
959
959
|
cur.currentPartText += ev.delta;
|
|
960
960
|
emit("response.output_text.delta", {
|
|
@@ -970,7 +970,7 @@ export function encodeStream(
|
|
|
970
970
|
break;
|
|
971
971
|
}
|
|
972
972
|
case "text_end": {
|
|
973
|
-
if (
|
|
973
|
+
if (state.open?.kind !== "message") break;
|
|
974
974
|
const cur: OpenMessage = state.open;
|
|
975
975
|
const text = ev.content ?? cur.currentPartText;
|
|
976
976
|
emit("response.output_text.done", {
|
|
@@ -997,7 +997,7 @@ export function encodeStream(
|
|
|
997
997
|
break;
|
|
998
998
|
}
|
|
999
999
|
case "thinking_delta": {
|
|
1000
|
-
if (
|
|
1000
|
+
if (state.open?.kind !== "reasoning") break;
|
|
1001
1001
|
const cur: OpenReasoning = state.open;
|
|
1002
1002
|
cur.reasoningText += ev.delta;
|
|
1003
1003
|
emit("response.reasoning_summary_text.delta", {
|
|
@@ -1009,7 +1009,7 @@ export function encodeStream(
|
|
|
1009
1009
|
break;
|
|
1010
1010
|
}
|
|
1011
1011
|
case "thinking_end": {
|
|
1012
|
-
if (
|
|
1012
|
+
if (state.open?.kind !== "reasoning") break;
|
|
1013
1013
|
const cur: OpenReasoning = state.open;
|
|
1014
1014
|
const text = ev.content ?? cur.reasoningText;
|
|
1015
1015
|
cur.reasoningText = text;
|
|
@@ -1034,7 +1034,7 @@ export function encodeStream(
|
|
|
1034
1034
|
break;
|
|
1035
1035
|
}
|
|
1036
1036
|
case "toolcall_delta": {
|
|
1037
|
-
if (
|
|
1037
|
+
if (state.open?.kind !== "function_call") break;
|
|
1038
1038
|
const cur: OpenFunctionCall = state.open;
|
|
1039
1039
|
cur.argsText += ev.delta;
|
|
1040
1040
|
if (cur.customWireName) {
|
|
@@ -1053,7 +1053,7 @@ export function encodeStream(
|
|
|
1053
1053
|
break;
|
|
1054
1054
|
}
|
|
1055
1055
|
case "toolcall_end": {
|
|
1056
|
-
if (
|
|
1056
|
+
if (state.open?.kind !== "function_call") break;
|
|
1057
1057
|
const cur: OpenFunctionCall = state.open;
|
|
1058
1058
|
// Promote possibly-late info from the canonical ToolCall.
|
|
1059
1059
|
const tc = ev.toolCall;
|
|
@@ -23,6 +23,8 @@ export interface OAuthCallbackFlowOptions {
|
|
|
23
23
|
preferredPort: number;
|
|
24
24
|
callbackPath?: string;
|
|
25
25
|
callbackHostname?: string;
|
|
26
|
+
/** Local listener hostname; defaults to callbackHostname when omitted. */
|
|
27
|
+
callbackBindHostname?: string;
|
|
26
28
|
/** Exact redirect URI advertised to the provider; disables port fallback. */
|
|
27
29
|
redirectUri?: string;
|
|
28
30
|
}
|
|
@@ -35,6 +37,7 @@ export abstract class OAuthCallbackFlow {
|
|
|
35
37
|
preferredPort: number;
|
|
36
38
|
callbackPath: string;
|
|
37
39
|
callbackHostname: string;
|
|
40
|
+
callbackBindHostname: string;
|
|
38
41
|
redirectUri?: string;
|
|
39
42
|
#callbackResolve?: (result: CallbackResult) => void;
|
|
40
43
|
#callbackReject?: (error: string) => void;
|
|
@@ -49,12 +52,14 @@ export abstract class OAuthCallbackFlow {
|
|
|
49
52
|
this.preferredPort = preferredPortOrOptions;
|
|
50
53
|
this.callbackPath = callbackPath;
|
|
51
54
|
this.callbackHostname = DEFAULT_HOSTNAME;
|
|
55
|
+
this.callbackBindHostname = DEFAULT_HOSTNAME;
|
|
52
56
|
return;
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
this.preferredPort = preferredPortOrOptions.preferredPort;
|
|
56
60
|
this.callbackPath = preferredPortOrOptions.callbackPath ?? CALLBACK_PATH;
|
|
57
61
|
this.callbackHostname = preferredPortOrOptions.callbackHostname ?? DEFAULT_HOSTNAME;
|
|
62
|
+
this.callbackBindHostname = preferredPortOrOptions.callbackBindHostname ?? this.callbackHostname;
|
|
58
63
|
this.redirectUri = preferredPortOrOptions.redirectUri;
|
|
59
64
|
}
|
|
60
65
|
|
|
@@ -144,7 +149,7 @@ export abstract class OAuthCallbackFlow {
|
|
|
144
149
|
*/
|
|
145
150
|
#createServer(port: number, expectedState: string): Bun.Server<unknown> {
|
|
146
151
|
return Bun.serve({
|
|
147
|
-
hostname: this.
|
|
152
|
+
hostname: this.callbackBindHostname,
|
|
148
153
|
port,
|
|
149
154
|
reusePort: false,
|
|
150
155
|
fetch: req => this.#handleCallback(req, expectedState),
|