iris-chatbot 5.3.0 → 5.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iris-chatbot",
3
- "version": "5.3.0",
3
+ "version": "5.3.1",
4
4
  "private": false,
5
5
  "description": "One-command installer for the Iris project template.",
6
6
  "bin": {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "iris",
3
- "version": "5.3.0",
3
+ "version": "5.3.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "iris",
9
- "version": "5.3.0",
9
+ "version": "5.3.1",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.72.1",
12
12
  "clsx": "^2.1.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iris",
3
- "version": "5.3.0",
3
+ "version": "5.3.1",
4
4
  "private": true,
5
5
  "description": "One-command installer for the Iris project template.",
6
6
  "engines": {
@@ -638,10 +638,103 @@ function normalizeWebSourcesEnabled(value: boolean | undefined): boolean {
638
638
  return value !== false;
639
639
  }
640
640
 
641
+ type WebSearchMode = "off" | "auto" | "required";
642
+
641
643
  function supportsWebSourcesViaOpenAI(connection: RuntimeConnection): boolean {
642
644
  return connection.kind === "builtin" && connection.provider === "openai";
643
645
  }
644
646
 
647
+ function getLastUserMessageText(messages: ChatMessageInput[]): string {
648
+ return [...messages].reverse().find((message) => message.role === "user")?.content?.trim() ?? "";
649
+ }
650
+
651
+ function decideWebSearchMode(params: {
652
+ enabled: boolean;
653
+ connection: RuntimeConnection;
654
+ messages: ChatMessageInput[];
655
+ }): WebSearchMode {
656
+ if (!params.enabled || !supportsWebSourcesViaOpenAI(params.connection)) {
657
+ return "off";
658
+ }
659
+
660
+ const text = getLastUserMessageText(params.messages).replace(/\s+/g, " ").trim().toLowerCase();
661
+ if (!text) {
662
+ return "auto";
663
+ }
664
+
665
+ const disableSearchRequested =
666
+ /\b(?:no|without|skip)\s+(?:web\s+)?(?:search|browsing|browse|lookup|look up)\b/.test(text) ||
667
+ /\b(?:don't|do not)\s+(?:web\s+)?(?:search|browse|look up|lookup)\b/.test(text) ||
668
+ /\boffline only\b/.test(text);
669
+ if (disableSearchRequested) {
670
+ return "off";
671
+ }
672
+
673
+ const explicitSearchRequested =
674
+ /\bsearch(?:\s+the)?\s+web\b/.test(text) ||
675
+ /\blook(?:\s+it)?\s+up\b/.test(text) ||
676
+ /\bcheck(?:\s+it)?\s+online\b/.test(text) ||
677
+ /\bverify(?:\s+it)?\s+online\b/.test(text) ||
678
+ /\bbrowse(?:\s+the)?\s+web\b/.test(text) ||
679
+ /\bgoogle\s+(?:it|this)\b/.test(text);
680
+ if (explicitSearchRequested) {
681
+ return "required";
682
+ }
683
+
684
+ const asksForSources =
685
+ /\b(?:source|sources|cite|citation|citations|reference|references|link|links)\b/.test(text);
686
+ const freshnessSignals =
687
+ /\b(?:latest|current|currently|today|right now|as of|recent|recently|up[- ]to[- ]date|breaking)\b/.test(
688
+ text,
689
+ );
690
+ const volatileDomainSignals =
691
+ /\b(?:price|pricing|cost|fee|subscription|per token|rate limit|stock|share price|market cap|forecast|weather|score|standings|odds|election|poll)\b/.test(
692
+ text,
693
+ );
694
+ const leadershipSignals =
695
+ /\b(?:who is|current)\s+(?:the\s+)?(?:ceo|president|prime minister|governor|mayor)\b/.test(text);
696
+ const metricSignals =
697
+ /\b(?:average|median|how many|number of|count|rate|percentage|percent|statistics?|stats?)\b/.test(
698
+ text,
699
+ );
700
+ const metricEntitySignals =
701
+ /\b(?:users?|people|prompts?|requests?|queries?|api|model|gpt|traffic|revenue|downloads?|adoption|daily|weekly|monthly|yearly|per day|per week|per month)\b/.test(
702
+ text,
703
+ );
704
+
705
+ if (
706
+ asksForSources ||
707
+ freshnessSignals ||
708
+ volatileDomainSignals ||
709
+ leadershipSignals ||
710
+ (metricSignals && metricEntitySignals)
711
+ ) {
712
+ return "required";
713
+ }
714
+
715
+ const likelyFactualQuestion =
716
+ text.includes("?") || /^(?:what|who|when|where|which|how)\b/.test(text);
717
+ const uncertaintySignals =
718
+ /\b(?:not sure|unsure|uncertain|verify|double-check|confirm|accurate|accuracy)\b/.test(text);
719
+ if (likelyFactualQuestion && uncertaintySignals) {
720
+ return "auto";
721
+ }
722
+
723
+ return "off";
724
+ }
725
+
726
+ function withWebSearchGuidance(system: string | undefined, mode: WebSearchMode): string | undefined {
727
+ const trimmed = system?.trim() || "";
728
+ if (mode === "off") {
729
+ return trimmed || undefined;
730
+ }
731
+ const guidance =
732
+ mode === "required"
733
+ ? "Web search is required for this turn. Use web_search before answering and cite the sources you relied on."
734
+ : "Use web_search when the request depends on current or uncertain facts (pricing, statistics, recency). For stable/general knowledge, answer directly without web_search.";
735
+ return trimmed ? `${trimmed}\n\n${guidance}` : guidance;
736
+ }
737
+
645
738
  function mergeCitationSources(
646
739
  target: Map<string, ProviderCitationSource>,
647
740
  sources: ProviderCitationSource[] | undefined,
@@ -2487,6 +2580,7 @@ async function streamPlainChat(params: {
2487
2580
  system?: string;
2488
2581
  messages: ChatMessageInput[];
2489
2582
  enableWebSources: boolean;
2583
+ webSearchMode?: WebSearchMode;
2490
2584
  send: (chunk: ChatStreamChunk) => void;
2491
2585
  signal?: AbortSignal;
2492
2586
  }) {
@@ -2536,20 +2630,30 @@ async function streamPlainChat(params: {
2536
2630
  baseURL: openAIBaseURL,
2537
2631
  defaultHeaders: openAIHeaders,
2538
2632
  });
2539
- const useWebSources =
2540
- params.enableWebSources && supportsWebSourcesViaOpenAI(params.connection);
2633
+ const useWebSources = params.enableWebSources && supportsWebSourcesViaOpenAI(params.connection);
2634
+ const webSearchMode: WebSearchMode = useWebSources
2635
+ ? params.webSearchMode === "required"
2636
+ ? "required"
2637
+ : "auto"
2638
+ : "off";
2639
+ const instructions = withWebSearchGuidance(params.system, webSearchMode);
2541
2640
  const response = await client.responses.create(
2542
2641
  {
2543
2642
  model: params.model,
2544
- instructions: params.system,
2643
+ instructions,
2545
2644
  input: params.messages.map((message) => ({
2546
2645
  type: "message",
2547
2646
  role: message.role,
2548
2647
  content: message.content,
2549
2648
  })),
2550
- tools: useWebSources ? [{ type: "web_search" }] : undefined,
2551
- tool_choice: useWebSources ? "auto" : undefined,
2552
- include: useWebSources ? ["web_search_call.action.sources"] : undefined,
2649
+ tools: webSearchMode !== "off" ? [{ type: "web_search" }] : undefined,
2650
+ tool_choice:
2651
+ webSearchMode === "required"
2652
+ ? "required"
2653
+ : webSearchMode === "auto"
2654
+ ? "auto"
2655
+ : undefined,
2656
+ include: webSearchMode !== "off" ? ["web_search_call.action.sources"] : undefined,
2553
2657
  stream: true,
2554
2658
  },
2555
2659
  { signal: params.signal },
@@ -3003,8 +3107,12 @@ export async function POST(request: Request) {
3003
3107
  }
3004
3108
 
3005
3109
  const webSourcesEnabled = normalizeWebSourcesEnabled(body.enableWebSources);
3006
- const enableWebSourcesForConnection =
3007
- webSourcesEnabled && supportsWebSourcesViaOpenAI(connection);
3110
+ const webSearchMode = decideWebSearchMode({
3111
+ enabled: webSourcesEnabled,
3112
+ connection,
3113
+ messages: sanitizedMessages,
3114
+ });
3115
+ const enableWebSourcesForConnection = webSearchMode !== "off";
3008
3116
  const localToolsRequested = normalizeLocalTools(body.localTools);
3009
3117
  const memoryContext = sanitizeMemoryContext(body.memory);
3010
3118
  const requestMeta = sanitizeChatRequestMeta(body.meta);
@@ -3111,6 +3219,7 @@ export async function POST(request: Request) {
3111
3219
  system,
3112
3220
  messages: sanitizedMessages,
3113
3221
  enableWebSources: enableWebSourcesForConnection,
3222
+ webSearchMode,
3114
3223
  send,
3115
3224
  signal: request.signal,
3116
3225
  });