@agent-native/core 0.71.0 → 0.72.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +60 -0
- package/corpus/core/docs/content/actions.md +23 -0
- package/corpus/core/docs/content/audit-log.md +111 -0
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/action.ts +80 -1
- package/corpus/core/src/agent/production-agent.ts +27 -0
- package/corpus/core/src/agent/run-store.ts +18 -1
- package/corpus/core/src/application-state/store.ts +5 -0
- package/corpus/core/src/audit/actions/get-audit-event.ts +23 -0
- package/corpus/core/src/audit/actions/list-audit-events.ts +65 -0
- package/corpus/core/src/audit/cleanup-job.ts +100 -0
- package/corpus/core/src/audit/config.ts +91 -0
- package/corpus/core/src/audit/index.ts +43 -0
- package/corpus/core/src/audit/record.ts +143 -0
- package/corpus/core/src/audit/redact.ts +109 -0
- package/corpus/core/src/audit/store.ts +244 -0
- package/corpus/core/src/audit/types.ts +125 -0
- package/corpus/core/src/chat-threads/store.ts +10 -0
- package/corpus/core/src/client/AssistantChat.tsx +6 -0
- package/corpus/core/src/client/chat/repo-helpers.ts +38 -0
- package/corpus/core/src/db/client.ts +4 -0
- package/corpus/core/src/db/widen-columns.ts +75 -0
- package/corpus/core/src/mcp/build-server.ts +1 -0
- package/corpus/core/src/oauth-tokens/store.ts +6 -0
- package/corpus/core/src/provider-api/custom-registry.ts +8 -0
- package/corpus/core/src/resources/store.ts +10 -0
- package/corpus/core/src/scripts/runner.ts +6 -3
- package/corpus/core/src/server/action-discovery.ts +6 -0
- package/corpus/core/src/server/action-routes.ts +1 -0
- package/corpus/core/src/server/auth.ts +5 -0
- package/corpus/core/src/server/core-routes-plugin.ts +14 -0
- package/corpus/core/src/server/security-headers.ts +9 -6
- package/corpus/core/src/settings/store.ts +6 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +93 -0
- package/corpus/core/src/usage/store.ts +6 -0
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +60 -6
- package/corpus/templates/calendar/changelog/2026-06-23-added-a-heads-up-explaining-google-s-app-not-verified-screen.md +6 -0
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +20 -43
- package/corpus/templates/clips/app/components/recorder/recording-toolbar.tsx +5 -1
- package/corpus/templates/clips/app/lib/countdown-audio-cue.ts +3 -51
- package/corpus/templates/clips/changelog/2026-06-23-public-clips-now-play-inline-in-slack-connect-a-workspac.md +6 -0
- package/corpus/templates/clips/chrome-extension/PERMISSIONS.md +72 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -10
- package/corpus/templates/clips/chrome-extension/src/background.ts +34 -1
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +138 -11
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +50 -33
- package/corpus/templates/clips/chrome-extension/src/overlay.css +11 -27
- package/corpus/templates/clips/chrome-extension/src/overlay.html +7 -1
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +33 -38
- package/corpus/templates/clips/chrome-extension/src/popup.ts +6 -24
- package/corpus/templates/clips/chrome-extension/vite.config.ts +5 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +43 -3
- package/corpus/templates/clips/server/lib/media-permissions.ts +5 -1
- package/corpus/templates/clips/shared/recording-audio.ts +62 -0
- package/corpus/templates/clips/shared/recording-core.ts +94 -0
- package/dist/action.d.ts +31 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +45 -1
- package/dist/action.js.map +1 -1
- package/dist/agent/context-xray/schema.d.ts +1 -1
- package/dist/agent/observational-memory/schema.d.ts +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +28 -0
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +18 -1
- package/dist/agent/run-store.js.map +1 -1
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +5 -0
- package/dist/application-state/store.js.map +1 -1
- package/dist/audit/actions/get-audit-event.d.ts +11 -0
- package/dist/audit/actions/get-audit-event.d.ts.map +1 -0
- package/dist/audit/actions/get-audit-event.js +22 -0
- package/dist/audit/actions/get-audit-event.js.map +1 -0
- package/dist/audit/actions/list-audit-events.d.ts +22 -0
- package/dist/audit/actions/list-audit-events.d.ts.map +1 -0
- package/dist/audit/actions/list-audit-events.js +61 -0
- package/dist/audit/actions/list-audit-events.js.map +1 -0
- package/dist/audit/cleanup-job.d.ts +12 -0
- package/dist/audit/cleanup-job.d.ts.map +1 -0
- package/dist/audit/cleanup-job.js +93 -0
- package/dist/audit/cleanup-job.js.map +1 -0
- package/dist/audit/config.d.ts +30 -0
- package/dist/audit/config.d.ts.map +1 -0
- package/dist/audit/config.js +65 -0
- package/dist/audit/config.js.map +1 -0
- package/dist/audit/index.d.ts +13 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +6 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/record.d.ts +24 -0
- package/dist/audit/record.d.ts.map +1 -0
- package/dist/audit/record.js +106 -0
- package/dist/audit/record.js.map +1 -0
- package/dist/audit/redact.d.ts +28 -0
- package/dist/audit/redact.d.ts.map +1 -0
- package/dist/audit/redact.js +109 -0
- package/dist/audit/redact.js.map +1 -0
- package/dist/audit/store.d.ts +14 -0
- package/dist/audit/store.d.ts.map +1 -0
- package/dist/audit/store.js +219 -0
- package/dist/audit/store.js.map +1 -0
- package/dist/audit/types.d.ts +114 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/audit/types.js +15 -0
- package/dist/audit/types.js.map +1 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +10 -0
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +6 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/chat/repo-helpers.d.ts +16 -0
- package/dist/client/chat/repo-helpers.d.ts.map +1 -1
- package/dist/client/chat/repo-helpers.js +40 -0
- package/dist/client/chat/repo-helpers.js.map +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +3 -0
- package/dist/db/client.js.map +1 -1
- package/dist/db/widen-columns.d.ts +39 -0
- package/dist/db/widen-columns.d.ts.map +1 -0
- package/dist/db/widen-columns.js +73 -0
- package/dist/db/widen-columns.js.map +1 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +1 -0
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/oauth-tokens/store.d.ts.map +1 -1
- package/dist/oauth-tokens/store.js +6 -0
- package/dist/oauth-tokens/store.js.map +1 -1
- package/dist/provider-api/custom-registry.d.ts.map +1 -1
- package/dist/provider-api/custom-registry.js +8 -0
- package/dist/provider-api/custom-registry.js.map +1 -1
- package/dist/resources/store.d.ts.map +1 -1
- package/dist/resources/store.js +9 -0
- package/dist/resources/store.js.map +1 -1
- package/dist/scripts/runner.js +4 -3
- package/dist/scripts/runner.js.map +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +6 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +1 -0
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +5 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +13 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/security-headers.d.ts +8 -5
- package/dist/server/security-headers.d.ts.map +1 -1
- package/dist/server/security-headers.js +9 -6
- package/dist/server/security-headers.js.map +1 -1
- package/dist/settings/store.d.ts.map +1 -1
- package/dist/settings/store.js +6 -0
- package/dist/settings/store.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/audit-log/SKILL.md +93 -0
- package/dist/usage/store.d.ts.map +1 -1
- package/dist/usage/store.js +5 -0
- package/dist/usage/store.js.map +1 -1
- package/docs/content/actions.md +23 -0
- package/docs/content/audit-log.md +111 -0
- package/package.json +2 -1
- package/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +93 -0
|
@@ -46,6 +46,29 @@ const TRANSCODE_RATE_LIMIT_OVERHEAD_KBPS: f64 = 64.0;
|
|
|
46
46
|
const TRANSCODE_FRAME_RATE_LIMIT: u32 = 30;
|
|
47
47
|
const NORMALIZED_AUDIO_BITRATE_KBPS: u32 = 160;
|
|
48
48
|
const AUDIO_LOUDNESS_FILTER: &str = "loudnorm=I=-16:TP=-1.5:LRA=11";
|
|
49
|
+
// When the mic is captured alongside system audio, ScreenCaptureKit lays the
|
|
50
|
+
// two sources out as the left/right channels of a single stereo track, which
|
|
51
|
+
// plays back stuck on one speaker. Force the input to stereo (mono sources
|
|
52
|
+
// duplicate), then sum both channels into each output so audio is centered.
|
|
53
|
+
// Runs before loudnorm so level is normalized on the corrected signal. Only
|
|
54
|
+
// applied when the mic was captured — a system-audio-only recording has real
|
|
55
|
+
// stereo content that must not be flattened.
|
|
56
|
+
const AUDIO_DOWNMIX_FILTER: &str =
|
|
57
|
+
"aformat=channel_layouts=stereo,pan=stereo|FL=0.5*FL+0.5*FR|FR=0.5*FL+0.5*FR";
|
|
58
|
+
// loudnorm operates internally at 192 kHz and emits at 192 kHz; without an
|
|
59
|
+
// explicit output rate the AAC track ends up at 192 kHz and plays back slow.
|
|
60
|
+
const AUDIO_OUTPUT_SAMPLE_RATE: u32 = 48000;
|
|
61
|
+
|
|
62
|
+
// Loudness normalization, optionally preceded by the centered-stereo downmix
|
|
63
|
+
// that repairs the mic+system L/R split. Pair with `-ar AUDIO_OUTPUT_SAMPLE_RATE`
|
|
64
|
+
// so loudnorm's 192 kHz output is resampled back.
|
|
65
|
+
fn audio_filter_chain(downmix: bool) -> String {
|
|
66
|
+
if downmix {
|
|
67
|
+
format!("{AUDIO_DOWNMIX_FILTER},{AUDIO_LOUDNESS_FILTER}")
|
|
68
|
+
} else {
|
|
69
|
+
AUDIO_LOUDNESS_FILTER.to_string()
|
|
70
|
+
}
|
|
71
|
+
}
|
|
49
72
|
const NATIVE_CAPTURE_MAX_LONG_EDGE: u32 = 1280;
|
|
50
73
|
const NATIVE_CAPTURE_FPS: u32 = 24;
|
|
51
74
|
const AVCONVERT_PATH: &str = "/usr/bin/avconvert";
|
|
@@ -252,6 +275,11 @@ struct SavedNativeRecording {
|
|
|
252
275
|
height: Option<u32>,
|
|
253
276
|
bytes: u64,
|
|
254
277
|
has_audio: bool,
|
|
278
|
+
// Whether the mic was captured. Drives the centered-stereo downmix repair
|
|
279
|
+
// for the mic+system L/R split. Defaults to false for recordings queued
|
|
280
|
+
// before this field existed so their audio is left untouched.
|
|
281
|
+
#[serde(default)]
|
|
282
|
+
mic_captured: bool,
|
|
255
283
|
has_camera: bool,
|
|
256
284
|
saved_at: String,
|
|
257
285
|
last_attempt_at: Option<String>,
|
|
@@ -1746,6 +1774,7 @@ fn saved_recording_from_session(
|
|
|
1746
1774
|
height: session.height,
|
|
1747
1775
|
bytes,
|
|
1748
1776
|
has_audio,
|
|
1777
|
+
mic_captured: session.restart.include_audio,
|
|
1749
1778
|
has_camera,
|
|
1750
1779
|
saved_at: now_iso(),
|
|
1751
1780
|
last_attempt_at: None,
|
|
@@ -2211,6 +2240,7 @@ async fn upload_recording_file(
|
|
|
2211
2240
|
session.height,
|
|
2212
2241
|
Some(duration_ms),
|
|
2213
2242
|
has_audio,
|
|
2243
|
+
session.restart.include_audio,
|
|
2214
2244
|
)?;
|
|
2215
2245
|
let upload_result = upload_prepared_recording_file(
|
|
2216
2246
|
app,
|
|
@@ -2247,6 +2277,7 @@ async fn upload_saved_recording_file(
|
|
|
2247
2277
|
saved.height,
|
|
2248
2278
|
Some(saved.duration_ms),
|
|
2249
2279
|
saved.has_audio,
|
|
2280
|
+
saved.mic_captured,
|
|
2250
2281
|
)?;
|
|
2251
2282
|
let upload_result = upload_prepared_recording_file(
|
|
2252
2283
|
app,
|
|
@@ -2560,6 +2591,7 @@ fn prepare_recording_file(
|
|
|
2560
2591
|
height: Option<u32>,
|
|
2561
2592
|
duration_ms: Option<u128>,
|
|
2562
2593
|
has_audio: bool,
|
|
2594
|
+
downmix_audio: bool,
|
|
2563
2595
|
) -> Result<PreparedRecordingFile, String> {
|
|
2564
2596
|
let metadata = std::fs::metadata(path).map_err(|e| {
|
|
2565
2597
|
let diag = describe_recording_path(path);
|
|
@@ -2591,7 +2623,8 @@ fn prepare_recording_file(
|
|
|
2591
2623
|
if let Some(ffmpeg_path) = ffmpeg_path.as_deref() {
|
|
2592
2624
|
let normalized_path = normalized_recording_path(path);
|
|
2593
2625
|
let _ = std::fs::remove_file(&normalized_path);
|
|
2594
|
-
match normalize_audio_with_ffmpeg(ffmpeg_path, path, &normalized_path)
|
|
2626
|
+
match normalize_audio_with_ffmpeg(ffmpeg_path, path, &normalized_path, downmix_audio)
|
|
2627
|
+
{
|
|
2595
2628
|
Ok(()) => {
|
|
2596
2629
|
let normalized_bytes = std::fs::metadata(&normalized_path)
|
|
2597
2630
|
.map_err(|e| format!("normalized recording file missing: {e}"))?
|
|
@@ -2649,6 +2682,7 @@ fn prepare_recording_file(
|
|
|
2649
2682
|
height,
|
|
2650
2683
|
duration_ms,
|
|
2651
2684
|
has_audio,
|
|
2685
|
+
downmix_audio,
|
|
2652
2686
|
) {
|
|
2653
2687
|
Ok(()) => {
|
|
2654
2688
|
let compressed_bytes = std::fs::metadata(&compressed_path)
|
|
@@ -2967,6 +3001,7 @@ fn normalize_audio_with_ffmpeg(
|
|
|
2967
3001
|
ffmpeg_path: &str,
|
|
2968
3002
|
source: &Path,
|
|
2969
3003
|
output: &Path,
|
|
3004
|
+
downmix_audio: bool,
|
|
2970
3005
|
) -> Result<(), String> {
|
|
2971
3006
|
let audio_bitrate = format!("{NORMALIZED_AUDIO_BITRATE_KBPS}k");
|
|
2972
3007
|
let mut command = Command::new(ffmpeg_path);
|
|
@@ -2988,9 +3023,11 @@ fn normalize_audio_with_ffmpeg(
|
|
|
2988
3023
|
.arg("-b:a")
|
|
2989
3024
|
.arg(audio_bitrate)
|
|
2990
3025
|
.arg("-af")
|
|
2991
|
-
.arg(
|
|
3026
|
+
.arg(audio_filter_chain(downmix_audio))
|
|
2992
3027
|
.arg("-ac")
|
|
2993
3028
|
.arg("2")
|
|
3029
|
+
.arg("-ar")
|
|
3030
|
+
.arg(AUDIO_OUTPUT_SAMPLE_RATE.to_string())
|
|
2994
3031
|
.arg("-movflags")
|
|
2995
3032
|
.arg("+faststart")
|
|
2996
3033
|
.arg("-f")
|
|
@@ -3049,6 +3086,7 @@ fn transcode_with_ffmpeg(
|
|
|
3049
3086
|
height: Option<u32>,
|
|
3050
3087
|
duration_ms: Option<u128>,
|
|
3051
3088
|
normalize_audio: bool,
|
|
3089
|
+
downmix_audio: bool,
|
|
3052
3090
|
) -> Result<(), String> {
|
|
3053
3091
|
let mut command = Command::new(ffmpeg_path);
|
|
3054
3092
|
command
|
|
@@ -3072,7 +3110,7 @@ fn transcode_with_ffmpeg(
|
|
|
3072
3110
|
}
|
|
3073
3111
|
|
|
3074
3112
|
if normalize_audio {
|
|
3075
|
-
command.arg("-af").arg(
|
|
3113
|
+
command.arg("-af").arg(audio_filter_chain(downmix_audio));
|
|
3076
3114
|
}
|
|
3077
3115
|
|
|
3078
3116
|
let duration_rate_limit =
|
|
@@ -3111,6 +3149,8 @@ fn transcode_with_ffmpeg(
|
|
|
3111
3149
|
.arg(audio_bitrate)
|
|
3112
3150
|
.arg("-ac")
|
|
3113
3151
|
.arg("2")
|
|
3152
|
+
.arg("-ar")
|
|
3153
|
+
.arg(AUDIO_OUTPUT_SAMPLE_RATE.to_string())
|
|
3114
3154
|
.arg("-movflags")
|
|
3115
3155
|
.arg("+faststart")
|
|
3116
3156
|
.arg("-f")
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
// camera=* (not (self)) so the Clips browser extension's camera bubble — injected
|
|
2
|
+
// as a cross-origin iframe — can run on Clips pages too; (self) only allows the
|
|
3
|
+
// app's own same-origin camera. Display-capture stays same-origin. The browser
|
|
4
|
+
// still prompts for camera/mic permission per origin.
|
|
1
5
|
export const MEDIA_CAPTURE_PERMISSIONS_POLICY =
|
|
2
|
-
"camera
|
|
6
|
+
"camera=*, microphone=(self), display-capture=(self), geolocation=(), screen-wake-lock=()";
|
|
3
7
|
|
|
4
8
|
export function withMediaCapturePermissions(response: Response): Response {
|
|
5
9
|
const headers = new Headers(response.headers);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical Clips "ready" chime, shared by every recorder surface so they
|
|
3
|
+
* all sound identical:
|
|
4
|
+
* - the web app recorder (app/lib/countdown-audio-cue.ts)
|
|
5
|
+
* - the Chrome extension (chrome-extension/src/offscreen.ts)
|
|
6
|
+
* - mirrors the desktop app's start cue
|
|
7
|
+
*
|
|
8
|
+
* Framework-free Web Audio — safe to import anywhere; the functions only touch
|
|
9
|
+
* `window`/`AudioContext` when called, so importing the module is SSR-safe.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Schedule the "ready" chime on an already-running {@link AudioContext}: a soft
|
|
14
|
+
* rising two-note (D5 → A5) with a faint high shimmer (A6). Each voice has a
|
|
15
|
+
* fast attack and a smooth exponential tail so it reads as a gentle
|
|
16
|
+
* confirmation rather than a harsh beep. Kept under ~380ms so it lands cleanly
|
|
17
|
+
* just as capture begins. The caller owns the context lifecycle; resolves once
|
|
18
|
+
* the last voice has finished.
|
|
19
|
+
*/
|
|
20
|
+
export function scheduleReadyChime(ctx: AudioContext): Promise<void> {
|
|
21
|
+
return new Promise<void>((resolve) => {
|
|
22
|
+
const t0 = ctx.currentTime + 0.005;
|
|
23
|
+
const voices = [
|
|
24
|
+
{ freq: 587.33, at: 0.0, dur: 0.22, peak: 0.06 }, // D5
|
|
25
|
+
{ freq: 880.0, at: 0.06, dur: 0.26, peak: 0.075 }, // A5
|
|
26
|
+
{ freq: 1760.0, at: 0.065, dur: 0.14, peak: 0.02 }, // A6 shimmer
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
let lastStop = t0;
|
|
30
|
+
for (const voice of voices) {
|
|
31
|
+
const startAt = t0 + voice.at;
|
|
32
|
+
const stopAt = startAt + voice.dur;
|
|
33
|
+
lastStop = Math.max(lastStop, stopAt);
|
|
34
|
+
|
|
35
|
+
const oscillator = ctx.createOscillator();
|
|
36
|
+
oscillator.type = "sine";
|
|
37
|
+
oscillator.frequency.setValueAtTime(voice.freq, startAt);
|
|
38
|
+
|
|
39
|
+
const gain = ctx.createGain();
|
|
40
|
+
gain.gain.setValueAtTime(0.0001, startAt);
|
|
41
|
+
gain.gain.exponentialRampToValueAtTime(voice.peak, startAt + 0.012);
|
|
42
|
+
gain.gain.exponentialRampToValueAtTime(0.0001, stopAt);
|
|
43
|
+
|
|
44
|
+
oscillator.connect(gain);
|
|
45
|
+
gain.connect(ctx.destination);
|
|
46
|
+
|
|
47
|
+
oscillator.start(startAt);
|
|
48
|
+
oscillator.stop(stopAt + 0.02);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let resolved = false;
|
|
52
|
+
const finish = (): void => {
|
|
53
|
+
if (resolved) return;
|
|
54
|
+
resolved = true;
|
|
55
|
+
resolve();
|
|
56
|
+
};
|
|
57
|
+
window.setTimeout(
|
|
58
|
+
finish,
|
|
59
|
+
Math.ceil((lastStop - ctx.currentTime) * 1000) + 60,
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-agnostic recording primitives shared by BOTH recorders:
|
|
3
|
+
* - the web app recorder (app/components/recorder/recorder-engine.ts)
|
|
4
|
+
* - the Chrome extension (chrome-extension/src/offscreen.ts)
|
|
5
|
+
*
|
|
6
|
+
* Keep this free of React, chrome.*, Node-only APIs, and any DOM beyond the
|
|
7
|
+
* media types (MediaRecorder, URLSearchParams) so both build targets — the
|
|
8
|
+
* Vite app build and the extension's separate Vite build — can import it.
|
|
9
|
+
*
|
|
10
|
+
* The two recorders intentionally keep their own *orchestration* and *upload
|
|
11
|
+
* strategy* (the extension streams each timeslice chunk from an offscreen
|
|
12
|
+
* document that survives navigation; the web app assembles + slices on stop with
|
|
13
|
+
* retry/compression). What MUST stay identical is the on-the-wire contract with
|
|
14
|
+
* the server's chunk-upload route and the MediaRecorder codec choice — that's
|
|
15
|
+
* what lives here.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** MediaRecorder codecs to try, best-supported first.
|
|
19
|
+
*
|
|
20
|
+
* vp8 is listed before vp9 because some display-capture streams report vp9
|
|
21
|
+
* support but reject the encoder configuration; vp8 is the most broadly
|
|
22
|
+
* accepted. MP4/avc1 is the Safari/WebKit fallback. */
|
|
23
|
+
export function pickMimeTypeCandidates(): string[] {
|
|
24
|
+
return [
|
|
25
|
+
"video/webm;codecs=vp8,opus",
|
|
26
|
+
"video/webm;codecs=vp9,opus",
|
|
27
|
+
"video/webm;codecs=vp8",
|
|
28
|
+
"video/webm;codecs=vp9",
|
|
29
|
+
"video/webm",
|
|
30
|
+
"video/mp4;codecs=avc1",
|
|
31
|
+
"video/mp4",
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** First supported codec from {@link pickMimeTypeCandidates}, or "" to let the
|
|
36
|
+
* browser pick its own default (callers should treat "" as "omit mimeType"). */
|
|
37
|
+
export function pickMimeType(): string {
|
|
38
|
+
if (typeof MediaRecorder === "undefined") return "video/webm";
|
|
39
|
+
for (const type of pickMimeTypeCandidates()) {
|
|
40
|
+
try {
|
|
41
|
+
if (MediaRecorder.isTypeSupported(type)) return type;
|
|
42
|
+
} catch {
|
|
43
|
+
// isTypeSupported can throw on some builds — treat as unsupported.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Query params understood by the chunk-upload route
|
|
50
|
+
* (`/api/uploads/:id/chunk`). This is the on-the-wire contract — the route in
|
|
51
|
+
* `server/routes/api/uploads/[recordingId]/chunk.post.ts` reads exactly these. */
|
|
52
|
+
export type ChunkUploadParams = {
|
|
53
|
+
index: number;
|
|
54
|
+
total?: number;
|
|
55
|
+
isFinal?: boolean;
|
|
56
|
+
mimeType?: string;
|
|
57
|
+
durationMs?: number;
|
|
58
|
+
width?: number;
|
|
59
|
+
height?: number;
|
|
60
|
+
hasAudio?: boolean;
|
|
61
|
+
hasCamera?: boolean;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Encode {@link ChunkUploadParams} as the chunk-upload query string. Booleans
|
|
65
|
+
* become `1`/`0` and `durationMs` is rounded — matching what the route parses. */
|
|
66
|
+
export function chunkUploadQuery(params: ChunkUploadParams): string {
|
|
67
|
+
const q = new URLSearchParams();
|
|
68
|
+
q.set("index", String(params.index));
|
|
69
|
+
if (params.total !== undefined) q.set("total", String(params.total));
|
|
70
|
+
q.set("isFinal", params.isFinal ? "1" : "0");
|
|
71
|
+
if (params.mimeType) q.set("mimeType", params.mimeType);
|
|
72
|
+
if (params.durationMs !== undefined) {
|
|
73
|
+
q.set("durationMs", String(Math.round(params.durationMs)));
|
|
74
|
+
}
|
|
75
|
+
if (params.width !== undefined) q.set("width", String(params.width));
|
|
76
|
+
if (params.height !== undefined) q.set("height", String(params.height));
|
|
77
|
+
if (params.hasAudio !== undefined) {
|
|
78
|
+
q.set("hasAudio", params.hasAudio ? "1" : "0");
|
|
79
|
+
}
|
|
80
|
+
if (params.hasCamera !== undefined) {
|
|
81
|
+
q.set("hasCamera", params.hasCamera ? "1" : "0");
|
|
82
|
+
}
|
|
83
|
+
return q.toString();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Full chunk-upload URL: `<chunkBaseUrl>?<encoded params>`. `chunkBaseUrl` is
|
|
87
|
+
* the per-recording endpoint (e.g. `/api/uploads/<id>/chunk` or its absolute
|
|
88
|
+
* form) with no existing query string. */
|
|
89
|
+
export function chunkUploadUrl(
|
|
90
|
+
chunkBaseUrl: string,
|
|
91
|
+
params: ChunkUploadParams,
|
|
92
|
+
): string {
|
|
93
|
+
return `${chunkBaseUrl}?${chunkUploadQuery(params)}`;
|
|
94
|
+
}
|
package/dist/action.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentChatAttachment, AgentChatEvent } from "./agent/types.js";
|
|
2
2
|
import { type ActionChatUIConfig } from "./action-ui.js";
|
|
3
|
+
import type { ActionAuditConfig } from "./audit/types.js";
|
|
3
4
|
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
4
5
|
/**
|
|
5
6
|
* How an action's `run` was invoked. Tagged at each dispatch site so the action
|
|
@@ -66,6 +67,21 @@ export interface ActionRunContext {
|
|
|
66
67
|
* attaching an `"abort"` listener is always safe.
|
|
67
68
|
*/
|
|
68
69
|
signal?: AbortSignal;
|
|
70
|
+
/**
|
|
71
|
+
* Name of the action being invoked (the registry key, e.g.
|
|
72
|
+
* `delete-recording`). Set at each dispatch site so cross-cutting concerns —
|
|
73
|
+
* notably the audit log — can attribute the call. `undefined` for direct
|
|
74
|
+
* programmatic `run()` calls that bypass the dispatcher.
|
|
75
|
+
*/
|
|
76
|
+
actionName?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Agent conversation thread + turn that triggered this call, populated only
|
|
79
|
+
* inside the agent tool loop (`caller: "tool"`). Lets the audit log link a
|
|
80
|
+
* mutation to the specific agent run/turn that caused it. `undefined` on
|
|
81
|
+
* every human/programmatic surface.
|
|
82
|
+
*/
|
|
83
|
+
threadId?: string;
|
|
84
|
+
turnId?: string;
|
|
69
85
|
}
|
|
70
86
|
export interface AgentActionStopOptions {
|
|
71
87
|
/** Optional stable code surfaced in run metadata and tests. */
|
|
@@ -315,6 +331,14 @@ interface DefineActionWithSchema<TSchema extends StandardSchemaV1, TReturn = any
|
|
|
315
331
|
* as "approval required" (fail closed).
|
|
316
332
|
*/
|
|
317
333
|
needsApproval?: boolean | ((args: StandardSchemaV1.InferOutput<TSchema>, ctx?: ActionRunContext) => boolean | Promise<boolean>);
|
|
334
|
+
/**
|
|
335
|
+
* Audit-log configuration. **Default-on for mutating actions** — you only
|
|
336
|
+
* need this to tune capture: declare the mutated `target` (so the change
|
|
337
|
+
* shows up in the owner's audit trail) and/or a `summary`, opt a read-only
|
|
338
|
+
* action in via `onRead`, or opt a noisy action out via `enabled: false`.
|
|
339
|
+
* See the `audit-log` skill.
|
|
340
|
+
*/
|
|
341
|
+
audit?: ActionAuditConfig;
|
|
318
342
|
}
|
|
319
343
|
interface DefineActionWithParams<TParams extends Record<string, ParameterSchema> | undefined = Record<string, ParameterSchema> | undefined, TReturn = any> {
|
|
320
344
|
description: string;
|
|
@@ -362,6 +386,9 @@ interface DefineActionWithParams<TParams extends Record<string, ParameterSchema>
|
|
|
362
386
|
/** Opt-in human-in-the-loop approval gate (default off). See the schema
|
|
363
387
|
* overload above for full semantics. */
|
|
364
388
|
needsApproval?: boolean | ((args: InferParams<TParams>, ctx?: ActionRunContext) => boolean | Promise<boolean>);
|
|
389
|
+
/** Audit-log configuration (default-on for mutations). See the schema
|
|
390
|
+
* overload above and the `audit-log` skill. */
|
|
391
|
+
audit?: ActionAuditConfig;
|
|
365
392
|
}
|
|
366
393
|
/**
|
|
367
394
|
* Opaque typed wrapper returned by `defineAction`. The type parameters carry
|
|
@@ -406,6 +433,10 @@ export interface ActionDefinition<TInput, TReturn> {
|
|
|
406
433
|
* agent loop emits `approval_required` and pauses instead of executing this
|
|
407
434
|
* action until a human approves the specific call. */
|
|
408
435
|
readonly needsApproval?: boolean | ((args: TInput, ctx?: ActionRunContext) => boolean | Promise<boolean>);
|
|
436
|
+
/** Resolved audit-log configuration. Present only when the caller passed
|
|
437
|
+
* `audit`. The audit capture wrapper is baked into `run`; this field is for
|
|
438
|
+
* introspection. */
|
|
439
|
+
readonly audit?: ActionAuditConfig;
|
|
409
440
|
}
|
|
410
441
|
/**
|
|
411
442
|
* Define an agent action. Place in `actions/` directory — auto-discovered by the framework.
|
package/dist/action.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,mBAAmB,EACnB,cAAc,EACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEhF;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACvC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,mCAAmC;IACnC,MAAM,EAAE,YAAY,CAAC;IACrB;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACpC;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"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"}
|
package/dist/action.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { normalizeActionChatUIConfig, } from "./action-ui.js";
|
|
2
|
+
import { normalizeAuditConfig, resolveAuditAttach } from "./audit/config.js";
|
|
2
3
|
/**
|
|
3
4
|
* Throw from an action when the agent should stop the current turn instead of
|
|
4
5
|
* feeding the failure back to the model for another retry.
|
|
@@ -74,6 +75,15 @@ export function defineAction(options) {
|
|
|
74
75
|
: inferredReadOnly
|
|
75
76
|
? true
|
|
76
77
|
: undefined;
|
|
78
|
+
// Audit: wrap the validated run so every mutating call records an audit
|
|
79
|
+
// event (who/what/when/from-where, and for the agent which run). Default-on
|
|
80
|
+
// for mutations; read-only actions opt in via `audit.onRead`. The wrapper
|
|
81
|
+
// lazily imports the DB-touching recorder so `action.ts` keeps no static DB
|
|
82
|
+
// dependency.
|
|
83
|
+
const auditConfig = normalizeAuditConfig(options.audit);
|
|
84
|
+
const finalRun = resolveAuditAttach(auditConfig, readOnly)
|
|
85
|
+
? wrapRunWithAudit(run, auditConfig)
|
|
86
|
+
: run;
|
|
77
87
|
// toolCallable: thread through whatever the caller declared. We DO NOT
|
|
78
88
|
// default to `true` here — the absence of an explicit field is meaningful
|
|
79
89
|
// to the tools bridge: it lets us emit a one-shot warning when an action
|
|
@@ -122,7 +132,7 @@ export function defineAction(options) {
|
|
|
122
132
|
description: options.description,
|
|
123
133
|
parameters: toolParameters,
|
|
124
134
|
},
|
|
125
|
-
run,
|
|
135
|
+
run: finalRun,
|
|
126
136
|
...(hasSchema ? { schema: options.schema } : {}),
|
|
127
137
|
...(options.http !== undefined ? { http: options.http } : {}),
|
|
128
138
|
...(typeof options.requiresAuth === "boolean"
|
|
@@ -149,6 +159,40 @@ export function defineAction(options) {
|
|
|
149
159
|
typeof options.needsApproval === "function"
|
|
150
160
|
? { needsApproval: options.needsApproval }
|
|
151
161
|
: {}),
|
|
162
|
+
...(auditConfig ? { audit: auditConfig } : {}),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Wrap an action's (already input/output-validated) run so each call records an
|
|
167
|
+
* audit event after it resolves — on success and on error. Best-effort: the
|
|
168
|
+
* recorder swallows its own failures and the original result/throw is always
|
|
169
|
+
* preserved, so auditing can never change an action's behavior. The DB-touching
|
|
170
|
+
* recorder is imported lazily so merely defining an action pulls in no DB code.
|
|
171
|
+
*/
|
|
172
|
+
function wrapRunWithAudit(run, auditConfig) {
|
|
173
|
+
return async function auditedRun(args, ctx) {
|
|
174
|
+
let result;
|
|
175
|
+
let error;
|
|
176
|
+
let threw = false;
|
|
177
|
+
try {
|
|
178
|
+
result = await run(args, ctx);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
error = err;
|
|
182
|
+
threw = true;
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
const { recordActionAudit } = await import("./audit/record.js");
|
|
186
|
+
await recordActionAudit(threw
|
|
187
|
+
? { config: auditConfig, args, ctx, status: "error", error }
|
|
188
|
+
: { config: auditConfig, args, ctx, status: "success", result });
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Recorder failed to load/run — never affect the action.
|
|
192
|
+
}
|
|
193
|
+
if (threw)
|
|
194
|
+
throw error;
|
|
195
|
+
return result;
|
|
152
196
|
};
|
|
153
197
|
}
|
|
154
198
|
// ---------------------------------------------------------------------------
|