@agent-native/core 0.167.4 → 0.168.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 +1 -1
- package/corpus/templates/brain/actions/list-sources.ts +17 -7
- package/corpus/templates/brain/app/components/brain/Surface.tsx +4 -2
- package/corpus/templates/brain/app/lib/brain.ts +13 -3
- package/corpus/templates/brain/server/lib/brain-health.ts +5 -8
- package/corpus/templates/brain/server/lib/brain.ts +1 -0
- package/corpus/templates/brain/server/lib/capture-sanitization.ts +5 -0
- package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +3 -2
- package/corpus/templates/clips/desktop/src/app.tsx +11 -10
- package/corpus/templates/clips/desktop/src/lib/desktop-oauth-window.ts +23 -0
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +32 -0
- package/dist/client/AboutAgentNativeDialog.d.ts +5 -0
- package/dist/client/AboutAgentNativeDialog.js +56 -0
- package/dist/client/AgentPanel.d.ts +3 -1
- package/dist/client/AgentPanel.js +2 -2
- package/dist/client/CommandMenu.d.ts +6 -1
- package/dist/client/CommandMenu.js +46 -3
- package/dist/client/EnvironmentBadge.js +4 -1
- package/dist/client/agent-native-version.d.ts +12 -0
- package/dist/client/agent-native-version.js +36 -0
- package/dist/client/agent-page/AgentTabsPage.d.ts +4 -1
- package/dist/client/agent-page/AgentTabsPage.js +2 -2
- package/dist/client/integrations/IntegrationConnectionChoice.d.ts +4 -1
- package/dist/client/integrations/IntegrationConnectionChoice.js +6 -2
- package/dist/client/onboarding/FirstRunOnboarding.js +9 -5
- package/dist/client/resources/McpIntegrationDialog.d.ts +3 -1
- package/dist/client/resources/McpIntegrationDialog.js +181 -112
- package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
- package/dist/client/resources/mcp-integration-catalog.js +5 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/config.d.ts +3 -1
- package/dist/config.js +14 -9
- package/dist/localization/core-messages/ar-SA.js +6 -0
- package/dist/localization/core-messages/de-DE.js +6 -0
- package/dist/localization/core-messages/en-US.d.ts +6 -0
- package/dist/localization/core-messages/en-US.js +6 -0
- package/dist/localization/core-messages/es-ES.js +6 -0
- package/dist/localization/core-messages/fr-FR.js +6 -0
- package/dist/localization/core-messages/hi-IN.js +6 -0
- package/dist/localization/core-messages/ja-JP.js +6 -0
- package/dist/localization/core-messages/ko-KR.js +6 -0
- package/dist/localization/core-messages/pt-BR.js +6 -0
- package/dist/localization/core-messages/zh-CN.js +6 -0
- package/dist/localization/core-messages/zh-TW.js +6 -0
- package/dist/localization/core-messages.d.ts +6 -0
- package/dist/localization/default-messages.d.ts +9 -0
- package/dist/localization/default-messages.js +9 -0
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/vite/agent-native-config-loader.js +1 -1
- package/dist/vite/client.js +9 -8
- package/dist/vite/package-versions.d.ts +1 -0
- package/dist/vite/package-versions.js +97 -0
- package/docs/content/agent-native-config.mdx +55 -31
- package/docs/content/environment-variables.mdx +51 -14
- package/package.json +1 -1
package/corpus/README.md
CHANGED
|
@@ -6,6 +6,7 @@ import { z } from "zod";
|
|
|
6
6
|
import { getDb, schema } from "../server/db/index.js";
|
|
7
7
|
import { nextBrainSourceSyncAt } from "../server/jobs/sync-sources.js";
|
|
8
8
|
import { listAccessibleAudienceIds } from "../server/lib/audiences.js";
|
|
9
|
+
import { sourceHealthState } from "../server/lib/brain-health.js";
|
|
9
10
|
import { parseJson, serializeSource } from "../server/lib/brain.js";
|
|
10
11
|
import { sourceProviderSchema } from "./_schemas.js";
|
|
11
12
|
|
|
@@ -71,14 +72,23 @@ export default defineAction({
|
|
|
71
72
|
.from(schema.brainSources)
|
|
72
73
|
.where(and(...clauses))
|
|
73
74
|
.orderBy(desc(schema.brainSources.updatedAt));
|
|
75
|
+
const nowMs = Date.now();
|
|
74
76
|
const sources = await Promise.all(
|
|
75
|
-
rows.map(async (row) =>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
rows.map(async (row) => {
|
|
78
|
+
const latest = await latestRun(row.id);
|
|
79
|
+
const nextSyncAt = nextBrainSourceSyncAt(row);
|
|
80
|
+
return {
|
|
81
|
+
...serializeSource(row),
|
|
82
|
+
recordCount: await sourceRecordCount(row.id),
|
|
83
|
+
latestRun: latest,
|
|
84
|
+
nextSyncAt,
|
|
85
|
+
health: sourceHealthState(row, latest, nextSyncAt, nowMs),
|
|
86
|
+
};
|
|
87
|
+
}),
|
|
81
88
|
);
|
|
82
|
-
return {
|
|
89
|
+
return {
|
|
90
|
+
count: rows.length,
|
|
91
|
+
sources,
|
|
92
|
+
};
|
|
83
93
|
},
|
|
84
94
|
});
|
|
@@ -117,7 +117,8 @@ export function StatusBadge({ status }: { status: string }) {
|
|
|
117
117
|
? IconCircleCheck
|
|
118
118
|
: normalized.includes("review") ||
|
|
119
119
|
normalized.includes("degraded") ||
|
|
120
|
-
normalized.includes("stale")
|
|
120
|
+
normalized.includes("stale") ||
|
|
121
|
+
normalized.includes("needs")
|
|
121
122
|
? IconClock
|
|
122
123
|
: normalized.includes("error")
|
|
123
124
|
? IconAlertTriangle
|
|
@@ -132,7 +133,8 @@ export function StatusBadge({ status }: { status: string }) {
|
|
|
132
133
|
"border-border bg-secondary text-secondary-foreground",
|
|
133
134
|
(normalized.includes("review") ||
|
|
134
135
|
normalized.includes("degraded") ||
|
|
135
|
-
normalized.includes("stale")
|
|
136
|
+
normalized.includes("stale") ||
|
|
137
|
+
normalized.includes("needs")) &&
|
|
136
138
|
"border-amber-500/35 bg-amber-500/10 text-amber-700 dark:text-amber-300",
|
|
137
139
|
normalized.includes("error") &&
|
|
138
140
|
"border-destructive/35 bg-destructive/10 text-destructive",
|
|
@@ -20,7 +20,14 @@ export type BrainView =
|
|
|
20
20
|
| "settings";
|
|
21
21
|
|
|
22
22
|
export type KnowledgeStatus = "approved" | "needs_review" | "draft" | "stale";
|
|
23
|
-
export type SourceHealth =
|
|
23
|
+
export type SourceHealth =
|
|
24
|
+
| "healthy"
|
|
25
|
+
| "needs_setup"
|
|
26
|
+
| "needs_sync"
|
|
27
|
+
| "stale"
|
|
28
|
+
| "degraded"
|
|
29
|
+
| "paused"
|
|
30
|
+
| "error";
|
|
24
31
|
export type ReviewPriority = "high" | "medium" | "low";
|
|
25
32
|
|
|
26
33
|
export interface Citation {
|
|
@@ -1144,8 +1151,11 @@ export function sourceDescription(source: BrainSource) {
|
|
|
1144
1151
|
export function sourceHealth(source: BrainSource): SourceHealth {
|
|
1145
1152
|
if (source.health) return source.health;
|
|
1146
1153
|
if (sourceRetryAfter(source)) return "degraded";
|
|
1147
|
-
if (source.status === "active")
|
|
1148
|
-
|
|
1154
|
+
if (source.status === "active") {
|
|
1155
|
+
if (source.lastError) return "degraded";
|
|
1156
|
+
if (sourceAutoSync(source) && !source.lastSyncedAt) return "needs_sync";
|
|
1157
|
+
return "healthy";
|
|
1158
|
+
}
|
|
1149
1159
|
if (source.status === "error") return "error";
|
|
1150
1160
|
if (source.status === "paused" || source.status === "archived")
|
|
1151
1161
|
return "paused";
|
|
@@ -189,9 +189,9 @@ function latestIso(values: Array<string | null | undefined>) {
|
|
|
189
189
|
return latest;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
function sourceHealthState(
|
|
192
|
+
export function sourceHealthState(
|
|
193
193
|
source: SourceRow,
|
|
194
|
-
latestRun: SyncRunRow | null,
|
|
194
|
+
latestRun: Pick<SyncRunRow, "status"> | null,
|
|
195
195
|
nextSyncAt: string | null,
|
|
196
196
|
nowMs: number,
|
|
197
197
|
): BrainSourceHealthState {
|
|
@@ -530,12 +530,9 @@ export async function readBrainHealth() {
|
|
|
530
530
|
};
|
|
531
531
|
});
|
|
532
532
|
|
|
533
|
-
const sourceHealthCounts = countStatuses<
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
...sourceSummaries.map((source) => ({ status: source.health })),
|
|
537
|
-
...sourceRows.map((source) => ({ status: source.status })),
|
|
538
|
-
]);
|
|
533
|
+
const sourceHealthCounts = countStatuses<BrainSourceHealthState>(
|
|
534
|
+
sourceSummaries.map((source) => ({ status: source.health })),
|
|
535
|
+
);
|
|
539
536
|
const captureCounts = countStatuses(captureRows);
|
|
540
537
|
const captureDispositionCounts = countStatuses(
|
|
541
538
|
captureRows.map((capture) => ({
|
|
@@ -755,6 +755,7 @@ export async function createCapture(values: {
|
|
|
755
755
|
title: source.title,
|
|
756
756
|
provider: source.provider as BrainSourceProvider,
|
|
757
757
|
ownerEmail: source.ownerEmail,
|
|
758
|
+
orgId: source.orgId,
|
|
758
759
|
},
|
|
759
760
|
sourceConfig: parseJson<Record<string, unknown>>(source.configJson, {}),
|
|
760
761
|
settings,
|
|
@@ -71,6 +71,7 @@ export interface CaptureSanitizationInput {
|
|
|
71
71
|
title: string;
|
|
72
72
|
provider: BrainSourceProvider;
|
|
73
73
|
ownerEmail: string;
|
|
74
|
+
orgId?: string | null;
|
|
74
75
|
};
|
|
75
76
|
sourceConfig?: Record<string, unknown>;
|
|
76
77
|
settings: BrainSettings;
|
|
@@ -440,6 +441,10 @@ async function classifyWithApprovedModel(
|
|
|
440
441
|
apiKeyEnvVar: userApiKey.apiKeyEnvVar,
|
|
441
442
|
appId: "brain",
|
|
442
443
|
engineOption: engineName,
|
|
444
|
+
credentialIdentity: {
|
|
445
|
+
userEmail: input.source.ownerEmail,
|
|
446
|
+
orgId: input.source.orgId ?? undefined,
|
|
447
|
+
},
|
|
443
448
|
});
|
|
444
449
|
|
|
445
450
|
const maxChars = Math.min(
|
|
@@ -10,7 +10,8 @@ declare global {
|
|
|
10
10
|
var __AGENT_NATIVE_BRAIN_SCHEDULED_RUNTIME__: boolean | undefined;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const BRAIN_QUEUE_SWEEP_LIMIT =
|
|
13
|
+
export const BRAIN_QUEUE_SWEEP_LIMIT = 25;
|
|
14
|
+
export const BRAIN_MAX_DISTILLATIONS_PER_SWEEP = 2;
|
|
14
15
|
|
|
15
16
|
function productionLike() {
|
|
16
17
|
return (
|
|
@@ -53,7 +54,7 @@ export default defineEventHandler(async (event) => {
|
|
|
53
54
|
processBrainIngestQueueOnce({
|
|
54
55
|
limit: BRAIN_QUEUE_SWEEP_LIMIT,
|
|
55
56
|
runDistillation: true,
|
|
56
|
-
maxDistillations:
|
|
57
|
+
maxDistillations: BRAIN_MAX_DISTILLATIONS_PER_SWEEP,
|
|
57
58
|
}),
|
|
58
59
|
expireSensitivityQuarantines(),
|
|
59
60
|
]);
|
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
startBubbleWebrtc,
|
|
68
68
|
type BubbleWebrtcHandle,
|
|
69
69
|
} from "./lib/bubble-webrtc";
|
|
70
|
+
import { openBoundOAuthWindow } from "./lib/desktop-oauth-window";
|
|
70
71
|
import {
|
|
71
72
|
getCameraStreamWithFallback,
|
|
72
73
|
isMediaConstraintFailure,
|
|
@@ -2126,15 +2127,17 @@ export function App() {
|
|
|
2126
2127
|
void tick();
|
|
2127
2128
|
}
|
|
2128
2129
|
|
|
2129
|
-
// Google verification stays in the bound Tauri WebView so the
|
|
2130
|
-
// the same browser-binding cookie. Magic-link verification
|
|
2131
|
-
// in the system browser through its own exchange flow.
|
|
2130
|
+
// Google verification stays in a child of the bound Tauri WebView so the
|
|
2131
|
+
// callback sees the same browser-binding cookie. Magic-link verification
|
|
2132
|
+
// still completes in the system browser through its own exchange flow.
|
|
2132
2133
|
async function signInExternal() {
|
|
2133
2134
|
if (signInInflightRef.current) return;
|
|
2134
2135
|
signInInflightRef.current = true;
|
|
2136
|
+
let oauthWindow: ReturnType<typeof openBoundOAuthWindow> | null = null;
|
|
2135
2137
|
|
|
2136
2138
|
try {
|
|
2137
2139
|
setSignInError(null);
|
|
2140
|
+
oauthWindow = openBoundOAuthWindow();
|
|
2138
2141
|
const flowId = crypto.randomUUID?.() ?? null;
|
|
2139
2142
|
const verifier = (() => {
|
|
2140
2143
|
const randomUuid = crypto.randomUUID;
|
|
@@ -2163,7 +2166,6 @@ export function App() {
|
|
|
2163
2166
|
const authParams = new URLSearchParams({
|
|
2164
2167
|
desktop: "1",
|
|
2165
2168
|
flow_id: flowId,
|
|
2166
|
-
webview: "1",
|
|
2167
2169
|
});
|
|
2168
2170
|
const authResponse = await fetch(
|
|
2169
2171
|
`${base}/_agent-native/google/auth-url?${authParams.toString()}`,
|
|
@@ -2194,13 +2196,12 @@ export function App() {
|
|
|
2194
2196
|
: "Could not start Google sign-in.";
|
|
2195
2197
|
throw new Error(message);
|
|
2196
2198
|
}
|
|
2199
|
+
oauthWindow.location.href = authPayload.url;
|
|
2197
2200
|
setSignInPending("google");
|
|
2198
|
-
|
|
2199
|
-
// browser-binding cookie here, and the callback returns this page with
|
|
2200
|
-
// the staged session cookie after Google completes.
|
|
2201
|
-
window.location.href = authPayload.url;
|
|
2201
|
+
startDesktopAuthExchange(flowId, "google", verifier);
|
|
2202
2202
|
} catch (err) {
|
|
2203
2203
|
console.error("[clips-tray] signInExternal failed:", err);
|
|
2204
|
+
oauthWindow?.close();
|
|
2204
2205
|
signInInflightRef.current = false;
|
|
2205
2206
|
setSignInPending(null);
|
|
2206
2207
|
setSignInError(
|
|
@@ -3962,8 +3963,8 @@ export function App() {
|
|
|
3962
3963
|
// (not a separate Tauri window). This avoids Tauri 2's separate-WebKit-
|
|
3963
3964
|
// data-store-per-WebviewWindow cookie-jar issue — the cookie is set in
|
|
3964
3965
|
// the same webview that reads it on the next /auth/session poll.
|
|
3965
|
-
// Google verification uses the bound WebView, while magic-link
|
|
3966
|
-
// uses the system browser and password stays inline here.
|
|
3966
|
+
// Google verification uses a popup in the bound WebView, while magic-link
|
|
3967
|
+
// verification uses the system browser and password stays inline here.
|
|
3967
3968
|
if (authStatus === "anon") {
|
|
3968
3969
|
return (
|
|
3969
3970
|
<div className="app" ref={appRef}>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type OAuthWindow = Pick<Window, "close"> & {
|
|
2
|
+
location: Pick<Location, "href">;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
type OpenOAuthWindow = (url: string, target: string) => OAuthWindow | null;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Open a same-WebView OAuth child before awaiting the auth URL.
|
|
9
|
+
*
|
|
10
|
+
* The parent keeps polling the exchange while the child completes Google
|
|
11
|
+
* OAuth. Using window.open keeps both pages in the Tauri WebView cookie
|
|
12
|
+
* partition; the system-browser shell opener would lose the binding cookie.
|
|
13
|
+
*/
|
|
14
|
+
export function openBoundOAuthWindow(
|
|
15
|
+
openWindow: OpenOAuthWindow = (url, target) =>
|
|
16
|
+
window.open(url, target) as OAuthWindow | null,
|
|
17
|
+
): OAuthWindow {
|
|
18
|
+
const oauthWindow = openWindow("about:blank", "_blank");
|
|
19
|
+
if (!oauthWindow) {
|
|
20
|
+
throw new Error("Could not open the Google sign-in window.");
|
|
21
|
+
}
|
|
22
|
+
return oauthWindow;
|
|
23
|
+
}
|
|
@@ -2,6 +2,7 @@ use std::{
|
|
|
2
2
|
ffi::OsString,
|
|
3
3
|
path::{Path, PathBuf},
|
|
4
4
|
process::{Command, Stdio},
|
|
5
|
+
sync::atomic::{AtomicU64, Ordering},
|
|
5
6
|
};
|
|
6
7
|
|
|
7
8
|
use tauri::{AppHandle, Emitter, Manager, WebviewUrl, WebviewWindow, WebviewWindowBuilder};
|
|
@@ -13,6 +14,7 @@ use crate::state::{
|
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
const POPOVER_SHADOW_GUTTER_LOGICAL: f64 = 24.0;
|
|
17
|
+
static OAUTH_WINDOW_COUNTER: AtomicU64 = AtomicU64::new(0);
|
|
16
18
|
const POPOVER_DEFAULT_WIDTH_LOGICAL: f64 = 320.0;
|
|
17
19
|
const POPOVER_DEFAULT_HEIGHT_LOGICAL: f64 = 520.0;
|
|
18
20
|
|
|
@@ -109,6 +111,7 @@ pub fn set_capture_included(window: &WebviewWindow) {
|
|
|
109
111
|
|
|
110
112
|
pub fn build_popover_window(app: &mut tauri::App) -> Result<WebviewWindow, tauri::Error> {
|
|
111
113
|
let gutter = POPOVER_SHADOW_GUTTER_LOGICAL * 2.0;
|
|
114
|
+
let app_handle = app.handle().clone();
|
|
112
115
|
WebviewWindowBuilder::new(app, "popover", WebviewUrl::App("index.html".into()))
|
|
113
116
|
.title("Clips")
|
|
114
117
|
.inner_size(
|
|
@@ -126,6 +129,35 @@ pub fn build_popover_window(app: &mut tauri::App) -> Result<WebviewWindow, tauri
|
|
|
126
129
|
.focused(true)
|
|
127
130
|
.shadow(false)
|
|
128
131
|
.accept_first_mouse(true)
|
|
132
|
+
// Tauri does not create a native child for window.open by default.
|
|
133
|
+
// Create it here with the opener's webview configuration so Google
|
|
134
|
+
// OAuth stays in a visible child window and shares the binding cookie.
|
|
135
|
+
.on_new_window(move |url, features| {
|
|
136
|
+
let label = format!(
|
|
137
|
+
"google-oauth-{}",
|
|
138
|
+
OAUTH_WINDOW_COUNTER.fetch_add(1, Ordering::Relaxed)
|
|
139
|
+
);
|
|
140
|
+
let popup = WebviewWindowBuilder::new(&app_handle, label, WebviewUrl::External(url))
|
|
141
|
+
.title("Sign in to Clips")
|
|
142
|
+
.inner_size(520.0, 720.0)
|
|
143
|
+
.resizable(true)
|
|
144
|
+
.always_on_top(false)
|
|
145
|
+
.focused(true)
|
|
146
|
+
.window_features(features)
|
|
147
|
+
.build();
|
|
148
|
+
|
|
149
|
+
match popup {
|
|
150
|
+
Ok(window) => {
|
|
151
|
+
set_capture_excluded(&window);
|
|
152
|
+
configure_overlay_behavior(&window);
|
|
153
|
+
tauri::webview::NewWindowResponse::Create { window }
|
|
154
|
+
}
|
|
155
|
+
Err(error) => {
|
|
156
|
+
eprintln!("[clips-tray] failed to create OAuth popup: {error}");
|
|
157
|
+
tauri::webview::NewWindowResponse::Deny
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
})
|
|
129
161
|
.build()
|
|
130
162
|
}
|
|
131
163
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from "@agent-native/toolkit/ui/button";
|
|
3
|
+
import { IconCheck, IconCode, IconCopy, IconX } from "@tabler/icons-react";
|
|
4
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { formatAgentNativeDiagnostics, getAgentNativeDiagnostics, getAgentNativePackageVersions, } from "./agent-native-version.js";
|
|
6
|
+
import { writeClipboardText } from "./clipboard.js";
|
|
7
|
+
import { Dialog, DialogContent, DialogTitle } from "./components/ui/dialog.js";
|
|
8
|
+
import { useT } from "./i18n.js";
|
|
9
|
+
export function AboutAgentNativeDialog({ open, onOpenChange, }) {
|
|
10
|
+
const t = useT();
|
|
11
|
+
const [copyState, setCopyState] = useState("idle");
|
|
12
|
+
const copyResetTimer = useRef(null);
|
|
13
|
+
const packageVersions = getAgentNativePackageVersions();
|
|
14
|
+
const diagnostics = useMemo(() => formatAgentNativeDiagnostics(), []);
|
|
15
|
+
const { buildId, environment } = getAgentNativeDiagnostics();
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!open) {
|
|
18
|
+
setCopyState("idle");
|
|
19
|
+
}
|
|
20
|
+
}, [open]);
|
|
21
|
+
useEffect(() => () => {
|
|
22
|
+
if (copyResetTimer.current !== null) {
|
|
23
|
+
window.clearTimeout(copyResetTimer.current);
|
|
24
|
+
}
|
|
25
|
+
}, []);
|
|
26
|
+
const handleCopy = async () => {
|
|
27
|
+
const didCopy = await writeClipboardText(diagnostics);
|
|
28
|
+
setCopyState(didCopy ? "copied" : "failed");
|
|
29
|
+
if (copyResetTimer.current !== null) {
|
|
30
|
+
window.clearTimeout(copyResetTimer.current);
|
|
31
|
+
}
|
|
32
|
+
copyResetTimer.current = window.setTimeout(() => {
|
|
33
|
+
setCopyState("idle");
|
|
34
|
+
copyResetTimer.current = null;
|
|
35
|
+
}, 1600);
|
|
36
|
+
};
|
|
37
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { "aria-describedby": undefined, className: "max-w-md gap-5", children: [_jsxs(DialogTitle, { className: "flex items-center gap-2 text-base", children: [_jsx(IconCode, { className: "size-4 text-muted-foreground" }), t("agentChat.aboutAgentNative.title", {
|
|
38
|
+
defaultValue: "About Agent Native",
|
|
39
|
+
})] }), _jsx("div", { className: "overflow-hidden rounded-md border border-border", children: packageVersions.length > 0 ? (packageVersions.map(({ name, version }) => (_jsxs("div", { className: "flex items-center justify-between gap-4 border-b border-border px-3 py-2 last:border-b-0", children: [_jsx("span", { className: "min-w-0 truncate font-mono text-xs text-foreground", children: name }), _jsxs("span", { className: "shrink-0 font-mono text-xs text-muted-foreground", children: [_jsx("span", { className: "sr-only", children: t("agentChat.aboutAgentNative.version", {
|
|
40
|
+
defaultValue: "Version",
|
|
41
|
+
}) }), version] })] }, name)))) : (_jsxs("div", { className: "px-3 py-2 font-mono text-xs text-muted-foreground", children: ["@agent-native/core -", " ", t("agentChat.aboutAgentNative.unknown", {
|
|
42
|
+
defaultValue: "Unknown",
|
|
43
|
+
})] })) }), _jsxs("dl", { className: "grid gap-2 text-xs", children: [_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsx("dt", { className: "text-muted-foreground", children: t("agentChat.aboutAgentNative.environment", {
|
|
44
|
+
defaultValue: "Environment",
|
|
45
|
+
}) }), _jsx("dd", { className: "font-mono text-foreground", children: environment })] }), _jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsx("dt", { className: "text-muted-foreground", children: t("agentChat.aboutAgentNative.build", {
|
|
46
|
+
defaultValue: "Build",
|
|
47
|
+
}) }), _jsx("dd", { className: "max-w-[16rem] truncate font-mono text-foreground", children: buildId })] })] }), _jsxs(Button, { className: "w-full", onClick: () => void handleCopy(), type: "button", variant: "outline", children: [copyState === "copied" ? (_jsx(IconCheck, {})) : copyState === "failed" ? (_jsx(IconX, {})) : (_jsx(IconCopy, {})), copyState === "copied"
|
|
48
|
+
? t("agentChat.common.copied", { defaultValue: "Copied" })
|
|
49
|
+
: copyState === "failed"
|
|
50
|
+
? t("agentChat.recovery.copyFailed", {
|
|
51
|
+
defaultValue: "Copy failed",
|
|
52
|
+
})
|
|
53
|
+
: t("agentChat.aboutAgentNative.copyDiagnostics", {
|
|
54
|
+
defaultValue: "Copy diagnostics",
|
|
55
|
+
})] })] }) }));
|
|
56
|
+
}
|
|
@@ -187,6 +187,8 @@ export interface AgentSidebarProps {
|
|
|
187
187
|
onAgentChange?: AssistantChatProps["onAgentChange"];
|
|
188
188
|
/** Route local runtime setup through the host's native bridge. */
|
|
189
189
|
onConnectLocalRuntime?: AssistantChatProps["onConnectLocalRuntime"];
|
|
190
|
+
/** Route hosted provider setup through the host's native bridge. */
|
|
191
|
+
onConnectProvider?: AssistantChatProps["onConnectProvider"];
|
|
190
192
|
/** Bring-your-own runtime used by embedded hosts such as Electron. */
|
|
191
193
|
runtime?: AssistantChatProps["runtime"];
|
|
192
194
|
/** Explicit key for recreating an injected runtime adapter. */
|
|
@@ -258,7 +260,7 @@ export interface AgentSidebarProps {
|
|
|
258
260
|
* Wraps app content with a toggleable agent sidebar.
|
|
259
261
|
* Use AgentToggleButton in your header to open/close it.
|
|
260
262
|
*/
|
|
261
|
-
export declare function AgentSidebar({ children, emptyStateText, suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, availableAgents, availableModels, modelListLoading, selectedAgent, onAgentChange, onConnectLocalRuntime, runtime, adapterReloadKey, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position, defaultOpen, animateMobile, animateDesktop, chatViewTransition, chatViewTransitionHandoff, storageKey, openStorageKey, apiUrl, agentChatSurface, desktopIdentityUnauthenticated, desktopIdentityAuthenticated, showTabBar, suppressInlineOpenApp, composerPlaceholder, openOnChatRunning, onFullscreenRequest, scope, isolateHistoryByScope, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding, }: AgentSidebarProps): React.JSX.Element;
|
|
263
|
+
export declare function AgentSidebar({ children, emptyStateText, suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, availableAgents, availableModels, modelListLoading, selectedAgent, onAgentChange, onConnectLocalRuntime, onConnectProvider, runtime, adapterReloadKey, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position, defaultOpen, animateMobile, animateDesktop, chatViewTransition, chatViewTransitionHandoff, storageKey, openStorageKey, apiUrl, agentChatSurface, desktopIdentityUnauthenticated, desktopIdentityAuthenticated, showTabBar, suppressInlineOpenApp, composerPlaceholder, openOnChatRunning, onFullscreenRequest, scope, isolateHistoryByScope, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding, }: AgentSidebarProps): React.JSX.Element;
|
|
262
264
|
/**
|
|
263
265
|
* Focus the agent chat composer input.
|
|
264
266
|
* Opens the sidebar if closed, then focuses the text input.
|
|
@@ -1418,7 +1418,7 @@ export function AgentChatSurface({ mode = "panel", className, defaultMode = "cha
|
|
|
1418
1418
|
* Wraps app content with a toggleable agent sidebar.
|
|
1419
1419
|
* Use AgentToggleButton in your header to open/close it.
|
|
1420
1420
|
*/
|
|
1421
|
-
export function AgentSidebar({ children, emptyStateText = "How can I help you?", suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, availableAgents, availableModels, modelListLoading, selectedAgent, onAgentChange, onConnectLocalRuntime, runtime, adapterReloadKey, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position = "right", defaultOpen = false, animateMobile = true, animateDesktop = true, chatViewTransition = false, chatViewTransitionHandoff = false, storageKey, openStorageKey, apiUrl, agentChatSurface, desktopIdentityUnauthenticated, desktopIdentityAuthenticated, showTabBar = true, suppressInlineOpenApp, composerPlaceholder, openOnChatRunning = false, onFullscreenRequest, scope, isolateHistoryByScope = false, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding = false, }) {
|
|
1421
|
+
export function AgentSidebar({ children, emptyStateText = "How can I help you?", suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, availableAgents, availableModels, modelListLoading, selectedAgent, onAgentChange, onConnectLocalRuntime, onConnectProvider, runtime, adapterReloadKey, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position = "right", defaultOpen = false, animateMobile = true, animateDesktop = true, chatViewTransition = false, chatViewTransitionHandoff = false, storageKey, openStorageKey, apiUrl, agentChatSurface, desktopIdentityUnauthenticated, desktopIdentityAuthenticated, showTabBar = true, suppressInlineOpenApp, composerPlaceholder, openOnChatRunning = false, onFullscreenRequest, scope, isolateHistoryByScope = false, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding = false, }) {
|
|
1422
1422
|
const staticHostedHarnessEnabled = isHostedHarnessConfigured(injectedAgentNativeConfig().harness);
|
|
1423
1423
|
const hostedHarnessQuery = useActionQuery("get-hosted-harness-config", undefined, { enabled: staticHostedHarnessEnabled });
|
|
1424
1424
|
const hostedHarnessStatus = hostedHarnessQuery.data;
|
|
@@ -2059,7 +2059,7 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
|
|
|
2059
2059
|
? "desktop"
|
|
2060
2060
|
: undefined, "data-agent-sidebar-layout": panelLayout, "data-agent-sidebar-position": effectivePosition, "data-agent-native-hosted-harness-ui": hostedHarnessUi ? "desktop" : undefined, "data-agent-sidebar-state": panelOpen ? "open" : "closed", "data-agent-sidebar-per-app-chat": isPerAppChatSidebar ? "true" : undefined, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, "data-agent-sidebar-chat-handoff": chatViewTransitionHandoff ? "true" : undefined, style: chatViewTransition
|
|
2061
2061
|
? getAgentChatViewTransitionStyle(panelStyle)
|
|
2062
|
-
: panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, availableAgents: effectiveAvailableAgents, availableModels: availableModels, modelListLoading: modelListLoading, selectedAgent: effectiveSelectedAgent, onAgentChange: effectiveOnAgentChange, hostedHarness: hostedHarnessEnabled, onConnectLocalRuntime: onConnectLocalRuntime, runtime: runtime, adapterReloadKey: adapterReloadKey, threadFooterSlot: threadFooterSlot, apiUrl: apiUrl, agentChatSurface: agentChatSurface, desktopIdentityUnauthenticated: desktopIdentityUnauthenticated, desktopIdentityAuthenticated: desktopIdentityAuthenticated, showTabBar: effectiveShowTabBar, suppressInlineOpenApp: suppressInlineOpenApp, composerPlaceholder: composerPlaceholder, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false), onSnapTo75Percent: isMobile ? undefined : snapTo75Percent, isWideDrawer: isMobile ? false : isWideDrawer, onExitWideDrawer: isMobile ? undefined : exitWideDrawer, onFullViewRequest: onFullscreenRequest, storageKey: storageKey, scope: scope, isolateHistoryByScope: isolateHistoryByScope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync, agentPageHref: agentPageHref, allowSettingsMode: false, chatOnly: true }) }) }), showResizeHandle && isLeft && (_jsx(ResizeHandle, { position: effectivePosition, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd }))] })) : null;
|
|
2062
|
+
: panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, availableAgents: effectiveAvailableAgents, availableModels: availableModels, modelListLoading: modelListLoading, selectedAgent: effectiveSelectedAgent, onAgentChange: effectiveOnAgentChange, hostedHarness: hostedHarnessEnabled, onConnectProvider: onConnectProvider, onConnectLocalRuntime: onConnectLocalRuntime, runtime: runtime, adapterReloadKey: adapterReloadKey, threadFooterSlot: threadFooterSlot, apiUrl: apiUrl, agentChatSurface: agentChatSurface, desktopIdentityUnauthenticated: desktopIdentityUnauthenticated, desktopIdentityAuthenticated: desktopIdentityAuthenticated, showTabBar: effectiveShowTabBar, suppressInlineOpenApp: suppressInlineOpenApp, composerPlaceholder: composerPlaceholder, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false), onSnapTo75Percent: isMobile ? undefined : snapTo75Percent, isWideDrawer: isMobile ? false : isWideDrawer, onExitWideDrawer: isMobile ? undefined : exitWideDrawer, onFullViewRequest: onFullscreenRequest, storageKey: storageKey, scope: scope, isolateHistoryByScope: isolateHistoryByScope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync, agentPageHref: agentPageHref, allowSettingsMode: false, chatOnly: true }) }) }), showResizeHandle && isLeft && (_jsx(ResizeHandle, { position: effectivePosition, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd }))] })) : null;
|
|
2063
2063
|
const drawerPlaceholder = wideDrawerEnabled && !presentationMode && panelOpen ? (_jsx("div", { "aria-hidden": "true", className: "agent-sidebar-drawer-placeholder shrink-0", "data-agent-sidebar-placeholder": "true", style: { width: drawerPlaceholderWidth + 1 } })) : null;
|
|
2064
2064
|
return (_jsx(AgentSidebarOnboardingContext.Provider, { value: true, children: _jsxs(RealtimeVoiceModeProvider, { browserTabId: browserTabId, children: [showFirstRunOnboarding && (_jsx(Suspense, { fallback: null, children: _jsx(FirstRunOnboarding, {}) })), _jsxs("div", { className: "agent-sidebar-shell flex min-w-0 flex-1 h-screen overflow-hidden", "data-agent-sidebar-position": effectivePosition, "data-agent-native-hosted-harness-ui": hostedHarnessUi ? "desktop" : undefined, "data-agent-native-hosted-chat": isPerAppChatHosted ? "true" : undefined, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: [isMobile &&
|
|
2065
2065
|
!isPerAppChatHosted &&
|
|
@@ -89,8 +89,13 @@ export interface CommandMenuProps {
|
|
|
89
89
|
* multiple apps share an origin.
|
|
90
90
|
*/
|
|
91
91
|
changelogKey?: string;
|
|
92
|
+
/**
|
|
93
|
+
* Whether to show the built-in "About Agent Native" entry. Defaults to true
|
|
94
|
+
* for app-shell menus that provide a changelog; set false for local menus.
|
|
95
|
+
*/
|
|
96
|
+
showAbout?: boolean;
|
|
92
97
|
}
|
|
93
|
-
export declare function CommandMenu({ open, onOpenChange, children, renderResults, placeholder, emptyText: _emptyText, showAgentFallback, className, changelog, changelogLabel, changelogKey, }: CommandMenuProps): React.JSX.Element;
|
|
98
|
+
export declare function CommandMenu({ open, onOpenChange, children, renderResults, placeholder, emptyText: _emptyText, showAgentFallback, className, changelog, changelogLabel, changelogKey, showAbout: showAboutProp, }: CommandMenuProps): React.JSX.Element;
|
|
94
99
|
export declare namespace CommandMenu {
|
|
95
100
|
export { CommandGroup as Group };
|
|
96
101
|
export { CommandItem as Item };
|
|
@@ -16,12 +16,14 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
16
16
|
* </CommandMenu>
|
|
17
17
|
*/
|
|
18
18
|
import { Command as CommandPrimitive, CommandGroup as CommandGroupPrimitive, CommandInput as CommandInputPrimitive, CommandItem as CommandItemPrimitive, CommandList as CommandListPrimitive, CommandSeparator as CommandSeparatorPrimitive, CommandShortcut as CommandShortcutPrimitive, } from "@agent-native/toolkit/ui/command";
|
|
19
|
-
import { IconBook2, IconExternalLink, IconMessage, IconHistory, } from "@tabler/icons-react";
|
|
19
|
+
import { IconBook2, IconExternalLink, IconInfoCircle, IconMessage, IconHistory, } from "@tabler/icons-react";
|
|
20
20
|
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
21
21
|
import { parseChangelog } from "../changelog/parse.js";
|
|
22
|
+
import { AboutAgentNativeDialog } from "./AboutAgentNativeDialog.js";
|
|
22
23
|
import { sendToAgentChat } from "./agent-chat.js";
|
|
23
24
|
import { ChangelogDialog, useChangelogSeen } from "./changelog/Changelog.js";
|
|
24
25
|
import { Dialog, DialogContent, DialogTitle } from "./components/ui/dialog.js";
|
|
26
|
+
import { useT } from "./i18n.js";
|
|
25
27
|
import { cn } from "./utils.js";
|
|
26
28
|
const CommandMenuContext = createContext(null);
|
|
27
29
|
function useCommandMenuContext() {
|
|
@@ -122,15 +124,18 @@ function CommandDocsGroup({ docs, heading = "Docs" }) {
|
|
|
122
124
|
return null;
|
|
123
125
|
return (_jsx(CommandGroup, { heading: heading, children: docs.map((doc) => (_jsxs(CommandItem, { onSelect: () => openDocsHref(doc.href), keywords: [doc.title, doc.description ?? "", ...(doc.keywords ?? [])], deferSelect: false, className: "items-start py-2", children: [_jsx(IconBook2, { className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate font-medium", children: doc.title }), doc.description ? (_jsx("span", { className: "mt-0.5 block line-clamp-2 text-xs leading-snug text-muted-foreground", children: doc.description })) : null] }), _jsx(IconExternalLink, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" })] }, doc.href))) }));
|
|
124
126
|
}
|
|
125
|
-
export function CommandMenu({ open, onOpenChange, children, renderResults, placeholder = "Type a command or ask AI...", emptyText: _emptyText = "No commands found.", showAgentFallback = true, className, changelog, changelogLabel = "What's new", changelogKey, }) {
|
|
127
|
+
export function CommandMenu({ open, onOpenChange, children, renderResults, placeholder = "Type a command or ask AI...", emptyText: _emptyText = "No commands found.", showAgentFallback = true, className, changelog, changelogLabel = "What's new", changelogKey, showAbout: showAboutProp, }) {
|
|
126
128
|
const [search, setSearch] = useState("");
|
|
127
129
|
const inputRef = useRef(null);
|
|
128
130
|
const containerRef = useRef(null);
|
|
131
|
+
const t = useT();
|
|
129
132
|
// Built-in "What's new" changelog surface (only active when `changelog` is
|
|
130
133
|
// passed). The dialog is rendered alongside the menu so it survives the menu
|
|
131
134
|
// closing; the unseen dot persists per browser via localStorage.
|
|
132
135
|
const [changelogOpen, setChangelogOpen] = useState(false);
|
|
136
|
+
const [aboutOpen, setAboutOpen] = useState(false);
|
|
133
137
|
const hasChangelog = typeof changelog === "string" && changelog.trim().length > 0;
|
|
138
|
+
const showAbout = showAboutProp ?? hasChangelog;
|
|
134
139
|
const changelogEntries = useMemo(() => (hasChangelog ? parseChangelog(changelog) : []), [hasChangelog, changelog]);
|
|
135
140
|
const latestChangelogId = changelogEntries[0]?.id;
|
|
136
141
|
const { unseen: changelogUnseen, markSeen: markChangelogSeen } = useChangelogSeen(changelogKey ?? "app", latestChangelogId);
|
|
@@ -140,6 +145,11 @@ export function CommandMenu({ open, onOpenChange, children, renderResults, place
|
|
|
140
145
|
// Let the menu close before the dialog opens (avoids overlay flicker).
|
|
141
146
|
setTimeout(() => setChangelogOpen(true), 50);
|
|
142
147
|
}, [onOpenChange, markChangelogSeen]);
|
|
148
|
+
const openAbout = useCallback(() => {
|
|
149
|
+
onOpenChange(false);
|
|
150
|
+
// Let the menu close before the dialog opens (avoids overlay flicker).
|
|
151
|
+
setTimeout(() => setAboutOpen(true), 50);
|
|
152
|
+
}, [onOpenChange]);
|
|
143
153
|
// Focus input when opening; clear search while closed so reopen never renders
|
|
144
154
|
// dynamic results for the previous query.
|
|
145
155
|
useEffect(() => {
|
|
@@ -178,6 +188,36 @@ export function CommandMenu({ open, onOpenChange, children, renderResults, place
|
|
|
178
188
|
.toLowerCase()
|
|
179
189
|
.includes(search.toLowerCase());
|
|
180
190
|
const showChangelogRow = hasChangelog && changelogRowMatches;
|
|
191
|
+
const aboutLabel = t("agentChat.aboutAgentNative.title", {
|
|
192
|
+
defaultValue: "About Agent Native",
|
|
193
|
+
});
|
|
194
|
+
const aboutVersionLabel = t("agentChat.aboutAgentNative.version", {
|
|
195
|
+
defaultValue: "Version",
|
|
196
|
+
});
|
|
197
|
+
const aboutEnvironmentLabel = t("agentChat.aboutAgentNative.environment", {
|
|
198
|
+
defaultValue: "Environment",
|
|
199
|
+
});
|
|
200
|
+
const aboutBuildLabel = t("agentChat.aboutAgentNative.build", {
|
|
201
|
+
defaultValue: "Build",
|
|
202
|
+
});
|
|
203
|
+
const aboutDiagnosticsLabel = t("agentChat.aboutAgentNative.copyDiagnostics", {
|
|
204
|
+
defaultValue: "Copy diagnostics",
|
|
205
|
+
});
|
|
206
|
+
const aboutRowMatches = !search ||
|
|
207
|
+
[
|
|
208
|
+
aboutLabel,
|
|
209
|
+
"agent native",
|
|
210
|
+
aboutVersionLabel,
|
|
211
|
+
"versions",
|
|
212
|
+
"package",
|
|
213
|
+
aboutEnvironmentLabel,
|
|
214
|
+
aboutBuildLabel,
|
|
215
|
+
aboutDiagnosticsLabel,
|
|
216
|
+
]
|
|
217
|
+
.join(" ")
|
|
218
|
+
.toLowerCase()
|
|
219
|
+
.includes(search.toLowerCase());
|
|
220
|
+
const showAboutRow = showAbout && aboutRowMatches;
|
|
181
221
|
// Filter children based on search
|
|
182
222
|
const filterChildren = (nodes) => {
|
|
183
223
|
return React.Children.map(nodes, (child) => {
|
|
@@ -242,7 +282,10 @@ export function CommandMenu({ open, onOpenChange, children, renderResults, place
|
|
|
242
282
|
}, className: cn("fixed left-1/2 top-[15vh] !z-50 !max-h-none -translate-x-1/2 !translate-y-0 !gap-0 w-full max-w-lg", "rounded-lg border border-border bg-popover p-0 text-popover-foreground shadow-lg", className), style: {
|
|
243
283
|
animation: "none",
|
|
244
284
|
transition: "none",
|
|
245
|
-
}, children: [_jsx(DialogTitle, { className: "sr-only", children: placeholder }), _jsx(CommandPrimitive, { loop: true, shouldFilter: false, className: "h-auto rounded-lg", children: _jsxs(CommandMenuContext.Provider, { value: { search, onOpenChange }, children: [_jsx(CommandInputPrimitive, { ref: inputRef, value: search, onValueChange: setSearch, placeholder: placeholder }), _jsxs(CommandListPrimitive, { children: [dynamicResults, hasResults && filteredChildren, showChangelogRow && (_jsxs(_Fragment, { children: [hasResults && _jsx(CommandSeparator, {}), _jsx("div", { className: "p-1", children: _jsxs(CommandItemPrimitive, { className: "cursor-pointer gap-2 py-2", onSelect: openChangelog, children: [_jsx(IconHistory, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { children: changelogLabel }), changelogUnseen && (_jsx("span", { className: "ms-auto h-2 w-2 rounded-full bg-primary", "aria-label": "New updates available" }))] }) })] })),
|
|
285
|
+
}, children: [_jsx(DialogTitle, { className: "sr-only", children: placeholder }), _jsx(CommandPrimitive, { loop: true, shouldFilter: false, className: "h-auto rounded-lg", children: _jsxs(CommandMenuContext.Provider, { value: { search, onOpenChange }, children: [_jsx(CommandInputPrimitive, { ref: inputRef, value: search, onValueChange: setSearch, placeholder: placeholder }), _jsxs(CommandListPrimitive, { children: [dynamicResults, hasResults && filteredChildren, showChangelogRow && (_jsxs(_Fragment, { children: [hasResults && _jsx(CommandSeparator, {}), _jsx("div", { className: "p-1", children: _jsxs(CommandItemPrimitive, { className: "cursor-pointer gap-2 py-2", onSelect: openChangelog, children: [_jsx(IconHistory, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { children: changelogLabel }), changelogUnseen && (_jsx("span", { className: "ms-auto h-2 w-2 rounded-full bg-primary", "aria-label": "New updates available" }))] }) })] })), showAboutRow && (_jsxs(_Fragment, { children: [(hasResults || showChangelogRow) && _jsx(CommandSeparator, {}), _jsx("div", { className: "p-1", children: _jsxs(CommandItemPrimitive, { className: "cursor-pointer gap-2 py-2", onSelect: openAbout, children: [_jsx(IconInfoCircle, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { children: aboutLabel })] }) })] })), showAgentFallback && (_jsxs(_Fragment, { children: [(hasResults ||
|
|
286
|
+
showChangelogRow ||
|
|
287
|
+
showAboutRow ||
|
|
288
|
+
hasDynamicResults) && _jsx(CommandSeparator, {}), _jsx("div", { className: "p-1", children: _jsxs(CommandItemPrimitive, { className: "cursor-pointer gap-2 py-2", onSelect: handleSubmitToAgent, children: [_jsx(IconMessage, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { children: search.trim() ? (_jsxs(_Fragment, { children: ["Ask AI:", " ", _jsxs("span", { className: "text-muted-foreground", children: ["\"", search, "\""] })] })) : (_jsx("span", { className: "text-muted-foreground", children: "Ask AI anything..." })) }), search.trim() && (_jsx("span", { className: "ms-auto text-xs text-muted-foreground", children: "\u21B5" }))] }) })] }))] })] }) })] }) }), hasChangelog && (_jsx(ChangelogDialog, { open: changelogOpen, onOpenChange: setChangelogOpen, markdown: changelog, title: changelogLabel })), showAbout && (_jsx(AboutAgentNativeDialog, { open: aboutOpen, onOpenChange: setAboutOpen }))] }));
|
|
246
289
|
}
|
|
247
290
|
// Helper to extract text content from React children
|
|
248
291
|
function getTextContent(children) {
|
|
@@ -6,6 +6,7 @@ import { BETA_OPT_OUT_QUERY_PARAM, BETA_OPT_OUT_STORAGE_KEY, buildEnvironmentOpt
|
|
|
6
6
|
import { trackEvent } from "./analytics.js";
|
|
7
7
|
import { injectedAgentNativeConfig } from "./app-config.js";
|
|
8
8
|
import { useSession } from "./use-session.js";
|
|
9
|
+
import { cn } from "./utils.js";
|
|
9
10
|
export { BETA_OPT_OUT_DURATION_MS, BETA_OPT_OUT_QUERY_PARAM, BETA_OPT_OUT_STORAGE_KEY, buildEnvironmentOptOutUrl, buildEnvironmentUrl, resolveEnvironmentTargets, } from "../shared/environment-lanes.js";
|
|
10
11
|
export function isBuilderIoEmployee(email) {
|
|
11
12
|
return email?.trim().toLowerCase().endsWith("@builder.io") ?? false;
|
|
@@ -88,7 +89,9 @@ function EnvironmentBadgeContent({ environment, targets, }) {
|
|
|
88
89
|
const title = environment === "beta"
|
|
89
90
|
? "You're on Agent Native Beta"
|
|
90
91
|
: "You're on Agent Native Production";
|
|
91
|
-
return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { "aria-label": `Open ${title.toLowerCase()} switcher`, className: "fixed bottom-3 right-3 z-[100] h-6 min-w-0 rounded-xl
|
|
92
|
+
return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { "aria-label": `Open ${title.toLowerCase()} switcher`, className: cn("fixed bottom-3 right-3 z-[100] h-6 min-w-0 rounded-xl px-2 text-[11px] font-semibold uppercase tracking-[0.5px] shadow-sm backdrop-blur-sm", environment === "beta"
|
|
93
|
+
? "border-primary/80"
|
|
94
|
+
: "border-border/80 bg-background/95 text-foreground"), size: "sm", variant: environment === "beta" ? "default" : "outline", children: label }) }), _jsxs(PopoverContent, { align: "center", className: "w-[280px] p-5", side: "top", sideOffset: 8, children: [_jsx("div", { className: "mb-1 text-sm font-semibold leading-5", children: title }), _jsx("div", { className: "mb-4 text-sm text-muted-foreground", children: "Choose where you want to continue." }), _jsx("div", { className: "grid gap-2", children: environment === "beta" ? (_jsx(EnvironmentLink, { href: productionHref, label: "Switch to production" })) : (_jsx(EnvironmentLink, { href: betaHref, label: "Go to beta" })) })] })] }));
|
|
92
95
|
}
|
|
93
96
|
function ProductionEnvironmentBadge({ targets, }) {
|
|
94
97
|
const { session, status } = useSession();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface AgentNativePackageVersion {
|
|
2
|
+
name: string;
|
|
3
|
+
version: string;
|
|
4
|
+
}
|
|
5
|
+
export interface AgentNativeDiagnostics {
|
|
6
|
+
buildId: string;
|
|
7
|
+
environment: string;
|
|
8
|
+
packages: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
export declare function getAgentNativePackageVersions(): AgentNativePackageVersion[];
|
|
11
|
+
export declare function getAgentNativeDiagnostics(): AgentNativeDiagnostics;
|
|
12
|
+
export declare function formatAgentNativeDiagnostics(): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { injectedAgentNativeConfig } from "./app-config.js";
|
|
2
|
+
import { clientBuildId } from "./build-compatibility.js";
|
|
3
|
+
function readPackageVersions(value) {
|
|
4
|
+
if (!value || typeof value !== "object") {
|
|
5
|
+
return {};
|
|
6
|
+
}
|
|
7
|
+
return Object.fromEntries(Object.entries(value)
|
|
8
|
+
.filter(([name, version]) => name.startsWith("@agent-native/") &&
|
|
9
|
+
typeof version === "string" &&
|
|
10
|
+
version.trim().length > 0)
|
|
11
|
+
.map(([name, version]) => [name, version.trim()]));
|
|
12
|
+
}
|
|
13
|
+
function injectedPackageVersions() {
|
|
14
|
+
if (typeof __AGENT_NATIVE_PACKAGE_VERSIONS__ !== "undefined") {
|
|
15
|
+
return readPackageVersions(__AGENT_NATIVE_PACKAGE_VERSIONS__);
|
|
16
|
+
}
|
|
17
|
+
return readPackageVersions(globalThis.__AGENT_NATIVE_PACKAGE_VERSIONS__);
|
|
18
|
+
}
|
|
19
|
+
export function getAgentNativePackageVersions() {
|
|
20
|
+
return Object.entries(injectedPackageVersions())
|
|
21
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
22
|
+
.map(([name, version]) => ({ name, version }));
|
|
23
|
+
}
|
|
24
|
+
export function getAgentNativeDiagnostics() {
|
|
25
|
+
return {
|
|
26
|
+
buildId: clientBuildId() || "development",
|
|
27
|
+
environment: injectedAgentNativeConfig().deployment?.environment ?? "unknown",
|
|
28
|
+
packages: Object.fromEntries(getAgentNativePackageVersions().map(({ name, version }) => [
|
|
29
|
+
name,
|
|
30
|
+
version,
|
|
31
|
+
])),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function formatAgentNativeDiagnostics() {
|
|
35
|
+
return JSON.stringify(getAgentNativeDiagnostics(), null, 2);
|
|
36
|
+
}
|