@agent-native/core 0.76.12 → 0.76.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +7 -4
- package/corpus/templates/clips/app/components/recorder/camera-visualizer.tsx +88 -10
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +64 -0
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +94 -9
- package/corpus/templates/clips/app/lib/camera-blur.ts +341 -0
- package/corpus/templates/clips/app/lib/camera-composite.ts +6 -1
- package/corpus/templates/clips/app/lib/recorder-preferences.ts +15 -0
- package/corpus/templates/clips/app/routes/record.tsx +13 -0
- package/corpus/templates/clips/desktop/src/app.tsx +101 -69
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +109 -11
- package/corpus/templates/clips/desktop/src/styles.css +19 -4
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +143 -86
- package/corpus/templates/clips/package.json +1 -0
- package/corpus/templates/clips/vite.config.ts +38 -1
- package/dist/agent/production-agent.d.ts +7 -4
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +7 -4
- package/dist/agent/production-agent.js.map +1 -1
- package/package.json +1 -1
|
@@ -41,7 +41,7 @@ pub async fn native_speech_start(
|
|
|
41
41
|
// contextual_strings (personal vocabulary) is staged separately via
|
|
42
42
|
// `native_speech_set_vocabulary` so mic metadata can flow through
|
|
43
43
|
// meeting capture without coupling vocabulary into that path.
|
|
44
|
-
macos::native_speech_start_impl(app, locale, mic_device_id, mic_device_label)
|
|
44
|
+
macos::native_speech_start_impl(app, locale, mic_device_id, mic_device_label)
|
|
45
45
|
}
|
|
46
46
|
#[cfg(not(target_os = "macos"))]
|
|
47
47
|
{
|
|
@@ -85,7 +85,7 @@ pub async fn native_speech_request_permission() -> Result<bool, String> {
|
|
|
85
85
|
pub async fn native_speech_stop(app: AppHandle) -> Result<(), String> {
|
|
86
86
|
#[cfg(target_os = "macos")]
|
|
87
87
|
{
|
|
88
|
-
macos::native_speech_stop_impl(app)
|
|
88
|
+
macos::native_speech_stop_impl(app)
|
|
89
89
|
}
|
|
90
90
|
#[cfg(not(target_os = "macos"))]
|
|
91
91
|
{
|
|
@@ -98,7 +98,7 @@ pub async fn native_speech_stop(app: AppHandle) -> Result<(), String> {
|
|
|
98
98
|
pub async fn native_speech_cancel(app: AppHandle) -> Result<(), String> {
|
|
99
99
|
#[cfg(target_os = "macos")]
|
|
100
100
|
{
|
|
101
|
-
macos::native_speech_cancel_impl(app)
|
|
101
|
+
macos::native_speech_cancel_impl(app)
|
|
102
102
|
}
|
|
103
103
|
#[cfg(not(target_os = "macos"))]
|
|
104
104
|
{
|
|
@@ -112,7 +112,7 @@ pub(crate) mod macos {
|
|
|
112
112
|
use std::ffi::c_void;
|
|
113
113
|
use std::mem::size_of;
|
|
114
114
|
use std::ptr::NonNull;
|
|
115
|
-
use std::sync::atomic::{AtomicBool, Ordering};
|
|
115
|
+
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
|
116
116
|
use std::sync::{Arc, Mutex, OnceLock};
|
|
117
117
|
|
|
118
118
|
use block2::{RcBlock, StackBlock};
|
|
@@ -163,6 +163,11 @@ pub(crate) mod macos {
|
|
|
163
163
|
/// Set by `stop()` so the result handler suppresses further partials
|
|
164
164
|
/// but still emits the final transcript when it arrives.
|
|
165
165
|
stopped: Arc<AtomicBool>,
|
|
166
|
+
/// Guards against double-removal of the audio tap. `removeTapOnBus`
|
|
167
|
+
/// throws NSException (aborting the process) if called when no tap is
|
|
168
|
+
/// installed; we swap this to false on the first removal and skip
|
|
169
|
+
/// subsequent calls.
|
|
170
|
+
tap_installed: AtomicBool,
|
|
166
171
|
}
|
|
167
172
|
|
|
168
173
|
// SAFETY: see the doc comment on `SpeechSession`. We never alias the
|
|
@@ -177,6 +182,14 @@ pub(crate) mod macos {
|
|
|
177
182
|
SLOT.get_or_init(|| Mutex::new(None))
|
|
178
183
|
}
|
|
179
184
|
|
|
185
|
+
/// Bumped at the start of every `native_speech_start_impl` call. The
|
|
186
|
+
/// auto-restart thread captures the value at decision time and skips the
|
|
187
|
+
/// restart if a newer session has since been requested.
|
|
188
|
+
fn session_generation() -> &'static AtomicU64 {
|
|
189
|
+
static GEN: OnceLock<AtomicU64> = OnceLock::new();
|
|
190
|
+
GEN.get_or_init(|| AtomicU64::new(0))
|
|
191
|
+
}
|
|
192
|
+
|
|
180
193
|
#[derive(Serialize, Clone)]
|
|
181
194
|
struct PartialPayload {
|
|
182
195
|
text: String,
|
|
@@ -475,9 +488,16 @@ pub(crate) mod macos {
|
|
|
475
488
|
// message-thread-safe per Apple's docs. `inputNode` returns a
|
|
476
489
|
// singleton already retained by the engine; both calls are
|
|
477
490
|
// fire-and-forget and have no return value.
|
|
491
|
+
//
|
|
492
|
+
// Guard against double-removal: `removeTapOnBus` throws NSException
|
|
493
|
+
// (which Rust cannot catch, aborting the process) when called on a
|
|
494
|
+
// node that has no tap installed. The swap ensures only the first
|
|
495
|
+
// caller executes the remove.
|
|
478
496
|
unsafe {
|
|
479
|
-
|
|
480
|
-
|
|
497
|
+
if session.tap_installed.swap(false, Ordering::SeqCst) {
|
|
498
|
+
let input = session.engine.inputNode();
|
|
499
|
+
input.removeTapOnBus(0);
|
|
500
|
+
}
|
|
481
501
|
if session.engine.isRunning() {
|
|
482
502
|
session.engine.stop();
|
|
483
503
|
}
|
|
@@ -509,6 +529,18 @@ pub(crate) mod macos {
|
|
|
509
529
|
}
|
|
510
530
|
}
|
|
511
531
|
|
|
532
|
+
/// Benign end-of-utterance errors from SFSpeechRecognizer allow auto-restart;
|
|
533
|
+
/// config/auth errors do not. Keys off the stable NSError domain + code rather
|
|
534
|
+
/// than localizedDescription, which is locale-dependent.
|
|
535
|
+
///
|
|
536
|
+
/// kAFAssistantErrorDomain codes (internal but stable across macOS versions):
|
|
537
|
+
/// 203 — no speech detected
|
|
538
|
+
/// 1110 — recognition request timed out
|
|
539
|
+
fn is_transient_recognizer_error(err: &NSError) -> bool {
|
|
540
|
+
let domain: Retained<NSString> = unsafe { objc2::msg_send![err, domain] };
|
|
541
|
+
domain.to_string() == "kAFAssistantErrorDomain" && matches!(err.code(), 203 | 1110)
|
|
542
|
+
}
|
|
543
|
+
|
|
512
544
|
/// Pending personal-vocabulary list staged by
|
|
513
545
|
/// `native_speech_set_vocabulary`. Consumed (taken) by the next
|
|
514
546
|
/// `native_speech_start_impl` call.
|
|
@@ -530,19 +562,19 @@ pub(crate) mod macos {
|
|
|
530
562
|
.unwrap_or_default()
|
|
531
563
|
}
|
|
532
564
|
|
|
533
|
-
pub
|
|
565
|
+
pub fn native_speech_start_impl(
|
|
534
566
|
app: AppHandle,
|
|
535
567
|
locale: Option<String>,
|
|
536
568
|
mic_device_id: Option<String>,
|
|
537
569
|
mic_device_label: Option<String>,
|
|
538
570
|
) -> Result<(), String> {
|
|
539
|
-
|
|
571
|
+
// Bump the generation so any pending auto-restart for the previous
|
|
572
|
+
// session's transient error will see the counter has changed and abort.
|
|
573
|
+
let my_gen = session_generation().fetch_add(1, Ordering::SeqCst) + 1;
|
|
574
|
+
|
|
575
|
+
let contextual_strings = {
|
|
540
576
|
let v = take_pending_vocabulary();
|
|
541
|
-
|
|
542
|
-
None
|
|
543
|
-
} else {
|
|
544
|
-
Some(v)
|
|
545
|
-
}
|
|
577
|
+
(!v.is_empty()).then_some(v)
|
|
546
578
|
};
|
|
547
579
|
// Cancel any prior session first — there's only one mic tap per input
|
|
548
580
|
// node, and we want a deterministic state going in.
|
|
@@ -597,16 +629,12 @@ pub(crate) mod macos {
|
|
|
597
629
|
mic_device_label.as_deref(),
|
|
598
630
|
)?;
|
|
599
631
|
let input_node = unsafe { engine.inputNode() };
|
|
600
|
-
//
|
|
601
|
-
//
|
|
602
|
-
//
|
|
603
|
-
//
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
// speaks but SFSpeechRecognizer reports "No speech detected". Mirrors
|
|
607
|
-
// the working `start_raw_mic_capture` ordering.
|
|
608
|
-
unsafe { engine.prepare() };
|
|
609
|
-
let format = unsafe { input_node.outputFormatForBus(0) };
|
|
632
|
+
// `prepare()` must run after pinning the device so the AUHAL adopts
|
|
633
|
+
// the new hardware format before we install a tap. It can throw
|
|
634
|
+
// NSException when a Bluetooth device (e.g. AirPods) is mid-SCO↔A2DP
|
|
635
|
+
// codec switch — catch it and surface as a recoverable Rust error.
|
|
636
|
+
objc2::exception::catch(std::panic::AssertUnwindSafe(|| unsafe { engine.prepare() }))
|
|
637
|
+
.map_err(|e| format!("AVAudioEngine prepare threw: {e:?}"))?;
|
|
610
638
|
|
|
611
639
|
// Install a tap that forwards every PCM buffer into the recognition
|
|
612
640
|
// request. The tap callback runs on the realtime audio thread —
|
|
@@ -657,30 +685,33 @@ pub(crate) mod macos {
|
|
|
657
685
|
dyn Fn(std::ptr::NonNull<AVAudioPCMBuffer>, std::ptr::NonNull<AVAudioTime>)
|
|
658
686
|
+ 'static,
|
|
659
687
|
> = (&*tap_block) as *const _ as *mut _;
|
|
660
|
-
|
|
688
|
+
// `installTapOnBus` throws NSException if the hardware is
|
|
689
|
+
// unavailable. Catch it so we return a clean Err instead of
|
|
690
|
+
// aborting the process.
|
|
691
|
+
objc2::exception::catch(std::panic::AssertUnwindSafe(|| unsafe {
|
|
661
692
|
input_node.installTapOnBus_bufferSize_format_block(
|
|
662
|
-
0,
|
|
663
|
-
|
|
664
|
-
Some(&format),
|
|
693
|
+
0, 1024,
|
|
694
|
+
None, // use hardware's current format — avoids SCO↔A2DP stale-format race
|
|
665
695
|
block_ptr,
|
|
666
696
|
);
|
|
667
|
-
}
|
|
697
|
+
}))
|
|
698
|
+
.map_err(|e| format!("installTapOnBus threw: {e:?}"))?;
|
|
668
699
|
}
|
|
669
700
|
|
|
670
|
-
// Start the engine
|
|
671
|
-
//
|
|
672
|
-
|
|
673
|
-
// SAFETY: `prepare` and `startAndReturnError` are documented as the
|
|
674
|
-
// standard kick-off; they touch the audio HAL and may fail when the
|
|
675
|
-
// input device is in a weird state.
|
|
676
|
-
if let Err(err) = unsafe {
|
|
701
|
+
// Start the engine; if it fails tear down the tap so the next start
|
|
702
|
+
// doesn't see a stale tap on the input node.
|
|
703
|
+
objc2::exception::catch(std::panic::AssertUnwindSafe(|| unsafe {
|
|
677
704
|
engine.prepare();
|
|
678
705
|
engine.startAndReturnError()
|
|
679
|
-
}
|
|
680
|
-
|
|
706
|
+
}))
|
|
707
|
+
.map_err(|e| format!("AVAudioEngine start threw: {e:?}"))
|
|
708
|
+
.and_then(|r| {
|
|
709
|
+
r.map_err(|e| format!("AVAudioEngine start failed: {}", ns_error_message(&e)))
|
|
710
|
+
})
|
|
711
|
+
.map_err(|msg| {
|
|
681
712
|
unsafe { input_node.removeTapOnBus(0) };
|
|
682
|
-
|
|
683
|
-
}
|
|
713
|
+
msg
|
|
714
|
+
})?;
|
|
684
715
|
|
|
685
716
|
// Cancel + stop flags shared with the result handler.
|
|
686
717
|
let cancelled = Arc::new(AtomicBool::new(false));
|
|
@@ -689,41 +720,64 @@ pub(crate) mod macos {
|
|
|
689
720
|
// Build the result handler. SFSpeechRecognizer invokes this once
|
|
690
721
|
// per partial result and once with `isFinal=true` when the request
|
|
691
722
|
// ends.
|
|
692
|
-
let app_for_handler = app.clone();
|
|
693
|
-
let cancelled_for_handler = cancelled.clone();
|
|
694
|
-
let stopped_for_handler = stopped.clone();
|
|
695
723
|
// SAFETY: the block runs on the recognizer's queue (default = main).
|
|
696
724
|
// We capture clones of `AppHandle` (cheap, refcounted) and the two
|
|
697
725
|
// atomics. We never touch ObjC objects from outside their native
|
|
698
726
|
// lifetime — both `result` and `error` are passed in raw and we
|
|
699
727
|
// wrap them via `&*ptr` only after a null check.
|
|
700
|
-
let result_handler = RcBlock::new(
|
|
728
|
+
let result_handler = RcBlock::new({
|
|
729
|
+
let app = app.clone();
|
|
730
|
+
let cancelled = cancelled.clone();
|
|
731
|
+
let stopped = stopped.clone();
|
|
732
|
+
let locale = locale.clone();
|
|
733
|
+
let mic_device_id = mic_device_id.clone();
|
|
734
|
+
let mic_device_label = mic_device_label.clone();
|
|
701
735
|
move |result_ptr: *mut SFSpeechRecognitionResult, error_ptr: *mut NSError| {
|
|
702
|
-
let
|
|
703
|
-
let
|
|
736
|
+
let is_cancelled = cancelled.load(Ordering::SeqCst);
|
|
737
|
+
let is_stopped = stopped.load(Ordering::SeqCst);
|
|
704
738
|
// Error path: surface and clean up the slot.
|
|
705
739
|
if !error_ptr.is_null() && result_ptr.is_null() {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
740
|
+
let err = unsafe { &*error_ptr };
|
|
741
|
+
let msg = ns_error_message(err);
|
|
742
|
+
let transient = is_transient_recognizer_error(err);
|
|
743
|
+
eprintln!(
|
|
744
|
+
"[speech] recognizer ended with error (code {}, transient={transient}): {msg}",
|
|
745
|
+
err.code()
|
|
746
|
+
);
|
|
747
|
+
|
|
748
|
+
if !is_cancelled && !transient {
|
|
749
|
+
let _ = app.emit(
|
|
713
750
|
"voice:speech-error",
|
|
714
|
-
ErrorPayload {
|
|
715
|
-
error: msg,
|
|
716
|
-
source: "mic",
|
|
717
|
-
},
|
|
751
|
+
ErrorPayload { error: msg, source: "mic" },
|
|
718
752
|
);
|
|
719
753
|
}
|
|
720
754
|
clear_session_slot();
|
|
755
|
+
|
|
756
|
+
if !is_cancelled && !is_stopped && transient {
|
|
757
|
+
let gen = my_gen;
|
|
758
|
+
let app = app.clone();
|
|
759
|
+
let locale = locale.clone();
|
|
760
|
+
let mic_device_id = mic_device_id.clone();
|
|
761
|
+
let mic_device_label = mic_device_label.clone();
|
|
762
|
+
std::thread::spawn(move || {
|
|
763
|
+
std::thread::sleep(std::time::Duration::from_millis(300));
|
|
764
|
+
// A newer session was started during the wait — don't clobber it.
|
|
765
|
+
if session_generation().load(Ordering::SeqCst) != gen {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
if let Err(e) = native_speech_start_impl(
|
|
769
|
+
app.clone(), locale, mic_device_id, mic_device_label,
|
|
770
|
+
) {
|
|
771
|
+
let _ = app.emit(
|
|
772
|
+
"voice:speech-error",
|
|
773
|
+
ErrorPayload { error: e, source: "mic" },
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
});
|
|
777
|
+
}
|
|
721
778
|
return;
|
|
722
779
|
}
|
|
723
|
-
if result_ptr.is_null() {
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
if cancelled {
|
|
780
|
+
if result_ptr.is_null() || is_cancelled {
|
|
727
781
|
return;
|
|
728
782
|
}
|
|
729
783
|
// SAFETY: `result_ptr` was non-null per the check above; the
|
|
@@ -731,11 +785,9 @@ pub(crate) mod macos {
|
|
|
731
785
|
// this callback.
|
|
732
786
|
let result = unsafe { &*result_ptr };
|
|
733
787
|
let transcription = unsafe { result.bestTranscription() };
|
|
734
|
-
let
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
if is_final {
|
|
738
|
-
let _ = app_for_handler.emit(
|
|
788
|
+
let text = unsafe { transcription.formattedString() }.to_string();
|
|
789
|
+
if unsafe { result.isFinal() } {
|
|
790
|
+
let _ = app.emit(
|
|
739
791
|
"voice:final-transcript",
|
|
740
792
|
FinalPayload {
|
|
741
793
|
text,
|
|
@@ -743,8 +795,8 @@ pub(crate) mod macos {
|
|
|
743
795
|
},
|
|
744
796
|
);
|
|
745
797
|
clear_session_slot();
|
|
746
|
-
} else if !
|
|
747
|
-
let _ =
|
|
798
|
+
} else if !is_stopped {
|
|
799
|
+
let _ = app.emit(
|
|
748
800
|
"voice:partial-transcript",
|
|
749
801
|
PartialPayload {
|
|
750
802
|
text,
|
|
@@ -752,8 +804,8 @@ pub(crate) mod macos {
|
|
|
752
804
|
},
|
|
753
805
|
);
|
|
754
806
|
}
|
|
755
|
-
}
|
|
756
|
-
);
|
|
807
|
+
}
|
|
808
|
+
});
|
|
757
809
|
|
|
758
810
|
// Kick off the recognition task. This retains the request + handler
|
|
759
811
|
// and returns a task we can later cancel().
|
|
@@ -772,6 +824,7 @@ pub(crate) mod macos {
|
|
|
772
824
|
task,
|
|
773
825
|
cancelled,
|
|
774
826
|
stopped,
|
|
827
|
+
tap_installed: AtomicBool::new(true),
|
|
775
828
|
});
|
|
776
829
|
}
|
|
777
830
|
|
|
@@ -831,16 +884,9 @@ pub(crate) mod macos {
|
|
|
831
884
|
);
|
|
832
885
|
}
|
|
833
886
|
}
|
|
834
|
-
// Finalize VPIO format negotiation
|
|
835
|
-
unsafe { engine.prepare() }
|
|
836
|
-
|
|
837
|
-
let format = unsafe { input_node.outputFormatForBus(0) };
|
|
838
|
-
let sample_rate = unsafe { format.sampleRate() };
|
|
839
|
-
eprintln!(
|
|
840
|
-
"[whisper-mic] tap format after prepare: {} Hz, {} ch",
|
|
841
|
-
sample_rate as u32,
|
|
842
|
-
unsafe { format.channelCount() }
|
|
843
|
-
);
|
|
887
|
+
// Finalize VPIO format negotiation.
|
|
888
|
+
objc2::exception::catch(std::panic::AssertUnwindSafe(|| unsafe { engine.prepare() }))
|
|
889
|
+
.map_err(|e| format!("AVAudioEngine prepare threw: {e:?}"))?;
|
|
844
890
|
|
|
845
891
|
{
|
|
846
892
|
let on_samples = on_samples.clone();
|
|
@@ -877,14 +923,14 @@ pub(crate) mod macos {
|
|
|
877
923
|
dyn Fn(std::ptr::NonNull<AVAudioPCMBuffer>, std::ptr::NonNull<AVAudioTime>)
|
|
878
924
|
+ 'static,
|
|
879
925
|
> = (&*tap_block) as *const _ as *mut _;
|
|
880
|
-
unsafe {
|
|
926
|
+
objc2::exception::catch(std::panic::AssertUnwindSafe(|| unsafe {
|
|
881
927
|
input_node.installTapOnBus_bufferSize_format_block(
|
|
882
|
-
0,
|
|
883
|
-
|
|
884
|
-
Some(&format),
|
|
928
|
+
0, 1024,
|
|
929
|
+
None, // use hardware's current format — avoids SCO↔A2DP stale-format race
|
|
885
930
|
block_ptr,
|
|
886
931
|
);
|
|
887
|
-
}
|
|
932
|
+
}))
|
|
933
|
+
.map_err(|e| format!("installTapOnBus threw: {e:?}"))?;
|
|
888
934
|
}
|
|
889
935
|
|
|
890
936
|
if let Err(err) = unsafe { engine.startAndReturnError() } {
|
|
@@ -893,6 +939,17 @@ pub(crate) mod macos {
|
|
|
893
939
|
return Err(format!("AVAudioEngine start failed: {msg}"));
|
|
894
940
|
}
|
|
895
941
|
|
|
942
|
+
// Read the format only after the engine has started — at this point the
|
|
943
|
+
// engine has committed to its I/O configuration and the sample rate
|
|
944
|
+
// matches what the tap will actually deliver.
|
|
945
|
+
let format = unsafe { input_node.outputFormatForBus(0) };
|
|
946
|
+
let sample_rate = unsafe { format.sampleRate() };
|
|
947
|
+
eprintln!(
|
|
948
|
+
"[whisper-mic] tap format after start: {} Hz, {} ch",
|
|
949
|
+
sample_rate as u32,
|
|
950
|
+
unsafe { format.channelCount() }
|
|
951
|
+
);
|
|
952
|
+
|
|
896
953
|
// Disable other-audio ducking so the separately-captured system audio
|
|
897
954
|
// isn't dropped to near-silent while the mic VPIO runs.
|
|
898
955
|
unsafe {
|
|
@@ -917,7 +974,7 @@ pub(crate) mod macos {
|
|
|
917
974
|
})
|
|
918
975
|
}
|
|
919
976
|
|
|
920
|
-
pub
|
|
977
|
+
pub fn native_speech_stop_impl(_app: AppHandle) -> Result<(), String> {
|
|
921
978
|
// Take the session out so subsequent `stop()` calls are no-ops. We
|
|
922
979
|
// KEEP the recognition task running — calling `endAudio()` lets it
|
|
923
980
|
// deliver a final result via the handler, which then emits
|
|
@@ -949,7 +1006,7 @@ pub(crate) mod macos {
|
|
|
949
1006
|
Ok(())
|
|
950
1007
|
}
|
|
951
1008
|
|
|
952
|
-
pub
|
|
1009
|
+
pub fn native_speech_cancel_impl(_app: AppHandle) -> Result<(), String> {
|
|
953
1010
|
let session = {
|
|
954
1011
|
let mut slot = session_slot().lock().map_err(|e| e.to_string())?;
|
|
955
1012
|
slot.take()
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import fs from "fs";
|
|
1
2
|
import path from "path";
|
|
2
3
|
import { createRequire } from "module";
|
|
3
4
|
import { reactRouter } from "@react-router/dev/vite";
|
|
4
5
|
import { agentNative } from "@agent-native/core/vite";
|
|
5
|
-
import { defineConfig } from "vite";
|
|
6
|
+
import { defineConfig, type Plugin } from "vite";
|
|
6
7
|
|
|
7
8
|
const _require = createRequire(import.meta.url);
|
|
8
9
|
const ffmpegDir = path.resolve(
|
|
@@ -10,6 +11,41 @@ const ffmpegDir = path.resolve(
|
|
|
10
11
|
"../..",
|
|
11
12
|
);
|
|
12
13
|
|
|
14
|
+
// Self-host the MediaPipe WASM at /mediapipe/wasm by copying it out of the
|
|
15
|
+
// installed package at dev/build start, rather than committing ~21MB or loading
|
|
16
|
+
// from a CDN. Gitignored; the small model is vendored in public/mediapipe/.
|
|
17
|
+
const MEDIAPIPE_WASM_FILES = [
|
|
18
|
+
"vision_wasm_internal.js",
|
|
19
|
+
"vision_wasm_internal.wasm",
|
|
20
|
+
"vision_wasm_nosimd_internal.js",
|
|
21
|
+
"vision_wasm_nosimd_internal.wasm",
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
function copyMediapipeWasm(): Plugin {
|
|
25
|
+
return {
|
|
26
|
+
name: "clips-copy-mediapipe-wasm",
|
|
27
|
+
buildStart() {
|
|
28
|
+
try {
|
|
29
|
+
const wasmSrc = path.join(
|
|
30
|
+
path.dirname(_require.resolve("@mediapipe/tasks-vision")),
|
|
31
|
+
"wasm",
|
|
32
|
+
);
|
|
33
|
+
const wasmDest = path.resolve(
|
|
34
|
+
import.meta.dirname,
|
|
35
|
+
"public/mediapipe/wasm",
|
|
36
|
+
);
|
|
37
|
+
fs.mkdirSync(wasmDest, { recursive: true });
|
|
38
|
+
for (const file of MEDIAPIPE_WASM_FILES) {
|
|
39
|
+
fs.copyFileSync(path.join(wasmSrc, file), path.join(wasmDest, file));
|
|
40
|
+
}
|
|
41
|
+
} catch (err) {
|
|
42
|
+
// Don't fail the build — camera blur degrades to recording un-blurred.
|
|
43
|
+
this.warn(`could not copy MediaPipe WASM assets: ${err}`);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
13
49
|
export default defineConfig({
|
|
14
50
|
plugins: [
|
|
15
51
|
reactRouter(),
|
|
@@ -19,6 +55,7 @@ export default defineConfig({
|
|
|
19
55
|
ssrStubs: ["shiki"],
|
|
20
56
|
fsAllow: [ffmpegDir],
|
|
21
57
|
}),
|
|
58
|
+
copyMediapipeWasm(),
|
|
22
59
|
],
|
|
23
60
|
optimizeDeps: {
|
|
24
61
|
exclude: ["@ffmpeg/ffmpeg", "@ffmpeg/util"],
|
|
@@ -10,11 +10,14 @@ export { PROVIDER_TO_ENV };
|
|
|
10
10
|
/**
|
|
11
11
|
* Grace window + poll interval for the foreground circuit-breaker that confirms
|
|
12
12
|
* a background worker actually CLAIMED a 202-dispatched run before recovering
|
|
13
|
-
* inline. The grace
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* inline. The grace must cover the worker's cold-start + per-request init before
|
|
14
|
+
* it reaches `claimBackgroundRun`: light apps win the claim in ~1-2s, but heavy
|
|
15
|
+
* apps (e.g. analytics) were observed in prod taking >8s, so an 8s grace made
|
|
16
|
+
* their worker lose the race every time and always fall back to inline (adding
|
|
17
|
+
* ~8s latency with no background budget). 15s covers the slow apps while staying
|
|
18
|
+
* well within the foreground's ~40s soft-timeout.
|
|
16
19
|
*/
|
|
17
|
-
export declare const BACKGROUND_CLAIM_GRACE_MS =
|
|
20
|
+
export declare const BACKGROUND_CLAIM_GRACE_MS = 15000;
|
|
18
21
|
export declare const BACKGROUND_CLAIM_POLL_MS = 400;
|
|
19
22
|
export type BackgroundDispatchOutcome = {
|
|
20
23
|
action: "stream";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"production-agent.d.ts","sourceRoot":"","sources":["../../src/agent/production-agent.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,IAAI,cAAc,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,KAAK,EACV,UAAU,EAEV,mBAAmB,EAEnB,cAAc,EACd,kBAAkB,EAClB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,aAAa,EACb,iBAAiB,EAGlB,MAAM,mBAAmB,CAAC;AAmB3B,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAShE,OAAO,EAEL,cAAc,EACd,qBAAqB,EACrB,0BAA0B,EAC1B,MAAM,EACN,QAAQ,EAET,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AA+BlD,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,+BAA+B,CAAC;AAuBvC,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,iBAAiB,CAAC;AAsBzB,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B
|
|
1
|
+
{"version":3,"file":"production-agent.d.ts","sourceRoot":"","sources":["../../src/agent/production-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -41,11 +41,14 @@ export { PROVIDER_TO_ENV };
|
|
|
41
41
|
/**
|
|
42
42
|
* Grace window + poll interval for the foreground circuit-breaker that confirms
|
|
43
43
|
* a background worker actually CLAIMED a 202-dispatched run before recovering
|
|
44
|
-
* inline. The grace
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* inline. The grace must cover the worker's cold-start + per-request init before
|
|
45
|
+
* it reaches `claimBackgroundRun`: light apps win the claim in ~1-2s, but heavy
|
|
46
|
+
* apps (e.g. analytics) were observed in prod taking >8s, so an 8s grace made
|
|
47
|
+
* their worker lose the race every time and always fall back to inline (adding
|
|
48
|
+
* ~8s latency with no background budget). 15s covers the slow apps while staying
|
|
49
|
+
* well within the foreground's ~40s soft-timeout.
|
|
47
50
|
*/
|
|
48
|
-
export const BACKGROUND_CLAIM_GRACE_MS =
|
|
51
|
+
export const BACKGROUND_CLAIM_GRACE_MS = 15_000;
|
|
49
52
|
export const BACKGROUND_CLAIM_POLL_MS = 400;
|
|
50
53
|
/**
|
|
51
54
|
* Decide what the foreground should do after attempting a durable background
|