@agent-native/core 0.209.0 → 0.209.1-nightly-20261015005848

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.
@@ -357,7 +357,12 @@ export interface ProductionAgentOptions {
357
357
  runNoProgressTimeoutMs?: number;
358
358
  durableBackgroundRuns?: boolean;
359
359
  onRunStart?: (send: (event: AgentChatEvent) => void, threadId: string, runId: string) => void | Promise<void>;
360
- onEngineResolved?: (engine: AgentEngine, model: string) => void;
360
+ /**
361
+ * Called when the run's engine, model, and effort resolve, and again before
362
+ * each model call, because a call can run on a rate-limit fallback model or
363
+ * at the lower effort an empty-response retry steps down to.
364
+ */
365
+ onEngineResolved?: (engine: AgentEngine, model: string, reasoningEffort: ReasoningEffort | undefined) => void;
361
366
  resolveOwnerEmail?: (event: any) => string | Promise<string>;
362
367
  finalResponseGuard?: AgentLoopFinalResponseGuard;
363
368
  skipFilesContext?: boolean;
@@ -674,6 +679,12 @@ export declare function runAgentLoop(opts: {
674
679
  unknownWriteToolNames?: Set<string>;
675
680
  internalContinuation?: boolean;
676
681
  onModelInput?: ModelInputObserver;
682
+ /**
683
+ * The model and effort each model call uses. Either can change mid-run: a
684
+ * rate limit falls back to another model, and an empty response steps effort
685
+ * down.
686
+ */
687
+ onModelSettings?: (model: string, reasoningEffort: ReasoningEffort | undefined) => void;
677
688
  onUsage?: (usage: AgentLoopUsage) => void;
678
689
  onOutcome?: (outcome: AgentLoopOutcome) => void;
679
690
  ownerEmail?: string | null;
@@ -4584,6 +4584,7 @@ export async function runAgentLoop(opts) {
4584
4584
  : effectiveReasoningEffort,
4585
4585
  providerOptions,
4586
4586
  };
4587
+ opts.onModelSettings?.(model, effectiveReasoningEffort);
4587
4588
  usage.llmCalls = (usage.llmCalls ?? 0) + 1;
4588
4589
  notifyModelInputObserver(opts.onModelInput, engineMessages);
4589
4590
  const eventStream = engine.stream(streamOpts);
@@ -8539,7 +8540,7 @@ export function createProductionAgentHandler(options) {
8539
8540
  configuredEffort: options.reasoningEffort,
8540
8541
  });
8541
8542
  const modelSupportsVision = isAgentModelVisionCapable(effectiveModel, engine.capabilities.vision === true);
8542
- options.onEngineResolved?.(engine, effectiveModel);
8543
+ options.onEngineResolved?.(engine, effectiveModel, reasoningEffort);
8543
8544
  console.log(`[agent-chat] resolved engine=${engine.name} model=${effectiveModel} requestModel=${requestModel ?? "(none)"} requestEngine=${requestEngine ?? "(none)"} modelSource=${modelSelectionSource} engineDefault=${engine.defaultModel} effort=${reasoningEffort ?? "unset"} turnId=${requestTurnId ?? "(none)"}`);
8544
8545
  if (!(await isResolvedEngineUsableForRequest(engine, {
8545
8546
  apiKey: effectiveApiKey,
@@ -9792,9 +9793,26 @@ export function createProductionAgentHandler(options) {
9792
9793
  : "") +
9793
9794
  `\n</custom-agent-profile>`;
9794
9795
  let responseText = "";
9795
- const subUsage = await runAgentLoop({
9796
+ // A profile is its own model conversation running beside
9797
+ // others, so it gets its own run context: its model and effort
9798
+ // never stand in for another loop's, and it starts with
9799
+ // nothing read, since the run's reads are what the run's
9800
+ // model saw. New per-conversation fields reset here too.
9801
+ const profileRun = {
9802
+ ...getRequestRunContext(),
9803
+ model: profile.model ?? model,
9804
+ reasoningEffort,
9805
+ toolSearchReads: undefined,
9806
+ extensionContentReads: undefined,
9807
+ extensionExcerptReads: undefined,
9808
+ };
9809
+ const profileLoopOpts = {
9796
9810
  engine,
9797
9811
  model: profile.model ?? model,
9812
+ onModelSettings: (loopModel, effort) => {
9813
+ profileRun.model = loopModel;
9814
+ profileRun.reasoningEffort = effort;
9815
+ },
9798
9816
  systemPrompt: profilePrompt,
9799
9817
  tools: requestTools,
9800
9818
  availableTools: availableRequestTools,
@@ -9848,7 +9866,8 @@ export function createProductionAgentHandler(options) {
9848
9866
  ...(resolvedRunSoftTimeoutMs > 0
9849
9867
  ? { runSoftTimeoutMs: resolvedRunSoftTimeoutMs }
9850
9868
  : {}),
9851
- });
9869
+ };
9870
+ const subUsage = await runWithRequestContext({ ...getRequestContext(), run: profileRun }, () => runAgentLoop(profileLoopOpts));
9852
9871
  await control.flushEvents();
9853
9872
  try {
9854
9873
  const ownerEmail = options.resolveOwnerEmail
@@ -9968,6 +9987,9 @@ export function createProductionAgentHandler(options) {
9968
9987
  const agentLoopOpts = {
9969
9988
  engine,
9970
9989
  model: effectiveModel,
9990
+ // Custom agent profile loops report into their own run context
9991
+ // copies, so only this loop sets the run's model and effort.
9992
+ onModelSettings: (model, effort) => options.onEngineResolved?.(engine, model, effort),
9971
9993
  runId,
9972
9994
  followUpSuggestions: true,
9973
9995
  systemPrompt: requestSystemPrompt,
@@ -17,7 +17,7 @@ export declare function getAgentSidebarMaxWidth(viewportWidth?: number): number;
17
17
  export declare function clampAgentSidebarWidth(width: number, viewportWidth?: number): number;
18
18
  export declare function getAgentSidebarOpenPreferenceKey(storageKey?: string | null): string;
19
19
  export declare function dispatchAgentSidebarStateChange(detail: AgentSidebarStateChangeDetail): void;
20
- export declare function setAgentSidebarOpenPreference(open: boolean, storageKey?: string | null): void;
20
+ export declare function setAgentSidebarOpenPreference(open: boolean, storageKey?: string | null): boolean;
21
21
  export declare function requestAgentSidebarOpen(): void;
22
22
  export declare function getAgentSidebarUrlOpenOverride(): boolean | null;
23
23
  export declare function consumeAgentSidebarUrlOpenOverride(storageKey?: string | null): boolean | null;
@@ -34,6 +34,75 @@ export function getAgentSidebarOpenPreferenceKey(storageKey) {
34
34
  const suffix = storageKey?.trim();
35
35
  return suffix ? `agent-native.${suffix}.sidebar-open` : SIDEBAR_OPEN_KEY;
36
36
  }
37
+ function getExplicitUrlOpenSessionKey(storageKey) {
38
+ return `${getAgentSidebarOpenPreferenceKey(storageKey)}.explicit-url-open`;
39
+ }
40
+ function getExplicitUrlOpenSessionIntent(storageKey) {
41
+ if (typeof window === "undefined")
42
+ return null;
43
+ try {
44
+ return (window.sessionStorage.getItem(getExplicitUrlOpenSessionKey(storageKey)) === "true");
45
+ }
46
+ catch {
47
+ // coercion-ok: null distinguishes unreadable storage from a missing false intent.
48
+ return null;
49
+ }
50
+ }
51
+ function setExplicitUrlOpenSessionIntent(open, storageKey) {
52
+ if (typeof window === "undefined")
53
+ return false;
54
+ try {
55
+ const key = getExplicitUrlOpenSessionKey(storageKey);
56
+ if (open) {
57
+ window.sessionStorage.setItem(key, "true");
58
+ }
59
+ else {
60
+ window.sessionStorage.removeItem(key);
61
+ }
62
+ return true;
63
+ }
64
+ catch {
65
+ // coercion-ok: false keeps the explicit URL intent available when the session write fails.
66
+ return false;
67
+ }
68
+ }
69
+ function writeAgentSidebarOpenPreference(open, storageKey) {
70
+ if (typeof window === "undefined")
71
+ return false;
72
+ try {
73
+ window.localStorage.setItem(getAgentSidebarOpenPreferenceKey(storageKey), String(open));
74
+ return true;
75
+ }
76
+ catch {
77
+ // coercion-ok: false keeps the URL override retryable when preference persistence fails.
78
+ return false;
79
+ }
80
+ }
81
+ function replaceAgentSidebarUrlOpenOverride(open) {
82
+ if (typeof window === "undefined")
83
+ return false;
84
+ try {
85
+ const url = new URL(window.location.href);
86
+ if (open === null) {
87
+ url.searchParams.delete(AGENT_SIDEBAR_QUERY_PARAM);
88
+ }
89
+ else {
90
+ url.searchParams.set(AGENT_SIDEBAR_QUERY_PARAM, open
91
+ ? AGENT_SIDEBAR_QUERY_VALUE_OPEN
92
+ : AGENT_SIDEBAR_QUERY_VALUE_CLOSED);
93
+ }
94
+ const nextUrl = `${url.pathname}${url.search}${url.hash}`;
95
+ const currentUrl = `${window.location.pathname}${window.location.search}${window.location.hash}`;
96
+ if (nextUrl === currentUrl)
97
+ return true;
98
+ window.history.replaceState(window.history.state, "", nextUrl);
99
+ return true;
100
+ }
101
+ catch {
102
+ // coercion-ok: false tells the caller the URL intent could not be updated.
103
+ return false;
104
+ }
105
+ }
37
106
  export function dispatchAgentSidebarStateChange(detail) {
38
107
  if (typeof window === "undefined")
39
108
  return;
@@ -43,11 +112,21 @@ export function dispatchAgentSidebarStateChange(detail) {
43
112
  }
44
113
  export function setAgentSidebarOpenPreference(open, storageKey) {
45
114
  if (typeof window === "undefined")
46
- return;
47
- try {
48
- localStorage.setItem(getAgentSidebarOpenPreferenceKey(storageKey), String(open));
115
+ return false;
116
+ const urlOverride = getAgentSidebarUrlOpenOverride();
117
+ const sessionIntentSaved = urlOverride !== null || !open
118
+ ? setExplicitUrlOpenSessionIntent(open, storageKey)
119
+ : true;
120
+ const preferenceSaved = writeAgentSidebarOpenPreference(open, storageKey);
121
+ const storageSaved = sessionIntentSaved && preferenceSaved;
122
+ if (urlOverride !== null || !storageSaved) {
123
+ let urlOverrideSaved = replaceAgentSidebarUrlOpenOverride(storageSaved ? null : open);
124
+ if (storageSaved && !urlOverrideSaved) {
125
+ urlOverrideSaved = replaceAgentSidebarUrlOpenOverride(open);
126
+ }
127
+ return storageSaved && urlOverrideSaved;
49
128
  }
50
- catch { }
129
+ return storageSaved;
51
130
  }
52
131
  export function requestAgentSidebarOpen() {
53
132
  if (typeof window === "undefined")
@@ -72,7 +151,10 @@ export function consumeAgentSidebarUrlOpenOverride(storageKey) {
72
151
  const override = getAgentSidebarUrlOpenOverride();
73
152
  if (override === null || typeof window === "undefined")
74
153
  return override;
75
- setAgentSidebarOpenPreference(override, storageKey);
154
+ const preferenceSaved = writeAgentSidebarOpenPreference(override, storageKey);
155
+ const sessionIntentSaved = setExplicitUrlOpenSessionIntent(override, storageKey);
156
+ if (!preferenceSaved || !sessionIntentSaved)
157
+ return override;
76
158
  try {
77
159
  const url = new URL(window.location.href);
78
160
  url.searchParams.delete(AGENT_SIDEBAR_QUERY_PARAM);
@@ -125,6 +207,16 @@ export function getInitialAgentSidebarOpen(defaultOpen, storageKey, { ignoreUrlO
125
207
  if (urlOverride !== null)
126
208
  return urlOverride;
127
209
  }
210
+ if (getExplicitUrlOpenSessionIntent(storageKey) === true) {
211
+ try {
212
+ if (window.localStorage.getItem(getAgentSidebarOpenPreferenceKey(storageKey)) !== "false") {
213
+ return true;
214
+ }
215
+ }
216
+ catch {
217
+ return true;
218
+ }
219
+ }
128
220
  if (hasChatThreadDeepLink())
129
221
  return true;
130
222
  if (typeof window !== "undefined" &&
@@ -105,8 +105,8 @@ export function createRunCodeEntry(getActions, opts = {}) {
105
105
  " Supports stageAs/saveToFile/fetchAllPages; use cursorBodyPath for POST-body pagination.",
106
106
  " Example: `const data = await providerFetch('<provider-id>', '/records', { query: { limit: 100 } });`",
107
107
  " - `providerRequest(provider, path, init?)` — same authenticated call, but returns the full provider-api envelope with request, response status/headers, truncation, and body metadata.",
108
- " - `providerFetchAll(provider, path, init?)` — generic pagination helper for cursor, page, and offset APIs. Pass `pagination: { itemsPath, cursorPath or nextCursorPath, cursorParam or cursorBodyPath, pageParam, offsetParam, pageSize, maxPages }`. Returns `{ items, pages, pageCount, itemCount, hasMore, lastCursor, stoppedReason }`.",
109
- " - `providerSearchAll(provider, path, init?, options?)` — streaming search helper for broad provider corpora such as transcripts, messages, tickets, issues, notes, events, or documents. Use this before hand-written loops when searching many provider records for terms/phrases/regexes or proving absence. Pass the same `pagination` config as `providerFetchAll`, plus options like `{ query, queries, terms, regex, textPaths, idPaths, metadataPaths, maxHits }`. Returns structured hits with item ids, paths, snippets, page/item indexes, and coverage fields (`pageCount`, `itemCount`, `hasMore`, `stoppedReason`).",
108
+ " - `providerFetchAll(provider, path, init?)` — generic pagination helper for cursor, page, and offset APIs, for a cohort already narrowed by a server-side filter (not for finding one entity or topic). Pass `pagination: { itemsPath, cursorPath or nextCursorPath, cursorParam or cursorBodyPath, pageParam, offsetParam, pageSize, maxPages }`. Returns `{ items, pages, pageCount, itemCount, hasMore, lastCursor, stoppedReason }`.",
109
+ " - `providerSearchAll(provider, path, init?, options?)` — streaming search helper for broad provider corpora such as transcripts, messages, tickets, issues, notes, events, or documents. Use this before hand-written loops when a bounded cohort must be searched for terms/phrases/regexes or an absence claim needs proof; if the provider has a search or semantic tool for the question, use that first. Pass the same `pagination` config as `providerFetchAll`, plus options like `{ query, queries, terms, regex, textPaths, idPaths, metadataPaths, maxHits }`. Returns structured hits with item ids, paths, snippets, page/item indexes, and coverage fields (`pageCount`, `itemCount`, `hasMore`, `stoppedReason`).",
110
110
  " - `webFetch(url, init?)` — outbound HTTP request via the web-request action.",
111
111
  " Returns `{ status, body }` where body is the response text. Supports responseMode, extract, includeLinks, search, maxChars, and saveToFile.",
112
112
  " Example: `const { body } = await webFetch('https://api.example.com/data', { responseMode: 'raw' });`",
@@ -1057,6 +1057,9 @@ async function providerFetch(provider, apiPath, init = {}) {
1057
1057
  const detail = typeof r.text === "string" ? r.text : JSON.stringify(r.json ?? "");
1058
1058
  throw new Error(\`Provider request failed (\${r.status}): \${String(detail).slice(0, 500)}\`);
1059
1059
  }
1060
+ if (r.truncated === true) {
1061
+ throw new Error("Provider response was cut at the response size limit, so its body is incomplete. Request smaller pages or add a server-side filter; use providerRequest() to inspect the partial body.");
1062
+ }
1060
1063
  return r.json !== undefined ? r.json : r.text;
1061
1064
  }
1062
1065
  return parsed;
@@ -13,8 +13,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
13
13
  };
14
14
  }>>;
15
15
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- ok?: undefined;
17
16
  error: string;
17
+ ok?: undefined;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -1,6 +1,6 @@
1
1
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
2
- ok?: undefined;
3
2
  error: string;
3
+ ok?: undefined;
4
4
  } | {
5
5
  error?: undefined;
6
6
  ok: boolean;
@@ -201,9 +201,28 @@ async function handleMcpOAuthStart(event) {
201
201
  if (useRootGoogleCallback && !workspaceAppId) {
202
202
  return refuse(event, 400, "Workspace MCP OAuth is missing its app callback id.");
203
203
  }
204
+ const requestContext = {
205
+ userEmail: session.email,
206
+ orgId: org?.orgId ?? undefined,
207
+ };
208
+ let clientInformation;
209
+ try {
210
+ clientInformation = await runWithRequestContext(requestContext, () => resolveManagedMcpOAuthClient(urlCheck.url));
211
+ }
212
+ catch (error) {
213
+ return mcpOAuthStartFailureResponse(event, resolveMcpOAuthStartError(error));
214
+ }
215
+ if (managedMcpOAuthClientFor(urlCheck.url)?.requireClientCredentials &&
216
+ !clientInformation) {
217
+ return refuse(event, 400, MCP_OAUTH_MANAGED_CLIENT_MISSING_MESSAGE);
218
+ }
219
+ // A pre-registered client has a fixed redirect URI on the shared workspace
220
+ // callback. A dynamically registered client registers whatever URI this
221
+ // flow sends, so keep it on this app's mount: the provider then returns the
222
+ // user straight to the app that owns the flow cookie.
204
223
  const redirectUri = resolveOAuthRedirectUri(event, useRootGoogleCallback
205
224
  ? "/_agent-native/google/callback"
206
- : "/_agent-native/mcp/servers/oauth/callback");
225
+ : "/_agent-native/mcp/servers/oauth/callback", { appScopedCallback: !useRootGoogleCallback && !clientInformation });
207
226
  if (!redirectUri) {
208
227
  return refuse(event, 400, "Invalid MCP OAuth redirect URI.");
209
228
  }
@@ -218,17 +237,8 @@ async function handleMcpOAuthStart(event) {
218
237
  })
219
238
  : crypto.randomUUID();
220
239
  const safeReturnUrl = returnUrl ? safeReturnPath(returnUrl) : undefined;
221
- const requestContext = {
222
- userEmail: session.email,
223
- orgId: org?.orgId ?? undefined,
224
- };
225
240
  try {
226
241
  const started = await runWithRequestContext(requestContext, async () => {
227
- const clientInformation = await resolveManagedMcpOAuthClient(urlCheck.url);
228
- if (managedMcpOAuthClientFor(urlCheck.url)?.requireClientCredentials &&
229
- !clientInformation) {
230
- return null;
231
- }
232
242
  const storedCredentials = reconnectServer?.oauthSecretKey && reconnectScopeId
233
243
  ? await readMcpOAuthCredentials({
234
244
  key: reconnectServer.oauthSecretKey,
@@ -259,9 +269,6 @@ async function handleMcpOAuthStart(event) {
259
269
  : {}),
260
270
  });
261
271
  });
262
- if (!started) {
263
- return refuse(event, 400, MCP_OAUTH_MANAGED_CLIENT_MISSING_MESSAGE);
264
- }
265
272
  const flow = {
266
273
  name,
267
274
  url: urlCheck.url.toString(),
@@ -64,6 +64,6 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
64
64
  message?: undefined;
65
65
  summary?: undefined;
66
66
  spans?: undefined;
67
- error?: undefined;
68
67
  ok: boolean;
68
+ error?: undefined;
69
69
  }>>;
@@ -663,6 +663,9 @@ async function callProvider(runtime, request) {
663
663
  const detail = response.text ?? response.json ?? response.statusText ?? "";
664
664
  throw new Error(`Provider request failed (${status}): ${stringifyBrief(detail, 500)}`);
665
665
  }
666
+ if (response.truncated === true) {
667
+ throw new Error(`Provider response was cut at the response size limit, so this page is incomplete and would be recorded as empty. Lower the page size or fields, or add a filter in the job request.`);
668
+ }
666
669
  return {
667
670
  body: response.json ??
668
671
  (typeof response.text === "string" ? tryParseJson(response.text) : null),
@@ -595,6 +595,7 @@ const PROVIDER_CONFIGS = {
595
595
  },
596
596
  ],
597
597
  notes: [
598
+ "To answer a question about a Gong account, deal, customer, or topic, use Gong's connected MCP tools (ask_account, ask_deal, generate_brief) when available; Gong searches the calls server-side and answers in one request. Gong's REST API has no account, company, or topic filter, so finding one account's calls or a topic through /calls or /calls/extensive means scanning the whole org, and those responses truncate at the size limit. If the Analytics app is connected, ask it with call-agent; it owns Gong search. Use the REST endpoints below only for exact counts, verbatim quotes, or proof of absence across a bounded cohort.",
598
599
  "For broad corpus work, call /calls/extensive with provider-api-request and stageAs/saveToFile. Gong returns the next cursor at records.cursor and expects the next cursor in the POST body at cursor, so use pagination { nextCursorPath: 'records.cursor', cursorBodyPath: 'cursor' } for stageAs or fetchAllPages { cursorPath: 'records.cursor', cursorBodyPath: 'cursor' } for saveToFile.",
599
600
  "The public Gong REST API does not expose an arbitrary transcript-text filter. Use configured keyword tracker results from /calls/extensive when they cover the requested term; otherwise batch transcripts with POST /calls/transcript and body { filter: { callIds: [...] } } after narrowing or staging call ids.",
600
601
  ],
@@ -1452,6 +1453,7 @@ export async function executeProviderApiRequest(args, runtime) {
1452
1453
  contentType: resp.contentType,
1453
1454
  status: resp.status,
1454
1455
  ok: resp.ok,
1456
+ truncated: resp.truncated,
1455
1457
  };
1456
1458
  });
1457
1459
  const allItemsJson = JSON.stringify(items, null, 2);
@@ -1492,6 +1494,9 @@ export async function executeProviderApiRequest(args, runtime) {
1492
1494
  },
1493
1495
  }), config);
1494
1496
  if (args.saveToFile) {
1497
+ if (response.truncated) {
1498
+ throw new Error(`The response was cut at ${effectiveMaxBytes} bytes (${response.size} available), so saving it would persist an incomplete file. Narrow the request with a server-side filter or fetch it in pages with fetchAllPages.`);
1499
+ }
1495
1500
  const rawText = response.text ??
1496
1501
  (response.json !== undefined ? JSON.stringify(response.json) : "");
1497
1502
  const saved = (await handleSaveToFile(args.saveToFile, rawText, response.contentType, response.status, response.ok));
@@ -1527,13 +1532,21 @@ export async function executeProviderApiRequest(args, runtime) {
1527
1532
  },
1528
1533
  response,
1529
1534
  guidance: [
1530
- "This was a raw provider API request. Use provider docs/spec URLs to choose endpoints and include method/path/status plus relevant filters in the methodology. Prefer this escape hatch whenever canned actions are too narrow.",
1535
+ "This was a raw provider API request. Use provider docs/spec URLs to choose endpoints and include method/path/status plus relevant filters in the methodology. A data API returns records: when the provider can filter, search, or answer the question itself, make it do that instead of pulling records to filter locally.",
1536
+ response.truncated
1537
+ ? truncatedResponseGuidance(response.size, effectiveMaxBytes)
1538
+ : null,
1531
1539
  providerAccessErrorGuidance(config, response.status),
1532
1540
  ]
1533
1541
  .filter(Boolean)
1534
1542
  .join(" "),
1535
1543
  };
1536
1544
  }
1545
+ // A truncated body is incomplete, not a smaller answer. Raising maxBytes and
1546
+ // paging the whole collection is the wrong recovery, so name the right ones.
1547
+ function truncatedResponseGuidance(size, maxBytes) {
1548
+ return `This response is incomplete: ${size} bytes came back and only the first ${maxBytes} are included. Do not raise maxBytes or page the whole collection to filter it locally. Add a server-side filter or query parameter, use the provider's own search or semantic tool, or run the scan with stageAs or provider-corpus-job. If none of those can express the question, say so or hand it to the app that owns this source.`;
1549
+ }
1537
1550
  const PROVIDER_ACCESS_ERROR_STATUSES = new Set([401, 403, 404]);
1538
1551
  function providerAccessErrorGuidance(config, status) {
1539
1552
  if (!PROVIDER_ACCESS_ERROR_STATUSES.has(status))
@@ -2216,6 +2229,7 @@ async function executeCustomProviderApiRequest(args, customConfig, runtime) {
2216
2229
  contentType: resp.contentType,
2217
2230
  status: resp.status,
2218
2231
  ok: resp.ok,
2232
+ truncated: resp.truncated,
2219
2233
  };
2220
2234
  });
2221
2235
  const allItemsJson = JSON.stringify(items, null, 2);
@@ -2258,6 +2272,9 @@ async function executeCustomProviderApiRequest(args, customConfig, runtime) {
2258
2272
  },
2259
2273
  });
2260
2274
  if (args.saveToFile) {
2275
+ if (response.truncated) {
2276
+ throw new Error(`The response was cut at ${effectiveMaxBytes} bytes (${response.size} available), so saving it would persist an incomplete file. Narrow the request with a server-side filter or fetch it in pages with fetchAllPages.`);
2277
+ }
2261
2278
  const rawText = response.text ??
2262
2279
  (response.json !== undefined ? JSON.stringify(response.json) : "");
2263
2280
  const saved = (await handleSaveToFile(args.saveToFile, rawText, response.contentType, response.status, response.ok));
@@ -2295,7 +2312,14 @@ async function executeCustomProviderApiRequest(args, customConfig, runtime) {
2295
2312
  headerNames: Object.keys(headers).filter((name) => name.toLowerCase() !== "authorization"),
2296
2313
  },
2297
2314
  response,
2298
- guidance: "This was a raw provider API request to a custom provider. Use provider docs URLs to choose endpoints.",
2315
+ guidance: [
2316
+ "This was a raw provider API request to a custom provider. Use provider docs URLs to choose endpoints.",
2317
+ response.truncated
2318
+ ? truncatedResponseGuidance(response.size, effectiveMaxBytes)
2319
+ : null,
2320
+ ]
2321
+ .filter(Boolean)
2322
+ .join(" "),
2299
2323
  };
2300
2324
  }
2301
2325
  async function resolveCustomAuth(customConfig, runtime, ctx, args) {
@@ -4642,6 +4666,9 @@ async function fetchAllPages(config, executeOnePage) {
4642
4666
  const preview = page.text.replace(/\s+/g, " ").trim().slice(0, 500);
4643
4667
  throw new Error(`fetchAllPages request failed with HTTP ${page.status}${preview ? `: ${preview}` : ""}`);
4644
4668
  }
4669
+ if (page.truncated) {
4670
+ throw new Error(`fetchAllPages page ${pageCount} was cut at the response size limit, so its items and next cursor are incomplete. Request smaller pages (a lower limit or fewer fields) or add a server-side filter.`);
4671
+ }
4645
4672
  let body;
4646
4673
  try {
4647
4674
  body = JSON.parse(page.text);
@@ -202,6 +202,9 @@ export async function stagingExecuteRequest(args, execute, ctx) {
202
202
  if (!response?.ok) {
203
203
  fail(`Provider API returned status ${response?.status}: ${JSON.stringify(response?.json ?? response?.text).slice(0, 200)}`, { errorCode: "provider_api_rejected" });
204
204
  }
205
+ if (response.truncated === true) {
206
+ fail(`Provider response page ${pageIndex + 1} was cut at the response size limit, so staging it would drop rows. Request smaller pages (a lower limit or fewer fields) or add a server-side filter.`, { errorCode: "provider_response_truncated" });
207
+ }
205
208
  const body = response.json ??
206
209
  (response.text ? tryParseJson(response.text) : null);
207
210
  const pageRows = extractItemsArray(body, itemsPath);
@@ -10,6 +10,7 @@ import { getAppConfig } from "../../app-config/index.js";
10
10
  import { isFrameworkGroupedAction } from "../../framework-tools.js";
11
11
  import { isAuthenticatedReadAction, isAutoReadExcludedActionName, } from "../../mcp/build-server.js";
12
12
  import { withConfiguredAppBasePath } from "../app-base-path.js";
13
+ import { ensureRequestRunContext } from "../request-context.js";
13
14
  export function filterReadOnlyActions(actions) {
14
15
  return Object.fromEntries(Object.entries(actions).filter(([, entry]) => entry.readOnly === true));
15
16
  }
@@ -323,6 +324,16 @@ async function runDelegatedAgentLoop(runOptions, pluginOptions, timeoutOptions,
323
324
  : delegatedHardToolResultCap,
324
325
  },
325
326
  finalResponseGuard: pluginOptions.finalResponseGuard,
327
+ // Actions this run calls record the model and effort from the run
328
+ // context, which a rate-limit fallback or an effort step-down changes.
329
+ onModelSettings: (model, reasoningEffort) => {
330
+ runOptions.onModelSettings?.(model, reasoningEffort);
331
+ const runContext = ensureRequestRunContext();
332
+ if (runContext) {
333
+ runContext.model = model;
334
+ runContext.reasoningEffort = reasoningEffort;
335
+ }
336
+ },
326
337
  };
327
338
  const execute = (loopOptions = resolvedRunOptions) => runner(loopOptions, pluginOptions.runSoftTimeoutMs, timeoutOptions);
328
339
  if (!options.telemetry)
@@ -270,9 +270,13 @@ Available corpus-capable tools: ${available.join(", ")}.
270
270
 
271
271
  This workflow does not apply to ordinary structured lookups, bounded aggregates, or counts grouped over one known source. For those requests, use the single most directly authoritative source, run one bounded query, and answer as soon as it succeeds. Do not cross-check or expand into a corpus workflow unless the user asks for multiple sources, exhaustive unstructured-record coverage, or an absence claim.
272
272
 
273
- For broad provider searches, raw API access, multi-page cohorts, cross-source joins, classification over unstructured records, or absence-sensitive answers, do not stop at a bounded shortcut action. Use the provider's broad API/search/list surface, fetch every relevant page or an explicit bounded cohort, stage/save large responses when needed, and reduce the corpus with durable corpus jobs, staged-dataset queries, or code execution.
273
+ Retrieval ladder. Take the first rung that answers the question:
274
+ 1. A tool shaped like the question: the provider's native search, semantic, or MCP tool, or an owning app via \`call-agent\`. It searches provider-side in one request but reports no coverage, so absence claims and exact counts start at rung 3 or carry a coverage caveat.
275
+ 2. A server-side filter or query parameter on a bounded window.
276
+ 3. A staged or durable scan (\`stageAs\`, \`provider-corpus-job\`) over an explicit cohort, only for exhaustive coverage, exact counts, absence claims, classification, or cross-source joins: fetch every relevant page or the bounded cohort, stage large responses, and reduce them with corpus jobs, staged-dataset queries, or code over the staged data.
277
+ Pulling a collection into context or a run-code loop to filter it locally is not a rung; it means rung 1 or 2 is missing, so say so.
274
278
 
275
- When \`provider-corpus-job\` is available, prefer it for transcript/message/ticket/issue/document scans that may exceed one turn, need provider-side backoff, or need a defensible "not found" conclusion. Use operation="start" with mode="paginated-search" for any paginated provider endpoint, or mode="batch-search" when a prior cohort of ids/records must feed a second provider endpoint. Continue paused jobs with operation="continue" until status is completed or quota_wait, then read operation="results". In run-code, prefer providerFetchAll() for short cursor/page/offset pagination and providerRequest() when response status, headers, or truncation metadata matters. Report source, filters, row counts, pagination/truncation, failed pages, quota_wait times, and remaining gaps.`;
279
+ When \`provider-corpus-job\` is available, prefer it for transcript/message/ticket/issue/document scans that may exceed one turn, need provider-side backoff, or need a defensible "not found" conclusion. Use operation="start" with mode="paginated-search" for any paginated provider endpoint, or mode="batch-search" when a prior cohort of ids/records must feed a second provider endpoint. Continue paused jobs with operation="continue" until status is completed or quota_wait, then read operation="results". In run-code, use providerFetchAll() only for short cursor/page/offset pagination over a cohort you already narrowed, and providerRequest() when response status, headers, or truncation metadata matters. Report source, filters, row counts, pagination/truncation, failed pages, quota_wait times, and remaining gaps.`;
276
280
  }
277
281
  export async function collectFiles(dir, prefix, depth, results) {
278
282
  if (depth > 4 || results.length >= 500)
@@ -3697,11 +3697,12 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
3697
3697
  jevContextCompact: leanPrompt || lazyContext,
3698
3698
  initialToolNames: effectiveInitialToolNames,
3699
3699
  ...(options?.toolLimits ? { toolLimits: options.toolLimits } : {}),
3700
- onEngineResolved: (engine, model) => {
3700
+ onEngineResolved: (engine, model, reasoningEffort) => {
3701
3701
  const runCtx = ensureRequestRunContext();
3702
3702
  if (runCtx) {
3703
3703
  runCtx.engine = engine;
3704
3704
  runCtx.model = model;
3705
+ runCtx.reasoningEffort = reasoningEffort;
3705
3706
  }
3706
3707
  },
3707
3708
  onRunPrepared: persistSubmittedUserMessage,
@@ -3752,11 +3753,12 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
3752
3753
  resolveActionSurface: (details) => resolveObservabilityReviewSummaryActionSurface(details, options?.resolveActionSurface),
3753
3754
  skipFilesContext: true,
3754
3755
  initialToolNames: effectiveInitialToolNames,
3755
- onEngineResolved: (engine, model) => {
3756
+ onEngineResolved: (engine, model, reasoningEffort) => {
3756
3757
  const runCtx = ensureRequestRunContext();
3757
3758
  if (runCtx) {
3758
3759
  runCtx.engine = engine;
3759
3760
  runCtx.model = model;
3761
+ runCtx.reasoningEffort = reasoningEffort;
3760
3762
  }
3761
3763
  },
3762
3764
  onRunPrepared: persistSubmittedUserMessage,
@@ -3938,11 +3940,12 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
3938
3940
  skipFilesContext,
3939
3941
  initialToolNames: effectiveInitialToolNames,
3940
3942
  ...(options?.toolLimits ? { toolLimits: options.toolLimits } : {}),
3941
- onEngineResolved: (engine, model) => {
3943
+ onEngineResolved: (engine, model, reasoningEffort) => {
3942
3944
  const runCtx = ensureRequestRunContext();
3943
3945
  if (runCtx) {
3944
3946
  runCtx.engine = engine;
3945
3947
  runCtx.model = model;
3948
+ runCtx.reasoningEffort = reasoningEffort;
3946
3949
  }
3947
3950
  },
3948
3951
  onRunPrepared: persistSubmittedUserMessage,
@@ -1,9 +1,9 @@
1
1
  export declare function createAgentEngineOllamaModelsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
2
2
  error: string;
3
- ok?: undefined;
4
3
  models?: undefined;
4
+ ok?: undefined;
5
5
  } | {
6
- error?: undefined;
7
6
  ok: boolean;
8
7
  models: string[];
8
+ error?: undefined;
9
9
  }>>;
@@ -21,6 +21,14 @@ export declare function decodeNetlifyPreviewGoogleOAuthRelayState(value: string
21
21
  export declare function wrapNetlifyPreviewGoogleOAuthState(event: H3Event, state: string, callbackPath?: string): string;
22
22
  export type OAuthRedirectUriOptions = {
23
23
  allowRootCallback?: boolean;
24
+ /**
25
+ * Keep the callback under the app's own mount instead of the shared
26
+ * workspace root callback. Use for providers that register the redirect
27
+ * URI per flow (e.g. MCP dynamic client registration): the callback then
28
+ * lands on the app that started the flow without a root relay, which
29
+ * cannot recover the app id from an opaque state.
30
+ */
31
+ appScopedCallback?: boolean;
24
32
  useNetlifyPreviewGoogleOAuthRelay?: boolean;
25
33
  };
26
34
  /**
@@ -279,10 +279,15 @@ function isRequestUnderAppBasePath(event) {
279
279
  ];
280
280
  return frameworkPrefixes.some((prefix) => requestPath === prefix || requestPath.startsWith(`${prefix}/`));
281
281
  }
282
+ function usesRootOAuthCallback(pathname, options) {
283
+ return (!options.appScopedCallback &&
284
+ (isWorkspaceOAuthCallbackRelayEnabled() ||
285
+ options.allowRootCallback === true) &&
286
+ isFrameworkOAuthCallbackPath(pathname));
287
+ }
282
288
  function getDefaultOAuthRedirectUrl(event, path, options = {}) {
283
289
  const cleanPath = path.startsWith("/") ? path : `/${path}`;
284
- if ((isWorkspaceOAuthCallbackRelayEnabled() || options.allowRootCallback) &&
285
- isFrameworkOAuthCallbackPath(cleanPath)) {
290
+ if (usesRootOAuthCallback(cleanPath, options)) {
286
291
  return `${getOrigin(event)}${publicFrameworkPath(cleanPath)}`;
287
292
  }
288
293
  const basePath = isRequestUnderAppBasePath(event) ? getAppBasePath() : "";
@@ -347,9 +352,7 @@ export function isAllowedOAuthRedirectUri(candidate, event, expectedOrigin = get
347
352
  const allowedPrefixes = basePath && isRequestUnderAppBasePath(event)
348
353
  ? [
349
354
  `${basePath}/_agent-native/`,
350
- ...((isWorkspaceOAuthCallbackRelayEnabled() ||
351
- options.allowRootCallback) &&
352
- isFrameworkOAuthCallbackPath(pathname)
355
+ ...(usesRootOAuthCallback(pathname, options)
353
356
  ? ["/_agent-native/"]
354
357
  : []),
355
358
  ]
@@ -54,8 +54,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
54
54
  expiresAt?: undefined;
55
55
  ttlSeconds?: undefined;
56
56
  } | {
57
+ error?: undefined;
57
58
  token: string;
58
59
  expiresAt: string;
59
60
  ttlSeconds: number;
60
- error?: undefined;
61
61
  }>>;
@@ -1,6 +1,7 @@
1
1
  import type { AgentActionScope } from "../agent/types.js";
2
2
  import type { TrackingEventScope } from "../observability/tracing.js";
3
3
  import type { ContextStatus } from "../shared/context-status.js";
4
+ import type { ReasoningEffort } from "../shared/reasoning-effort.js";
4
5
  import type { SignupAttributionContext } from "./attribution.js";
5
6
  export interface RequestRunContext {
6
7
  waitUntil?: (promise: Promise<unknown>) => void;
@@ -19,6 +20,8 @@ export interface RequestRunContext {
19
20
  systemPrompt?: string;
20
21
  engine?: import("../agent/engine/types.js").AgentEngine;
21
22
  model?: string;
23
+ /** The run's resolved thinking effort; unset when the model takes none. */
24
+ reasoningEffort?: ReasoningEffort;
22
25
  allowedActionNames?: readonly string[];
23
26
  actionScope?: Readonly<AgentActionScope>;
24
27
  appAuthorization?: {
@@ -2,6 +2,7 @@ declare const _default: import("../../action.js").ActionDefinition<{
2
2
  resourceType: string;
3
3
  resourceId: string;
4
4
  }, {
5
+ role?: undefined;
5
6
  ownerEmail: any;
6
7
  visibility: any;
7
8
  shares: any[];
@@ -11,7 +12,6 @@ declare const _default: import("../../action.js").ActionDefinition<{
11
12
  supportsGroupShares?: boolean;
12
13
  };
13
14
  orgId?: undefined;
14
- role?: undefined;
15
15
  agentReadable?: undefined;
16
16
  } | {
17
17
  ownerEmail: string;
@@ -0,0 +1,160 @@
1
+ ---
2
+ title: "Create an App with an AI Agent"
3
+ description: "Hand one prompt to Claude, ChatGPT, Codex, Cursor, or another AI agent and have it create and start a new Agent-Native app for you."
4
+ ---
5
+
6
+ # Create an App with an AI Agent
7
+
8
+ You can ask an AI agent to create your Agent-Native app. You paste one prompt, the agent runs the setup commands, and it shows you a running app when it is done.
9
+
10
+ If you would rather type the commands yourself, follow [Getting Started](/docs/getting-started) instead.
11
+
12
+ ## Before you start
13
+
14
+ - An AI agent that can run terminal commands, such as Claude Code, Codex, or Cursor. Agents that only chat, such as ChatGPT or Claude on the web, can still help. See [Agents that can't run commands](#chat-only-agents).
15
+ - [Node.js](https://nodejs.org) 22.22 or later.
16
+ - An empty folder where the new app can live.
17
+
18
+ You don't need an API key to create the app. You only need one when you want the app's own agent to answer you. See [Connect an LLM](/docs/getting-started#connect-an-llm).
19
+
20
+ ## Paste this prompt
21
+
22
+ Open your agent in the empty folder and paste the prompt below. Change `my-app` in the first line to the name you want. You only need to change it once.
23
+
24
+ ```markdown
25
+ Create a new Agent-Native app in a new folder named my-app, and start
26
+ it. Use that name wherever a step below says APP_NAME.
27
+
28
+ 1. Check that Node.js is version 22.22 or later and that pnpm is
29
+ available. If pnpm is missing, run `corepack enable`. If corepack
30
+ is not available either, run `npm install -g pnpm`. If Node.js is
31
+ too old, stop and tell me instead of installing it.
32
+ 2. Run this command:
33
+ npx --yes @agent-native/core@latest create APP_NAME \
34
+ --standalone --template chat
35
+ 3. In the new APP_NAME folder, run `pnpm install`.
36
+ 4. Read APP_NAME/AGENTS.md so you know how the app is laid out.
37
+ 5. Start the app with `pnpm dev` and keep it running in the background.
38
+ 6. Read the local URL that `pnpm dev` prints. Check that it responds,
39
+ for example with `curl -I <url>`. Do not open a browser and do not
40
+ use headless browser tools. I will open the app myself.
41
+ 7. Show me the result. Give me the local URL and the response you got
42
+ from it. Do not just say that setup is complete.
43
+
44
+ Rules:
45
+
46
+ - Do not invent or ask me to paste API keys. Connecting an LLM is
47
+ optional and I will do it myself.
48
+ - Do not print secrets from any .env file.
49
+ - If a command fails, show me the error and what you tried. Do not hide
50
+ it.
51
+ ```
52
+
53
+ ## What the agent should do
54
+
55
+ A good run ends with these results, and you can check each one yourself:
56
+
57
+ - A new app folder, named `my-app` unless you changed it, that contains `actions/`, `app/`, and an `AGENTS.md` file.
58
+ - `pnpm dev` running without errors.
59
+ - A local URL, usually `http://localhost:8080`, that the agent has checked responds.
60
+
61
+ Then open the local URL in your own browser. On the Welcome screen, choose **Continue as local dev**. The Get started page appears.
62
+
63
+ If anything is missing, ask the agent to show the last command it ran and its output.
64
+
65
+ <Callout tone="info">
66
+
67
+ If the commands fail with peer dependency errors, an old copy of a package in the npx cache may be the cause. Ask the agent to run `npx clear-npx-cache` and try again.
68
+
69
+ </Callout>
70
+
71
+ ## Pick the right setup for your agent
72
+
73
+ | Agent type | Examples | How it works |
74
+ | ----------------------- | ----------------------------------------------------- | ------------------------------------------------------- |
75
+ | Terminal and IDE agents | Claude Code, Codex, Cursor, GitHub Copilot in VS Code | Paste the prompt. The agent runs every command for you. |
76
+ | Chat-only agents | ChatGPT, Claude on the web | Ask for the commands, then run them yourself. |
77
+
78
+ ### Agents that can't run commands {#chat-only-agents}
79
+
80
+ A chat-only agent can't open a terminal, so it can't create the app. Paste the prompt anyway and add this line at the top:
81
+
82
+ ```markdown
83
+ You can't run commands. Give me each command to run in my terminal,
84
+ one at a time, and wait for me to tell you what happened before moving
85
+ on.
86
+ ```
87
+
88
+ The agent walks you through the same steps and helps if something goes wrong.
89
+
90
+ ## Your agent and the app's agent
91
+
92
+ Two agents can work on your app, and they do different jobs.
93
+
94
+ - **Your own agent** is the one you pasted the prompt into, such as Claude Code, Codex, or Cursor. It lives outside the app, in your terminal or editor.
95
+ - **The app's agent** is the chat that comes built into the app. You open it in the browser while the app runs.
96
+
97
+ | | Your own agent (outside the app) | The app's agent (inside the app) |
98
+ | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
99
+ | Where you use it | Your terminal or editor | The app's chat in the browser |
100
+ | What it works on | Your project's files | The app's data and the screen you are looking at |
101
+ | What it can do | Create the project, install packages, run `pnpm dev`, write and change actions, pages, and database tables, and prepare a deploy | Call the app's actions as tools, read and update the app's data, and answer questions about what is on screen |
102
+ | Needs an LLM connected to the app | No, it uses its own model | Yes. See [Connect an LLM](/docs/getting-started#connect-an-llm) |
103
+ | Best for | Building and changing the app | Using the app and doing its everyday work |
104
+
105
+ Your own agent builds the app. The app's agent runs it. When your own agent adds an action, the app's agent can call that action right away because both use the same action.
106
+
107
+ ### Help your own agent build well
108
+
109
+ The generated app is set up so your own agent works well in it without extra instructions.
110
+
111
+ - `AGENTS.md` in the app root tells an agent how the app is laid out and which rules to follow.
112
+ - `.agents/skills/` holds short guides for common jobs, such as adding a feature or writing an action.
113
+ - Docs for your exact framework version are bundled with the app. An agent can search them with `pnpm action docs-search --query "<topic>"`.
114
+
115
+ When you ask for something new, you can tell your agent to read these first. For example: "Read AGENTS.md and the matching skill before you change anything."
116
+
117
+ To let your own agent use a running app's tools instead of its code, see [External Agents](/docs/external-agents).
118
+
119
+ ## Ask for your first change
120
+
121
+ With the app running, ask your agent for a small change and watch it work. Here are a few examples:
122
+
123
+ ```markdown
124
+ Add an action named list-notes that returns an empty list, then show
125
+ it on a new /notes page.
126
+ ```
127
+
128
+ ```markdown
129
+ Change the hello action so it greets people with "Welcome" instead of
130
+ "Hello", then call it for Alex to confirm.
131
+ ```
132
+
133
+ ```markdown
134
+ Read the docs for deploying an app, then tell me which steps I need to
135
+ take to put this app online.
136
+ ```
137
+
138
+ The agent changes the same actions that the UI and the app's own agent use. That shared action model is why one change shows up everywhere. [Key Concepts](/docs/key-concepts) explains how it fits together.
139
+
140
+ ## Next steps
141
+
142
+ <Cards>
143
+
144
+ ### [Getting Started](/docs/getting-started)
145
+
146
+ Create the same app by hand and learn how an action works.
147
+
148
+ ### [External Agents](/docs/external-agents)
149
+
150
+ Connect Claude, ChatGPT, Codex, or Cursor to an app that is already running.
151
+
152
+ ### [Actions](/docs/actions-overview)
153
+
154
+ Define the capabilities that both your UI and your agents use.
155
+
156
+ ### [Deploy an app](/docs/deploy-an-app)
157
+
158
+ Move from local development to a real database and a supported host.
159
+
160
+ </Cards>
@@ -15,6 +15,9 @@ the UI calls from code.
15
15
  In this guide, you'll create an agent with a chat UI and call its included
16
16
  `hello` action from the agent and the UI.
17
17
 
18
+ Prefer to have an AI agent do the setup? See
19
+ [Create an App with an AI Agent](/docs/create-with-an-agent).
20
+
18
21
  ## Prerequisites
19
22
 
20
23
  - [Node.js](https://nodejs.org) 22.22 or later
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.209.0",
3
+ "version": "0.209.1-nightly-20261015005848",
4
4
  "description": "The agentic application framework for building autonomous agents with intuitive UIs",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -704,7 +704,7 @@
704
704
  "yaml": "^2.9.0",
705
705
  "yjs": "^13.6.33",
706
706
  "zod": "^4.3.6",
707
- "@agent-native/agentkit": "^0.209.0",
707
+ "@agent-native/agentkit": "^0.209.1-nightly-20261015005848",
708
708
  "@agent-native/recap-cli": "^0.5.72"
709
709
  },
710
710
  "devDependencies": {
@@ -775,7 +775,7 @@
775
775
  "xlsx": "^0.18.5"
776
776
  },
777
777
  "peerDependencies": {
778
- "@agent-native/core-corpus": ">=0.196.0",
778
+ "@agent-native/core-corpus": "0.209.1-nightly-20261015005848",
779
779
  "@ai-sdk/anthropic": ">=3",
780
780
  "@ai-sdk/cohere": ">=3",
781
781
  "@ai-sdk/google": ">=3",