@agent-native/core 0.79.20 → 0.79.22
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/deployment.md +133 -0
- package/corpus/core/docs/content/faq.md +1 -1
- package/corpus/core/docs/content/multi-app-workspace.md +2 -0
- package/corpus/core/docs/content/tracking.md +3 -3
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/openai-compatible-endpoint.ts +25 -0
- package/corpus/core/src/agent/engine/provider-env-vars.ts +2 -0
- package/corpus/core/src/agent/engine/registry.ts +59 -11
- package/corpus/core/src/client/FeedbackButton.tsx +11 -1
- package/corpus/core/src/client/agent-engine-key.ts +57 -10
- package/corpus/core/src/client/analytics.ts +78 -27
- package/corpus/core/src/client/blocks/library/HighlightedCode.tsx +1 -1
- package/corpus/core/src/client/index.ts +2 -0
- package/corpus/core/src/client/session-replay.ts +159 -17
- package/corpus/core/src/client/settings/SettingsPanel.tsx +119 -4
- package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +5 -0
- package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +8 -3
- package/corpus/core/src/scripts/agent-engines/test-agent-engine.ts +54 -6
- package/corpus/core/src/server/agent-engine-api-key-route.ts +83 -12
- package/corpus/core/src/server/core-routes-plugin.ts +26 -2
- package/corpus/core/src/styles/blocks.css +23 -7
- package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -1
- package/corpus/templates/analytics/app/components/layout/MobileNav.tsx +5 -10
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +22 -4
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +64 -50
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +38 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-sync.ts +89 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +138 -59
- package/corpus/templates/analytics/changelog/2026-06-27-dashboard-charts-drag-smoothly-when-rearranging-panels.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-dashboard-email-reports-still-send-when-the-live-screenshot-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-fixed-dashboard-edits-so-charts-no-longer-briefly-snap-back-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-session-replay-lists-now-show-only-signed-in-recordings-with.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-sidebar-loading-placeholders-are-visible-in-light-mode.md +6 -0
- package/corpus/templates/analytics/netlify.toml +4 -0
- package/corpus/templates/analytics/scripts/seed-session-replay.ts +1 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +1 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +120 -29
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +1 -1
- package/corpus/templates/analytics/server/lib/session-replay.ts +158 -46
- package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/assets/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +6 -0
- package/corpus/templates/clips/app/components/capture-install-options.tsx +0 -9
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +20 -4
- package/corpus/templates/clips/app/hooks/use-desktop-promo.ts +6 -2
- package/corpus/templates/clips/changelog/2026-06-27-clips-no-longer-shows-desktop-app-prompts-on-mobile-screens.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-27-desktop-storage-setup-flow.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-27-recorder-download-options-now-show-the-chrome-extension-and-.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-27-recorder-setup-mobile-capture-options.md +6 -0
- package/corpus/templates/clips/chrome-extension/package.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/sentry.ts +17 -1
- package/corpus/templates/clips/desktop/package.json +1 -0
- package/corpus/templates/clips/desktop/scripts/check-tauri-prereqs.mjs +45 -0
- package/corpus/templates/clips/desktop/src/app.tsx +32 -3
- package/corpus/templates/clips/desktop/src/lib/sentry.ts +71 -0
- package/corpus/templates/clips/desktop/src/main.tsx +2 -0
- package/corpus/templates/clips/desktop/src/styles.css +67 -0
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +2 -1
- package/corpus/templates/clips/desktop/src-tauri/build.rs +29 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +3 -0
- package/corpus/templates/clips/desktop/src-tauri/src/logfile.rs +1 -0
- package/corpus/templates/clips/desktop/src-tauri/src/sentry_report.rs +142 -0
- package/corpus/templates/clips/desktop/vite.config.ts +66 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/design/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +6 -0
- package/corpus/templates/forms/actions/export-responses.ts +3 -2
- package/corpus/templates/forms/actions/list-responses.ts +2 -1
- package/corpus/templates/forms/actions/response-insights.ts +13 -4
- package/corpus/templates/forms/changelog/2026-06-27-anonymous-feedback-no-longer-shows-internal-agent-native-ano.md +6 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +5 -8
- package/corpus/templates/forms/server/lib/integrations.ts +9 -6
- package/corpus/templates/forms/shared/submitter-email.ts +20 -0
- package/corpus/templates/forms/shared/types.ts +1 -1
- package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +49 -10
- package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +6 -0
- package/dist/agent/engine/openai-compatible-endpoint.d.ts +3 -0
- package/dist/agent/engine/openai-compatible-endpoint.d.ts.map +1 -0
- package/dist/agent/engine/openai-compatible-endpoint.js +23 -0
- package/dist/agent/engine/openai-compatible-endpoint.js.map +1 -0
- package/dist/agent/engine/provider-env-vars.d.ts +1 -0
- package/dist/agent/engine/provider-env-vars.d.ts.map +1 -1
- package/dist/agent/engine/provider-env-vars.js +1 -0
- package/dist/agent/engine/provider-env-vars.js.map +1 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +39 -12
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/client/FeedbackButton.d.ts.map +1 -1
- package/dist/client/FeedbackButton.js +6 -1
- package/dist/client/FeedbackButton.js.map +1 -1
- package/dist/client/agent-engine-key.d.ts +14 -0
- package/dist/client/agent-engine-key.d.ts.map +1 -1
- package/dist/client/agent-engine-key.js +35 -10
- package/dist/client/agent-engine-key.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +71 -24
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/blocks/library/HighlightedCode.d.ts +1 -1
- package/dist/client/blocks/library/HighlightedCode.js +1 -1
- package/dist/client/blocks/library/HighlightedCode.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/session-replay.d.ts +1 -1
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +115 -17
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +42 -6
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +7 -7
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js +4 -0
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js +5 -4
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/test-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/test-agent-engine.js +37 -5
- package/dist/scripts/agent-engines/test-agent-engine.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +5 -5
- package/dist/server/agent-engine-api-key-route.d.ts.map +1 -1
- package/dist/server/agent-engine-api-key-route.js +71 -11
- package/dist/server/agent-engine-api-key-route.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +20 -3
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/styles/blocks.css +23 -7
- package/docs/content/deployment.md +133 -0
- package/docs/content/faq.md +1 -1
- package/docs/content/multi-app-workspace.md +2 -0
- package/docs/content/tracking.md +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
use std::sync::OnceLock;
|
|
2
|
+
use std::time::Duration;
|
|
3
|
+
|
|
4
|
+
static SENTRY_GUARD: OnceLock<&'static sentry::ClientInitGuard> = OnceLock::new();
|
|
5
|
+
|
|
6
|
+
const DIRECT_DSN_ENV: [(&str, Option<&str>); 7] = [
|
|
7
|
+
(
|
|
8
|
+
"CLIPS_DESKTOP_SENTRY_DSN",
|
|
9
|
+
option_env!("CLIPS_DESKTOP_SENTRY_DSN"),
|
|
10
|
+
),
|
|
11
|
+
("TAURI_SENTRY_DSN", option_env!("TAURI_SENTRY_DSN")),
|
|
12
|
+
("SENTRY_DESKTOP_DSN", option_env!("SENTRY_DESKTOP_DSN")),
|
|
13
|
+
("SENTRY_CLIENT_DSN", option_env!("SENTRY_CLIENT_DSN")),
|
|
14
|
+
(
|
|
15
|
+
"VITE_SENTRY_CLIENT_DSN",
|
|
16
|
+
option_env!("VITE_SENTRY_CLIENT_DSN"),
|
|
17
|
+
),
|
|
18
|
+
("VITE_SENTRY_DSN", option_env!("VITE_SENTRY_DSN")),
|
|
19
|
+
("SENTRY_DSN", option_env!("SENTRY_DSN")),
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const KEY_ENV: [(&str, Option<&str>); 3] = [
|
|
23
|
+
(
|
|
24
|
+
"CLIPS_DESKTOP_SENTRY_CLIENT_KEY",
|
|
25
|
+
option_env!("CLIPS_DESKTOP_SENTRY_CLIENT_KEY"),
|
|
26
|
+
),
|
|
27
|
+
("SENTRY_CLIENT_KEY", option_env!("SENTRY_CLIENT_KEY")),
|
|
28
|
+
(
|
|
29
|
+
"VITE_SENTRY_CLIENT_KEY",
|
|
30
|
+
option_env!("VITE_SENTRY_CLIENT_KEY"),
|
|
31
|
+
),
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const PROJECT_ENV: [(&str, Option<&str>); 3] = [
|
|
35
|
+
(
|
|
36
|
+
"CLIPS_DESKTOP_SENTRY_PROJECT_ID",
|
|
37
|
+
option_env!("CLIPS_DESKTOP_SENTRY_PROJECT_ID"),
|
|
38
|
+
),
|
|
39
|
+
("SENTRY_PROJECT_ID", option_env!("SENTRY_PROJECT_ID")),
|
|
40
|
+
(
|
|
41
|
+
"VITE_SENTRY_PROJECT_ID",
|
|
42
|
+
option_env!("VITE_SENTRY_PROJECT_ID"),
|
|
43
|
+
),
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const HOST_ENV: [(&str, Option<&str>); 3] = [
|
|
47
|
+
(
|
|
48
|
+
"CLIPS_DESKTOP_SENTRY_INGEST_HOST",
|
|
49
|
+
option_env!("CLIPS_DESKTOP_SENTRY_INGEST_HOST"),
|
|
50
|
+
),
|
|
51
|
+
("SENTRY_INGEST_HOST", option_env!("SENTRY_INGEST_HOST")),
|
|
52
|
+
(
|
|
53
|
+
"VITE_SENTRY_INGEST_HOST",
|
|
54
|
+
option_env!("VITE_SENTRY_INGEST_HOST"),
|
|
55
|
+
),
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
const ENVIRONMENT_ENV: [(&str, Option<&str>); 5] = [
|
|
59
|
+
(
|
|
60
|
+
"CLIPS_DESKTOP_SENTRY_ENVIRONMENT",
|
|
61
|
+
option_env!("CLIPS_DESKTOP_SENTRY_ENVIRONMENT"),
|
|
62
|
+
),
|
|
63
|
+
("SENTRY_ENVIRONMENT", option_env!("SENTRY_ENVIRONMENT")),
|
|
64
|
+
("NETLIFY_CONTEXT", option_env!("NETLIFY_CONTEXT")),
|
|
65
|
+
("VERCEL_ENV", option_env!("VERCEL_ENV")),
|
|
66
|
+
("NODE_ENV", option_env!("NODE_ENV")),
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
pub fn init() {
|
|
70
|
+
if SENTRY_GUARD.get().is_some() {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let Some(dsn) = resolve_sentry_dsn() else {
|
|
75
|
+
return;
|
|
76
|
+
};
|
|
77
|
+
let Ok(dsn) = dsn.parse() else {
|
|
78
|
+
eprintln!("[clips-tray] ignoring invalid Sentry DSN");
|
|
79
|
+
return;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
let guard = sentry::init(sentry::ClientOptions {
|
|
83
|
+
dsn: Some(dsn),
|
|
84
|
+
environment: Some(resolve_sentry_environment().into()),
|
|
85
|
+
release: Some(format!("clips-desktop@{}", env!("CARGO_PKG_VERSION")).into()),
|
|
86
|
+
send_default_pii: false,
|
|
87
|
+
before_send: Some(std::sync::Arc::new(|mut event| {
|
|
88
|
+
event.user = None;
|
|
89
|
+
Some(event)
|
|
90
|
+
})),
|
|
91
|
+
..Default::default()
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if guard.is_enabled() {
|
|
95
|
+
sentry::configure_scope(|scope| {
|
|
96
|
+
scope.set_tag("app", "agent-native-clips");
|
|
97
|
+
scope.set_tag("template", "clips");
|
|
98
|
+
scope.set_tag("runtime", "tauri-native");
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let _ = SENTRY_GUARD.set(Box::leak(Box::new(guard)));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
pub fn flush(timeout: Duration) {
|
|
106
|
+
if let Some(guard) = SENTRY_GUARD.get() {
|
|
107
|
+
guard.close(Some(timeout));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
fn resolve_sentry_dsn() -> Option<String> {
|
|
112
|
+
if let Some(dsn) = first_env(&DIRECT_DSN_ENV) {
|
|
113
|
+
return Some(dsn);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let key = first_env(&KEY_ENV)?;
|
|
117
|
+
let project = first_env(&PROJECT_ENV)?;
|
|
118
|
+
let host = first_env(&HOST_ENV)?;
|
|
119
|
+
Some(format!("https://{key}@{host}/{project}"))
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
fn resolve_sentry_environment() -> String {
|
|
123
|
+
first_env(&ENVIRONMENT_ENV).unwrap_or_else(|| "production".to_string())
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fn first_env(values: &[(&str, Option<&str>)]) -> Option<String> {
|
|
127
|
+
for (name, embedded) in values {
|
|
128
|
+
if let Ok(value) = std::env::var(name) {
|
|
129
|
+
let trimmed = value.trim();
|
|
130
|
+
if !trimmed.is_empty() {
|
|
131
|
+
return Some(trimmed.to_string());
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if let Some(value) = embedded {
|
|
135
|
+
let trimmed = value.trim();
|
|
136
|
+
if !trimmed.is_empty() {
|
|
137
|
+
return Some(trimmed.to_string());
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
None
|
|
142
|
+
}
|
|
@@ -1,6 +1,65 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
1
5
|
import react from "@vitejs/plugin-react";
|
|
2
6
|
import { defineConfig } from "vite";
|
|
3
7
|
|
|
8
|
+
const root = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const packageJson = JSON.parse(
|
|
10
|
+
readFileSync(resolve(root, "package.json"), "utf8"),
|
|
11
|
+
) as { version?: string };
|
|
12
|
+
|
|
13
|
+
function firstNonEmpty(...values: Array<string | undefined>): string {
|
|
14
|
+
for (const value of values) {
|
|
15
|
+
const trimmed = value?.trim();
|
|
16
|
+
if (trimmed) return trimmed;
|
|
17
|
+
}
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function resolveSentryDsn(): string {
|
|
22
|
+
const direct = firstNonEmpty(
|
|
23
|
+
process.env.CLIPS_DESKTOP_SENTRY_DSN,
|
|
24
|
+
process.env.TAURI_SENTRY_DSN,
|
|
25
|
+
process.env.SENTRY_DESKTOP_DSN,
|
|
26
|
+
process.env.SENTRY_CLIENT_DSN,
|
|
27
|
+
process.env.VITE_SENTRY_CLIENT_DSN,
|
|
28
|
+
process.env.VITE_SENTRY_DSN,
|
|
29
|
+
process.env.SENTRY_DSN,
|
|
30
|
+
);
|
|
31
|
+
if (direct) return direct;
|
|
32
|
+
|
|
33
|
+
const key = firstNonEmpty(
|
|
34
|
+
process.env.CLIPS_DESKTOP_SENTRY_CLIENT_KEY,
|
|
35
|
+
process.env.SENTRY_CLIENT_KEY,
|
|
36
|
+
process.env.VITE_SENTRY_CLIENT_KEY,
|
|
37
|
+
);
|
|
38
|
+
const projectId = firstNonEmpty(
|
|
39
|
+
process.env.CLIPS_DESKTOP_SENTRY_PROJECT_ID,
|
|
40
|
+
process.env.SENTRY_PROJECT_ID,
|
|
41
|
+
process.env.VITE_SENTRY_PROJECT_ID,
|
|
42
|
+
);
|
|
43
|
+
const host = firstNonEmpty(
|
|
44
|
+
process.env.CLIPS_DESKTOP_SENTRY_INGEST_HOST,
|
|
45
|
+
process.env.SENTRY_INGEST_HOST,
|
|
46
|
+
process.env.VITE_SENTRY_INGEST_HOST,
|
|
47
|
+
);
|
|
48
|
+
return key && projectId && host ? `https://${key}@${host}/${projectId}` : "";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function resolveSentryEnvironment(): string {
|
|
52
|
+
return (
|
|
53
|
+
firstNonEmpty(
|
|
54
|
+
process.env.CLIPS_DESKTOP_SENTRY_ENVIRONMENT,
|
|
55
|
+
process.env.SENTRY_ENVIRONMENT,
|
|
56
|
+
process.env.NETLIFY_CONTEXT,
|
|
57
|
+
process.env.VERCEL_ENV,
|
|
58
|
+
process.env.NODE_ENV,
|
|
59
|
+
) || "production"
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
4
63
|
// Tauri expects the frontend to be served from a fixed port during dev.
|
|
5
64
|
// 1420 is the convention the Tauri docs use; we keep it here so
|
|
6
65
|
// `tauri dev` and `vite dev` stay in sync out of the box.
|
|
@@ -20,6 +79,13 @@ import { defineConfig } from "vite";
|
|
|
20
79
|
export default defineConfig({
|
|
21
80
|
plugins: [react()],
|
|
22
81
|
clearScreen: false,
|
|
82
|
+
define: {
|
|
83
|
+
__CLIPS_DESKTOP_SENTRY_DSN__: JSON.stringify(resolveSentryDsn()),
|
|
84
|
+
__CLIPS_DESKTOP_SENTRY_ENVIRONMENT__: JSON.stringify(
|
|
85
|
+
resolveSentryEnvironment(),
|
|
86
|
+
),
|
|
87
|
+
__CLIPS_DESKTOP_VERSION__: JSON.stringify(packageJson.version ?? "0.0.0"),
|
|
88
|
+
},
|
|
23
89
|
server: {
|
|
24
90
|
port: 1420,
|
|
25
91
|
strictPort: true,
|
|
@@ -120,7 +120,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
120
120
|
)}
|
|
121
121
|
<div
|
|
122
122
|
className={cn(
|
|
123
|
-
"agent-layout-left-drawer fixed inset-y-0 start-0 z-50 md:static md:z-auto",
|
|
123
|
+
"agent-layout-left-drawer fixed inset-y-0 start-0 z-50 transition-transform duration-200 ease-out md:static md:z-auto md:transition-none",
|
|
124
124
|
mobileSidebarOpen
|
|
125
125
|
? "translate-x-0"
|
|
126
126
|
: "-translate-x-full rtl:translate-x-full md:translate-x-0 md:rtl:translate-x-0",
|
|
@@ -6,6 +6,7 @@ import { eq, desc } from "drizzle-orm";
|
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
8
|
import { getDb, schema } from "../server/db/index.js";
|
|
9
|
+
import { publicSubmitterEmail } from "../shared/submitter-email.js";
|
|
9
10
|
|
|
10
11
|
export default defineAction({
|
|
11
12
|
description: "Export form responses to CSV or JSON file.",
|
|
@@ -36,7 +37,7 @@ export default defineAction({
|
|
|
36
37
|
const data = responses.map((r) => ({
|
|
37
38
|
id: r.id,
|
|
38
39
|
submittedAt: r.submittedAt,
|
|
39
|
-
submitterEmail: r.submitterEmail
|
|
40
|
+
submitterEmail: publicSubmitterEmail(r.submitterEmail),
|
|
40
41
|
pageUrl: r.pageUrl ?? null,
|
|
41
42
|
clientSurface: r.clientSurface ?? null,
|
|
42
43
|
...JSON.parse(r.data),
|
|
@@ -56,7 +57,7 @@ export default defineAction({
|
|
|
56
57
|
return [
|
|
57
58
|
r.id,
|
|
58
59
|
r.submittedAt,
|
|
59
|
-
r.submitterEmail ?? "",
|
|
60
|
+
publicSubmitterEmail(r.submitterEmail) ?? "",
|
|
60
61
|
r.pageUrl ?? "",
|
|
61
62
|
r.clientSurface ?? "",
|
|
62
63
|
...fields.map((f: any) => {
|
|
@@ -4,6 +4,7 @@ import { eq, desc, sql } from "drizzle-orm";
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
|
|
6
6
|
import { getDb, schema } from "../server/db/index.js";
|
|
7
|
+
import { publicSubmitterEmail } from "../shared/submitter-email.js";
|
|
7
8
|
import type { FormResponse } from "../shared/types.js";
|
|
8
9
|
|
|
9
10
|
export default defineAction({
|
|
@@ -49,7 +50,7 @@ export default defineAction({
|
|
|
49
50
|
formId: r.formId,
|
|
50
51
|
data: JSON.parse(r.data),
|
|
51
52
|
submittedAt: r.submittedAt,
|
|
52
|
-
submitterEmail: r.submitterEmail
|
|
53
|
+
submitterEmail: publicSubmitterEmail(r.submitterEmail),
|
|
53
54
|
pageUrl: r.pageUrl ?? null,
|
|
54
55
|
clientSurface: r.clientSurface ?? null,
|
|
55
56
|
})) as FormResponse[],
|
|
@@ -14,6 +14,7 @@ import { and, desc, eq, inArray, isNull, sql } from "drizzle-orm";
|
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
|
|
16
16
|
import { getDb, schema } from "../server/db/index.js";
|
|
17
|
+
import { publicSubmitterEmail } from "../shared/submitter-email.js";
|
|
17
18
|
import type {
|
|
18
19
|
FormField,
|
|
19
20
|
ResponseInsightsChartSeries,
|
|
@@ -161,7 +162,9 @@ function buildSpecificFormTable(
|
|
|
161
162
|
totalRows: number,
|
|
162
163
|
): ResponseInsightsTable {
|
|
163
164
|
const fields = safeJson<FormField[]>(form.fields, []).slice(0, 7);
|
|
164
|
-
const hasSubmitter = responses.some((row) =>
|
|
165
|
+
const hasSubmitter = responses.some((row) =>
|
|
166
|
+
publicSubmitterEmail(row.submitterEmail),
|
|
167
|
+
);
|
|
165
168
|
const columns = [
|
|
166
169
|
{ key: "submittedAt", label: "Submitted" },
|
|
167
170
|
...(hasSubmitter ? [{ key: "submitterEmail", label: "Email" }] : []),
|
|
@@ -173,7 +176,9 @@ function buildSpecificFormTable(
|
|
|
173
176
|
id: response.id,
|
|
174
177
|
submittedAt: response.submittedAt,
|
|
175
178
|
...(hasSubmitter
|
|
176
|
-
? {
|
|
179
|
+
? {
|
|
180
|
+
submitterEmail: publicSubmitterEmail(response.submitterEmail) ?? "",
|
|
181
|
+
}
|
|
177
182
|
: {}),
|
|
178
183
|
...Object.fromEntries(
|
|
179
184
|
fields.map((field) => [field.id, cleanText(data[field.id])]),
|
|
@@ -198,7 +203,9 @@ function buildAllFormsTable(
|
|
|
198
203
|
tableLimit: number,
|
|
199
204
|
totalRows: number,
|
|
200
205
|
): ResponseInsightsTable {
|
|
201
|
-
const hasSubmitter = responses.some((row) =>
|
|
206
|
+
const hasSubmitter = responses.some((row) =>
|
|
207
|
+
publicSubmitterEmail(row.submitterEmail),
|
|
208
|
+
);
|
|
202
209
|
const columns = [
|
|
203
210
|
{ key: "submittedAt", label: "Submitted" },
|
|
204
211
|
{ key: "form", label: "Form" },
|
|
@@ -210,7 +217,9 @@ function buildAllFormsTable(
|
|
|
210
217
|
formId: response.formId,
|
|
211
218
|
submittedAt: response.submittedAt,
|
|
212
219
|
form: formsById.get(response.formId)?.title ?? response.formId,
|
|
213
|
-
...(hasSubmitter
|
|
220
|
+
...(hasSubmitter
|
|
221
|
+
? { submitterEmail: publicSubmitterEmail(response.submitterEmail) ?? "" }
|
|
222
|
+
: {}),
|
|
214
223
|
summary: responseSummary(response, fieldsByForm),
|
|
215
224
|
}));
|
|
216
225
|
|
|
@@ -17,6 +17,10 @@ import {
|
|
|
17
17
|
} from "h3";
|
|
18
18
|
import { nanoid } from "nanoid";
|
|
19
19
|
|
|
20
|
+
import {
|
|
21
|
+
cleanSubmitterEmail,
|
|
22
|
+
publicSubmitterEmail,
|
|
23
|
+
} from "../../shared/submitter-email.js";
|
|
20
24
|
import type {
|
|
21
25
|
FormField,
|
|
22
26
|
FormIntegration,
|
|
@@ -42,13 +46,6 @@ function cleanMetaText(value: unknown): string | null {
|
|
|
42
46
|
return trimmed.slice(0, MAX_META_TEXT_LENGTH);
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
function cleanSubmitterEmail(value: unknown): string | null {
|
|
46
|
-
if (typeof value !== "string") return null;
|
|
47
|
-
const trimmed = value.trim();
|
|
48
|
-
if (!trimmed || trimmed.length > 320 || !trimmed.includes("@")) return null;
|
|
49
|
-
return trimmed;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
49
|
// Allowlist the client-surface hint so only known values are stored. Anything
|
|
53
50
|
// else (including spoofed direct POSTs) is dropped to NULL.
|
|
54
51
|
const KNOWN_CLIENT_SURFACES = new Set(["web", "electron", "tauri"]);
|
|
@@ -340,7 +337,7 @@ export const listResponses = defineEventHandler(async (event: H3Event) => {
|
|
|
340
337
|
formId: r.formId,
|
|
341
338
|
data: JSON.parse(r.data),
|
|
342
339
|
submittedAt: r.submittedAt,
|
|
343
|
-
submitterEmail: r.submitterEmail,
|
|
340
|
+
submitterEmail: publicSubmitterEmail(r.submitterEmail),
|
|
344
341
|
pageUrl: r.pageUrl ?? null,
|
|
345
342
|
clientSurface: r.clientSurface ?? null,
|
|
346
343
|
})) as FormResponse[],
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
ssrfSafeToolFetch,
|
|
4
4
|
} from "@agent-native/core/tools/url-safety";
|
|
5
5
|
|
|
6
|
+
import { publicSubmitterEmail } from "../../shared/submitter-email.js";
|
|
6
7
|
import type {
|
|
7
8
|
FormIntegration,
|
|
8
9
|
FormField,
|
|
@@ -155,6 +156,7 @@ function formatDebugContext(submission: SubmissionPayload): string[] {
|
|
|
155
156
|
|
|
156
157
|
/** Slack Block Kit message */
|
|
157
158
|
export function buildSlackPayload(submission: SubmissionPayload) {
|
|
159
|
+
const submitterEmail = publicSubmitterEmail(submission.submitterEmail);
|
|
158
160
|
const fieldLines = submission.fields
|
|
159
161
|
.filter((f) => submission.data[f.id] !== undefined)
|
|
160
162
|
.map((f) => {
|
|
@@ -164,8 +166,8 @@ export function buildSlackPayload(submission: SubmissionPayload) {
|
|
|
164
166
|
});
|
|
165
167
|
|
|
166
168
|
const tsContext = `Submitted <!date^${Math.floor(new Date(submission.submittedAt).getTime() / 1000)}^{date_short_pretty} at {time}|${submission.submittedAt}>`;
|
|
167
|
-
const contextText =
|
|
168
|
-
? `${tsContext} by *${
|
|
169
|
+
const contextText = submitterEmail
|
|
170
|
+
? `${tsContext} by *${submitterEmail}*`
|
|
169
171
|
: tsContext;
|
|
170
172
|
const debugContext = formatDebugContext(submission);
|
|
171
173
|
|
|
@@ -201,6 +203,7 @@ export function buildSlackPayload(submission: SubmissionPayload) {
|
|
|
201
203
|
|
|
202
204
|
/** Discord webhook embed */
|
|
203
205
|
function buildDiscordPayload(submission: SubmissionPayload) {
|
|
206
|
+
const submitterEmail = publicSubmitterEmail(submission.submitterEmail);
|
|
204
207
|
const discordFields = submission.fields
|
|
205
208
|
.filter((f) => submission.data[f.id] !== undefined)
|
|
206
209
|
.map((f) => {
|
|
@@ -208,10 +211,10 @@ function buildDiscordPayload(submission: SubmissionPayload) {
|
|
|
208
211
|
const display = Array.isArray(val) ? val.join(", ") : String(val);
|
|
209
212
|
return { name: f.label, value: display, inline: true };
|
|
210
213
|
});
|
|
211
|
-
if (
|
|
214
|
+
if (submitterEmail) {
|
|
212
215
|
discordFields.push({
|
|
213
216
|
name: "Submitted by",
|
|
214
|
-
value:
|
|
217
|
+
value: submitterEmail,
|
|
215
218
|
inline: true,
|
|
216
219
|
});
|
|
217
220
|
}
|
|
@@ -261,7 +264,7 @@ function buildGoogleSheetsPayload(submission: SubmissionPayload) {
|
|
|
261
264
|
return {
|
|
262
265
|
formTitle: submission.formTitle,
|
|
263
266
|
submittedAt: submission.submittedAt,
|
|
264
|
-
submitterEmail: submission.submitterEmail ?? "",
|
|
267
|
+
submitterEmail: publicSubmitterEmail(submission.submitterEmail) ?? "",
|
|
265
268
|
chatSessionIds: (submission.chatSessionIds ?? []).join(", "),
|
|
266
269
|
activeRunId: submission.activeRunId ?? "",
|
|
267
270
|
pageUrl: submission.pageUrl ?? "",
|
|
@@ -278,7 +281,7 @@ function buildWebhookPayload(submission: SubmissionPayload) {
|
|
|
278
281
|
formTitle: submission.formTitle,
|
|
279
282
|
responseId: submission.responseId,
|
|
280
283
|
submittedAt: submission.submittedAt,
|
|
281
|
-
submitterEmail: submission.submitterEmail
|
|
284
|
+
submitterEmail: publicSubmitterEmail(submission.submitterEmail),
|
|
282
285
|
chatSessionIds: submission.chatSessionIds ?? [],
|
|
283
286
|
activeRunId: submission.activeRunId ?? null,
|
|
284
287
|
pageUrl: submission.pageUrl ?? null,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const AGENT_NATIVE_ANONYMOUS_EMAIL_RE = /^anon-[^@]+@agent-native\.com$/i;
|
|
2
|
+
|
|
3
|
+
export function isAgentNativeAnonymousEmail(value: unknown): boolean {
|
|
4
|
+
if (typeof value !== "string") return false;
|
|
5
|
+
return AGENT_NATIVE_ANONYMOUS_EMAIL_RE.test(value.trim());
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function cleanSubmitterEmail(value: unknown): string | null {
|
|
9
|
+
if (typeof value !== "string") return null;
|
|
10
|
+
const trimmed = value.trim();
|
|
11
|
+
if (!trimmed || trimmed.length > 320 || !trimmed.includes("@")) return null;
|
|
12
|
+
if (isAgentNativeAnonymousEmail(trimmed)) return null;
|
|
13
|
+
return trimmed;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function publicSubmitterEmail(
|
|
17
|
+
value: string | null | undefined,
|
|
18
|
+
): string | null {
|
|
19
|
+
return cleanSubmitterEmail(value);
|
|
20
|
+
}
|
|
@@ -145,7 +145,7 @@ export interface FormResponse {
|
|
|
145
145
|
formId: string;
|
|
146
146
|
data: Record<string, unknown>;
|
|
147
147
|
submittedAt: string;
|
|
148
|
-
/**
|
|
148
|
+
/** Real submitter email when known; synthetic anonymous-owner ids are hidden. */
|
|
149
149
|
submitterEmail?: string | null;
|
|
150
150
|
/**
|
|
151
151
|
* URL of the page the respondent was on, forwarded by trusted embeds (e.g.
|
|
@@ -279,6 +279,7 @@
|
|
|
279
279
|
--wf-muted: var(--plan-muted, hsl(var(--muted-foreground)));
|
|
280
280
|
--wf-line: var(--plan-line, hsl(var(--border)));
|
|
281
281
|
--wf-sketch: var(--plan-muted-line, hsl(var(--border)));
|
|
282
|
+
--wf-diagram-line: var(--wf-line);
|
|
282
283
|
--wf-paper: var(--plan-document, hsl(var(--background)));
|
|
283
284
|
--wf-card: var(--plan-block, hsl(var(--card)));
|
|
284
285
|
--wf-accent: hsl(var(--ring));
|
|
@@ -306,6 +307,10 @@
|
|
|
306
307
|
line-height: 1.4;
|
|
307
308
|
}
|
|
308
309
|
|
|
310
|
+
.plan-diagram-frame[data-theme="dark"] {
|
|
311
|
+
--wf-diagram-line: color-mix(in srgb, var(--wf-sketch) 72%, var(--wf-line));
|
|
312
|
+
}
|
|
313
|
+
|
|
309
314
|
.plan-diagram-frame[data-style="sketchy"] {
|
|
310
315
|
--wf-font: var(--wf-font-hand);
|
|
311
316
|
line-height: 1.32;
|
|
@@ -321,12 +326,11 @@
|
|
|
321
326
|
.plan-diagram-frame-content {
|
|
322
327
|
width: 100%;
|
|
323
328
|
padding: 8px 0;
|
|
329
|
+
direction: inherit;
|
|
324
330
|
}
|
|
325
331
|
|
|
326
332
|
.plan-diagram-frame-content
|
|
327
|
-
>
|
|
328
|
-
[data-diagram-frame]
|
|
329
|
-
) {
|
|
333
|
+
> .diagram-panel:not([data-rough]):not([data-diagram-frame]) {
|
|
330
334
|
--rough-skip: 1;
|
|
331
335
|
background: transparent;
|
|
332
336
|
border-color: transparent;
|
|
@@ -367,7 +371,8 @@
|
|
|
367
371
|
|
|
368
372
|
.plan-diagram-frame
|
|
369
373
|
:is(.diagram-panel, .diagram-card, .diagram-node, .diagram-box) {
|
|
370
|
-
|
|
374
|
+
--rough-stroke: var(--wf-diagram-line);
|
|
375
|
+
border: 1.25px solid var(--wf-diagram-line);
|
|
371
376
|
border-radius: var(--wf-radius);
|
|
372
377
|
background: var(--wf-card);
|
|
373
378
|
}
|
|
@@ -382,7 +387,8 @@
|
|
|
382
387
|
[class*="panel"],
|
|
383
388
|
[class*="box"]
|
|
384
389
|
) {
|
|
385
|
-
|
|
390
|
+
--rough-stroke: var(--wf-diagram-line);
|
|
391
|
+
border-color: var(--wf-diagram-line) !important;
|
|
386
392
|
background: var(--wf-card) !important;
|
|
387
393
|
color: var(--wf-ink) !important;
|
|
388
394
|
}
|
|
@@ -391,6 +397,19 @@
|
|
|
391
397
|
max-width: 100%;
|
|
392
398
|
}
|
|
393
399
|
|
|
400
|
+
/* Base padding so primitive text never touches the box edge, even when an author
|
|
401
|
+
* diagram omits its own padding. The wildcard selectors mirror the theme-color
|
|
402
|
+
* rules above so every box/card/panel variant authors use is covered. Author CSS
|
|
403
|
+
* (higher specificity, scoped to the diagram instance) still overrides this when
|
|
404
|
+
* it sets padding explicitly. */
|
|
405
|
+
.plan-diagram-frame :is(.diagram-node, .diagram-box, [class*="box"]) {
|
|
406
|
+
padding: 8px 12px;
|
|
407
|
+
}
|
|
408
|
+
.plan-diagram-frame
|
|
409
|
+
:is(.diagram-card, .diagram-panel, [class*="card"], [class*="panel"]) {
|
|
410
|
+
padding: 14px 16px;
|
|
411
|
+
}
|
|
412
|
+
|
|
394
413
|
.plan-diagram-frame :is(.diagram-node, .diagram-box, .diagram-card) small {
|
|
395
414
|
display: block;
|
|
396
415
|
max-width: 100%;
|
|
@@ -402,7 +421,8 @@
|
|
|
402
421
|
|
|
403
422
|
.plan-diagram-frame
|
|
404
423
|
:is(.diagram-pill, [class*="pill"], [class*="badge"], [class*="chip"]) {
|
|
405
|
-
|
|
424
|
+
--rough-stroke: var(--wf-diagram-line);
|
|
425
|
+
border-color: var(--wf-diagram-line) !important;
|
|
406
426
|
background: var(--wf-paper) !important;
|
|
407
427
|
color: var(--wf-ink) !important;
|
|
408
428
|
}
|
|
@@ -432,15 +452,24 @@
|
|
|
432
452
|
}
|
|
433
453
|
|
|
434
454
|
.plan-diagram-frame[data-style="sketchy"] :is(.diagram-node, .diagram-box) {
|
|
435
|
-
padding-inline:
|
|
455
|
+
padding-inline: 12px;
|
|
436
456
|
}
|
|
437
457
|
|
|
438
|
-
.plan-diagram-frame
|
|
458
|
+
.plan-diagram-frame
|
|
459
|
+
:is(.diagram-pill, [class*="pill"], [class*="badge"], [class*="chip"]) {
|
|
439
460
|
display: inline-flex;
|
|
440
461
|
align-items: center;
|
|
441
|
-
|
|
462
|
+
justify-content: center;
|
|
463
|
+
/* A pill hugs its label. `fit-content` is a definite cross size, so a flex
|
|
464
|
+
* column with the default `align-items: stretch` no longer blows the pill out
|
|
465
|
+
* to full width (the number chips and short status labels stay pill-shaped).
|
|
466
|
+
* The wildcard selectors match the theme-color rules so every pill/badge/chip
|
|
467
|
+
* variant used across the docs diagrams stays pill-shaped, not a full bar. */
|
|
468
|
+
width: fit-content;
|
|
469
|
+
max-width: 100%;
|
|
470
|
+
border: 1px solid var(--wf-diagram-line);
|
|
442
471
|
border-radius: 999px;
|
|
443
|
-
padding:
|
|
472
|
+
padding: 3px 11px;
|
|
444
473
|
color: var(--wf-ink);
|
|
445
474
|
background: var(--wf-paper);
|
|
446
475
|
}
|
|
@@ -480,5 +509,15 @@
|
|
|
480
509
|
[data-rough],
|
|
481
510
|
hr
|
|
482
511
|
) {
|
|
512
|
+
border-color: color-mix(
|
|
513
|
+
in srgb,
|
|
514
|
+
var(--wf-diagram-line) 54%,
|
|
515
|
+
transparent
|
|
516
|
+
) !important;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.plan-diagram-frame[data-rough-ready]
|
|
520
|
+
.plan-diagram-frame-content
|
|
521
|
+
> .diagram-panel:not([data-rough]):not([data-diagram-frame]) {
|
|
483
522
|
border-color: transparent !important;
|
|
484
523
|
}
|
|
@@ -87,7 +87,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
87
87
|
)}
|
|
88
88
|
<div
|
|
89
89
|
className={cn(
|
|
90
|
-
"agent-layout-left-drawer fixed inset-y-0 start-0 z-50 md:static md:z-auto",
|
|
90
|
+
"agent-layout-left-drawer fixed inset-y-0 start-0 z-50 transition-transform duration-200 ease-out md:static md:z-auto md:transition-none",
|
|
91
91
|
sidebarOpen
|
|
92
92
|
? "translate-x-0"
|
|
93
93
|
: "-translate-x-full rtl:translate-x-full md:translate-x-0 md:rtl:translate-x-0",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compatible-endpoint.d.ts","sourceRoot":"","sources":["../../../src/agent/engine/openai-compatible-endpoint.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,oBAAoB,CAAC;AAEzD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAsB5D"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const OPENAI_BASE_URL_ENV_VAR = "OPENAI_BASE_URL";
|
|
2
|
+
export function normalizeOpenAiBaseUrl(value) {
|
|
3
|
+
const trimmed = value.trim();
|
|
4
|
+
if (!trimmed) {
|
|
5
|
+
throw new Error("Endpoint URL is required.");
|
|
6
|
+
}
|
|
7
|
+
let url;
|
|
8
|
+
try {
|
|
9
|
+
url = new URL(trimmed);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
throw new Error("Endpoint URL must be a valid URL.");
|
|
13
|
+
}
|
|
14
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
15
|
+
throw new Error("Endpoint URL must start with http:// or https://.");
|
|
16
|
+
}
|
|
17
|
+
if (url.username || url.password) {
|
|
18
|
+
throw new Error("Endpoint URL must not include credentials.");
|
|
19
|
+
}
|
|
20
|
+
url.hash = "";
|
|
21
|
+
return url.toString().replace(/\/+$/, "");
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=openai-compatible-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compatible-endpoint.js","sourceRoot":"","sources":["../../../src/agent/engine/openai-compatible-endpoint.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG,iBAAiB,CAAC;AAEzD,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["export const OPENAI_BASE_URL_ENV_VAR = \"OPENAI_BASE_URL\";\n\nexport function normalizeOpenAiBaseUrl(value: string): string {\n const trimmed = value.trim();\n if (!trimmed) {\n throw new Error(\"Endpoint URL is required.\");\n }\n\n let url: URL;\n try {\n url = new URL(trimmed);\n } catch {\n throw new Error(\"Endpoint URL must be a valid URL.\");\n }\n\n if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n throw new Error(\"Endpoint URL must start with http:// or https://.\");\n }\n if (url.username || url.password) {\n throw new Error(\"Endpoint URL must not include credentials.\");\n }\n\n url.hash = \"\";\n return url.toString().replace(/\\/+$/, \"\");\n}\n"]}
|
|
@@ -14,6 +14,7 @@ export interface ProviderEnvMeta {
|
|
|
14
14
|
/** Input placeholder hint shown in the LLM picker's key field */
|
|
15
15
|
placeholder: string;
|
|
16
16
|
}
|
|
17
|
+
export { OPENAI_BASE_URL_ENV_VAR } from "./openai-compatible-endpoint.js";
|
|
17
18
|
export declare const PROVIDER_ENV_META: Record<string, ProviderEnvMeta>;
|
|
18
19
|
export declare const PROVIDER_TO_ENV: Record<string, string>;
|
|
19
20
|
export declare const PROVIDER_ENV_VARS: readonly string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-env-vars.d.ts","sourceRoot":"","sources":["../../../src/agent/engine/provider-env-vars.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAoC7D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAElD,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EACf,CAAC;AAEjC,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAG1D,CAAC"}
|
|
1
|
+
{"version":3,"file":"provider-env-vars.d.ts","sourceRoot":"","sources":["../../../src/agent/engine/provider-env-vars.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAoC7D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAElD,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EACf,CAAC;AAEjC,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAG1D,CAAC"}
|