@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.
@@ -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",
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.4",
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 (!entry || entry.credential.type !== "oauth" || entry.rotatesInMs === null) return false;
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);
@@ -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 (!selected || selected.credential.type !== "oauth") return false;
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 (!latest || latest.credential.type !== "oauth") return false;
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 (!thinking || thinking.type !== "enabled") return;
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 (!currentBlock || currentBlock.type !== "text") {
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
- !currentBlock ||
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 (!state.open || state.open.kind !== "message") break;
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 (!state.open || state.open.kind !== "message") break;
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 (!state.open || state.open.kind !== "reasoning") break;
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 (!state.open || state.open.kind !== "reasoning") break;
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 (!state.open || state.open.kind !== "function_call") break;
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 (!state.open || state.open.kind !== "function_call") break;
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.callbackHostname,
152
+ hostname: this.callbackBindHostname,
148
153
  port,
149
154
  reusePort: false,
150
155
  fetch: req => this.#handleCallback(req, expectedState),