@agent-native/core 0.94.3 → 0.95.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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +16 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +13 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +18 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +17 -0
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +17 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +15 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +11 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +12 -0
- package/corpus/core/docs/content/pr-visual-recap.mdx +20 -12
- package/corpus/core/docs/content/template-design.mdx +16 -0
- package/corpus/core/package.json +2 -2
- package/corpus/core/src/agent/engine/ai-sdk-engine.ts +3 -0
- package/corpus/core/src/agent/engine/registry.ts +6 -1
- package/corpus/core/src/agent/engine/types.ts +2 -0
- package/corpus/core/src/agent/production-agent.ts +20 -0
- package/corpus/core/src/agent/thread-data-builder.ts +41 -17
- package/corpus/core/src/cli/code-agent-executor.ts +61 -1
- package/corpus/core/src/cli/pr-visual-recap-workflow.ts +1 -1
- package/corpus/core/src/cli/recap.ts +262 -25
- package/corpus/core/src/client/AssistantChat.tsx +250 -25
- package/corpus/core/src/client/chat/tool-call-display.tsx +1 -1
- package/corpus/core/src/client/chat/use-reconnect-reader-owner.ts +28 -0
- package/corpus/core/src/client/guided-questions.tsx +9 -1
- package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +6 -7
- package/corpus/core/src/client/settings/UsageSection.tsx +26 -5
- package/corpus/core/src/client/sse-event-processor.ts +90 -21
- package/corpus/core/src/connections/catalog.ts +2 -2
- package/corpus/core/src/deploy/build.ts +3 -0
- package/corpus/core/src/index.ts +2 -0
- package/corpus/core/src/integrations/catalog.ts +2 -2
- package/corpus/core/src/server/auth.ts +1 -1
- package/corpus/core/src/server/credential-provider.ts +7 -3
- package/corpus/core/src/shared/cache-control.ts +10 -4
- package/corpus/core/src/usage/store.ts +82 -20
- package/corpus/templates/analytics/app/lib/data-sources.ts +5 -4
- package/corpus/templates/analytics/changelog/2026-07-10-slack-token-setup-marked-legacy.md +6 -0
- package/corpus/templates/analytics/server/lib/credential-keys.ts +6 -2
- package/corpus/templates/brain/changelog/2026-07-10-slack-backfill-token-marked-legacy.md +6 -0
- package/corpus/templates/brain/server/register-secrets.ts +2 -2
- package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -1
- package/corpus/templates/clips/app/components/library/page-header.tsx +19 -3
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +16 -12
- package/corpus/templates/clips/changelog/2026-07-10-new-recording-appears-once-when-the-library-sidebar-is-open.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-slack-token-fallback-guidance.md +6 -0
- package/corpus/templates/clips/server/register-secrets.ts +1 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +0 -66
- package/corpus/templates/content/app/routes/_app.local-files.tsx +7 -47
- package/corpus/templates/content/changelog/2026-07-10-local-folders-now-wait-for-an-explicit-pull-before-content-r.md +6 -0
- package/corpus/templates/content/package.json +1 -1
- package/corpus/templates/design/actions/generate-design.ts +128 -31
- package/corpus/templates/design/actions/present-design-variants.ts +37 -9
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +9 -3
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +32 -10
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +2 -2
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +9 -1
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -5
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
- package/corpus/templates/design/app/global.css +10 -0
- package/corpus/templates/design/app/hooks/use-question-flow.ts +9 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/design/app/i18n-data.ts +21 -11
- package/corpus/templates/design/changelog/2026-07-10-editor-panels-are-easier-to-distinguish-and-design-intake-qu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-interact-mode-now-stays-on-the-full-canvas-matches-edit-visu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-new-web-designs-open-at-desktop-size-and-adapt-across-mobile.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-tweaks-now-link-to-full-documentation.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/mail/app/i18n/ar-SA.ts +3 -3
- package/corpus/templates/mail/app/i18n/de-DE.ts +3 -3
- package/corpus/templates/mail/app/i18n/en-US.ts +4 -3
- package/corpus/templates/mail/app/i18n/es-ES.ts +3 -3
- package/corpus/templates/mail/app/i18n/fr-FR.ts +3 -3
- package/corpus/templates/mail/app/i18n/hi-IN.ts +3 -3
- package/corpus/templates/mail/app/i18n/ja-JP.ts +3 -3
- package/corpus/templates/mail/app/i18n/ko-KR.ts +3 -3
- package/corpus/templates/mail/app/i18n/pt-BR.ts +3 -3
- package/corpus/templates/mail/app/i18n/zh-CN.ts +3 -3
- package/corpus/templates/mail/app/i18n/zh-TW.ts +3 -3
- package/corpus/templates/mail/changelog/2026-07-10-slack-intake-marked-legacy.md +6 -0
- package/corpus/templates/mail/server/lib/env-config.ts +5 -4
- package/corpus/templates/plan/actions/record-recap-usage-cost.ts +49 -0
- package/corpus/templates/plan/actions/record-recap-usage.ts +15 -22
- package/corpus/templates/plan/package.json +1 -1
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +3 -0
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/registry.d.ts +1 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +2 -0
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/engine/types.d.ts +2 -0
- package/dist/agent/engine/types.d.ts.map +1 -1
- package/dist/agent/engine/types.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +20 -0
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +36 -18
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/cli/code-agent-executor.d.ts +2 -0
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +52 -3
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +1 -1
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts +22 -2
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +199 -22
- package/dist/cli/recap.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +3 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +200 -28
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/chat/tool-call-display.js +1 -1
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/use-reconnect-reader-owner.d.ts +11 -0
- package/dist/client/chat/use-reconnect-reader-owner.d.ts.map +1 -0
- package/dist/client/chat/use-reconnect-reader-owner.js +21 -0
- package/dist/client/chat/use-reconnect-reader-owner.js.map +1 -0
- package/dist/client/guided-questions.d.ts.map +1 -1
- package/dist/client/guided-questions.js +5 -1
- package/dist/client/guided-questions.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +5 -7
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/settings/UsageSection.d.ts.map +1 -1
- package/dist/client/settings/UsageSection.js +12 -3
- package/dist/client/settings/UsageSection.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +67 -20
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +2 -2
- package/dist/connections/catalog.js +2 -2
- package/dist/connections/catalog.js.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +3 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/catalog.js +2 -2
- package/dist/integrations/catalog.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +1 -1
- package/dist/server/auth.js.map +1 -1
- package/dist/server/credential-provider.d.ts +5 -3
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +7 -3
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/shared/cache-control.d.ts +8 -6
- package/dist/shared/cache-control.d.ts.map +1 -1
- package/dist/shared/cache-control.js +8 -3
- package/dist/shared/cache-control.js.map +1 -1
- package/dist/usage/store.d.ts +21 -0
- package/dist/usage/store.d.ts.map +1 -1
- package/dist/usage/store.js +54 -19
- package/dist/usage/store.js.map +1 -1
- package/docs/content/locales/ar-SA/template-design.mdx +13 -0
- package/docs/content/locales/de-DE/template-design.mdx +18 -0
- package/docs/content/locales/es-ES/template-design.mdx +16 -0
- package/docs/content/locales/fr-FR/template-design.mdx +17 -0
- package/docs/content/locales/hi-IN/template-design.mdx +16 -0
- package/docs/content/locales/ja-JP/template-design.mdx +17 -0
- package/docs/content/locales/ko-KR/template-design.mdx +15 -0
- package/docs/content/locales/pt-BR/template-design.mdx +16 -0
- package/docs/content/locales/zh-CN/template-design.mdx +11 -0
- package/docs/content/locales/zh-TW/template-design.mdx +12 -0
- package/docs/content/pr-visual-recap.mdx +20 -12
- package/docs/content/template-design.mdx +16 -0
- package/package.json +2 -2
|
@@ -231,12 +231,6 @@ export type PreparingActionState = {
|
|
|
231
231
|
toolEntries?: Map<string, PreparingActionEntry>;
|
|
232
232
|
};
|
|
233
233
|
|
|
234
|
-
function formatProgressBytes(bytes: number): string {
|
|
235
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
236
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
237
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
234
|
function activityProgressBytes(ev: SSEEvent): number | undefined {
|
|
241
235
|
return typeof ev.progressBytes === "number" &&
|
|
242
236
|
Number.isFinite(ev.progressBytes) &&
|
|
@@ -281,7 +275,7 @@ function preparationActivityLabel(
|
|
|
281
275
|
if (progressBytes <= 0) {
|
|
282
276
|
return `Preparing ${action}...`;
|
|
283
277
|
}
|
|
284
|
-
return `Writing ${action}
|
|
278
|
+
return `Writing ${action}...`;
|
|
285
279
|
}
|
|
286
280
|
|
|
287
281
|
function visibleActivityLabel(ev: SSEEvent, tool?: string): string {
|
|
@@ -301,16 +295,8 @@ function findPendingToolCallIndex(
|
|
|
301
295
|
// calls can be in flight simultaneously, and name-only matching would
|
|
302
296
|
// attach a result to the wrong call.
|
|
303
297
|
if (toolCallId) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (
|
|
307
|
-
part.type === "tool-call" &&
|
|
308
|
-
part.toolCallId === toolCallId &&
|
|
309
|
-
part.result === undefined
|
|
310
|
-
) {
|
|
311
|
-
return i;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
298
|
+
const exactIndex = findPendingToolCallIndexById(content, toolCallId);
|
|
299
|
+
if (exactIndex >= 0) return exactIndex;
|
|
314
300
|
// Fall through to name-matching: the start event may have arrived before
|
|
315
301
|
// the server started emitting ids (e.g. older server build), so the
|
|
316
302
|
// stored toolCallId is the locally-generated "tc_N" value rather than the
|
|
@@ -329,6 +315,76 @@ function findPendingToolCallIndex(
|
|
|
329
315
|
return -1;
|
|
330
316
|
}
|
|
331
317
|
|
|
318
|
+
function findPendingToolCallIndexById(
|
|
319
|
+
content: ContentPart[],
|
|
320
|
+
toolCallId: string,
|
|
321
|
+
): number {
|
|
322
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
323
|
+
const part = content[i];
|
|
324
|
+
if (
|
|
325
|
+
part.type === "tool-call" &&
|
|
326
|
+
part.toolCallId === toolCallId &&
|
|
327
|
+
part.result === undefined
|
|
328
|
+
) {
|
|
329
|
+
return i;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return -1;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function findOldestPendingActivityToolCallIndex(
|
|
336
|
+
content: ContentPart[],
|
|
337
|
+
toolName: string,
|
|
338
|
+
): number {
|
|
339
|
+
for (let i = 0; i < content.length; i += 1) {
|
|
340
|
+
const part = content[i];
|
|
341
|
+
if (
|
|
342
|
+
part.type === "tool-call" &&
|
|
343
|
+
part.toolName === toolName &&
|
|
344
|
+
part.activity === true &&
|
|
345
|
+
part.result === undefined
|
|
346
|
+
) {
|
|
347
|
+
return i;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return -1;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function findPendingActivityToolCallIndex(
|
|
354
|
+
content: ContentPart[],
|
|
355
|
+
toolName: string,
|
|
356
|
+
toolCallId?: string,
|
|
357
|
+
): number {
|
|
358
|
+
if (!toolCallId) {
|
|
359
|
+
return findPendingToolCallIndex(content, toolName);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Activity events emitted while the model is assembling tool input already
|
|
363
|
+
// carry the engine's stable call id. Match that id exactly so repeated
|
|
364
|
+
// progress for one call updates one placeholder while parallel same-name
|
|
365
|
+
// calls retain separate cards.
|
|
366
|
+
const exactIndex = findPendingToolCallIndexById(content, toolCallId);
|
|
367
|
+
if (exactIndex >= 0) return exactIndex;
|
|
368
|
+
|
|
369
|
+
// Older activity events may omit the id before a later progress event adds
|
|
370
|
+
// it. Upgrade one unambiguous reader-local placeholder instead of painting a
|
|
371
|
+
// second card for the same logical call.
|
|
372
|
+
const readerLocalCandidates: number[] = [];
|
|
373
|
+
for (let i = 0; i < content.length; i += 1) {
|
|
374
|
+
const part = content[i];
|
|
375
|
+
if (
|
|
376
|
+
part.type === "tool-call" &&
|
|
377
|
+
part.toolName === toolName &&
|
|
378
|
+
part.activity === true &&
|
|
379
|
+
part.result === undefined &&
|
|
380
|
+
/^tc_\d+$/.test(part.toolCallId)
|
|
381
|
+
) {
|
|
382
|
+
readerLocalCandidates.push(i);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return readerLocalCandidates.length === 1 ? readerLocalCandidates[0] : -1;
|
|
386
|
+
}
|
|
387
|
+
|
|
332
388
|
function findCompletedToolCallIndex(
|
|
333
389
|
content: ContentPart[],
|
|
334
390
|
toolCallId?: string,
|
|
@@ -1000,7 +1056,17 @@ export function processEvent(
|
|
|
1000
1056
|
}
|
|
1001
1057
|
if (!tool) return { action: "continue" };
|
|
1002
1058
|
|
|
1003
|
-
const pendingToolCallIndex =
|
|
1059
|
+
const pendingToolCallIndex = findPendingActivityToolCallIndex(
|
|
1060
|
+
content,
|
|
1061
|
+
tool,
|
|
1062
|
+
ev.id,
|
|
1063
|
+
);
|
|
1064
|
+
if (pendingToolCallIndex >= 0 && ev.id) {
|
|
1065
|
+
const pending = content[pendingToolCallIndex];
|
|
1066
|
+
if (pending?.type === "tool-call" && pending.toolCallId !== ev.id) {
|
|
1067
|
+
content[pendingToolCallIndex] = { ...pending, toolCallId: ev.id };
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1004
1070
|
if (pendingToolCallIndex === -1) {
|
|
1005
1071
|
// Only surface a placeholder spinner when this tool has no card yet. A
|
|
1006
1072
|
// trailing activity heartbeat that arrives after the matching tool_done
|
|
@@ -1011,12 +1077,13 @@ export function processEvent(
|
|
|
1011
1077
|
(part) =>
|
|
1012
1078
|
part.type === "tool-call" &&
|
|
1013
1079
|
part.toolName === tool &&
|
|
1014
|
-
part.result !== undefined
|
|
1080
|
+
part.result !== undefined &&
|
|
1081
|
+
(!ev.id || part.toolCallId === ev.id),
|
|
1015
1082
|
);
|
|
1016
1083
|
if (!hasCompletedSameTool) {
|
|
1017
1084
|
content.push({
|
|
1018
1085
|
type: "tool-call",
|
|
1019
|
-
toolCallId: `tc_${++toolCallCounter.value}`,
|
|
1086
|
+
toolCallId: ev.id ?? `tc_${++toolCallCounter.value}`,
|
|
1020
1087
|
toolName: tool,
|
|
1021
1088
|
argsText: "",
|
|
1022
1089
|
args: {},
|
|
@@ -1054,7 +1121,9 @@ export function processEvent(
|
|
|
1054
1121
|
}
|
|
1055
1122
|
// Pass the server-assigned id so we upgrade the pending activity card
|
|
1056
1123
|
// using id-match when available (parallel same-name calls stay separate).
|
|
1057
|
-
const pendingToolCallIndex =
|
|
1124
|
+
const pendingToolCallIndex = ev.id
|
|
1125
|
+
? findPendingActivityToolCallIndex(content, tool, ev.id)
|
|
1126
|
+
: findOldestPendingActivityToolCallIndex(content, tool);
|
|
1058
1127
|
const pendingToolCall =
|
|
1059
1128
|
pendingToolCallIndex >= 0 ? content[pendingToolCallIndex] : undefined;
|
|
1060
1129
|
const pendingIsActivityPlaceholder =
|
|
@@ -66,9 +66,9 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
|
|
|
66
66
|
credentialKeys: [
|
|
67
67
|
{
|
|
68
68
|
key: "SLACK_BOT_TOKEN",
|
|
69
|
-
label: "Slack bot token",
|
|
69
|
+
label: "Slack bot token (legacy)",
|
|
70
70
|
description:
|
|
71
|
-
"
|
|
71
|
+
"Legacy single-workspace fallback. For new messaging automations, connect Slack from Settings → Messaging instead.",
|
|
72
72
|
required: true,
|
|
73
73
|
},
|
|
74
74
|
],
|
|
@@ -32,6 +32,7 @@ import { normalizeAppBasePath } from "../server/app-base-path.js";
|
|
|
32
32
|
import {
|
|
33
33
|
DEFAULT_SSR_CDN_CACHE_CONTROL,
|
|
34
34
|
DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL,
|
|
35
|
+
DEFAULT_SSR_NETLIFY_VARY,
|
|
35
36
|
DEFAULT_SPECULATION_RULES_PATH,
|
|
36
37
|
DEFAULT_SSR_CACHE_CONTROL,
|
|
37
38
|
} from "../shared/cache-control.js";
|
|
@@ -908,6 +909,7 @@ function injectHeadScript(html, script) {
|
|
|
908
909
|
const DEFAULT_SSR_CACHE_CONTROL = ${JSON.stringify(DEFAULT_SSR_CACHE_CONTROL)};
|
|
909
910
|
const DEFAULT_SSR_CDN_CACHE_CONTROL = ${JSON.stringify(DEFAULT_SSR_CDN_CACHE_CONTROL)};
|
|
910
911
|
const DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL = ${JSON.stringify(DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL)};
|
|
912
|
+
const DEFAULT_SSR_NETLIFY_VARY = ${JSON.stringify(DEFAULT_SSR_NETLIFY_VARY)};
|
|
911
913
|
const DEFAULT_SPECULATION_RULES_PATH = ${JSON.stringify(DEFAULT_SPECULATION_RULES_PATH)};
|
|
912
914
|
const IMMUTABLE_ASSET_CACHE_CONTROL = ${JSON.stringify(IMMUTABLE_ASSET_CACHE_CONTROL)};
|
|
913
915
|
const IMMUTABLE_ASSET_PATHS = new Set(${JSON.stringify(
|
|
@@ -1003,6 +1005,7 @@ function applyDefaultSsrCacheHeader(headers, status, pathname) {
|
|
|
1003
1005
|
// Netlify-specific header so SSR HTML/.data are served from the shared
|
|
1004
1006
|
// durable CDN cache instead of stampeding origin — for every visitor.
|
|
1005
1007
|
headers.set("netlify-cdn-cache-control", DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL);
|
|
1008
|
+
headers.set("netlify-vary", DEFAULT_SSR_NETLIFY_VARY);
|
|
1006
1009
|
}
|
|
1007
1010
|
|
|
1008
1011
|
function applyDefaultSpeculationRulesHeader(headers, status, basePath) {
|
package/corpus/core/src/index.ts
CHANGED
|
@@ -137,10 +137,10 @@ const BUILT_IN_CHANNEL_CATALOG = [
|
|
|
137
137
|
credentialRequirements: [
|
|
138
138
|
{
|
|
139
139
|
key: "SLACK_BOT_TOKEN",
|
|
140
|
-
label: "Slack Bot Token",
|
|
140
|
+
label: "Slack Bot Token (legacy)",
|
|
141
141
|
required: false,
|
|
142
142
|
helpText:
|
|
143
|
-
"
|
|
143
|
+
"Legacy single-workspace fallback only. For new setups, install Slack from Settings → Messaging; managed OAuth stores each workspace token automatically.",
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
146
|
key: "SLACK_CLIENT_ID",
|
|
@@ -1627,7 +1627,7 @@ function loginHtmlResponse(loginHtml: string, event: H3Event): Response {
|
|
|
1627
1627
|
headers: {
|
|
1628
1628
|
"Content-Type": "text/html; charset=utf-8",
|
|
1629
1629
|
// The sign-in document is part of the public server shell. Keep it on the
|
|
1630
|
-
// same
|
|
1630
|
+
// same long-fresh/long-SWR CDN policy as React Router SSR so hosted
|
|
1631
1631
|
// template roots do not invoke origin just to render anonymous login UI.
|
|
1632
1632
|
// The login HTML is env-INDEPENDENT (a Google-only app always renders a
|
|
1633
1633
|
// working button), so a cached copy is never "wrong" — never downgrade
|
|
@@ -78,6 +78,8 @@ const APP_PROVIDED_DEPLOY_CREDENTIAL_KEYS = new Set([
|
|
|
78
78
|
"OPENAI_API_KEY",
|
|
79
79
|
"OPENAI_BASE_URL",
|
|
80
80
|
"OPENROUTER_API_KEY",
|
|
81
|
+
"GOOGLE_CLIENT_ID",
|
|
82
|
+
"GOOGLE_CLIENT_SECRET",
|
|
81
83
|
"GOOGLE_GENERATIVE_AI_API_KEY",
|
|
82
84
|
"GROQ_API_KEY",
|
|
83
85
|
"MISTRAL_API_KEY",
|
|
@@ -93,9 +95,11 @@ function isAppProvidedDeployCredentialKey(key: string | undefined): boolean {
|
|
|
93
95
|
* single-tenant contexts. In hosted production with a shared database, every
|
|
94
96
|
* signed-in user needs their own user/org/workspace credential for
|
|
95
97
|
* identity-bearing provider keys so one deploy key does not silently
|
|
96
|
-
* impersonate another tenant. App-provided
|
|
97
|
-
* they
|
|
98
|
-
* that
|
|
98
|
+
* impersonate another tenant. App-provided service credentials are different:
|
|
99
|
+
* they configure the deployed app itself rather than identifying a user. This
|
|
100
|
+
* includes LLM keys that let the app developer pay for model usage and OAuth
|
|
101
|
+
* client credentials whose per-user identity remains in scoped OAuth tokens.
|
|
102
|
+
* Key-aware callers may use those env vars.
|
|
99
103
|
*
|
|
100
104
|
* @deprecated Use `canUseDeployCredentialFallbackForRequest()` for generic
|
|
101
105
|
* provider secrets. This stricter helper remains for legacy call sites with
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
export const DEFAULT_SSR_CACHE_CONTROL =
|
|
2
|
-
"public, max-age=5, stale-while-revalidate=604800, stale-if-error=3600";
|
|
1
|
+
export const DEFAULT_SSR_CACHE_CONTROL = "public, max-age=0, must-revalidate";
|
|
3
2
|
|
|
4
|
-
export const DEFAULT_SSR_CDN_CACHE_CONTROL =
|
|
3
|
+
export const DEFAULT_SSR_CDN_CACHE_CONTROL =
|
|
4
|
+
"public, s-maxage=3600, stale-while-revalidate=604800, stale-if-error=3600";
|
|
5
5
|
|
|
6
6
|
export const DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL =
|
|
7
|
-
"public, durable,
|
|
7
|
+
"public, durable, s-maxage=3600, stale-while-revalidate=604800, stale-if-error=3600";
|
|
8
|
+
|
|
9
|
+
// React Router data requests can select a subset of route loaders with
|
|
10
|
+
// `?_routes=...`. Ignore every other query parameter (UTM tags, click ids,
|
|
11
|
+
// and similar tracking noise) so they cannot fragment Netlify's SSR cache.
|
|
12
|
+
export const DEFAULT_SSR_NETLIFY_VARY = "query=_routes";
|
|
8
13
|
|
|
9
14
|
export const DEFAULT_SSR_CACHE_HEADERS = {
|
|
10
15
|
"cache-control": DEFAULT_SSR_CACHE_CONTROL,
|
|
11
16
|
"cdn-cache-control": DEFAULT_SSR_CDN_CACHE_CONTROL,
|
|
12
17
|
"netlify-cdn-cache-control": DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL,
|
|
18
|
+
"netlify-vary": DEFAULT_SSR_NETLIFY_VARY,
|
|
13
19
|
} as const;
|
|
14
20
|
|
|
15
21
|
export const DEFAULT_SPECULATION_RULES_PATH =
|
|
@@ -197,6 +197,8 @@ export interface UsageRecord {
|
|
|
197
197
|
* provider-reported dollar cost so two surfaces agree exactly.
|
|
198
198
|
*/
|
|
199
199
|
costCentsX100?: number;
|
|
200
|
+
/** Whether cost is provider-reported, estimated, or unavailable. */
|
|
201
|
+
costSource?: UsageCostSource;
|
|
200
202
|
orgId?: string;
|
|
201
203
|
runId?: string;
|
|
202
204
|
threadId?: string;
|
|
@@ -206,6 +208,8 @@ export interface UsageRecord {
|
|
|
206
208
|
sourceId?: string;
|
|
207
209
|
}
|
|
208
210
|
|
|
211
|
+
export type UsageCostSource = "reported" | "estimated" | "unavailable";
|
|
212
|
+
|
|
209
213
|
let _initPromise: Promise<void> | undefined;
|
|
210
214
|
|
|
211
215
|
async function ensureUsageTable(): Promise<void> {
|
|
@@ -221,6 +225,7 @@ async function ensureUsageTable(): Promise<void> {
|
|
|
221
225
|
cache_read_tokens ${intType()} NOT NULL DEFAULT 0,
|
|
222
226
|
cache_write_tokens ${intType()} NOT NULL DEFAULT 0,
|
|
223
227
|
cost_cents_x100 ${intType()} NOT NULL DEFAULT 0,
|
|
228
|
+
cost_source TEXT NOT NULL DEFAULT 'estimated',
|
|
224
229
|
model TEXT NOT NULL DEFAULT '',
|
|
225
230
|
label TEXT NOT NULL DEFAULT 'chat',
|
|
226
231
|
app TEXT NOT NULL DEFAULT '',
|
|
@@ -240,6 +245,7 @@ async function ensureUsageTable(): Promise<void> {
|
|
|
240
245
|
const additions: Array<[string, string]> = [
|
|
241
246
|
["cache_read_tokens", `${intType()} NOT NULL DEFAULT 0`],
|
|
242
247
|
["cache_write_tokens", `${intType()} NOT NULL DEFAULT 0`],
|
|
248
|
+
["cost_source", `TEXT NOT NULL DEFAULT 'estimated'`],
|
|
243
249
|
["label", `TEXT NOT NULL DEFAULT 'chat'`],
|
|
244
250
|
["app", `TEXT NOT NULL DEFAULT ''`],
|
|
245
251
|
["ref_id", `TEXT NOT NULL DEFAULT ''`],
|
|
@@ -379,6 +385,7 @@ export async function recordUsage(
|
|
|
379
385
|
app,
|
|
380
386
|
refId,
|
|
381
387
|
costCentsX100,
|
|
388
|
+
costSource,
|
|
382
389
|
orgId,
|
|
383
390
|
runId,
|
|
384
391
|
threadId,
|
|
@@ -410,14 +417,24 @@ export async function recordUsage(
|
|
|
410
417
|
|
|
411
418
|
// Prefer an explicit precomputed cost (e.g. a provider-reported dollar cost);
|
|
412
419
|
// otherwise derive it from tokens via the pricing table.
|
|
420
|
+
const resolvedCostSource =
|
|
421
|
+
costSource ?? (costCentsX100 == null ? "estimated" : "reported");
|
|
413
422
|
const costX100 =
|
|
414
|
-
|
|
415
|
-
|
|
423
|
+
resolvedCostSource === "unavailable"
|
|
424
|
+
? 0
|
|
425
|
+
: (costCentsX100 ??
|
|
426
|
+
calculateCost(
|
|
427
|
+
inTok,
|
|
428
|
+
outTok,
|
|
429
|
+
modelName,
|
|
430
|
+
cacheReadTokens,
|
|
431
|
+
cacheWriteTokens,
|
|
432
|
+
));
|
|
416
433
|
const id = Date.now() * 1000 + Math.floor(Math.random() * 1000);
|
|
417
434
|
await client.execute({
|
|
418
435
|
sql: `INSERT INTO token_usage
|
|
419
|
-
(id, owner_email, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost_cents_x100, model, label, app, ref_id, org_id, run_id, thread_id, task_id, integration_scope_id, source_platform, source_id, created_at)
|
|
420
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
436
|
+
(id, owner_email, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost_cents_x100, cost_source, model, label, app, ref_id, org_id, run_id, thread_id, task_id, integration_scope_id, source_platform, source_id, created_at)
|
|
437
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
421
438
|
args: [
|
|
422
439
|
id,
|
|
423
440
|
ownerEmail,
|
|
@@ -426,6 +443,7 @@ export async function recordUsage(
|
|
|
426
443
|
cacheReadTokens,
|
|
427
444
|
cacheWriteTokens,
|
|
428
445
|
costX100,
|
|
446
|
+
resolvedCostSource,
|
|
429
447
|
modelName,
|
|
430
448
|
resolvedLabel,
|
|
431
449
|
resolvedApp,
|
|
@@ -469,6 +487,7 @@ export interface UsageBucket {
|
|
|
469
487
|
cacheReadTokens: number;
|
|
470
488
|
cacheWriteTokens: number;
|
|
471
489
|
cents: number;
|
|
490
|
+
cost: UsageCostAggregate;
|
|
472
491
|
calls: number;
|
|
473
492
|
}
|
|
474
493
|
|
|
@@ -476,9 +495,15 @@ export interface DailyBucket {
|
|
|
476
495
|
/** YYYY-MM-DD (UTC) */
|
|
477
496
|
date: string;
|
|
478
497
|
cents: number;
|
|
498
|
+
cost: UsageCostAggregate;
|
|
479
499
|
calls: number;
|
|
480
500
|
}
|
|
481
501
|
|
|
502
|
+
export type UsageCostAggregate =
|
|
503
|
+
| { status: "known"; knownCents: number; unavailableCalls: 0 }
|
|
504
|
+
| { status: "partial"; knownCents: number; unavailableCalls: number }
|
|
505
|
+
| { status: "unavailable"; knownCents: 0; unavailableCalls: number };
|
|
506
|
+
|
|
482
507
|
export interface UsageRecentEntry {
|
|
483
508
|
id: number;
|
|
484
509
|
createdAt: number;
|
|
@@ -490,11 +515,14 @@ export interface UsageRecentEntry {
|
|
|
490
515
|
cacheReadTokens: number;
|
|
491
516
|
cacheWriteTokens: number;
|
|
492
517
|
cents: number;
|
|
518
|
+
costSource: UsageCostSource;
|
|
493
519
|
}
|
|
494
520
|
|
|
495
521
|
export interface UsageSummary {
|
|
496
522
|
billing?: UsageBillingMode;
|
|
523
|
+
/** Legacy known-cost subtotal. Use totalCost to preserve unavailable spend. */
|
|
497
524
|
totalCents: number;
|
|
525
|
+
totalCost: UsageCostAggregate;
|
|
498
526
|
totalCalls: number;
|
|
499
527
|
totalInputTokens: number;
|
|
500
528
|
totalOutputTokens: number;
|
|
@@ -523,7 +551,8 @@ export async function getUsageSummary(
|
|
|
523
551
|
|
|
524
552
|
const totalRow = await client.execute({
|
|
525
553
|
sql: `SELECT
|
|
526
|
-
COALESCE(SUM(cost_cents_x100), 0) AS
|
|
554
|
+
COALESCE(SUM(CASE WHEN cost_source = 'unavailable' THEN 0 ELSE cost_cents_x100 END), 0) AS known_cents,
|
|
555
|
+
COALESCE(SUM(CASE WHEN cost_source = 'unavailable' THEN 1 ELSE 0 END), 0) AS unavailable_calls,
|
|
527
556
|
COUNT(*) AS calls,
|
|
528
557
|
COALESCE(SUM(input_tokens), 0) AS in_tok,
|
|
529
558
|
COALESCE(SUM(output_tokens), 0) AS out_tok,
|
|
@@ -536,7 +565,8 @@ export async function getUsageSummary(
|
|
|
536
565
|
|
|
537
566
|
const bucketSql = (col: string) => ({
|
|
538
567
|
sql: `SELECT ${col} AS k,
|
|
539
|
-
COALESCE(SUM(cost_cents_x100), 0) AS
|
|
568
|
+
COALESCE(SUM(CASE WHEN cost_source = 'unavailable' THEN 0 ELSE cost_cents_x100 END), 0) AS known_cents,
|
|
569
|
+
COALESCE(SUM(CASE WHEN cost_source = 'unavailable' THEN 1 ELSE 0 END), 0) AS unavailable_calls,
|
|
540
570
|
COUNT(*) AS calls,
|
|
541
571
|
COALESCE(SUM(input_tokens), 0) AS in_tok,
|
|
542
572
|
COALESCE(SUM(output_tokens), 0) AS out_tok,
|
|
@@ -545,16 +575,19 @@ export async function getUsageSummary(
|
|
|
545
575
|
FROM token_usage
|
|
546
576
|
WHERE owner_email = ? AND created_at >= ?
|
|
547
577
|
GROUP BY ${col}
|
|
548
|
-
ORDER BY
|
|
578
|
+
ORDER BY known_cents DESC`,
|
|
549
579
|
args: [options.ownerEmail, sinceMs],
|
|
550
580
|
});
|
|
551
581
|
|
|
552
582
|
const mapBuckets = (rows: unknown[]): UsageBucket[] =>
|
|
553
583
|
rows.map((r) => {
|
|
554
584
|
const row = r as Record<string, number | string | null>;
|
|
585
|
+
const knownCents = Number(row.known_cents ?? 0) / 100;
|
|
586
|
+
const unavailableCalls = Number(row.unavailable_calls ?? 0);
|
|
555
587
|
return {
|
|
556
588
|
key: String(row.k ?? ""),
|
|
557
|
-
cents:
|
|
589
|
+
cents: knownCents,
|
|
590
|
+
cost: buildUsageCostAggregate(knownCents, unavailableCalls),
|
|
558
591
|
calls: Number(row.calls ?? 0),
|
|
559
592
|
inputTokens: Number(row.in_tok ?? 0),
|
|
560
593
|
outputTokens: Number(row.out_tok ?? 0),
|
|
@@ -573,30 +606,42 @@ export async function getUsageSummary(
|
|
|
573
606
|
// date functions (SQLite `strftime`, Postgres `to_char`). Cheap enough
|
|
574
607
|
// for a 30-day window; if this grows, swap for a dialect-aware query.
|
|
575
608
|
const dayRows = await client.execute({
|
|
576
|
-
sql: `SELECT created_at, cost_cents_x100 FROM token_usage
|
|
609
|
+
sql: `SELECT created_at, cost_cents_x100, cost_source FROM token_usage
|
|
577
610
|
WHERE owner_email = ? AND created_at >= ?`,
|
|
578
611
|
args: [options.ownerEmail, sinceMs],
|
|
579
612
|
});
|
|
580
|
-
const dayMap = new Map<
|
|
581
|
-
|
|
613
|
+
const dayMap = new Map<
|
|
614
|
+
string,
|
|
615
|
+
{ knownCentsX100: number; unavailableCalls: number; calls: number }
|
|
616
|
+
>();
|
|
617
|
+
for (const row of dayRows.rows as Array<Record<string, number | string>>) {
|
|
582
618
|
const date = new Date(Number(row.created_at)).toISOString().slice(0, 10);
|
|
583
|
-
const prev = dayMap.get(date) ?? {
|
|
584
|
-
|
|
619
|
+
const prev = dayMap.get(date) ?? {
|
|
620
|
+
knownCentsX100: 0,
|
|
621
|
+
unavailableCalls: 0,
|
|
622
|
+
calls: 0,
|
|
623
|
+
};
|
|
624
|
+
if (row.cost_source === "unavailable") prev.unavailableCalls += 1;
|
|
625
|
+
else prev.knownCentsX100 += Number(row.cost_cents_x100 ?? 0);
|
|
585
626
|
prev.calls += 1;
|
|
586
627
|
dayMap.set(date, prev);
|
|
587
628
|
}
|
|
588
629
|
const byDay: DailyBucket[] = [...dayMap.entries()]
|
|
589
|
-
.map(([date, v]) =>
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
630
|
+
.map(([date, v]) => {
|
|
631
|
+
const knownCents = v.knownCentsX100 / 100;
|
|
632
|
+
return {
|
|
633
|
+
date,
|
|
634
|
+
cents: knownCents,
|
|
635
|
+
cost: buildUsageCostAggregate(knownCents, v.unavailableCalls),
|
|
636
|
+
calls: v.calls,
|
|
637
|
+
};
|
|
638
|
+
})
|
|
594
639
|
.sort((a, b) => a.date.localeCompare(b.date));
|
|
595
640
|
|
|
596
641
|
const recentRows = await client.execute({
|
|
597
642
|
sql: `SELECT id, created_at, label, app, model,
|
|
598
643
|
input_tokens, output_tokens, cache_read_tokens, cache_write_tokens,
|
|
599
|
-
cost_cents_x100
|
|
644
|
+
cost_cents_x100, cost_source
|
|
600
645
|
FROM token_usage
|
|
601
646
|
WHERE owner_email = ?
|
|
602
647
|
ORDER BY created_at DESC
|
|
@@ -616,11 +661,15 @@ export async function getUsageSummary(
|
|
|
616
661
|
cacheReadTokens: Number(row.cache_read_tokens ?? 0),
|
|
617
662
|
cacheWriteTokens: Number(row.cache_write_tokens ?? 0),
|
|
618
663
|
cents: Number(row.cost_cents_x100 ?? 0) / 100,
|
|
664
|
+
costSource: String(row.cost_source ?? "estimated") as UsageCostSource,
|
|
619
665
|
}));
|
|
620
666
|
|
|
667
|
+
const knownCents = Number(t.known_cents ?? 0) / 100;
|
|
668
|
+
const unavailableCalls = Number(t.unavailable_calls ?? 0);
|
|
621
669
|
return {
|
|
622
670
|
billing: USD_USAGE_BILLING,
|
|
623
|
-
totalCents:
|
|
671
|
+
totalCents: knownCents,
|
|
672
|
+
totalCost: buildUsageCostAggregate(knownCents, unavailableCalls),
|
|
624
673
|
totalCalls: Number(t.calls ?? 0),
|
|
625
674
|
totalInputTokens: Number(t.in_tok ?? 0),
|
|
626
675
|
totalOutputTokens: Number(t.out_tok ?? 0),
|
|
@@ -634,3 +683,16 @@ export async function getUsageSummary(
|
|
|
634
683
|
recent,
|
|
635
684
|
};
|
|
636
685
|
}
|
|
686
|
+
|
|
687
|
+
function buildUsageCostAggregate(
|
|
688
|
+
knownCents: number,
|
|
689
|
+
unavailableCalls: number,
|
|
690
|
+
): UsageCostAggregate {
|
|
691
|
+
if (unavailableCalls === 0) {
|
|
692
|
+
return { status: "known", knownCents, unavailableCalls: 0 };
|
|
693
|
+
}
|
|
694
|
+
if (knownCents === 0) {
|
|
695
|
+
return { status: "unavailable", knownCents: 0, unavailableCalls };
|
|
696
|
+
}
|
|
697
|
+
return { status: "partial", knownCents, unavailableCalls };
|
|
698
|
+
}
|
|
@@ -748,14 +748,15 @@ export const dataSources: DataSource[] = [
|
|
|
748
748
|
{
|
|
749
749
|
id: "slack",
|
|
750
750
|
name: "Slack",
|
|
751
|
-
description:
|
|
751
|
+
description:
|
|
752
|
+
"Channel history and workspace search. Prefer a Slack workspace integration from Settings > Connections; a local bot token remains available as a legacy fallback.",
|
|
752
753
|
category: "communication",
|
|
753
754
|
icon: IconMessage,
|
|
754
755
|
envKeys: ["SLACK_BOT_TOKEN"],
|
|
755
756
|
docsUrl: "https://api.slack.com/methods",
|
|
756
757
|
walkthroughSteps: [
|
|
757
758
|
{
|
|
758
|
-
title: "Create a Slack App",
|
|
759
|
+
title: "Create a Slack App for local fallback access",
|
|
759
760
|
description:
|
|
760
761
|
"Go to api.slack.com/apps, create a new app, and add OAuth scopes: channels:read, channels:history, search:read.",
|
|
761
762
|
url: "https://api.slack.com/apps",
|
|
@@ -767,10 +768,10 @@ export const dataSources: DataSource[] = [
|
|
|
767
768
|
'Under "OAuth & Permissions", install the app and copy the Bot User OAuth Token.',
|
|
768
769
|
},
|
|
769
770
|
{
|
|
770
|
-
title: "Enter your Bot Token",
|
|
771
|
+
title: "Enter your local fallback Bot Token",
|
|
771
772
|
description: 'Paste the Bot User OAuth Token (starts with "xoxb-").',
|
|
772
773
|
inputKey: "SLACK_BOT_TOKEN",
|
|
773
|
-
inputLabel: "Bot Token",
|
|
774
|
+
inputLabel: "Bot Token (legacy local fallback)",
|
|
774
775
|
inputPlaceholder: "xoxb-...",
|
|
775
776
|
inputType: "password",
|
|
776
777
|
},
|
|
@@ -107,10 +107,14 @@ export const credentialKeys: CredentialKeyConfig[] = [
|
|
|
107
107
|
required: false,
|
|
108
108
|
},
|
|
109
109
|
// Slack
|
|
110
|
-
{
|
|
110
|
+
{
|
|
111
|
+
key: "SLACK_BOT_TOKEN",
|
|
112
|
+
label: "Slack Bot Token (legacy local fallback)",
|
|
113
|
+
required: false,
|
|
114
|
+
},
|
|
111
115
|
{
|
|
112
116
|
key: "SLACK_BOT_TOKEN_2",
|
|
113
|
-
label: "Slack Bot Token (secondary)",
|
|
117
|
+
label: "Slack Bot Token (legacy secondary fallback)",
|
|
114
118
|
required: false,
|
|
115
119
|
},
|
|
116
120
|
// Notion
|
|
@@ -2,9 +2,9 @@ import { registerRequiredSecret } from "@agent-native/core/secrets";
|
|
|
2
2
|
|
|
3
3
|
registerRequiredSecret({
|
|
4
4
|
key: "SLACK_BOT_TOKEN",
|
|
5
|
-
label: "Slack Bot Token",
|
|
5
|
+
label: "Slack Bot Token (local fallback)",
|
|
6
6
|
description:
|
|
7
|
-
"Optional
|
|
7
|
+
"Optional local fallback for Brain channel backfills. Prefer a Slack workspace integration in Settings > Connections. Brain only scans allow-listed channels and never enumerates DMs.",
|
|
8
8
|
docsUrl: "https://api.slack.com/authentication/token-types",
|
|
9
9
|
scope: "workspace",
|
|
10
10
|
kind: "api-key",
|
|
@@ -154,6 +154,9 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
|
|
|
154
154
|
);
|
|
155
155
|
const [headerSlot, setHeaderSlot] = useState<HTMLElement | null>(null);
|
|
156
156
|
const showCollapsedSidebar = sidebarCollapsed && !isMobile;
|
|
157
|
+
const sidebarHasNewRecordingAction = isMobile
|
|
158
|
+
? sidebarOpen
|
|
159
|
+
: !sidebarCollapsed;
|
|
157
160
|
|
|
158
161
|
// Routes whose page renders its own h-12 toolbar. Layout still mounts Sidebar
|
|
159
162
|
// + AgentSidebar, but skips its own header so there's no double-header.
|
|
@@ -603,7 +606,10 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
|
|
|
603
606
|
</div>
|
|
604
607
|
)}
|
|
605
608
|
<main className="agent-native-app-main flex min-h-0 flex-1 flex-col overflow-y-auto">
|
|
606
|
-
<PageHeaderSlotProvider
|
|
609
|
+
<PageHeaderSlotProvider
|
|
610
|
+
slot={headerSlot}
|
|
611
|
+
sidebarHasNewRecordingAction={sidebarHasNewRecordingAction}
|
|
612
|
+
>
|
|
607
613
|
{children}
|
|
608
614
|
</PageHeaderSlotProvider>
|
|
609
615
|
</main>
|