@guideai/react-native 0.1.0 → 0.2.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/README.md CHANGED
@@ -24,6 +24,33 @@ GuideAI.configure({
24
24
  });
25
25
  ```
26
26
 
27
+ ### What else your API needs
28
+
29
+ Declare it once in the dashboard (**Copilot Tools → your API → Supplied by your app**), then supply the values:
30
+
31
+ ```ts
32
+ GuideAI.configure({
33
+ …,
34
+ getRequestHeaders: async () => ({ 'device-id': await getDeviceId() }), // declared headers
35
+ toolContext: { course: openCourseId }, // declared values; or GuideAI.setToolContext(…) later
36
+ });
37
+ ```
38
+
39
+ - **Headers:** sent on every call the assistant makes to your API, never to GuideAI. Only names declared in Copilot Tools are sent, and the app's value wins over anything the model sets. `Authorization` comes from `getAuthToken`, never from here.
40
+ - **Values:** each one fills the API inputs it's declared to fill (app key `course` fills `content_id`), so the assistant never asks the user for them.
41
+
42
+ The dashboard shows the exact snippet for your declarations.
43
+
44
+ ### Local or staging GuideAI
45
+
46
+ Production is the default. Point a development build somewhere else with `baseUrl`:
47
+
48
+ ```ts
49
+ GuideAI.configure({ …, baseUrl: __DEV__ ? 'http://localhost:8000' : undefined });
50
+ ```
51
+
52
+ Use `http://10.0.2.2:8000` from an Android emulator.
53
+
27
54
  `userProfile` is a few facts the agent pitches answers to (level, curriculum, language). Update it after login with `GuideAI.setUserProfile(profile)`.
28
55
 
29
56
  `getAuthToken` is read before every turn and may be async. The assistant calls your endpoints (the site's Copilot toolset) from the device with that token, so your API enforces the user's access exactly as it does for your own screens. A `401` asks `onAuthExpired` once and repeats the call. The token is sent only to your API, never to GuideAI, unless the toolset has `forward_user_token` switched on.
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const useOnboarding = require("./useOnboarding-C7eFhp2o.cjs");
3
+ const useOnboarding = require("./useOnboarding-DWkCW5v0.cjs");
4
4
  const jsxRuntime = require("react/jsx-runtime");
5
5
  const React = require("react");
6
6
  function GuideAIScreen({
package/dist/index.d.ts CHANGED
@@ -342,6 +342,9 @@ interface OnboardingLauncher {
342
342
  interface OnboardingAppearance {
343
343
  template: 'classic' | 'minimal' | 'bold';
344
344
  accent_color: string;
345
+ /** Optional checklist surface and text colours; missing values use the SDK theme. */
346
+ background_color?: string | null;
347
+ text_color?: string | null;
345
348
  /** Missing means the default card; position missing means left. */
346
349
  layout?: 'card' | 'modal' | 'side';
347
350
  position?: 'left' | 'right';
@@ -471,7 +474,8 @@ interface KVStore {
471
474
  }
472
475
  /**
473
476
  * Where a host keeps credentials the copilot may read, named by the
474
- * source a site configured (`localStorage`, `sessionStorage`, `cookie`).
477
+ * source a site configured (`localStorage`, `sessionStorage`, `cookie`),
478
+ * or `app` for values the host app hands over itself (declared headers).
475
479
  *
476
480
  * Returns null for a source this platform does not have. A mobile app has
477
481
  * no cookie jar, and saying so plainly is better than returning an empty
@@ -479,6 +483,15 @@ interface KVStore {
479
483
  */
480
484
  interface CredentialSource {
481
485
  read(source: string, key: string): string | null;
486
+ /**
487
+ * The signed-in user's bearer token, when the host hands it over itself.
488
+ *
489
+ * A native app keeps its token where it chooses (SecureStore,
490
+ * AsyncStorage), not in a store the site's dashboard can name. When this
491
+ * returns a token it wins over the configured storage lookup for a
492
+ * `bearer` toolset; null falls back to that lookup.
493
+ */
494
+ authToken?(): string | null;
482
495
  }
483
496
 
484
497
  /**
@@ -639,6 +652,12 @@ declare class CopilotHarness {
639
652
  distinct_id?: string;
640
653
  }): void;
641
654
  setToolContext(values: Record<string, string> | undefined): void;
655
+ /**
656
+ * The app's tool inputs as the API names them. A value declared in Copilot
657
+ * Tools as filling other inputs (app key `course` fills `content_id`) is
658
+ * sent under those names too; one the app set by that name already wins.
659
+ */
660
+ private contextForTools;
642
661
  /** Whether copilot action tools are available for this site. */
643
662
  isEnabled(): boolean;
644
663
  /**
@@ -726,6 +745,12 @@ declare class CopilotHarness {
726
745
  private hasAnyLocalTools;
727
746
  private canExecuteTool;
728
747
  private executeLocalTool;
748
+ /**
749
+ * An MCP tool, after the user approved it: we cannot call it — it is
750
+ * reached from GuideAI's network with a secret the client never holds —
751
+ * so the backend runs it, told who the user is by their token.
752
+ */
753
+ private executeOnServer;
729
754
  private executeLocalToolBatch;
730
755
  private _formatToolResult;
731
756
  private _readFormatToolResultStream;
@@ -755,6 +780,12 @@ interface SyncNativeStore {
755
780
 
756
781
  /** Returns the signed-in user's token, or null when signed out. May be async. */
757
782
  type AuthTokenGetter = () => string | null | undefined | Promise<string | null | undefined>;
783
+ /**
784
+ * Values for the headers the site's toolset declares as supplied by the app
785
+ * (Copilot Tools → "Supplied by your app"). May be async. Only declared
786
+ * names are ever sent.
787
+ */
788
+ type RequestHeadersGetter = () => Record<string, string> | null | undefined | Promise<Record<string, string> | null | undefined>;
758
789
 
759
790
  /** What a host says about one control on screen. */
760
791
  interface DeclaredElement {
@@ -820,8 +851,8 @@ interface GuideAIConfig {
820
851
  */
821
852
  origin?: string;
822
853
  /**
823
- * Where the GuideAI backend lives. Defaults to the hosted service, so
824
- * only self-hosted deployments set it.
854
+ * Where the GuideAI backend lives. Defaults to production; set it to test
855
+ * against a local or staging GuideAI (`http://localhost:8000`).
825
856
  */
826
857
  baseUrl?: string;
827
858
  /**
@@ -856,6 +887,20 @@ interface GuideAIConfig {
856
887
  * Omitted: getAuthToken() is asked again.
857
888
  */
858
889
  onAuthExpired?: AuthTokenGetter;
890
+ /**
891
+ * Values for the headers your toolset declares in Copilot Tools as
892
+ * "Supplied by your app" — a device id, a tenant: `async () => ({
893
+ * 'device-id': id })`. Read before every turn; sent only to your API,
894
+ * never to GuideAI, and only for declared names.
895
+ */
896
+ getRequestHeaders?: RequestHeadersGetter;
897
+ /**
898
+ * Values the app knows right now — the course open on screen: `{ course:
899
+ * '42' }`. Each fills the API inputs of the same name, or those the
900
+ * toolset declares it fills (Copilot Tools → "Supplied by your app").
901
+ * Change it with GuideAI.setToolContext().
902
+ */
903
+ toolContext?: Record<string, string>;
859
904
  /**
860
905
  * Facts about the signed-in user for the agent to pitch answers to —
861
906
  * `{ age: 12, class: 'JSS1', country: 'Nigeria', language: 'en' }`.
@@ -880,6 +925,8 @@ type GuideAIUserProfile = Record<string, string | number | boolean | Array<strin
880
925
  declare function configure(config: GuideAIConfig): void;
881
926
  /** Call after login so chat and the checklist use the same person. */
882
927
  declare function identify(userId: string | null): void;
928
+ /** Replace the tool inputs the app knows now (e.g. when another course opens). */
929
+ declare function setToolContext(values: Record<string, string> | null): void;
883
930
  /** Replace what the agent knows about the user (after login, or a profile edit). */
884
931
  declare function setUserProfile(profile: GuideAIUserProfile | null): void;
885
932
  /** Whether configure() has run. Lets a host render its own fallback. */
@@ -890,6 +937,7 @@ declare const GuideAI: {
890
937
  configure: typeof configure;
891
938
  identify: typeof identify;
892
939
  setUserProfile: typeof setUserProfile;
940
+ setToolContext: typeof setToolContext;
893
941
  isConfigured: typeof isConfigured;
894
942
  reset: typeof reset;
895
943
  };
@@ -1040,4 +1088,4 @@ declare function useOnboarding(): {
1040
1088
  };
1041
1089
 
1042
1090
  export { GuideAI, GuideAIScreen, useGuideAI, useGuideAIElement, useOnboarding };
1043
- export type { AuthTokenGetter, DeclaredElement, ElementHandlers, GuideAIConfig, HeadlessImage as GuideAIImage, GuideAIMessage, GuideAIScreenProps, GuideAIUserProfile, GuideAIVoiceRecording, GuideAIVoiceResult, NavigationRefLike, OnboardingState, OnboardingStepState, SyncNativeStore, UseGuideAIElementOptions, UseGuideAIResult };
1091
+ export type { AuthTokenGetter, DeclaredElement, ElementHandlers, GuideAIConfig, HeadlessImage as GuideAIImage, GuideAIMessage, GuideAIScreenProps, GuideAIUserProfile, GuideAIVoiceRecording, GuideAIVoiceResult, NavigationRefLike, OnboardingState, OnboardingStepState, RequestHeadersGetter, SyncNativeStore, UseGuideAIElementOptions, UseGuideAIResult };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { u as useGuideAIRuntime, S as ScreenRegistry, R as RegistryContext, a as useScreenRegistry } from "./useOnboarding-DhVtf0U2.js";
2
- import { G, b, c } from "./useOnboarding-DhVtf0U2.js";
1
+ import { u as useGuideAIRuntime, S as ScreenRegistry, R as RegistryContext, a as useScreenRegistry } from "./useOnboarding-DAEGoYSs.js";
2
+ import { G, b, c } from "./useOnboarding-DAEGoYSs.js";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import { useMemo, useEffect, useRef } from "react";
5
5
  function GuideAIScreen({
package/dist/ui.cjs CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const React = require("react");
5
5
  const reactNative = require("react-native");
6
- const useOnboarding = require("./useOnboarding-C7eFhp2o.cjs");
6
+ const useOnboarding = require("./useOnboarding-DWkCW5v0.cjs");
7
7
  function parseInline(text) {
8
8
  const spans = [];
9
9
  const pattern = /(`[^`]+`)|(\*\*[^*]+\*\*)|(__[^_]+__)|(\*[^*\n]+\*)|(_[^_\n]+_)|(\[[^\]]+\]\([^)]+\))/g;
package/dist/ui.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import React, { useRef, useState, useEffect, useCallback, useMemo, useContext, createContext } from "react";
3
3
  import { View, StyleSheet, Text, ScrollView, Linking, KeyboardAvoidingView, Pressable, Alert, FlatList, ActivityIndicator, TextInput, Platform, StatusBar, Animated, Easing, Dimensions, PanResponder, Modal } from "react-native";
4
- import { r as requireConfigured, b as useGuideAI, c as useOnboarding, E as EP } from "./useOnboarding-DhVtf0U2.js";
4
+ import { r as requireConfigured, b as useGuideAI, c as useOnboarding, E as EP } from "./useOnboarding-DAEGoYSs.js";
5
5
  function parseInline(text) {
6
6
  const spans = [];
7
7
  const pattern = /(`[^`]+`)|(\*\*[^*]+\*\*)|(__[^_]+__)|(\*[^*\n]+\*)|(_[^_\n]+_)|(\[[^\]]+\]\([^)]+\))/g;
@@ -83,7 +83,7 @@ function describeToolCall(toolCall) {
83
83
  const ownScope = /\s+(me|self|current|mine)$/.test(noun);
84
84
  if (ownScope) noun = `your ${noun.replace(/\s+(me|self|current|mine)$/, "")}`;
85
85
  if (SELF_DESCRIBING.test(noun) || ownScope) return `${verb} ${noun}`;
86
- const singular = noun.replace(new RegExp("([a-z])(?<!s|u|i)s$"), "$1");
86
+ const singular = noun.replace(/([a-z])(?<!s|u|i)s$/, "$1");
87
87
  return `${verb} ${singular} information`;
88
88
  }
89
89
  function describeToolBatch(toolCalls) {
@@ -651,8 +651,11 @@ class ToolExecutor {
651
651
  }
652
652
  /** Read the user's auth token from the configured browser storage. */
653
653
  getAuthToken() {
654
+ var _a, _b;
654
655
  if (this.authConfig.type === "none") return null;
655
656
  try {
657
+ const supplied = this.authConfig.type === "bearer" ? (_b = (_a = this.credentials).authToken) == null ? void 0 : _b.call(_a) : null;
658
+ if (supplied) return supplied;
656
659
  let raw = null;
657
660
  const storageKey = this.authConfig.key;
658
661
  if (storageKey && this.authConfig.source) {
@@ -838,6 +841,7 @@ class ToolExecutor {
838
841
  });
839
842
  }
840
843
  _buildHeaders(toolCall) {
844
+ var _a;
841
845
  const headers = {
842
846
  "Content-Type": "application/json",
843
847
  Accept: "application/json"
@@ -884,6 +888,16 @@ class ToolExecutor {
884
888
  mergeHeader(name, value);
885
889
  }
886
890
  }
891
+ for (const declared of (_a = this.authConfig.app_headers) != null ? _a : []) {
892
+ if (!(declared == null ? void 0 : declared.name)) continue;
893
+ let value = null;
894
+ try {
895
+ value = this.credentials.read("app", declared.name);
896
+ } catch {
897
+ value = null;
898
+ }
899
+ mergeHeader(declared.name, value);
900
+ }
887
901
  return headers;
888
902
  }
889
903
  _resolveHeaderValue(value) {
@@ -1026,6 +1040,7 @@ const EP = {
1026
1040
  guidesRecord: () => _j([..._v, "guides", "record"]),
1027
1041
  events: () => _j([..._v, "events"]),
1028
1042
  chatAsk: () => _j([..._v, "chat", "ask"]),
1043
+ chatExecuteTool: () => _j([..._v, "chat", "execute-tool"]),
1029
1044
  onboardingCurrent: (userId) => `${_j([..._v, "onboarding", "current"])}?user_id=${encodeURIComponent(userId)}`,
1030
1045
  onboardingObserve: () => _j([..._v, "onboarding", "observe"]),
1031
1046
  onboardingDismiss: () => _j([..._v, "onboarding", "dismiss"]),
@@ -1083,6 +1098,9 @@ const MAX_CHAIN_ROUNDS = 5;
1083
1098
  const MAX_TOTAL_TOOL_CALLS = 10;
1084
1099
  const MAX_REPAIR_ROUNDS = 1;
1085
1100
  const REPAIRABLE_ERROR_TYPES = /* @__PURE__ */ new Set(["validation", "client", "not_found"]);
1101
+ function isServerTool(toolCall) {
1102
+ return (toolCall.method || "").toUpperCase() === "MCP";
1103
+ }
1086
1104
  class CopilotHarness {
1087
1105
  /**
1088
1106
  * @param tools How this platform actually touches the screen. Defaults to
@@ -1166,6 +1184,24 @@ class CopilotHarness {
1166
1184
  setToolContext(values) {
1167
1185
  this.toolContext = values && Object.keys(values).length > 0 ? values : void 0;
1168
1186
  }
1187
+ /**
1188
+ * The app's tool inputs as the API names them. A value declared in Copilot
1189
+ * Tools as filling other inputs (app key `course` fills `content_id`) is
1190
+ * sent under those names too; one the app set by that name already wins.
1191
+ */
1192
+ contextForTools() {
1193
+ var _a, _b, _c, _d;
1194
+ if (!this.toolContext) return void 0;
1195
+ const out = { ...this.toolContext };
1196
+ for (const input of (_c = (_b = (_a = this.activeTools) == null ? void 0 : _a.auth_config) == null ? void 0 : _b.app_inputs) != null ? _c : []) {
1197
+ const value = (input == null ? void 0 : input.key) ? this.toolContext[input.key] : void 0;
1198
+ if (value === void 0) continue;
1199
+ for (const name of (_d = input.fills) != null ? _d : []) {
1200
+ if (name && !(name in out)) out[name] = value;
1201
+ }
1202
+ }
1203
+ return out;
1204
+ }
1169
1205
  /** Whether copilot action tools are available for this site. */
1170
1206
  isEnabled() {
1171
1207
  return this.tools.definitions().length > 0 || this.activeTools !== null && this.activeTools.tools.length > 0;
@@ -1180,8 +1216,7 @@ class CopilotHarness {
1180
1216
  * 5. For non-tool queries, returns JSON response directly
1181
1217
  */
1182
1218
  async processMessage(question, pageUrl, pageSnapshot, chatMode, onStatus, onTextDelta, onToolCallEvent, abortSignal, userContext, onboardingUserId) {
1183
- var _a2, _b2, _c2;
1184
- var _a, _b, _c, _d, _e, _f, _g, _h;
1219
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j2, _k;
1185
1220
  const inputCheck = this.validator.validateUserInput(question);
1186
1221
  if (!inputCheck.valid) {
1187
1222
  return this._errorResponse(inputCheck.error || "Invalid input.");
@@ -1196,10 +1231,10 @@ class CopilotHarness {
1196
1231
  });
1197
1232
  const conversationHistory = this.memory.getRecentForLLM(10);
1198
1233
  const mayForwardToken = ((_b = (_a = this.activeTools) == null ? void 0 : _a.auth_config) == null ? void 0 : _b.forward_user_token) === true;
1199
- const userToken = mayForwardToken ? (_a2 = (_c = this.toolExecutor) == null ? void 0 : _c.getAuthToken()) != null ? _a2 : null : null;
1234
+ const userToken = mayForwardToken ? (_d = (_c = this.toolExecutor) == null ? void 0 : _c.getAuthToken()) != null ? _d : null : null;
1200
1235
  let analytics = {};
1201
1236
  try {
1202
- analytics = (_b2 = (_e = (_d = this.config).analyticsIds) == null ? void 0 : _e.call(_d)) != null ? _b2 : {};
1237
+ analytics = (_g = (_f = (_e = this.config).analyticsIds) == null ? void 0 : _f.call(_e)) != null ? _g : {};
1203
1238
  } catch {
1204
1239
  }
1205
1240
  const requestBody = {
@@ -1209,8 +1244,8 @@ class CopilotHarness {
1209
1244
  distinct_id: analytics.distinct_id || void 0,
1210
1245
  page_snapshot: pageSnapshot,
1211
1246
  chat_mode: chatMode || "guidance",
1212
- assistant_label: ((_f = this.config.assistantLabel) == null ? void 0 : _f.trim()) || void 0,
1213
- delegate_instruction: ((_g = this.config.delegationInstruction) == null ? void 0 : _g.trim().slice(0, 1e3)) || void 0,
1247
+ assistant_label: ((_h = this.config.assistantLabel) == null ? void 0 : _h.trim()) || void 0,
1248
+ delegate_instruction: ((_i = this.config.delegationInstruction) == null ? void 0 : _i.trim().slice(0, 1e3)) || void 0,
1214
1249
  conversation_history: conversationHistory,
1215
1250
  stream: this.api.supportsStreaming,
1216
1251
  user_token: userToken || void 0,
@@ -1218,8 +1253,8 @@ class CopilotHarness {
1218
1253
  client_tools: chatMode === "assistant" ? this.tools.definitions() : void 0,
1219
1254
  user_context: userContext,
1220
1255
  onboarding_user_id: onboardingUserId,
1221
- tool_context: this.toolContext,
1222
- client_capabilities: ((_h = this.config.clientCapabilities) == null ? void 0 : _h.length) ? this.config.clientCapabilities : void 0
1256
+ tool_context: this.contextForTools(),
1257
+ client_capabilities: ((_j2 = this.config.clientCapabilities) == null ? void 0 : _j2.length) ? this.config.clientCapabilities : void 0
1223
1258
  };
1224
1259
  let rawResponse;
1225
1260
  try {
@@ -1259,7 +1294,7 @@ class CopilotHarness {
1259
1294
  const harnessResponse = this._handleJsonResponse(response, chatMode);
1260
1295
  if (harnessResponse.autoExecuteToolCall && harnessResponse.pendingToolCall) {
1261
1296
  return this._executePendingToolCall(
1262
- (_c2 = harnessResponse.pendingToolCalls) != null ? _c2 : [harnessResponse.pendingToolCall],
1297
+ (_k = harnessResponse.pendingToolCalls) != null ? _k : [harnessResponse.pendingToolCall],
1263
1298
  sanitizedQuestion,
1264
1299
  onStatus,
1265
1300
  onTextDelta,
@@ -1584,8 +1619,7 @@ class CopilotHarness {
1584
1619
  return result.trim();
1585
1620
  }
1586
1621
  _parseStreamedResponse(response) {
1587
- var _a2;
1588
- var _a, _b, _c, _d;
1622
+ var _a, _b, _c, _d, _e;
1589
1623
  const respCheck = this.validator.validateResponse(response);
1590
1624
  const answer = respCheck.sanitized || response.answer || "";
1591
1625
  if ((_a = response.tool_call) == null ? void 0 : _a.requires_confirm) {
@@ -1615,7 +1649,7 @@ class CopilotHarness {
1615
1649
  let toolResult;
1616
1650
  if (response.tool_result) {
1617
1651
  toolResult = {
1618
- success: (_a2 = response.tool_result.success) != null ? _a2 : true,
1652
+ success: (_c = response.tool_result.success) != null ? _c : true,
1619
1653
  data: response.tool_result.data,
1620
1654
  error: response.tool_result.error,
1621
1655
  status: response.tool_result.status
@@ -1635,10 +1669,10 @@ class CopilotHarness {
1635
1669
  escalation: response.escalation || void 0,
1636
1670
  demo: response.demo || void 0,
1637
1671
  point: response.point || void 0,
1638
- actions: ((_c = response.actions) == null ? void 0 : _c.length) ? response.actions : void 0,
1672
+ actions: ((_d = response.actions) == null ? void 0 : _d.length) ? response.actions : void 0,
1639
1673
  payment: response.payment || void 0,
1640
1674
  coach: response.coach || void 0,
1641
- quickReplies: ((_d = response.quick_replies) == null ? void 0 : _d.length) ? response.quick_replies : void 0
1675
+ quickReplies: ((_e = response.quick_replies) == null ? void 0 : _e.length) ? response.quick_replies : void 0
1642
1676
  };
1643
1677
  }
1644
1678
  /**
@@ -1666,14 +1700,13 @@ class CopilotHarness {
1666
1700
  return plan;
1667
1701
  }
1668
1702
  _handleJsonResponse(response, chatMode, toolResult) {
1669
- var _a2;
1670
- var _a, _b, _c;
1703
+ var _a, _b, _c, _d;
1671
1704
  const respCheck = this.validator.validateResponse(response);
1672
1705
  if (!respCheck.valid) {
1673
1706
  return this._errorResponse(respCheck.error || "Invalid server response.");
1674
1707
  }
1675
1708
  const answer = respCheck.sanitized || response.answer;
1676
- const plan = (_a2 = this._announcePlan(response.plan)) != null ? _a2 : this.currentPlan;
1709
+ const plan = (_a = this._announcePlan(response.plan)) != null ? _a : this.currentPlan;
1677
1710
  if (response.tool_call && response.tool_call.requires_confirm) {
1678
1711
  return {
1679
1712
  mode: "answer",
@@ -1690,7 +1723,7 @@ class CopilotHarness {
1690
1723
  answer,
1691
1724
  plan,
1692
1725
  pendingToolCall: response.tool_call,
1693
- pendingToolCalls: ((_a = response.tool_calls) == null ? void 0 : _a.length) ? response.tool_calls : [response.tool_call],
1726
+ pendingToolCalls: ((_b = response.tool_calls) == null ? void 0 : _b.length) ? response.tool_calls : [response.tool_call],
1694
1727
  autoExecuteToolCall: true,
1695
1728
  autoExecute: false
1696
1729
  };
@@ -1718,10 +1751,10 @@ class CopilotHarness {
1718
1751
  escalation: response.escalation || void 0,
1719
1752
  demo: response.demo || void 0,
1720
1753
  point: response.point || void 0,
1721
- actions: ((_b = response.actions) == null ? void 0 : _b.length) ? response.actions : void 0,
1754
+ actions: ((_c = response.actions) == null ? void 0 : _c.length) ? response.actions : void 0,
1722
1755
  payment: response.payment || void 0,
1723
1756
  coach: response.coach || void 0,
1724
- quickReplies: ((_c = response.quick_replies) == null ? void 0 : _c.length) ? response.quick_replies : void 0
1757
+ quickReplies: ((_d = response.quick_replies) == null ? void 0 : _d.length) ? response.quick_replies : void 0
1725
1758
  };
1726
1759
  this.memory.addMessage({
1727
1760
  role: "assistant",
@@ -1756,7 +1789,7 @@ class CopilotHarness {
1756
1789
  tool_history: toolHistory,
1757
1790
  tools_remaining: budget == null ? void 0 : budget.toolsRemaining,
1758
1791
  force_answer: (_a = budget == null ? void 0 : budget.forceAnswer) != null ? _a : false,
1759
- tool_context: this.toolContext,
1792
+ tool_context: this.contextForTools(),
1760
1793
  client_tools: this.tools.definitions()
1761
1794
  }
1762
1795
  );
@@ -1935,12 +1968,14 @@ class CopilotHarness {
1935
1968
  return !!this.toolExecutor || this.tools.definitions().length > 0;
1936
1969
  }
1937
1970
  canExecuteTool(toolCall) {
1971
+ if (isServerTool(toolCall)) return true;
1938
1972
  if (this.tools.canExecute(toolCall.tool)) {
1939
1973
  return this.tools.canExecuteCall(toolCall);
1940
1974
  }
1941
1975
  return !!this.toolExecutor;
1942
1976
  }
1943
1977
  executeLocalTool(toolCall) {
1978
+ if (isServerTool(toolCall)) return this.executeOnServer(toolCall);
1944
1979
  if (this.tools.canExecute(toolCall.tool)) {
1945
1980
  return this.tools.execute(toolCall);
1946
1981
  }
@@ -1951,6 +1986,30 @@ class CopilotHarness {
1951
1986
  error_type: "tool_unavailable"
1952
1987
  });
1953
1988
  }
1989
+ /**
1990
+ * An MCP tool, after the user approved it: we cannot call it — it is
1991
+ * reached from GuideAI's network with a secret the client never holds —
1992
+ * so the backend runs it, told who the user is by their token.
1993
+ */
1994
+ async executeOnServer(toolCall) {
1995
+ var _a, _b;
1996
+ try {
1997
+ return await this.api.post(EP.chatExecuteTool(), {
1998
+ tool: toolCall.tool,
1999
+ method: toolCall.method,
2000
+ path: toolCall.path,
2001
+ params: toolCall.params,
2002
+ body: toolCall.body,
2003
+ user_token: (_b = (_a = this.toolExecutor) == null ? void 0 : _a.getAuthToken()) != null ? _b : void 0
2004
+ });
2005
+ } catch (error) {
2006
+ return {
2007
+ success: false,
2008
+ error: error instanceof Error ? error.message : "The tool could not be run.",
2009
+ error_type: "tool_unavailable"
2010
+ };
2011
+ }
2012
+ }
1954
2013
  executeLocalToolBatch(toolCalls, onComplete) {
1955
2014
  return Promise.all(toolCalls.map(async (toolCall) => {
1956
2015
  const result = await this.executeLocalTool(toolCall);
@@ -2348,6 +2407,7 @@ class RNCredentialSource {
2348
2407
  this.storage = storage;
2349
2408
  this.session = session;
2350
2409
  this.hostToken = null;
2410
+ this.appValues = /* @__PURE__ */ new Map();
2351
2411
  }
2352
2412
  /**
2353
2413
  * Set by the runtime from `getAuthToken()` before every turn, so the
@@ -2359,12 +2419,20 @@ class RNCredentialSource {
2359
2419
  authToken() {
2360
2420
  return this.hostToken;
2361
2421
  }
2422
+ /** Set from `getRequestHeaders()` before every turn. */
2423
+ setAppValues(values) {
2424
+ this.appValues = new Map(Object.entries(values).map(([k, v]) => [k.toLowerCase(), v]));
2425
+ }
2362
2426
  read(source, key) {
2427
+ var _a;
2363
2428
  switch (source) {
2364
2429
  case "localStorage":
2365
2430
  return this.storage.getItem(key);
2366
2431
  case "sessionStorage":
2367
2432
  return this.session.getItem(key);
2433
+ // A header the toolset declares as supplied by the app.
2434
+ case "app":
2435
+ return (_a = this.appValues.get(key.toLowerCase())) != null ? _a : null;
2368
2436
  // No cookie jar on a device. Saying so is the honest answer.
2369
2437
  case "cookie":
2370
2438
  return null;
@@ -2378,6 +2446,7 @@ function rnPlatform(options = {}) {
2378
2446
  const session = new MemoryStore();
2379
2447
  return { storage, session, credentials: new RNCredentialSource(storage, session) };
2380
2448
  }
2449
+ const RESERVED_HEADERS = /* @__PURE__ */ new Set(["authorization", "host", "content-length", "cookie"]);
2381
2450
  class HostAuth {
2382
2451
  constructor(credentials, options = {}) {
2383
2452
  this.credentials = credentials;
@@ -2390,9 +2459,24 @@ class HostAuth {
2390
2459
  current() {
2391
2460
  return this.credentials.authToken();
2392
2461
  }
2393
- /** Read the host's token now. Never throws: a failed read is "signed out". */
2462
+ /** Read the host's token and extra headers now. Never throws. */
2394
2463
  async refresh() {
2395
2464
  var _a;
2465
+ if (this.options.getRequestHeaders) {
2466
+ let raw = null;
2467
+ try {
2468
+ raw = await this.options.getRequestHeaders();
2469
+ } catch (error) {
2470
+ console.warn("[GuideAI] getRequestHeaders failed; sending none:", error);
2471
+ }
2472
+ const clean = {};
2473
+ for (const [name, value] of Object.entries(raw != null ? raw : {})) {
2474
+ if (/^[A-Za-z0-9-]{1,64}$/.test(name) && !RESERVED_HEADERS.has(name.toLowerCase()) && typeof value === "string" && value && !/[\r\n]/.test(value)) {
2475
+ clean[name] = value;
2476
+ }
2477
+ }
2478
+ this.credentials.setAppValues(clean);
2479
+ }
2396
2480
  if (!this.options.getAuthToken) return null;
2397
2481
  let token = null;
2398
2482
  try {
@@ -3159,7 +3243,7 @@ ${text}`);
3159
3243
  console.log(`${"═".repeat(60)}
3160
3244
  `);
3161
3245
  }
3162
- const DEFAULT_BASE_URL = "https://api.guideai.dev";
3246
+ const DEFAULT_BASE_URL = "https://cdn.3guideai.com";
3163
3247
  let configured = null;
3164
3248
  function configure(config) {
3165
3249
  var _a, _b, _c, _d, _e, _f;
@@ -3173,7 +3257,11 @@ function configure(config) {
3173
3257
  const runtime = new GuideAIRuntime({
3174
3258
  requestOrigin: config.origin,
3175
3259
  store: config.store,
3176
- auth: { getAuthToken: config.getAuthToken, onAuthExpired: config.onAuthExpired },
3260
+ auth: {
3261
+ getAuthToken: config.getAuthToken,
3262
+ onAuthExpired: config.onAuthExpired,
3263
+ getRequestHeaders: config.getRequestHeaders
3264
+ },
3177
3265
  navigation: config.navigation ? navigationBridge(
3178
3266
  typeof config.navigation === "function" ? config.navigation : () => config.navigation
3179
3267
  ) : void 0
@@ -3194,6 +3282,7 @@ function configure(config) {
3194
3282
  debug ? traceTransport(runtime.transport) : runtime.transport,
3195
3283
  runtime.credentials
3196
3284
  );
3285
+ if (config.toolContext) harness.setToolContext(config.toolContext);
3197
3286
  configured = {
3198
3287
  runtime,
3199
3288
  harness,
@@ -3207,6 +3296,10 @@ function identify(userId) {
3207
3296
  if (!configured) throw new Error("Call GuideAI.configure() before identify().");
3208
3297
  configured.visitorId = (userId == null ? void 0 : userId.trim()) || null;
3209
3298
  }
3299
+ function setToolContext(values) {
3300
+ if (!configured) throw new Error("Call GuideAI.configure() before setToolContext().");
3301
+ configured.harness.setToolContext(values != null ? values : void 0);
3302
+ }
3210
3303
  function setUserProfile(profile) {
3211
3304
  if (!configured) throw new Error("Call GuideAI.configure() before setUserProfile().");
3212
3305
  configured.profile = profile;
@@ -3225,7 +3318,7 @@ function isConfigured() {
3225
3318
  function reset() {
3226
3319
  configured = null;
3227
3320
  }
3228
- const GuideAI = { configure, identify, setUserProfile, isConfigured, reset };
3321
+ const GuideAI = { configure, identify, setUserProfile, setToolContext, isConfigured, reset };
3229
3322
  const AUDIO_TYPES = {
3230
3323
  m4a: "audio/m4a",
3231
3324
  mp4: "audio/mp4",
@@ -3496,4 +3589,4 @@ export {
3496
3589
  requireConfigured as r,
3497
3590
  useGuideAIRuntime as u
3498
3591
  };
3499
- //# sourceMappingURL=useOnboarding-DhVtf0U2.js.map
3592
+ //# sourceMappingURL=useOnboarding-DAEGoYSs.js.map