@agent-native/core 0.107.0 → 0.107.2
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 +1 -1
- package/corpus/core/CHANGELOG.md +16 -0
- package/corpus/core/docs/content/integrations.mdx +27 -27
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/artifact-response.ts +32 -10
- package/corpus/core/src/agent/production-agent.ts +19 -0
- package/corpus/core/src/agent/run-store.ts +98 -2
- package/corpus/core/src/client/AssistantChat.tsx +13 -0
- package/corpus/core/src/client/CommandMenu.tsx +5 -0
- package/corpus/core/src/client/active-run-state.ts +34 -0
- package/corpus/core/src/client/agent-chat-adapter.ts +4 -0
- package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +41 -11
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +27 -9
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +45 -0
- package/corpus/core/src/client/sharing/ShareButton.tsx +30 -9
- package/corpus/core/src/client/use-agent-chat-home-handoff.ts +2 -2
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +107 -3
- package/corpus/core/src/integrations/pending-tasks-store.ts +98 -1
- package/corpus/core/src/integrations/plugin.ts +129 -4
- package/corpus/core/src/integrations/webhook-handler.ts +339 -36
- package/corpus/core/src/localization/default-messages.ts +4 -1
- package/corpus/core/src/secrets/register-framework-secrets.ts +28 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +122 -9
- package/corpus/core/src/vite/client.ts +24 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -21
- package/corpus/templates/analytics/AGENTS.md +8 -0
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +1 -1
- package/corpus/templates/analytics/actions/update-dashboard.ts +6 -2
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +35 -7
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +11 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/extension-slot.ts +11 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +27 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extension-boxes.md +6 -0
- package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +8 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/assets/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/brain/app/hooks/use-navigation-state.ts +6 -1
- package/corpus/templates/brain/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/calendar/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +4 -1
- package/corpus/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
- package/corpus/templates/clips/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/content/actions/_content-space-access.ts +45 -2
- package/corpus/templates/content/actions/create-content-database.ts +41 -7
- package/corpus/templates/content/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/content/app/root.tsx +1 -10
- package/corpus/templates/content/changelog/2026-07-17-creating-a-database-now-completes-reliably-in-hosted-workspa.md +6 -0
- package/corpus/templates/content/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +4 -1
- package/corpus/templates/dispatch/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/forms/app/components/layout/Layout.tsx +2 -4
- package/corpus/templates/forms/app/components/ui/popover.tsx +25 -1
- package/corpus/templates/forms/app/hooks/use-navigation-state.ts +6 -1
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +13 -10
- package/corpus/templates/forms/app/root.tsx +6 -1
- package/corpus/templates/forms/changelog/2026-07-17-form-builder-popovers-stay-within-the-viewport.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-17-form-editor-loading-matches-current-sidebar-free-layout.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/mail/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +14 -3
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +8 -1
- package/corpus/templates/plan/app/root.tsx +0 -2
- package/corpus/templates/plan/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +23 -23
- package/corpus/templates/slides/changelog/2026-07-17-duplicated-slides-now-stay-in-the-deck.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/tasks/app/components/layout/Layout.tsx +2 -13
- package/corpus/templates/tasks/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it.md +6 -0
- package/dist/a2a/artifact-response.d.ts +5 -1
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +18 -12
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +13 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-store.d.ts +17 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +84 -2
- package/dist/agent/run-store.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +10 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +4 -0
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/client/active-run-state.d.ts +7 -0
- package/dist/client/active-run-state.d.ts.map +1 -1
- package/dist/client/active-run-state.js +28 -0
- package/dist/client/active-run-state.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +4 -1
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
- package/dist/client/resources/McpConnectionSuggestion.js +27 -8
- package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +4 -2
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.d.ts +6 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +33 -0
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +15 -12
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts +1 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.js +1 -1
- package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/integrations/a2a-continuation-processor.js +62 -5
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/pending-tasks-store.d.ts +3 -0
- package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-store.js +75 -1
- package/dist/integrations/pending-tasks-store.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +81 -5
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts +23 -2
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +257 -35
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +3 -1
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
- package/dist/secrets/register-framework-secrets.js +25 -0
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat-plugin.d.ts +6 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +94 -7
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +4 -1
- package/dist/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +20 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/integrations.mdx +27 -27
- package/package.json +1 -1
- package/src/templates/chat/app/hooks/use-navigation-state.ts +4 -1
- package/src/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
|
@@ -704,6 +704,7 @@ export default createAgentChatPlugin({
|
|
|
704
704
|
analyticsSourceGuidanceOpening() +
|
|
705
705
|
"DASHBOARD CREATION RULE — You may create dashboards, analyses, SQL panels, or other resources only when the user explicitly asks you to (e.g. 'build me a dashboard for...', 'create a new analysis', 'add a chart for...'). Never create any resource proactively during research, trend analysis, or answering questions. If you think a dashboard would be useful, suggest it and wait for explicit confirmation before creating anything. Never add new items to the sidebar or modify existing dashboards without an explicit user directive. " +
|
|
706
706
|
"DASHBOARD MUTATION RULE — For dashboard edits, default to `mutate-dashboard` with the typed `dashboard.*` script API so the main payload is a string and avoids native-array serialization traps. It can move panels by id, edit titles/SQL/config, insert, duplicate, remove, and patch dashboard fields in one atomic save. The script API is constrained: no variables/imports/loops/functions, only JSON-compatible arguments on documented dashboard methods. Do not count shifting `/panels/<index>` positions for ordinary dashboard edits unless the user specifically asks for low-level JSON-pointer operations. " +
|
|
707
|
+
'DASHBOARD EXTENSION BOX RULE — Analytics dashboards support extension boxes. Insert `chartType: "extension"` panels with `config.extensionSlotId` set to `analytics.dashboard.<dashboard-id>.panel.<panel-id>`, then call `add-extension-slot-target` and `install-extension` with that same id. The install is per-user; the extension box stays on the shared dashboard and receives dashboard/panel/current-filter context. Use `get-sql-dashboard` panel summaries to inspect an existing box; `config.extensionId` is only the legacy direct-embed format. ' +
|
|
707
708
|
"EXTENSION DATA-REPAIR RULE — When fixing data in an existing extension-backed dashboard or migrated surface such as Risk Meeting, inspect the current dashboard and extension first, then use `update-extension` `patches`/`edits` that change only the data-loading seam. Preserve the existing layout, CSS, copy, and interactions; never reconstruct the full HTML body for a data-only fix. Full-body replacement is blocked unless `allowFullReplacement=true`, which is reserved for an explicit visual rewrite or a complete replacement body supplied by the user. If a focused edit fails, change the target instead of retrying identical arguments. " +
|
|
708
709
|
'FIRST-PARTY DASHBOARD TIME RULE — AI-generated `source: "first-party"` panels are dashboard-time-bound by default: set `config.timeScope` to `dashboard` and include a matching dashboard time predicate. `{{timeRange}}` requires a matching `filters` entry with `id: "timeRange"` and `type: "select"`; `{{<id>Start}}`/`{{<id>End}}` require a matching `type: "date-range"` filter with that id. Allowed `timeScope` values are `dashboard`, `fixed-window`, `cohort-history`, and `all-time`; use `all-time` only when the user requests full available history and put all-time, lifetime, or historical in the title or description. Server validation rejects unbound first-party SQL. ' +
|
|
709
710
|
"DASHBOARD READ RULE — `get-sql-dashboard` is compact by default: use its `panels` summaries plus `layout.panelOrder`, `layout.firstPanelIds`, and `layout.groups[].rows[].rowNumber/panelIds` for orientation and verification. Pass `includeConfig: true` only when you truly need full panel SQL/config. " +
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appBasePath,
|
|
3
3
|
appPath,
|
|
4
|
+
isAgentChatHomeHandoffActive,
|
|
4
5
|
markAgentChatHomeHandoff,
|
|
5
6
|
useAgentRouteState,
|
|
6
7
|
} from "@agent-native/core/client";
|
|
@@ -106,7 +107,11 @@ export function useNavigationState() {
|
|
|
106
107
|
return `${path}${params.size ? `?${params.toString()}` : ""}`;
|
|
107
108
|
},
|
|
108
109
|
onNavigate: (_command, path) => {
|
|
109
|
-
if (
|
|
110
|
+
if (
|
|
111
|
+
location.pathname === "/" &&
|
|
112
|
+
pathnameFromPath(path) !== "/" &&
|
|
113
|
+
isAgentChatHomeHandoffActive("brain")
|
|
114
|
+
) {
|
|
110
115
|
markAgentChatHomeHandoff("brain");
|
|
111
116
|
}
|
|
112
117
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appBasePath,
|
|
3
|
+
isAgentChatHomeHandoffActive,
|
|
3
4
|
appPath,
|
|
4
5
|
markAgentChatHomeHandoff,
|
|
5
6
|
useAgentRouteState,
|
|
@@ -34,7 +35,9 @@ export function useNavigationState() {
|
|
|
34
35
|
isChatPath(location.pathname) &&
|
|
35
36
|
!isChatPath(pathnameFromPath(path))
|
|
36
37
|
) {
|
|
37
|
-
|
|
38
|
+
if (isAgentChatHomeHandoffActive("chat")) {
|
|
39
|
+
markAgentChatHomeHandoff("chat");
|
|
40
|
+
}
|
|
38
41
|
}
|
|
39
42
|
},
|
|
40
43
|
});
|
|
@@ -559,7 +559,7 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
|
|
|
559
559
|
|
|
560
560
|
<AgentSidebar
|
|
561
561
|
position="right"
|
|
562
|
-
defaultOpen={
|
|
562
|
+
defaultOpen={false}
|
|
563
563
|
emptyStateText={t("navigation.agentEmptyState")}
|
|
564
564
|
suggestions={[
|
|
565
565
|
t("navigation.agentSuggestionSummary"),
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import { getDbExec } from "@agent-native/core/db";
|
|
2
|
+
import { table, text } from "@agent-native/core/db/schema";
|
|
2
3
|
import { getRequestUserEmail } from "@agent-native/core/server/request-context";
|
|
3
|
-
import { eq } from "drizzle-orm";
|
|
4
|
+
import { and, eq, sql } from "drizzle-orm";
|
|
4
5
|
|
|
5
6
|
import { getDb, schema } from "../server/db/index.js";
|
|
6
7
|
|
|
8
|
+
// Keep these lightweight table references local. Importing the public org
|
|
9
|
+
// barrel also initializes auth's long-lived cleanup timer, which breaks test
|
|
10
|
+
// suites that intentionally drain fake timers.
|
|
11
|
+
const organizations = table("organizations", {
|
|
12
|
+
id: text("id").primaryKey(),
|
|
13
|
+
name: text("name").notNull(),
|
|
14
|
+
createdBy: text("created_by").notNull(),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const orgMembers = table("org_members", {
|
|
18
|
+
orgId: text("org_id").notNull(),
|
|
19
|
+
email: text("email").notNull(),
|
|
20
|
+
role: text("role").notNull(),
|
|
21
|
+
});
|
|
22
|
+
|
|
7
23
|
export type ContentSpaceRole = "viewer" | "editor" | "owner";
|
|
8
24
|
|
|
9
25
|
export type ContentSpaceAccess = {
|
|
@@ -21,7 +37,32 @@ export function normalizeContentSpaceEmail(email: string): string {
|
|
|
21
37
|
export async function getContentOrganizationMembership(
|
|
22
38
|
orgId: string,
|
|
23
39
|
userEmail: string,
|
|
40
|
+
options: { db?: any } = {},
|
|
24
41
|
): Promise<{ role: string; name: string; createdBy: string } | null> {
|
|
42
|
+
if (options.db) {
|
|
43
|
+
const [row] = await options.db
|
|
44
|
+
.select({
|
|
45
|
+
role: orgMembers.role,
|
|
46
|
+
name: organizations.name,
|
|
47
|
+
createdBy: organizations.createdBy,
|
|
48
|
+
})
|
|
49
|
+
.from(orgMembers)
|
|
50
|
+
.innerJoin(organizations, eq(organizations.id, orgMembers.orgId))
|
|
51
|
+
.where(
|
|
52
|
+
and(
|
|
53
|
+
eq(orgMembers.orgId, orgId),
|
|
54
|
+
sql`LOWER(${orgMembers.email}) = ${normalizeContentSpaceEmail(userEmail)}`,
|
|
55
|
+
),
|
|
56
|
+
)
|
|
57
|
+
.limit(1);
|
|
58
|
+
return row
|
|
59
|
+
? {
|
|
60
|
+
role: String(row.role ?? "member").toLowerCase(),
|
|
61
|
+
name: row.name,
|
|
62
|
+
createdBy: row.createdBy,
|
|
63
|
+
}
|
|
64
|
+
: null;
|
|
65
|
+
}
|
|
25
66
|
const result = await getDbExec().execute({
|
|
26
67
|
sql: `SELECT m.role AS role, o.name AS name, o.created_by AS "createdBy"
|
|
27
68
|
FROM org_members m
|
|
@@ -90,11 +131,12 @@ export async function listContentOrganizationMemberships(userEmail: string) {
|
|
|
90
131
|
export async function resolveContentSpaceAccess(
|
|
91
132
|
spaceId: string,
|
|
92
133
|
requiredRole: "viewer" | "editor" = "viewer",
|
|
134
|
+
options: { db?: any } = {},
|
|
93
135
|
): Promise<ContentSpaceAccess> {
|
|
94
136
|
const userEmail = getRequestUserEmail();
|
|
95
137
|
if (!userEmail) throw new Error("no authenticated user");
|
|
96
138
|
const normalizedUserEmail = normalizeContentSpaceEmail(userEmail);
|
|
97
|
-
const [space] = await getDb()
|
|
139
|
+
const [space] = await (options.db ?? getDb())
|
|
98
140
|
.select()
|
|
99
141
|
.from(schema.contentSpaces)
|
|
100
142
|
.where(eq(schema.contentSpaces.id, spaceId));
|
|
@@ -115,6 +157,7 @@ export async function resolveContentSpaceAccess(
|
|
|
115
157
|
const membership = await getContentOrganizationMembership(
|
|
116
158
|
space.orgId,
|
|
117
159
|
normalizedUserEmail,
|
|
160
|
+
options,
|
|
118
161
|
);
|
|
119
162
|
if (!membership)
|
|
120
163
|
throw new Error(`Not authorized for Content space "${spaceId}"`);
|
|
@@ -5,7 +5,13 @@ import {
|
|
|
5
5
|
getRequestOrgId,
|
|
6
6
|
getRequestUserEmail,
|
|
7
7
|
} from "@agent-native/core/server/request-context";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
accessFilter,
|
|
10
|
+
assertAccess,
|
|
11
|
+
currentAccess,
|
|
12
|
+
ForbiddenError,
|
|
13
|
+
type ShareRole,
|
|
14
|
+
} from "@agent-native/core/sharing";
|
|
9
15
|
import { and, eq, sql } from "drizzle-orm";
|
|
10
16
|
import { z } from "zod";
|
|
11
17
|
|
|
@@ -158,9 +164,34 @@ export async function resolveContentDatabaseSpace(
|
|
|
158
164
|
return spaceId;
|
|
159
165
|
}
|
|
160
166
|
|
|
167
|
+
async function assertDocumentEditorAccess(db: any, documentId: string) {
|
|
168
|
+
const [document] = await db
|
|
169
|
+
.select()
|
|
170
|
+
.from(schema.documents)
|
|
171
|
+
.where(
|
|
172
|
+
and(
|
|
173
|
+
eq(schema.documents.id, documentId),
|
|
174
|
+
accessFilter(
|
|
175
|
+
schema.documents,
|
|
176
|
+
schema.documentShares,
|
|
177
|
+
currentAccess(),
|
|
178
|
+
"editor",
|
|
179
|
+
),
|
|
180
|
+
),
|
|
181
|
+
);
|
|
182
|
+
if (!document) {
|
|
183
|
+
throw new ForbiddenError(`No editor access to document ${documentId}`);
|
|
184
|
+
}
|
|
185
|
+
return document;
|
|
186
|
+
}
|
|
187
|
+
|
|
161
188
|
export async function createContentDatabaseRecord(
|
|
162
189
|
args: CreateDatabaseRequest,
|
|
163
|
-
options: {
|
|
190
|
+
options: {
|
|
191
|
+
db?: any;
|
|
192
|
+
spaceId?: string;
|
|
193
|
+
resolveSpaceAccess?: typeof resolveContentSpaceAccess;
|
|
194
|
+
} = {},
|
|
164
195
|
): Promise<string> {
|
|
165
196
|
const db = options.db ?? getDb();
|
|
166
197
|
const now = new Date().toISOString();
|
|
@@ -178,8 +209,7 @@ export async function createContentDatabaseRecord(
|
|
|
178
209
|
}> = [];
|
|
179
210
|
|
|
180
211
|
if (documentId) {
|
|
181
|
-
const
|
|
182
|
-
const document = access.resource;
|
|
212
|
+
const document = await assertDocumentEditorAccess(db, documentId);
|
|
183
213
|
ownerEmail = document.ownerEmail as string;
|
|
184
214
|
orgId = (document.orgId as string | null) ?? null;
|
|
185
215
|
spaceId = (document.spaceId as string | null) ?? spaceId;
|
|
@@ -230,8 +260,7 @@ export async function createContentDatabaseRecord(
|
|
|
230
260
|
let hideFromSearch = 0;
|
|
231
261
|
|
|
232
262
|
if (parentId) {
|
|
233
|
-
const
|
|
234
|
-
const parent = parentAccess.resource;
|
|
263
|
+
const parent = await assertDocumentEditorAccess(db, parentId);
|
|
235
264
|
ownerEmail = parent.ownerEmail as string;
|
|
236
265
|
orgId = (parent.orgId as string | null) ?? null;
|
|
237
266
|
spaceId = (parent.spaceId as string | null) ?? spaceId;
|
|
@@ -257,7 +286,12 @@ export async function createContentDatabaseRecord(
|
|
|
257
286
|
"A top-level database requires a resolved Content space",
|
|
258
287
|
);
|
|
259
288
|
}
|
|
260
|
-
const spaceAccess = await
|
|
289
|
+
const spaceAccess = await (
|
|
290
|
+
options.resolveSpaceAccess ?? resolveContentSpaceAccess
|
|
291
|
+
)(spaceId, "editor", { db });
|
|
292
|
+
if (spaceAccess.space.id !== spaceId) {
|
|
293
|
+
throw new Error("Resolved Content space does not match the request");
|
|
294
|
+
}
|
|
261
295
|
ownerEmail = getRequestUserEmail() ?? ownerEmail;
|
|
262
296
|
orgId = spaceAccess.space.orgId;
|
|
263
297
|
visibility = orgId ? "org" : "private";
|
|
@@ -189,7 +189,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
189
189
|
)}
|
|
190
190
|
<AgentSidebar
|
|
191
191
|
position="right"
|
|
192
|
-
defaultOpen={
|
|
192
|
+
defaultOpen={false}
|
|
193
193
|
agentPageHref="/agent"
|
|
194
194
|
emptyStateText={t("chat.emptyState")}
|
|
195
195
|
suggestions={[
|
|
@@ -479,15 +479,6 @@ function PublicAgentShell({ children }: { children: React.ReactNode }) {
|
|
|
479
479
|
|
|
480
480
|
useEffect(() => setMounted(true), []);
|
|
481
481
|
|
|
482
|
-
useEffect(() => {
|
|
483
|
-
if (!mounted) return;
|
|
484
|
-
if (!window.matchMedia("(min-width: 768px)").matches) return;
|
|
485
|
-
const id = window.setTimeout(() => {
|
|
486
|
-
window.dispatchEvent(new Event("agent-panel:open"));
|
|
487
|
-
}, 0);
|
|
488
|
-
return () => window.clearTimeout(id);
|
|
489
|
-
}, [mounted]);
|
|
490
|
-
|
|
491
482
|
const content = <>{children}</>;
|
|
492
483
|
|
|
493
484
|
if (!mounted) {
|
|
@@ -503,7 +494,7 @@ function PublicAgentShell({ children }: { children: React.ReactNode }) {
|
|
|
503
494
|
return (
|
|
504
495
|
<AgentSidebar
|
|
505
496
|
position="right"
|
|
506
|
-
defaultOpen
|
|
497
|
+
defaultOpen={false}
|
|
507
498
|
defaultSidebarWidth={420}
|
|
508
499
|
emptyStateText={t("chat.publicEmptyState")}
|
|
509
500
|
suggestions={[
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appBasePath,
|
|
3
3
|
appPath,
|
|
4
|
+
isAgentChatHomeHandoffActive,
|
|
4
5
|
markAgentChatHomeHandoff,
|
|
5
6
|
useAgentRouteState,
|
|
6
7
|
} from "@agent-native/core/client";
|
|
@@ -54,7 +55,9 @@ export function useNavigationState(extensions?: DispatchExtensionConfig) {
|
|
|
54
55
|
routerPath(location.pathname) === "/chat" &&
|
|
55
56
|
pathnameFromPath(path) !== "/chat"
|
|
56
57
|
) {
|
|
57
|
-
|
|
58
|
+
if (isAgentChatHomeHandoffActive("dispatch")) {
|
|
59
|
+
markAgentChatHomeHandoff("dispatch");
|
|
60
|
+
}
|
|
58
61
|
}
|
|
59
62
|
},
|
|
60
63
|
});
|
|
@@ -51,8 +51,6 @@ export function Layout({ children }: LayoutProps) {
|
|
|
51
51
|
if (!formId) return null;
|
|
52
52
|
return { type: "form" as const, id: formId };
|
|
53
53
|
}, [location.pathname]);
|
|
54
|
-
const sidebarScope = chatHomeHandoffActive ? null : formScope;
|
|
55
|
-
|
|
56
54
|
if (BARE_ROUTES.has(location.pathname)) {
|
|
57
55
|
return <>{children}</>;
|
|
58
56
|
}
|
|
@@ -89,7 +87,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
89
87
|
<AgentSidebar
|
|
90
88
|
position="right"
|
|
91
89
|
agentPageHref="/agent"
|
|
92
|
-
defaultOpen
|
|
90
|
+
defaultOpen={false}
|
|
93
91
|
chatViewTransition
|
|
94
92
|
storageKey="forms"
|
|
95
93
|
browserTabId={TAB_ID}
|
|
@@ -101,7 +99,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
101
99
|
t("agent.suggestionSubmissions"),
|
|
102
100
|
t("agent.suggestionExport"),
|
|
103
101
|
]}
|
|
104
|
-
scope={
|
|
102
|
+
scope={formScope}
|
|
105
103
|
>
|
|
106
104
|
<div className="flex h-full flex-1 flex-col overflow-hidden">
|
|
107
105
|
{showHeader ? <Header /> : null}
|
|
@@ -1 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
import {
|
|
2
|
+
Popover,
|
|
3
|
+
PopoverAnchor,
|
|
4
|
+
PopoverContent as ToolkitPopoverContent,
|
|
5
|
+
PopoverTrigger,
|
|
6
|
+
} from "@agent-native/toolkit/ui/popover";
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
|
|
9
|
+
import { cn } from "@/lib/utils";
|
|
10
|
+
|
|
11
|
+
const PopoverContent = React.forwardRef<
|
|
12
|
+
React.ElementRef<typeof ToolkitPopoverContent>,
|
|
13
|
+
React.ComponentPropsWithoutRef<typeof ToolkitPopoverContent>
|
|
14
|
+
>(({ className, collisionPadding = 16, ...props }, ref) => (
|
|
15
|
+
<ToolkitPopoverContent
|
|
16
|
+
ref={ref}
|
|
17
|
+
collisionPadding={collisionPadding}
|
|
18
|
+
className={cn("max-w-[calc(100vw-2rem)]", className)}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
));
|
|
22
|
+
|
|
23
|
+
PopoverContent.displayName = ToolkitPopoverContent.displayName;
|
|
24
|
+
|
|
25
|
+
export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appBasePath,
|
|
3
|
+
isAgentChatHomeHandoffActive,
|
|
3
4
|
markAgentChatHomeHandoff,
|
|
4
5
|
useAgentRouteState,
|
|
5
6
|
} from "@agent-native/core/client";
|
|
@@ -131,7 +132,11 @@ export function useNavigationState() {
|
|
|
131
132
|
navigateOptions: { flushSync: true, replace: true },
|
|
132
133
|
onNavigate: (_command, path) => {
|
|
133
134
|
void prewarmFormsRoutePath(path);
|
|
134
|
-
if (
|
|
135
|
+
if (
|
|
136
|
+
location.pathname === "/ask" &&
|
|
137
|
+
path !== "/ask" &&
|
|
138
|
+
isAgentChatHomeHandoffActive("forms")
|
|
139
|
+
) {
|
|
135
140
|
markAgentChatHomeHandoff("forms");
|
|
136
141
|
}
|
|
137
142
|
},
|
|
@@ -359,10 +359,19 @@ export function FormBuilderPage() {
|
|
|
359
359
|
<Skeleton className="h-8 w-20 rounded-md" />
|
|
360
360
|
</div>
|
|
361
361
|
</div>
|
|
362
|
-
{/*
|
|
363
|
-
<div className="
|
|
364
|
-
<div className="flex-1
|
|
365
|
-
<
|
|
362
|
+
{/* Tabs */}
|
|
363
|
+
<div className="border-b border-border px-2 sm:px-4 py-2 shrink-0 overflow-hidden">
|
|
364
|
+
<div className="flex w-max items-center gap-1 rounded-lg bg-muted/40 p-1">
|
|
365
|
+
<Skeleton className="h-8 w-12 rounded-md" />
|
|
366
|
+
<Skeleton className="h-8 w-16 rounded-md" />
|
|
367
|
+
<Skeleton className="h-8 w-16 rounded-md" />
|
|
368
|
+
<Skeleton className="h-8 w-24 rounded-md" />
|
|
369
|
+
</div>
|
|
370
|
+
</div>
|
|
371
|
+
{/* Body: builder */}
|
|
372
|
+
<div className="flex flex-1 overflow-hidden relative">
|
|
373
|
+
<div className="flex-1 overflow-auto bg-muted/30">
|
|
374
|
+
<div className="max-w-2xl mx-auto py-4 sm:py-8 px-3 sm:px-4 space-y-4">
|
|
366
375
|
<Skeleton className="h-8 w-2/3" />
|
|
367
376
|
<Skeleton className="h-4 w-1/2" />
|
|
368
377
|
<div className="space-y-3 pt-4">
|
|
@@ -378,12 +387,6 @@ export function FormBuilderPage() {
|
|
|
378
387
|
</div>
|
|
379
388
|
</div>
|
|
380
389
|
</div>
|
|
381
|
-
<div className="hidden lg:block w-72 border-s border-border p-4 space-y-4">
|
|
382
|
-
<Skeleton className="h-4 w-32" />
|
|
383
|
-
<Skeleton className="h-9 w-full" />
|
|
384
|
-
<Skeleton className="h-9 w-full" />
|
|
385
|
-
<Skeleton className="h-9 w-full" />
|
|
386
|
-
</div>
|
|
387
390
|
</div>
|
|
388
391
|
</div>
|
|
389
392
|
);
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
useCommandMenuShortcut,
|
|
9
9
|
getThemeInitScript,
|
|
10
10
|
configureTracking,
|
|
11
|
+
isAgentChatHomeHandoffActive,
|
|
11
12
|
markAgentChatHomeHandoff,
|
|
12
13
|
navigateWithAgentChatViewTransition,
|
|
13
14
|
setClientAppState,
|
|
@@ -199,7 +200,11 @@ function OpenLinkInterceptor() {
|
|
|
199
200
|
if (!path) return;
|
|
200
201
|
|
|
201
202
|
event.preventDefault();
|
|
202
|
-
if (
|
|
203
|
+
if (
|
|
204
|
+
location.pathname === "/ask" &&
|
|
205
|
+
path !== "/ask" &&
|
|
206
|
+
isAgentChatHomeHandoffActive("forms")
|
|
207
|
+
) {
|
|
203
208
|
markAgentChatHomeHandoff("forms");
|
|
204
209
|
}
|
|
205
210
|
navigateWithAgentChatViewTransition(navigate, path);
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
DevDatabaseLink,
|
|
4
4
|
FeedbackButton,
|
|
5
5
|
appPath,
|
|
6
|
+
isAgentChatHomeHandoffActive,
|
|
6
7
|
markAgentChatHomeHandoff,
|
|
7
8
|
navigateWithAgentChatViewTransition,
|
|
8
9
|
PromptComposer,
|
|
@@ -442,13 +443,17 @@ function PlansSidebarSection({ collapsed }: { collapsed: boolean }) {
|
|
|
442
443
|
signInForPlanCreate();
|
|
443
444
|
return;
|
|
444
445
|
}
|
|
445
|
-
|
|
446
|
+
if (location.pathname === "/" && isAgentChatHomeHandoffActive("plans")) {
|
|
447
|
+
markAgentChatHomeHandoff("plans");
|
|
448
|
+
}
|
|
446
449
|
navigateWithAgentChatViewTransition(navigate, "/plans?create=1");
|
|
447
450
|
};
|
|
448
451
|
|
|
449
452
|
const openPlanPath = (event: MouseEvent<HTMLAnchorElement>, path: string) => {
|
|
450
453
|
event.preventDefault();
|
|
451
|
-
|
|
454
|
+
if (location.pathname === "/" && isAgentChatHomeHandoffActive("plans")) {
|
|
455
|
+
markAgentChatHomeHandoff("plans");
|
|
456
|
+
}
|
|
452
457
|
navigateWithAgentChatViewTransition(navigate, path);
|
|
453
458
|
};
|
|
454
459
|
|
|
@@ -738,7 +743,13 @@ export function Sidebar({
|
|
|
738
743
|
<Link
|
|
739
744
|
to={item.href}
|
|
740
745
|
onClick={() => {
|
|
741
|
-
if (
|
|
746
|
+
if (
|
|
747
|
+
item.href !== "/" &&
|
|
748
|
+
location.pathname === "/" &&
|
|
749
|
+
isAgentChatHomeHandoffActive("plans")
|
|
750
|
+
) {
|
|
751
|
+
markAgentChatHomeHandoff("plans");
|
|
752
|
+
}
|
|
742
753
|
}}
|
|
743
754
|
className={cn(
|
|
744
755
|
"flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
agentNativePath,
|
|
3
3
|
appBasePath,
|
|
4
|
+
isAgentChatHomeHandoffActive,
|
|
4
5
|
markAgentChatHomeHandoff,
|
|
5
6
|
} from "@agent-native/core/client";
|
|
6
7
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
@@ -108,7 +109,13 @@ export function useNavigationState() {
|
|
|
108
109
|
deleteCommand();
|
|
109
110
|
const path = planNavigateCommandPath(cmd);
|
|
110
111
|
void prewarmPlanRoutePath(path);
|
|
111
|
-
if (
|
|
112
|
+
if (
|
|
113
|
+
location.pathname === "/" &&
|
|
114
|
+
path !== "/" &&
|
|
115
|
+
isAgentChatHomeHandoffActive("plans")
|
|
116
|
+
) {
|
|
117
|
+
markAgentChatHomeHandoff("plans");
|
|
118
|
+
}
|
|
112
119
|
const commitNavigation = () =>
|
|
113
120
|
navigate(path, { replace: true, flushSync: true });
|
|
114
121
|
if (
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
createAgentNativeQueryClient,
|
|
7
7
|
getLocaleInitScript,
|
|
8
8
|
getThemeInitScript,
|
|
9
|
-
markAgentChatHomeHandoff,
|
|
10
9
|
navigateWithAgentChatViewTransition,
|
|
11
10
|
useCommandMenuShortcut,
|
|
12
11
|
useT,
|
|
@@ -153,7 +152,6 @@ function AppContent() {
|
|
|
153
152
|
useCommandMenuShortcut(useCallback(() => setCmdkOpen(true), []));
|
|
154
153
|
const go = useCallback(
|
|
155
154
|
(path: string) => {
|
|
156
|
-
if (path !== "/") markAgentChatHomeHandoff("plans");
|
|
157
155
|
navigateWithAgentChatViewTransition(navigate, path);
|
|
158
156
|
setCmdkOpen(false);
|
|
159
157
|
},
|